@@ -30,18 +30,18 @@ def _impl(ctx):
3030 # TODO @aignas 2025-03-02: create an executable file here that is using a
3131 # python and uv toolchains.
3232
33- if ctx .files .src_outs :
33+ if ctx .files .maybe_out :
3434 args .add_all ([
3535 "--src-out" ,
36- ctx .files .src_outs [0 ].path ,
36+ ctx .files .maybe_out [0 ].path ,
3737 ])
3838 args .add ("--output-file" , ctx .outputs .out )
3939 args .add_all (ctx .files .srcs )
4040
4141 ctx .actions .run (
4242 executable = ctx .executable .cmd ,
4343 mnemonic = "RulesPythonLock" ,
44- inputs = ctx .files .srcs + ctx .files .src_outs ,
44+ inputs = ctx .files .srcs + ctx .files .maybe_out ,
4545 outputs = [
4646 ctx .outputs .out ,
4747 ],
@@ -65,31 +65,12 @@ _lock = rule(
6565 cfg = "target" ,
6666 ),
6767 "env" : attr .string_dict (),
68+ "maybe_out" : attr .label (allow_single_file = True ),
6869 "out" : attr .output (mandatory = True ),
69- "src_outs" : attr .label_list (mandatory = True , allow_files = True ),
7070 "srcs" : attr .label_list (mandatory = True , allow_files = True ),
7171 },
7272)
7373
74- def _glob (path ):
75- """A small function to return a list of existing outputs.
76-
77- If the file referenced by the input argument exists, then it will return
78- it, otherwise it will return an empty list. This is useful to for programs
79- like pip-compile which behave differently if the output file exists and
80- update the output file in place.
81-
82- The API of the function ensures that path is not a glob itself.
83-
84- Args:
85- path: {type}`str` the file name.
86- """
87- for p in native .glob ([path ], allow_empty = True ):
88- if path == p :
89- return [p ]
90-
91- return []
92-
9374def lock (* , name , srcs , out , args = [], ** kwargs ):
9475 """Pin the requirements based on the src files.
9576
@@ -125,13 +106,13 @@ def lock(*, name, srcs, out, args = [], **kwargs):
125106 args += user_args
126107
127108 run_args = []
128- existing_outputs = _glob (out )
129- if existing_outputs :
109+ maybe_out = _maybe_path (out )
110+ if maybe_out :
130111 # This means that the output file already exists and it should be used
131112 # to create a new file. This will be taken care by the locker tool.
132113 #
133114 # TODO @aignas 2025-03-02: similarly to sphinx rule, expand the output to short_path
134- run_args += ["--output-file" , "$(rootpath {})" .format (existing_outputs [ 0 ] )]
115+ run_args += ["--output-file" , "$(rootpath {})" .format (maybe_out )]
135116 else :
136117 # TODO @aignas 2025-03-02: pass the output as a string
137118 run_out = "{}/{}" .format (pkg , out )
@@ -159,7 +140,7 @@ def lock(*, name, srcs, out, args = [], **kwargs):
159140 srcs = [locker_target + ".py" ],
160141 data = [
161142 "//python/uv:current_toolchain" ,
162- ] + srcs + existing_outputs ,
143+ ] + srcs + ([ maybe_out ] if maybe_out else []) ,
163144 args = run_args ,
164145 tags = ["manual" ],
165146 deps = ["//python/runfiles" ],
@@ -171,7 +152,7 @@ def lock(*, name, srcs, out, args = [], **kwargs):
171152 # Check if the output file already exists, if yes, first copy it to the
172153 # output file location in order to make `uv` not change the requirements if
173154 # we are just running the command.
174- src_outs = existing_outputs ,
155+ maybe_out = maybe_out ,
175156 out = out + ".new" ,
176157 tags = [
177158 "local" ,
@@ -183,11 +164,11 @@ def lock(*, name, srcs, out, args = [], **kwargs):
183164 cmd = locker_target ,
184165 )
185166
186- if existing_outputs :
167+ if maybe_out :
187168 diff_test (
188169 name = name + "_test" ,
189170 file1 = out + ".new" ,
190- file2 = existing_outputs [ 0 ] ,
171+ file2 = maybe_out ,
191172 tags = ["manual" ],
192173 )
193174
@@ -212,3 +193,22 @@ def lock(*, name, srcs, out, args = [], **kwargs):
212193 tags = ["manual" ],
213194 ** kwargs
214195 )
196+
197+ def _maybe_path (path ):
198+ """A small function to return a list of existing outputs.
199+
200+ If the file referenced by the input argument exists, then it will return
201+ it, otherwise it will return an empty list. This is useful to for programs
202+ like pip-compile which behave differently if the output file exists and
203+ update the output file in place.
204+
205+ The API of the function ensures that path is not a glob itself.
206+
207+ Args:
208+ path: {type}`str` the file name.
209+ """
210+ for p in native .glob ([path ], allow_empty = True ):
211+ if path == p :
212+ return p
213+
214+ return None
0 commit comments