| #!/usr/bin/env python3 |
| # |
| # Copyright 2021 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # pylint: disable=invalid-name |
| # pylint: disable=line-too-long |
| # pylint: disable=missing-function-docstring |
| """An interactive script to add modules into a Bazel registry. |
| |
| What this script can do: |
| - Initialize the Bazel Registry. |
| - Generate/update the metadata.json for a module. |
| - Add specified MODULE.bazel |
| - Generate MODULE.bazel file with given module information |
| - module name |
| - version |
| - compatibility level |
| - dependencies |
| - Generate the source.json file with given source information |
| - The archive url |
| - patch files |
| - Add specified BUILD file for non-Bazel project by turning it into a patch. |
| - Add specified presubmit.yml file. |
| - Generate presubmit.yml file by given build & test targets. |
| |
| """ |
| |
| import argparse |
| import os |
| import sys |
| import time |
| |
| from registry import Module |
| from registry import RegistryClient |
| from registry import log |
| |
| import bcr_validation |
| |
| |
| YELLOW = "\x1b[33m" |
| RESET = "\x1b[0m" |
| |
| |
| def yes_or_no(question, default): |
| if default: |
| question += " [Y/n]: " |
| else: |
| question += " [y/N]: " |
| |
| var = None |
| while var is None: |
| user_input = ask_input(question).strip().lower() |
| if user_input == "y": |
| var = True |
| elif user_input == "n": |
| var = False |
| elif not user_input: |
| var = default |
| else: |
| print("Invalid selection: {}".format(user_input)) |
| return var |
| |
| |
| def ask_input(msg): |
| return input(f"{YELLOW}ACTION: {RESET}{msg}") |
| |
| |
| def from_user_input(): |
| name = ask_input("Please enter the module name: ") |
| version = ask_input("Please enter the module version: ") |
| compatibility = ask_input("Please enter the compatibility level [default is 0]: ") or "0" |
| module = Module(name, version, compatibility) |
| |
| url = ask_input("Please enter the URL of the source archive: ") |
| strip_prefix = ask_input("Please enter the strip_prefix value of the archive [default None]: ") or None |
| module.set_source(url, strip_prefix) |
| |
| if yes_or_no("Do you want to add patch files?", False): |
| patches = ask_input("Please enter patch file paths, separated by `,`: ") |
| for patch in patches.strip().split(","): |
| module.add_patch(patch.strip()) |
| patch_strip = ( |
| ask_input("Please enter the patch strip number [Default is 1, compatible with git generated " "patches]: ") |
| or "1" |
| ) |
| module.set_patch_strip(int(patch_strip.strip())) |
| |
| if yes_or_no("Do you want to add a BUILD file?", False): |
| build_file = ask_input("Please enter the path of the BUILD file to be added: ") |
| module.set_build_file(build_file.strip()) |
| |
| if yes_or_no("Do you want to specify a MODULE.bazel file?", False): |
| path = ask_input("Please enter the MODULE.bazel file path: ").strip() |
| module.set_module_dot_bazel(path) |
| else: |
| if yes_or_no("Do you want to specify dependencies for this module?", False): |
| deps = ask_input("Please enter dependencies in the form of <name>@<version>, separated by `,`: ") |
| for dep in deps.strip().split(","): |
| name, version = dep.split("@") |
| module.add_dep(name, version) |
| |
| presubmit_url = "https://github.com/bazelbuild/bazel-central-registry/tree/main/docs#presubmit" |
| if yes_or_no(f"Do you want to specify an existing presubmit.yml file? (See {presubmit_url})", False): |
| path = ask_input("Please enter the presubmit.yml file path: ").strip() |
| module.set_presubmit_yml(path) |
| else: |
| first = True |
| while not module.build_targets: |
| if not first: |
| print("Build targets cannot be empty, please re-enter!") |
| first = False |
| build_targets = ask_input( |
| "Please enter a list of build targets you want to expose to downstream users, separated by `,`: " |
| ) |
| for target in build_targets.strip().split(","): |
| if target: |
| module.add_build_target(target) |
| |
| if yes_or_no("Do you have a test module in your source archive?", True): |
| module.test_module_path = ask_input("Please enter the test module path in your source archive: ") |
| first = True |
| while not (module.test_module_build_targets or module.test_module_test_targets): |
| if not first: |
| print("Build targets and test targets cannot both be empty, please re-enter!") |
| first = False |
| build_targets = ask_input( |
| "Please enter a list of build targets for the test module, separated by `,`: " |
| ) |
| for target in build_targets.strip().split(","): |
| if target: |
| module.add_test_module_build_target(target) |
| test_targets = ask_input("Please enter a list of test targets for the test module, separated by `,`: ") |
| for target in test_targets.strip().split(","): |
| if target: |
| module.add_test_module_test_target(target) |
| return module |
| |
| |
| def get_maintainers_from_input(): |
| maintainers = [] |
| prefix = "a" |
| explain = ( |
| " (See https://github.com/bazelbuild/bazel-central-registry/tree/main" |
| "/docs/bcr-policies.md#become-a-module-maintainer)" |
| ) |
| while yes_or_no(f"Do you want to add {prefix} maintainer for this module?{explain}", False): |
| maintainer = {} |
| name = ask_input("Please enter maintainer name: ") |
| maintainer["name"] = name |
| email = ask_input("Please enter the maintainer's email address: ") |
| maintainer["email"] = email |
| username = ask_input("(Optional) Please enter the maintainer's github username: ") |
| if username: |
| maintainer["github"] = username |
| maintainers.append(maintainer) |
| prefix = "another" |
| explain = "" |
| return maintainers |
| |
| |
| def main(argv=None): |
| if argv is None: |
| argv = sys.argv[1:] |
| |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--registry", |
| type=str, |
| default=".", |
| help="Specify the root path of the registry (default: the current working directory).", |
| ) |
| parser.add_argument( |
| "--input", |
| type=str, |
| help="Take module information from a json file, which can be generated from previous input.", |
| ) |
| |
| args = parser.parse_args(argv) |
| |
| if args.input: |
| log(f"Getting module information from {args.input}...") |
| module = Module() |
| module.from_json(args.input) |
| else: |
| log("Getting module information from user input...") |
| module = from_user_input() |
| timestamp = time.strftime("%Y%m%d-%H%M%S") |
| log(f"Saving module information to {module.name}.{timestamp}.json") |
| log(f"You can use it via --input={module.name}.{timestamp}.json") |
| module.dump(f"{module.name}.{timestamp}.json") |
| |
| client = RegistryClient(args.registry) |
| |
| if not client.contains(module.name): |
| log(f"{module.name} is a new Bazel module...") |
| homepage = ask_input("Please enter the homepage url for this module: ").strip() |
| maintainers = get_maintainers_from_input() |
| source_repository = "" |
| if module.url.startswith("https://github.com/"): |
| parts = module.url.split("/") |
| source_repository = "github:" + parts[3] + "/" + parts[4] |
| client.init_module(module.name, maintainers, homepage, source_repository) |
| |
| client.add(module, override=True) |
| log(f"{module.name} {module.version} is added into the registry.") |
| |
| log(f"Running ./tools/bcr_validation.py --check={module.name}@{module.version} --fix") |
| bcr_validation.main([f"--check={module.name}@{module.version}", "--fix"]) |
| |
| |
| if __name__ == "__main__": |
| # Under 'bazel run' we want to run within the source folder instead of the execroot. |
| if os.getenv("BUILD_WORKSPACE_DIRECTORY"): |
| os.chdir(os.getenv("BUILD_WORKSPACE_DIRECTORY")) |
| sys.exit(main()) |