Skip to content

Commit af3533d

Browse files
committed
wip
1 parent c12a10c commit af3533d

File tree

4 files changed

+129
-124
lines changed

4 files changed

+129
-124
lines changed

docs/requirements.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# This file was autogenerated by uv via the following command:
2-
# 'bazel run //docs:requirements.update'
3-
--index-url https://pypi.org/simple
4-
2+
# bazel run //docs:requirements.update.update
53
absl-py==2.1.0 \
64
--hash=sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 \
75
--hash=sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff

python/uv/private/lock.bzl

Lines changed: 118 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -21,49 +21,6 @@ load("//python:py_binary.bzl", "py_binary")
2121

2222
visibility(["//..."])
2323

24-
def _impl(ctx):
25-
args = ctx.actions.args()
26-
27-
# TODO @aignas 2025-03-02: create an executable file here that is using a
28-
# python and uv toolchains.
29-
30-
if ctx.files.maybe_out:
31-
args.add_all([
32-
"--src-out",
33-
ctx.files.maybe_out[0].path,
34-
])
35-
args.add("--output-file", ctx.outputs.out)
36-
args.add_all(ctx.files.srcs)
37-
38-
ctx.actions.run(
39-
executable = ctx.executable.cmd,
40-
mnemonic = "RulesPythonLock",
41-
inputs = ctx.files.srcs + ctx.files.maybe_out,
42-
outputs = [
43-
ctx.outputs.out,
44-
],
45-
arguments = [args],
46-
tools = [ctx.executable.cmd],
47-
progress_message = "Locking requirements using uv",
48-
env = ctx.attr.env,
49-
)
50-
51-
return [DefaultInfo(files = depset([ctx.outputs.out]))]
52-
53-
_lock = rule(
54-
implementation = _impl,
55-
doc = """\
56-
""",
57-
attrs = {
58-
"args": attr.string_list(),
59-
"cmd": attr.label(mandatory = True, executable = True, cfg = "target"),
60-
"env": attr.string_dict(),
61-
"maybe_out": attr.label(mandatory = False, allow_single_file = True),
62-
"out": attr.output(mandatory = True),
63-
"srcs": attr.label_list(mandatory = True, allow_files = True),
64-
},
65-
)
66-
6724
_uv_toolchain = Label("//python/uv:uv_toolchain_type")
6825
_py_toolchain = Label("//python:toolchain_type")
6926

@@ -75,46 +32,99 @@ _LockInfo = provider(
7532
"srcs": "",
7633
"template": "",
7734
"uv": "",
78-
}
35+
},
7936
)
8037

8138
def _impl2(ctx):
8239
args = ctx.attr.args
83-
srcs = ctx.attr.srcs
40+
srcs = ctx.files.srcs
41+
existing_output = ctx.files.existing_output
42+
output = ctx.outputs.output
8443

8544
toolchain_info = ctx.toolchains[_uv_toolchain]
8645
uv = toolchain_info.uv_toolchain_info.uv[DefaultInfo].files_to_run.executable
8746

88-
py_runtime = ctx.toolchains[_py_toolchain]
89-
fail(py_runtime)
90-
py = ""
47+
py_runtime = ctx.toolchains[_py_toolchain].py3_runtime
48+
49+
substitutions = {
50+
" uv ": " {} ".format(uv.path),
51+
"$bazel_out": output.path,
52+
"out=": "out=" + existing_output[0].path,
53+
}
54+
if existing_output:
55+
substitutions["# before exec"] = ""
56+
57+
cmd = ctx.actions.declare_file(ctx.label.name)
58+
ctx.actions.expand_template(
59+
template = ctx.files._template[0],
60+
substitutions = substitutions,
61+
output = cmd,
62+
is_executable = True,
63+
)
64+
65+
run_args = []
66+
lock_args = ctx.actions.args()
67+
for _args in [
68+
("--no-python-downloads",),
69+
("--no-cache",),
70+
("--generate-hashes",),
71+
("--no-strip-extras",),
72+
(
73+
"--custom-compile-command",
74+
# TODO @aignas 2025-03-13:
75+
"'bazel run //{}:{}.update'".format(ctx.label.package, ctx.attr.update_target),
76+
),
77+
]:
78+
lock_args.add(*_args)
79+
run_args.extend([a for a in _args])
80+
81+
lock_args.add_all(args)
82+
lock_args.add_all(srcs)
83+
lock_args.add("--python", py_runtime.interpreter)
84+
85+
ctx.actions.run(
86+
executable = cmd,
87+
mnemonic = "RulesPythonLock",
88+
inputs = srcs + ctx.files.existing_output,
89+
outputs = [output],
90+
arguments = [lock_args],
91+
tools = [cmd],
92+
progress_message = "Locking requirements using uv",
93+
env = ctx.attr.env,
94+
)
9195

9296
return [
93-
DefaultInfo(files = depset([ctx.outputs.out])),
97+
DefaultInfo(files = depset([ctx.outputs.output])),
9498
_LockInfo(
95-
args = args,
99+
args = run_args + args,
96100
srcs = srcs,
97101
uv = uv,
98-
py = py,
99-
template = ctx.attr._template,
102+
py = py_runtime,
103+
template = ctx.files._template[0],
100104
),
101105
]
102106

103-
_lock2 = rule(
107+
_lock = rule(
104108
implementation = _impl2,
105109
doc = """\
106110
""",
107111
attrs = {
108112
"args": attr.string_list(),
109113
"env": attr.string_dict(),
110114
"existing_output": attr.label(
111-
mandatory = False, allow_single_file = True,
115+
mandatory = False,
116+
allow_single_file = True,
112117
doc = "An already existing output file that is used as a basis for futher modifications and the locking is not done from scratch",
113118
),
114119
"output": attr.output(mandatory = False),
115120
"python_version": attr.string(doc = "TODO: how do I create a transition thing?"),
116121
"srcs": attr.label_list(mandatory = True, allow_files = True),
117-
"_template": attr.label(default = "//python/uv/private:pip_compile_template"),
122+
"update_target": attr.string(mandatory = True),
123+
"_template": attr.label(
124+
default = "//python/uv/private:pip_compile_template",
125+
cfg = "exec",
126+
executable = True,
127+
),
118128
},
119129
toolchains = [
120130
_uv_toolchain,
@@ -123,26 +133,60 @@ _lock2 = rule(
123133
)
124134

125135
def _impl3(ctx):
126-
fail()
136+
info = ctx.attr.lock[_LockInfo]
137+
template = info.template
138+
uv = info.uv
139+
args = info.args
140+
srcs = info.srcs
141+
py_runtime = info.py
142+
143+
args = args + [
144+
src.short_path
145+
for src in srcs
146+
] + [
147+
"--python",
148+
py_runtime.interpreter.short_path,
149+
]
150+
151+
substitutions = {
152+
"out=": "out={}/{}".format(ctx.label.package, ctx.attr.output),
153+
"uv ": "{} {} ".format(uv.short_path, " ".join(args)),
154+
}
155+
156+
executable = ctx.actions.declare_file(ctx.label.name)
157+
ctx.actions.expand_template(
158+
template = template,
159+
substitutions = substitutions,
160+
output = executable,
161+
is_executable = True,
162+
)
163+
164+
runfiles = ctx.runfiles(
165+
transitive_files = depset(
166+
srcs + [uv],
167+
transitive = [
168+
py_runtime.files,
169+
],
170+
),
171+
)
172+
return [
173+
DefaultInfo(
174+
executable = executable,
175+
runfiles = runfiles,
176+
),
177+
]
127178

128179
_lock_run = rule(
129180
implementation = _impl3,
130181
doc = """\
131182
""",
132183
attrs = {
133-
"lock": attr.label(
134-
doc = "",
135-
providers = [_LockInfo],
136-
),
137-
"out": attr.string(),
184+
"lock": attr.label(providers = [_LockInfo]),
185+
"output": attr.string(),
138186
},
139-
toolchains = [
140-
_uv_toolchain,
141-
_py_toolchain,
142-
],
187+
executable = True,
143188
)
144189

145-
146190
def _maybe_file(path):
147191
"""A small function to return a list of existing outputs.
148192
@@ -183,67 +227,15 @@ def lock(*, name, srcs, out, args = [], **kwargs):
183227
update_target = "{}.update".format(name)
184228
locker_target = "{}.run".format(name)
185229

186-
# TODO @aignas 2025-03-02: move the following args to a template expansion action
187-
user_args = args
188-
args = [
189-
# FIXME @aignas 2025-03-02: this acts differently in native_binary and the rule
190-
"--custom-compile-command='bazel run //{}:{}'".format(pkg, update_target),
191-
"--generate-hashes",
192-
"--emit-index-url",
193-
"--no-strip-extras",
194-
"--no-python-downloads",
195-
"--no-cache",
196-
]
197-
args += user_args
198-
199-
run_args = []
200230
maybe_out = _maybe_file(out)
201-
if maybe_out:
202-
# This means that the output file already exists and it should be used
203-
# to create a new file. This will be taken care by the locker tool.
204-
#
205-
# TODO @aignas 2025-03-02: similarly to sphinx rule, expand the output to short_path
206-
run_args += ["--output-file", "$(rootpath {})".format(maybe_out)]
207-
else:
208-
# TODO @aignas 2025-03-02: pass the output as a string
209-
run_out = "{}/{}".format(pkg, out)
210-
run_args += ["--output-file", run_out]
211-
212-
# args just get passed as is
213-
run_args += [
214-
# TODO @aignas 2025-03-02: get the full source location for these
215-
"$(rootpath {})".format(s)
216-
for s in srcs
217-
]
218-
219-
expand_template(
220-
name = locker_target + "_gen",
221-
out = locker_target + ".py",
222-
template = "//python/uv/private:pip_compile.py",
223-
substitutions = {
224-
" args = []": " args = " + repr(args),
225-
},
226-
tags = ["manual"],
227-
)
228-
229-
py_binary(
230-
name = locker_target,
231-
srcs = [locker_target + ".py"],
232-
data = [
233-
"//python/uv:current_toolchain",
234-
] + srcs + ([maybe_out] if maybe_out else []),
235-
args = run_args,
236-
tags = ["manual"],
237-
deps = ["//python/runfiles"],
238-
)
239-
240-
_lock2(
231+
_lock(
241232
name = name,
242233
srcs = srcs,
243234
# Check if the output file already exists, if yes, first copy it to the
244235
# output file location in order to make `uv` not change the requirements if
245236
# we are just running the command.
246237
existing_output = maybe_out,
238+
update_target = update_target,
247239
output = out + ".new",
248240
tags = [
249241
"local",
@@ -261,6 +253,12 @@ def lock(*, name, srcs, out, args = [], **kwargs):
261253
tags = ["manual"],
262254
)
263255

256+
_lock_run(
257+
name = locker_target,
258+
lock = name,
259+
output = out,
260+
)
261+
264262
# Write a script that can be used for updating the in-tree version of the
265263
# requirements file
266264
expand_template(

python/uv/private/pip_compile.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# before exec Copy-Item $SRC$ $OUT$
2+
& uv $args

python/uv/private/pip_compile.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
#!/bin/bash
22
set -euxo pipefail
33

4-
exec uv --output-file "$@"
4+
out=
5+
if [[ -n "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
6+
out="${BUILD_WORKSPACE_DIRECTORY}/$out"
7+
else
8+
cp -v "$out" "$bazel_out"
9+
out="$bazel_out"
10+
fi
11+
exec uv pip compile --output-file "$out" "$@"

0 commit comments

Comments
 (0)