| #!/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 |