def add_transforms(self, path, transforms): """Define transforms for path. Each transform is an extended FTL node with `Transform` nodes as some values. Transforms are stored in their lazy AST form until `merge_changeset` is called, at which point they are evaluated to real FTL nodes with migrated translations. Each transform is scanned for `Source` nodes which will be used to build the list of dependencies for the transformed message. """ def get_sources(acc, cur): if isinstance(cur, Source): acc.add((cur.path, cur.key)) return acc for node in transforms: # Scan `node` for `Source` nodes and collect the information they # store into a set of dependencies. dependencies = fold(get_sources, node, set()) # Set these sources as dependencies for the current transform. self.dependencies[(path, node.id.name)] = dependencies path_transforms = self.transforms.setdefault(path, []) path_transforms += transforms
def add_transforms(self, target, reference, transforms): """Define transforms for target using reference as template. `target` is a path of the destination FTL file relative to the localization directory. `reference` is a path to the template FTL file relative to the reference directory. Each transform is an extended FTL node with `Transform` nodes as some values. Transforms are stored in their lazy AST form until `merge_changeset` is called, at which point they are evaluated to real FTL nodes with migrated translations. Each transform is scanned for `Source` nodes which will be used to build the list of dependencies for the transformed message. """ def get_sources(acc, cur): if isinstance(cur, Source): acc.add((cur.path, cur.key)) return acc reference_ast = self.read_reference_ftl(reference) self.reference_resources[target] = reference_ast for node in transforms: ident = node.id.name # Scan `node` for `Source` nodes and collect the information they # store into a set of dependencies. dependencies = fold(get_sources, node, set()) # Set these sources as dependencies for the current transform. self.dependencies[(target, ident)] = dependencies # The target Fluent message should exist in the reference file. If # it doesn't, it's probably a typo. if get_message(reference_ast.body, ident) is None: logger = logging.getLogger('migrate') logger.warn('{} "{}" was not found in {}'.format( type(node).__name__, ident, reference)) # Keep track of localization resource paths which were defined as # sources in the transforms. expected_paths = set() # Read all legacy translation files defined in Source transforms. This # may fail but a single missing legacy resource doesn't mean that the # migration can't succeed. for dependencies in self.dependencies.values(): for path in set(path for path, _ in dependencies): expected_paths.add(path) self.maybe_add_localization(path) # However, if all legacy resources are missing, bail out early. There # are no translations to migrate. We'd also get errors in hg annotate. if len(expected_paths) > 0 and len(self.localization_resources) == 0: error_message = 'No localization files were found' logging.getLogger('migrate').error(error_message) raise EmptyLocalizationError(error_message) # Add the current transforms to any other transforms added earlier for # this path. path_transforms = self.transforms.setdefault(target, []) path_transforms += transforms if target not in self.localization_resources: target_ast = self.read_localization_ftl(target) self.localization_resources[target] = target_ast
def add_transforms(self, target, reference, transforms): """Define transforms for target using reference as template. `target` is a path of the destination FTL file relative to the localization directory. `reference` is a path to the template FTL file relative to the reference directory. Each transform is an extended FTL node with `Transform` nodes as some values. Transforms are stored in their lazy AST form until `merge_changeset` is called, at which point they are evaluated to real FTL nodes with migrated translations. Each transform is scanned for `Source` nodes which will be used to build the list of dependencies for the transformed message. """ def get_sources(acc, cur): if isinstance(cur, Source): acc.add((cur.path, cur.key)) return acc refpath = os.path.join(self.reference_dir, reference) try: ast = self.read_ftl_resource(refpath) except IOError as err: error_message = 'Missing reference file: {}'.format(refpath) logging.getLogger('migrate').error(error_message) raise UnreadableReferenceError(error_message) except UnicodeDecodeError as err: error_message = 'Error reading file {}: {}'.format(refpath, err) logging.getLogger('migrate').error(error_message) raise UnreadableReferenceError(error_message) else: # The reference file will be used by the merge function as # a template for serializing the merge results. self.reference_resources[target] = ast for node in transforms: # Scan `node` for `Source` nodes and collect the information they # store into a set of dependencies. dependencies = fold(get_sources, node, set()) # Set these sources as dependencies for the current transform. self.dependencies[(target, node.id.name)] = dependencies # Read all legacy translation files defined in Source transforms. for path in set(path for path, _ in dependencies): self.maybe_add_localization(path) path_transforms = self.transforms.setdefault(target, []) path_transforms += transforms if target not in self.localization_resources: fullpath = os.path.join(self.localization_dir, target) try: ast = self.read_ftl_resource(fullpath) except IOError: logger = logging.getLogger('migrate') logger.info( 'Localization file {} does not exist and ' 'it will be created'.format(target)) except UnicodeDecodeError: logger = logging.getLogger('migrate') logger.warn( 'Localization file {} will be re-created and some ' 'translations might be lost'.format(target)) else: self.localization_resources[target] = ast