refactor: use click in dependency_resolver.py (#1071)
Using click makes it easier to parse arguments. Many args are now named
arguments
(options), and the need for using positional args with stub `"None"`
values isn't
necessary anymore.
There is already a dependency on click via piptools, so this doesn't
introduce a new
dependency.
Relates to #1067
Co-authored-by: Logan Pulley <lpulley@ocient.com>
diff --git a/python/pip_install/requirements.bzl b/python/pip_install/requirements.bzl
index a487181..3935add 100644
--- a/python/pip_install/requirements.bzl
+++ b/python/pip_install/requirements.bzl
@@ -85,14 +85,19 @@
args = [
loc.format(requirements_in),
loc.format(requirements_txt),
- # String None is a placeholder for argv ordering.
- loc.format(requirements_linux) if requirements_linux else "None",
- loc.format(requirements_darwin) if requirements_darwin else "None",
- loc.format(requirements_windows) if requirements_windows else "None",
"//%s:%s.update" % (native.package_name(), name),
"--resolver=backtracking",
"--allow-unsafe",
- ] + (["--generate-hashes"] if generate_hashes else []) + extra_args
+ ]
+ if generate_hashes:
+ args.append("--generate-hashes")
+ if requirements_linux:
+ args.append("--requirements-linux={}".format(loc.format(requirements_linux)))
+ if requirements_darwin:
+ args.append("--requirements-darwin={}".format(loc.format(requirements_darwin)))
+ if requirements_windows:
+ args.append("--requirements-windows={}".format(loc.format(requirements_windows)))
+ args.extend(extra_args)
deps = [
requirement("build"),
diff --git a/python/pip_install/tools/dependency_resolver/dependency_resolver.py b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
index e277cf9..5e914bc 100644
--- a/python/pip_install/tools/dependency_resolver/dependency_resolver.py
+++ b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
@@ -19,7 +19,9 @@
import shutil
import sys
from pathlib import Path
+from typing import Optional, Tuple
+import click
import piptools.writer as piptools_writer
from piptools.scripts.compile import cli
@@ -77,24 +79,25 @@
return bazel_runfiles.Rlocation(file)
-if __name__ == "__main__":
- if len(sys.argv) < 4:
- print(
- "Expected at least two arguments: requirements_in requirements_out",
- file=sys.stderr,
- )
- sys.exit(1)
-
- parse_str_none = lambda s: None if s == "None" else s
+@click.command(context_settings={"ignore_unknown_options": True})
+@click.argument("requirements_in")
+@click.argument("requirements_txt")
+@click.argument("update_target_label")
+@click.option("--requirements-linux")
+@click.option("--requirements-darwin")
+@click.option("--requirements-windows")
+@click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
+def main(
+ requirements_in: str,
+ requirements_txt: str,
+ update_target_label: str,
+ requirements_linux: Optional[str],
+ requirements_darwin: Optional[str],
+ requirements_windows: Optional[str],
+ extra_args: Tuple[str, ...],
+) -> None:
bazel_runfiles = runfiles.Create()
- requirements_in = sys.argv.pop(1)
- requirements_txt = sys.argv.pop(1)
- requirements_linux = parse_str_none(sys.argv.pop(1))
- requirements_darwin = parse_str_none(sys.argv.pop(1))
- requirements_windows = parse_str_none(sys.argv.pop(1))
- update_target_label = sys.argv.pop(1)
-
requirements_file = _select_golden_requirements_file(
requirements_txt=requirements_txt, requirements_linux=requirements_linux,
requirements_darwin=requirements_darwin, requirements_windows=requirements_windows
@@ -128,6 +131,8 @@
os.environ["LC_ALL"] = "C.UTF-8"
os.environ["LANG"] = "C.UTF-8"
+ argv = []
+
UPDATE = True
# Detect if we are running under `bazel test`.
if "TEST_TMPDIR" in os.environ:
@@ -136,8 +141,7 @@
# to the real user cache, Bazel sandboxing makes the file read-only
# and we fail.
# In theory this makes the test more hermetic as well.
- sys.argv.append("--cache-dir")
- sys.argv.append(os.environ["TEST_TMPDIR"])
+ argv.append(f"--cache-dir={os.environ['TEST_TMPDIR']}")
# Make a copy for pip-compile to read and mutate.
requirements_out = os.path.join(
os.environ["TEST_TMPDIR"], os.path.basename(requirements_file) + ".out"
@@ -153,14 +157,13 @@
os.environ["CUSTOM_COMPILE_COMMAND"] = update_command
os.environ["PIP_CONFIG_FILE"] = os.getenv("PIP_CONFIG_FILE") or os.devnull
- sys.argv.append("--output-file")
- sys.argv.append(requirements_file_relative if UPDATE else requirements_out)
- sys.argv.append(
+ argv.append(f"--output-file={requirements_file_relative if UPDATE else requirements_out}")
+ argv.append(
requirements_in_relative
if Path(requirements_in_relative).exists()
else resolved_requirements_in
)
- print(sys.argv)
+ argv.extend(extra_args)
if UPDATE:
print("Updating " + requirements_file_relative)
@@ -176,7 +179,7 @@
resolved_requirements_file, requirements_file_tree
)
)
- cli()
+ cli(argv)
requirements_file_relative_path = Path(requirements_file_relative)
content = requirements_file_relative_path.read_text()
content = content.replace(absolute_path_prefix, "")
@@ -185,7 +188,7 @@
# cli will exit(0) on success
try:
print("Checking " + requirements_file)
- cli()
+ cli(argv)
print("cli() should exit", file=sys.stderr)
sys.exit(1)
except SystemExit as e:
@@ -219,3 +222,7 @@
file=sys.stderr,
)
sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()