# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. from mach.decorators import Command, CommandArgument LICENSE_HEADER = """# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """ GENERATED_HEADER = """ ### This file was AUTOMATICALLY GENERATED by `./mach update-glean-tags` ### DO NOT edit it by hand. """ @Command( "data-review", category="misc", description="Generate a skeleton data review request form for a given bug's data", ) @CommandArgument( "bug", default=None, nargs="?", type=str, help="bug number or search pattern" ) def data_review(command_context, bug=None): # Get the metrics_index's list of metrics indices # by loading the index as a module. import sys from os import path sys.path.append(path.join(path.dirname(__file__), path.pardir)) from pathlib import Path from glean_parser import data_review from metrics_index import metrics_yamls return data_review.generate( bug, [Path(command_context.topsrcdir) / x for x in metrics_yamls] ) @Command( "perf-data-review", category="misc", description="Generate a skeleton performance data review request form for a given bug's data", ) @CommandArgument( "bug", default=None, nargs="?", type=str, help="bug number or search pattern" ) def perf_data_review(command_context, bug=None): # Get the metrics_index's list of metrics indices # by loading the index as a module. import sys from os import path sys.path.append(path.join(path.dirname(__file__), path.pardir)) from metrics_index import metrics_yamls sys.path.append(path.dirname(__file__)) from pathlib import Path import perf_data_review return perf_data_review.generate( bug, [Path(command_context.topsrcdir) / x for x in metrics_yamls] ) @Command( "update-glean-tags", category="misc", description=( "Creates a list of valid glean tags based on in-tree bugzilla component definitions" ), ) def update_glean_tags(command_context): from pathlib import Path import yaml from mozbuild.backend.configenvironment import ConfigEnvironment from mozbuild.frontend.reader import BuildReader config = ConfigEnvironment( command_context.topsrcdir, command_context.topobjdir, defines=command_context.defines, substs=command_context.substs, ) reader = BuildReader(config) bug_components = set() for p in reader.read_topsrcdir(): if p.get("BUG_COMPONENT"): bug_components.add(p["BUG_COMPONENT"]) tags_filename = (Path(__file__).parent / "../tags.yaml").resolve() tags = {"$schema": "moz://mozilla.org/schemas/glean/tags/1-0-0"} for bug_component in bug_components: product = bug_component.product.strip() component = bug_component.component.strip() tags["{} :: {}".format(product, component)] = { "description": "The Bugzilla component which applies to this object." } open(tags_filename, "w").write( "{}\n{}\n\n".format(LICENSE_HEADER, GENERATED_HEADER) + yaml.dump(tags, width=78, explicit_start=True) ) def replace_in_file(path, pattern, replace): """ Replace `pattern` with `replace` in the file `path`. The file is modified on disk. Returns `True` if exactly one replacement happened. `False` otherwise. """ import re with open(path, "r+") as file: data = file.read() data, subs_made = re.subn(pattern, replace, data, flags=re.MULTILINE) file.seek(0) file.write(data) file.truncate() if subs_made != 1: return False return True def replace_in_file_or_die(path, pattern, replace): """ Replace `pattern` with `replace` in the file `path`. The file is modified on disk. If not exactly one occurrence of `pattern` was replaced it will exit with exit code 1. """ import sys success = replace_in_file(path, pattern, replace) if not success: print(f"ERROR: Failed to replace one occurrence in {path}") print(f" Pattern: {pattern}") print(f" Replace: {replace}") print("File was modified. Check the diff.") sys.exit(1) @Command( "update-glean", category="misc", description="Update Glean to the given version", ) @CommandArgument("version", help="Glean version to upgrade to") def update_glean(command_context, version): import textwrap from pathlib import Path topsrcdir = Path(command_context.topsrcdir) replace_in_file_or_die( topsrcdir / "build.gradle", r'gleanVersion = "[0-9.]+"', f'gleanVersion = "{version}"', ) replace_in_file_or_die( topsrcdir / "toolkit" / "components" / "glean" / "Cargo.toml", r'^glean = "[0-9.]+"', f'glean = "{version}"', ) replace_in_file_or_die( topsrcdir / "toolkit" / "components" / "glean" / "api" / "Cargo.toml", r'^glean = "[0-9.]+"', f'glean = "{version}"', ) replace_in_file_or_die( topsrcdir / "gfx" / "wr" / "webrender" / "Cargo.toml", r'^glean = { version = "[0-9.]+"(.+)}', f'glean = {{ version = "{version}"\\1}}', ) replace_in_file_or_die( topsrcdir / "gfx" / "wr" / "wr_glyph_rasterizer" / "Cargo.toml", r'^glean = { version = "[0-9.]+"(.+)}', f'glean = {{ version = "{version}"\\1}}', ) replace_in_file_or_die( topsrcdir / "python" / "sites" / "mach.txt", r"glean-sdk==[0-9.]+", f"glean-sdk=={version}", ) instructions = f""" We've edited the necessary files to require Glean SDK {version}. To ensure Glean and Firefox's other Rust dependencies are appropriately vendored, please run the following commands: cargo update -p glean ./mach vendor rust --ignore-modified `./mach vendor rust` may identify version mismatches. Please consult the Updating the Glean SDK docs for assistance: https://firefox-source-docs.mozilla.org/toolkit/components/glean/dev/updating_sdk.html The Glean SDK is already vetted and no additional vetting for it is necessary. To prune the configuration file after vendoring run: ./mach cargo vet prune Then, to update webrender which independently relies on the Glean SDK, run: cd gfx/wr cargo update -p glean Then, to ensure all is well, build Firefox and run the FOG tests. Instructions can be found here: https://firefox-source-docs.mozilla.org/toolkit/components/glean/dev/testing.html """ print(textwrap.dedent(instructions))