def PatchMojomAst(mojom_abspath, ast, enabled_features): """Search for mojom file in 'chromium_src' and apply AST changes. Can add imports, enums, interfaces, structs, unions. Can extend enum values, interface members, struct fields, union members. To be more strict with patching, attributes [BraveAdd] or [BraveExtend] should be used. """ # Get this script absolute location. this_py_path = os.path.realpath(__file__) # Get the original chromium dir location. chromium_original_dir = os.path.abspath(os.path.join(this_py_path, *[os.pardir] * 10)) if len(chromium_original_dir) >= len(mojom_abspath) + 1: raise RuntimeError("Could not get original chromium src dir") # Build brave/chromium_src path. chromium_src_abspath = os.path.join(chromium_original_dir, 'brave', 'chromium_src') if not os.path.isdir(chromium_src_abspath): raise RuntimeError("Could not find brave/chromium_src. %s is not a dir" % chromium_src_abspath) # Relative path. mojom_relpath = mojom_abspath[len(chromium_original_dir) + 1:] # Build possible brave/chromium_src/**/*.mojom path. brave_mojom_abspath = os.path.join(chromium_src_abspath, mojom_relpath) if not os.path.isfile(brave_mojom_abspath): # Nothing to patch. return # Open and parse brave/chromium_src/**/*.mojom file. with codecs.open(brave_mojom_abspath, encoding='utf-8') as f: brave_ast = parser.Parse(f.read(), brave_mojom_abspath) conditional_features.RemoveDisabledDefinitions(brave_ast, enabled_features) _ApplyBraveAstChanges(brave_ast, ast)
def _ParseMojoms(mojom_files, input_root_paths, output_root_path, enabled_features, allowed_imports=None): """Parses a set of mojom files and produces serialized module outputs. Args: mojom_files: A list of mojom files to process. Paths must be absolute paths which fall within one of the input or output root paths. input_root_paths: A list of absolute filesystem paths which may be used to resolve relative mojom file paths. output_root_path: An absolute filesystem path which will service as the root for all emitted artifacts. Artifacts produced from a given mojom file are based on the mojom's relative path, rebased onto this path. Additionally, the script expects this root to contain already-generated modules for any transitive dependencies not listed in mojom_files. enabled_features: A list of enabled feature names, controlling which AST nodes are filtered by [EnableIf] attributes. Returns: None. Upon completion, a mojom-module file will be saved for each input mojom. """ assert input_root_paths assert output_root_path loaded_mojom_asts = {} loaded_modules = {} input_dependencies = defaultdict(set) mojom_files_to_parse = dict((abs_path, _RebaseAbsolutePath(abs_path, input_root_paths)) for abs_path in mojom_files) abs_paths = dict( (path, abs_path) for abs_path, path in mojom_files_to_parse.items()) for mojom_abspath, _ in mojom_files_to_parse.items(): with open(mojom_abspath) as f: ast = parser.Parse(''.join(f.readlines()), mojom_abspath) conditional_features.RemoveDisabledDefinitions(ast, enabled_features) loaded_mojom_asts[mojom_abspath] = ast invalid_imports = [] for imp in ast.import_list: import_abspath = _ResolveRelativeImportPath(imp.import_filename, input_root_paths) if allowed_imports and import_abspath not in allowed_imports: invalid_imports.append(imp.import_filename) abs_paths[imp.import_filename] = import_abspath if import_abspath in mojom_files_to_parse: # This import is in the input list, so we're going to translate it # into a module below; however it's also a dependency of another input # module. We retain record of dependencies to help with input # processing later. input_dependencies[mojom_abspath].add((import_abspath, imp.import_filename)) else: # We have an import that isn't being parsed right now. It must already # be parsed and have a module file sitting in a corresponding output # location. module_path = _GetModuleFilename(imp.import_filename) module_abspath = _ResolveRelativeImportPath(module_path, [output_root_path]) with open(module_abspath, 'rb') as module_file: loaded_modules[import_abspath] = module.Module.Load(module_file) if invalid_imports: raise ValueError( '\nThe file %s imports the following files not allowed by build ' 'dependencies:\n\n%s\n' % (mojom_abspath, '\n'.join(invalid_imports))) # At this point all transitive imports not listed as inputs have been loaded # and we have a complete dependency tree of the unprocessed inputs. Now we can # load all the inputs, resolving dependencies among them recursively as we go. num_existing_modules_loaded = len(loaded_modules) for mojom_abspath, mojom_path in mojom_files_to_parse.items(): _EnsureInputLoaded(mojom_abspath, mojom_path, abs_paths, loaded_mojom_asts, input_dependencies, loaded_modules) assert (num_existing_modules_loaded + len(mojom_files_to_parse) == len(loaded_modules)) # Now we have fully translated modules for every input and every transitive # dependency. We can dump the modules to disk for other tools to use. for mojom_abspath, mojom_path in mojom_files_to_parse.items(): module_path = os.path.join(output_root_path, _GetModuleFilename(mojom_path)) module_dir = os.path.dirname(module_path) if not os.path.exists(module_dir): try: # Python 2 doesn't support exist_ok on makedirs(), so we just ignore # that failure if it happens. It's possible during build due to races # among build steps with module outputs in the same directory. os.makedirs(module_dir) except OSError as e: if e.errno != errno.EEXIST: raise with open(module_path, 'wb') as f: loaded_modules[mojom_abspath].Dump(f)
def parseAndAssertEqual(self, source, expected_source): definition = parser.Parse(source, "my_file.mojom") conditional_features.RemoveDisabledDefinitions(definition, ENABLED_FEATURES) expected = parser.Parse(expected_source, "my_file.mojom") self.assertEquals(definition, expected)
def _ParseAstHelper(args): mojom_abspath, enabled_features = args with codecs.open(mojom_abspath, encoding='utf-8') as f: ast = parser.Parse(f.read(), mojom_abspath) conditional_features.RemoveDisabledDefinitions(ast, enabled_features) return mojom_abspath, ast