-
Notifications
You must be signed in to change notification settings - Fork 541
/
pip_compile.py
121 lines (109 loc) · 4.39 KB
/
pip_compile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"Set defaults for the pip-compile command to run it under Bazel"
import os
import sys
from shutil import copyfile
from piptools.scripts.compile import cli
if len(sys.argv) < 4:
print(
"Expected at least two arguments: requirements_in requirements_out",
file=sys.stderr,
)
sys.exit(1)
requirements_in = os.path.relpath(sys.argv.pop(1))
requirements_txt = os.path.relpath(sys.argv.pop(1))
parts = requirements_in.split(os.path.sep, 2)
if parts[0] == "external":
requirements_in = parts[2]
requirements_txt = requirements_txt if "BUILD_WORKSPACE_DIRECTORY" in os.environ else os.path.join("..", "..", requirements_txt)
os.chdir(os.path.join(parts[0], parts[1]))
update_target_label = sys.argv.pop(1)
# Before loading click, set the locale for its parser.
# If it leaks through to the system setting, it may fail:
# RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII
# as encoding for the environment. Consult https://click.palletsprojects.com/python3/ for
# mitigation steps.
os.environ["LC_ALL"] = "C.UTF-8"
os.environ["LANG"] = "C.UTF-8"
UPDATE = True
# Detect if we are running under `bazel test`
if "TEST_TMPDIR" in os.environ:
UPDATE = False
# pip-compile wants the cache files to be writeable, but if we point
# 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"])
# Make a copy for pip-compile to read and mutate
requirements_out = os.path.join(
os.environ["TEST_TMPDIR"], os.path.basename(requirements_txt) + ".out"
)
copyfile(requirements_txt, requirements_out)
elif "BUILD_WORKSPACE_DIRECTORY" in os.environ:
# This value, populated when running under `bazel run`, is a path to the
# "root of the workspace where the build was run."
# This matches up with the values passed in via the macro using the 'rootpath' Make variable,
# which for source files provides a path "relative to your workspace root."
#
# Changing to the WORKSPACE root avoids 'file not found' errors when the `.update` target is run
# from different directories within the WORKSPACE.
requirements_txt = os.path.join(os.environ["BUILD_WORKSPACE_DIRECTORY"], requirements_txt)
else:
err_msg = (
"Expected to find BUILD_WORKSPACE_DIRECTORY (running under `bazel run`) or "
"TEST_TMPDIR (running under `bazel test`) in environment."
)
print(
err_msg,
file=sys.stderr,
)
sys.exit(1)
update_target_pkg = "/".join(requirements_in.split("/")[:-1])
# $(rootpath) in the workspace root gives ./requirements.in
if update_target_pkg == ".":
update_target_pkg = ""
update_command = os.getenv("CUSTOM_COMPILE_COMMAND") or "bazel run %s" % (
update_target_label,
)
os.environ["CUSTOM_COMPILE_COMMAND"] = update_command
os.environ["PIP_CONFIG_FILE"] = os.getenv("PIP_CONFIG_FILE") or os.devnull
sys.argv.append("--generate-hashes")
sys.argv.append("--output-file")
sys.argv.append(requirements_txt if UPDATE else requirements_out)
sys.argv.append(requirements_in)
if UPDATE:
print("Updating " + requirements_txt)
cli()
else:
# cli will exit(0) on success
try:
print("Checking " + requirements_txt)
cli()
print("cli() should exit", file=sys.stderr)
sys.exit(1)
except SystemExit as e:
if e.code == 2:
print(
"pip-compile exited with code 2. This means that pip-compile found "
"incompatible requirements or could not find a version that matches "
f"the install requirement in {requirements_in}.",
file=sys.stderr,
)
sys.exit(1)
elif e.code == 0:
golden = open(requirements_txt).readlines()
out = open(requirements_out).readlines()
if golden != out:
import difflib
print("".join(difflib.unified_diff(golden, out)), file=sys.stderr)
print(
"Lock file out of date. Run '" + update_command + "' to update.",
file=sys.stderr,
)
sys.exit(1)
sys.exit(0)
else:
print(
f"pip-compile unexpectedly exited with code {e.code}.", file=sys.stderr
)
sys.exit(1)