Skip to content

Commit 5705c72

Browse files
committed
wip
1 parent 44eec0b commit 5705c72

File tree

3 files changed

+43
-67
lines changed

3 files changed

+43
-67
lines changed

docs/BUILD.bazel

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ lock(
171171
out = "requirements.txt",
172172
args = [
173173
"--universal",
174+
],
175+
run_args = [
174176
"--upgrade",
175177
],
176178
visibility = ["//private:__pkg__"],

python/uv/private/lock.bzl

+34-62
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,18 @@ def _lock_impl(ctx):
4343
])
4444
args.add("--output-file", ctx.outputs.out)
4545
args.add_all(ctx.files.srcs)
46+
args.add_all(["--custom-compile-command", "bazel run //{}:{}.update".format(
47+
ctx.label.package,
48+
ctx.label.name,
49+
)])
50+
args.add_all([
51+
"--no-python-downloads",
52+
"--no-cache",
53+
])
54+
args.add_all(ctx.attr.args)
4655

4756
# We use a manual param file so that we can forward it to the debug executable rule
48-
param_file = ctx.actions.declare_file(ctx.label.name + ".params.txt")
57+
param_file = ctx.actions.declare_file(ctx.label.name + ".params")
4958
ctx.actions.write(
5059
output = param_file,
5160
content = args,
@@ -54,13 +63,14 @@ def _lock_impl(ctx):
5463
run_args = [param_file.path]
5564
args = ctx.actions.args()
5665
args.add_all(run_args)
66+
args.add_all(ctx.attr.run_args)
5767

58-
cmd = ctx.executable.cmd
68+
cmd = ctx.executable._cmd
5969

6070
srcs = ctx.files.srcs + ctx.files.maybe_out + [param_file]
6171
ctx.actions.run(
62-
executable = ctx.executable.cmd,
63-
mnemonic = "RulesPythonLock",
72+
executable = cmd,
73+
mnemonic = "RulesPythonUvPipCompile",
6474
inputs = srcs,
6575
outputs = [ctx.outputs.out],
6676
arguments = [args],
@@ -74,9 +84,9 @@ def _lock_impl(ctx):
7484
files = depset([ctx.outputs.out]),
7585
),
7686
_LockRunInfo(
77-
cmd = ctx.attr.cmd,
78-
cmd_file = ctx.executable.cmd,
79-
args = run_args,
87+
cmd = ctx.attr._cmd,
88+
cmd_file = cmd,
89+
args = param_file,
8090
srcs = srcs,
8191
),
8292
]
@@ -87,20 +97,27 @@ _lock = rule(
8797
""",
8898
attrs = {
8999
"args": attr.string_list(),
90-
"cmd": attr.label(
91-
mandatory = True,
92-
executable = True,
93-
cfg = "target",
94-
),
95100
"env": attr.string_dict(),
96101
"maybe_out": attr.label(allow_single_file = True),
97102
"out": attr.output(mandatory = True),
103+
"run_args": attr.string_list(),
98104
"srcs": attr.label_list(mandatory = True, allow_files = True),
105+
"_cmd": attr.label(
106+
default = "//python/uv/private:pip_compile",
107+
executable = True,
108+
cfg = "target",
109+
),
99110
},
100111
)
101112

102113
def _run_lock_impl(ctx):
103114
run_info = ctx.attr.lock[_LockRunInfo]
115+
params = ctx.actions.declare_file(ctx.label.name + ".params.txt")
116+
ctx.actions.symlink(
117+
output = params,
118+
target_file = run_info.args,
119+
)
120+
104121
executable = ctx.actions.declare_file(ctx.label.name + ".exe")
105122
ctx.actions.symlink(
106123
output = executable,
@@ -109,7 +126,7 @@ def _run_lock_impl(ctx):
109126
)
110127

111128
runfiles = ctx.runfiles(
112-
files = run_info.srcs,
129+
files = run_info.srcs + [run_info.cmd_file],
113130
transitive_files = run_info.cmd[DefaultInfo].files,
114131
).merge(run_info.cmd[DefaultInfo].default_runfiles)
115132

@@ -135,7 +152,7 @@ _run_lock = rule(
135152
executable = True,
136153
)
137154

138-
def lock(*, name, srcs, out, args = [], **kwargs):
155+
def lock(*, name, srcs, out, args = [], run_args = [], **kwargs):
139156
"""Pin the requirements based on the src files.
140157
141158
Differences with the current {obj}`compile_pip_requirements` rule:
@@ -156,60 +173,14 @@ def lock(*, name, srcs, out, args = [], **kwargs):
156173
update_target = "{}.update".format(name)
157174
locker_target = "{}.run".format(name)
158175

159-
# TODO @aignas 2025-03-02: move the following args to a template expansion action
160176
user_args = args
161177
args = [
162-
# FIXME @aignas 2025-03-02: this acts differently in native_binary and the rule
163-
"--custom-compile-command='bazel run //{}:{}'".format(pkg, update_target),
164178
"--generate-hashes",
165179
"--emit-index-url",
166180
"--no-strip-extras",
167-
"--no-python-downloads",
168-
"--no-cache",
169181
]
170182
args += user_args
171-
172-
run_args = []
173183
maybe_out = _maybe_path(out)
174-
if maybe_out:
175-
# This means that the output file already exists and it should be used
176-
# to create a new file. This will be taken care by the locker tool.
177-
#
178-
# TODO @aignas 2025-03-02: similarly to sphinx rule, expand the output to short_path
179-
run_args += ["--output-file", "$(rootpath {})".format(maybe_out)]
180-
else:
181-
# TODO @aignas 2025-03-02: pass the output as a string
182-
run_out = "{}/{}".format(pkg, out)
183-
run_args += ["--output-file", run_out]
184-
185-
# args just get passed as is
186-
run_args += [
187-
# TODO @aignas 2025-03-02: get the full source location for these
188-
"$(rootpath {})".format(s)
189-
for s in srcs
190-
]
191-
192-
expand_template(
193-
name = locker_target + "_gen",
194-
out = locker_target + ".py",
195-
template = "//python/uv/private:pip_compile.py",
196-
substitutions = {
197-
" args = []": " args = " + repr(args),
198-
},
199-
tags = ["manual"],
200-
)
201-
202-
py_binary(
203-
name = locker_target,
204-
srcs = [locker_target + ".py"],
205-
data = [
206-
"//python/uv:current_toolchain",
207-
] + srcs + ([maybe_out] if maybe_out else []),
208-
args = run_args,
209-
python_version = kwargs.get("python_version"),
210-
tags = ["manual"],
211-
deps = ["//python/runfiles"],
212-
)
213184

214185
_lock(
215186
name = name,
@@ -225,13 +196,14 @@ def lock(*, name, srcs, out, args = [], **kwargs):
225196
"no-cache",
226197
],
227198
args = args,
199+
run_args = run_args,
228200
target_compatible_with = _REQUIREMENTS_TARGET_COMPATIBLE_WITH,
229-
cmd = locker_target,
230201
)
231202

232203
_run_lock(
233-
name = name + ".run2",
204+
name = locker_target,
234205
lock = name,
206+
args = run_args,
235207
)
236208

237209
if maybe_out:

python/uv/private/pip_compile.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ def _run() -> None:
2020
uv = os.fsdecode(uv_path)
2121
env = os.environ.copy()
2222

23-
parser = argparse.ArgumentParser()
24-
parser.add_argument("file", type=Path)
25-
args = parser.parse_args()
26-
sys_args = args.file.read_text().strip().split("\n")
23+
# TODO @aignas 2025-03-11: this does not work when we try to pass extra args via bazel run
24+
# The best way is to do a template expansion.
25+
26+
params = Path(f"{sys.argv[0]}.params.txt")
27+
assert params.exists(), f"{params} does not exist"
28+
sys_args = params.read_text().strip().split("\n")
2729

2830
# Let `uv` know that it was spawned by this Python interpreter
2931
env["UV_INTERNAL__PARENT_INTERPRETER"] = sys.executable
@@ -51,7 +53,7 @@ def _run() -> None:
5153
shutil.copy(src, dst)
5254
sys_args[1] = str(dst)
5355

54-
uv_args = ["pip", "compile"] + args + sys_args
56+
uv_args = ["pip", "compile"] + args + sys_args + uv_args
5557

5658
if sys.platform == "win32":
5759
import subprocess

0 commit comments

Comments
 (0)