@@ -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
102113def  _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 :
0 commit comments