| #!/usr/bin/env python3 |
| # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| # for details. All rights reserved. Use of this source code is governed by a |
| # BSD-style license that can be found in the LICENSE file. |
| """Templating to help generate structured text.""" |
| |
| import os |
| import sys |
| import subprocess |
| import time |
| import emitter |
| import logging |
| |
| _logger = logging.getLogger('multiemitter') |
| |
| |
| class MultiEmitter(object): |
| """A set of Emitters that write to different files. |
| |
| Each entry has a key. |
| |
| file --> emitter |
| key --> emitter |
| |
| """ |
| |
| def __init__(self, logging_level=logging.WARNING): |
| self._key_to_emitter = {} # key -> Emitter |
| self._filename_to_emitter = {} # filename -> Emitter |
| |
| _logger.setLevel(logging_level) |
| |
| def FileEmitter(self, filename, key=None): |
| """Creates an emitter for writing to a file. |
| |
| When this MultiEmitter is flushed, the contents of the emitter are written |
| to the file. |
| |
| Arguments: |
| filename: a string, the path name of the file |
| key: provides an access key to retrieve the emitter. |
| |
| Returns: the emitter. |
| """ |
| e = emitter.Emitter() |
| self._filename_to_emitter[filename] = e |
| if key: |
| self.Associate(key, e) |
| return e |
| |
| def Associate(self, key, emitter): |
| """Associates a key with an emitter.""" |
| self._key_to_emitter[key] = emitter |
| |
| def Find(self, key): |
| """Returns the emitter associated with |key|.""" |
| return self._key_to_emitter[key] |
| |
| def Flush(self, writer=None): |
| """Writes all pending files. |
| |
| Arguments: |
| writer: a function called for each file and it's lines. |
| """ |
| if not writer: |
| writer = _WriteFile |
| for file in sorted(self._filename_to_emitter.keys()): |
| emitter = self._filename_to_emitter[file] |
| writer(file, emitter.Fragments()) |
| |
| |
| def _WriteFile(path, lines): |
| (dir, file) = os.path.split(path) |
| |
| # Ensure dir exists. |
| if dir: |
| if not os.path.isdir(dir): |
| _logger.info('Mkdir - %s' % dir) |
| os.makedirs(dir) |
| |
| # If file exists and is unchanged, return. |
| new_contents = ''.join(lines) |
| if os.path.exists(path): |
| with open(path) as fd: |
| contents = fd.read() |
| if new_contents == contents: |
| _logger.info('Unchanged file %s' % path) |
| return |
| |
| # Write the file. |
| num_attempts = 4 |
| for i in range(num_attempts): |
| try: |
| _logger.info('Writing (attempt %d) - %s' % (i + 1, path)) |
| with open(path, 'w') as fd: |
| fd.write(new_contents) |
| return |
| except IOError as error: |
| last_attempt = (i == (num_attempts - 1)) |
| if not last_attempt: |
| # Sleep for 50 ms and try again |
| time.sleep(0.05) |
| else: |
| _logger.info('Got exception (%s) ' % error) |
| raise error |