@@ -43,9 +43,18 @@ def _lock_impl(ctx):
43
43
])
44
44
args .add ("--output-file" , ctx .outputs .out )
45
45
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 )
46
55
47
56
# 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" )
49
58
ctx .actions .write (
50
59
output = param_file ,
51
60
content = args ,
@@ -54,13 +63,14 @@ def _lock_impl(ctx):
54
63
run_args = [param_file .path ]
55
64
args = ctx .actions .args ()
56
65
args .add_all (run_args )
66
+ args .add_all (ctx .attr .run_args )
57
67
58
- cmd = ctx .executable .cmd
68
+ cmd = ctx .executable ._cmd
59
69
60
70
srcs = ctx .files .srcs + ctx .files .maybe_out + [param_file ]
61
71
ctx .actions .run (
62
- executable = ctx . executable . cmd ,
63
- mnemonic = "RulesPythonLock " ,
72
+ executable = cmd ,
73
+ mnemonic = "RulesPythonUvPipCompile " ,
64
74
inputs = srcs ,
65
75
outputs = [ctx .outputs .out ],
66
76
arguments = [args ],
@@ -74,9 +84,9 @@ def _lock_impl(ctx):
74
84
files = depset ([ctx .outputs .out ]),
75
85
),
76
86
_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 ,
80
90
srcs = srcs ,
81
91
),
82
92
]
@@ -87,20 +97,27 @@ _lock = rule(
87
97
""" ,
88
98
attrs = {
89
99
"args" : attr .string_list (),
90
- "cmd" : attr .label (
91
- mandatory = True ,
92
- executable = True ,
93
- cfg = "target" ,
94
- ),
95
100
"env" : attr .string_dict (),
96
101
"maybe_out" : attr .label (allow_single_file = True ),
97
102
"out" : attr .output (mandatory = True ),
103
+ "run_args" : attr .string_list (),
98
104
"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
+ ),
99
110
},
100
111
)
101
112
102
113
def _run_lock_impl (ctx ):
103
114
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
+
104
121
executable = ctx .actions .declare_file (ctx .label .name + ".exe" )
105
122
ctx .actions .symlink (
106
123
output = executable ,
@@ -109,7 +126,7 @@ def _run_lock_impl(ctx):
109
126
)
110
127
111
128
runfiles = ctx .runfiles (
112
- files = run_info .srcs ,
129
+ files = run_info .srcs + [ run_info . cmd_file ] ,
113
130
transitive_files = run_info .cmd [DefaultInfo ].files ,
114
131
).merge (run_info .cmd [DefaultInfo ].default_runfiles )
115
132
@@ -135,7 +152,7 @@ _run_lock = rule(
135
152
executable = True ,
136
153
)
137
154
138
- def lock (* , name , srcs , out , args = [], ** kwargs ):
155
+ def lock (* , name , srcs , out , args = [], run_args = [], ** kwargs ):
139
156
"""Pin the requirements based on the src files.
140
157
141
158
Differences with the current {obj}`compile_pip_requirements` rule:
@@ -156,60 +173,14 @@ def lock(*, name, srcs, out, args = [], **kwargs):
156
173
update_target = "{}.update" .format (name )
157
174
locker_target = "{}.run" .format (name )
158
175
159
- # TODO @aignas 2025-03-02: move the following args to a template expansion action
160
176
user_args = args
161
177
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 ),
164
178
"--generate-hashes" ,
165
179
"--emit-index-url" ,
166
180
"--no-strip-extras" ,
167
- "--no-python-downloads" ,
168
- "--no-cache" ,
169
181
]
170
182
args += user_args
171
-
172
- run_args = []
173
183
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
- )
213
184
214
185
_lock (
215
186
name = name ,
@@ -225,13 +196,14 @@ def lock(*, name, srcs, out, args = [], **kwargs):
225
196
"no-cache" ,
226
197
],
227
198
args = args ,
199
+ run_args = run_args ,
228
200
target_compatible_with = _REQUIREMENTS_TARGET_COMPATIBLE_WITH ,
229
- cmd = locker_target ,
230
201
)
231
202
232
203
_run_lock (
233
- name = name + ".run2" ,
204
+ name = locker_target ,
234
205
lock = name ,
206
+ args = run_args ,
235
207
)
236
208
237
209
if maybe_out :
0 commit comments