@@ -18,7 +18,7 @@ def _is_symlink(f):
1818 else :
1919 return "-1"
2020
21- def _create_zipapp_main_py (ctx , py_runtime , py_executable , stage2_bootstrap ):
21+ def _create_zipapp_main_py (ctx , py_runtime , py_executable , stage2_bootstrap , runfiles ):
2222 venv_python_exe = py_executable .venv_python_exe
2323 if venv_python_exe :
2424 venv_python_exe_path = runfiles_root_path (ctx , venv_python_exe .short_path )
@@ -31,20 +31,40 @@ def _create_zipapp_main_py(ctx, py_runtime, py_executable, stage2_bootstrap):
3131 python_binary_actual_path = py_runtime .interpreter_path
3232
3333 zip_main_py = ctx .actions .declare_file (ctx .label .name + ".zip_main.py" )
34- ctx .actions .expand_template (
35- template = py_runtime .zip_main_template ,
36- output = zip_main_py ,
37- substitutions = {
38- "%EXTRACT_DIR%" : paths .join (
39- (ctx .label .repo_name or "_main" ),
40- ctx .label .package ,
41- ctx .label .name ,
42- ),
43- "%python_binary%" : venv_python_exe_path ,
44- "%python_binary_actual%" : python_binary_actual_path ,
45- "%stage2_bootstrap%" : runfiles_root_path (ctx , stage2_bootstrap .short_path ),
46- "%workspace_name%" : ctx .workspace_name ,
47- },
34+
35+ args = ctx .actions .args ()
36+ args .add (py_runtime .zip_main_template , format = "--template=%s" )
37+ args .add (zip_main_py , format = "--output=%s" )
38+
39+ args .add (
40+ "%EXTRACT_DIR%=" + paths .join (
41+ (ctx .label .repo_name or "_main" ),
42+ ctx .label .package ,
43+ ctx .label .name ,
44+ ),
45+ format = "--substitution=%s" ,
46+ )
47+ args .add ("%python_binary%=" + venv_python_exe_path , format = "--substitution=%s" )
48+ args .add ("%python_binary_actual%=" + python_binary_actual_path , format = "--substitution=%s" )
49+ args .add ("%stage2_bootstrap%=" + runfiles_root_path (ctx , stage2_bootstrap .short_path ), format = "--substitution=%s" )
50+ args .add ("%workspace_name%=" + ctx .workspace_name , format = "--substitution=%s" )
51+
52+ hash_files_manifest = ctx .actions .args ()
53+ hash_files_manifest .use_param_file ("--hash_files_manifest=%s" , use_always = True )
54+ hash_files_manifest .set_param_file_format ("multiline" )
55+
56+ inputs = builders .DepsetBuilder ()
57+ inputs .add (py_runtime .zip_main_template )
58+ _build_manifest (ctx , hash_files_manifest , runfiles , inputs )
59+
60+ actions_run (
61+ ctx ,
62+ executable = ctx .attr ._zip_main_maker ,
63+ arguments = [args , hash_files_manifest ],
64+ inputs = inputs .build (),
65+ outputs = [zip_main_py ],
66+ mnemonic = "PyZipAppCreateMainPy" ,
67+ progress_message = "Generating zipapp __main__.py: %{label}" ,
4868 )
4969 return zip_main_py
5070
@@ -60,9 +80,7 @@ def _map_zip_symlinks(entry):
6080def _map_zip_root_symlinks (entry ):
6181 return "rf-root-symlink|" + _is_symlink (entry .target_file ) + "|" + entry .path + "|" + entry .target_file .path
6282
63- def _build_manifest (ctx , manifest , runfiles , zip_main ):
64- manifest .add ("regular|0|__main__.py|{}" .format (zip_main .path ))
65-
83+ def _build_manifest (ctx , manifest , runfiles , inputs ):
6684 manifest .add_all (
6785 # NOTE: Accessing runfiles.empty_filenames materializes them. A lambda
6886 # is used to defer that.
@@ -75,7 +93,10 @@ def _build_manifest(ctx, manifest, runfiles, zip_main):
7593 manifest .add_all (runfiles .symlinks , map_each = _map_zip_symlinks )
7694 manifest .add_all (runfiles .root_symlinks , map_each = _map_zip_root_symlinks )
7795
78- inputs = [zip_main ]
96+ inputs .add (runfiles .files )
97+ inputs .add ([entry .target_file for entry in runfiles .symlinks .to_list ()])
98+ inputs .add ([entry .target_file for entry in runfiles .root_symlinks .to_list ()])
99+
79100 zip_repo_mapping_manifest = maybe_create_repo_mapping (
80101 ctx = ctx ,
81102 runfiles = runfiles ,
@@ -87,8 +108,7 @@ def _build_manifest(ctx, manifest, runfiles, zip_main):
87108 zip_repo_mapping_manifest .path ,
88109 format = "rf-root-symlink|0|_repo_mapping|%s" ,
89110 )
90- inputs .append (zip_repo_mapping_manifest )
91- return inputs
111+ inputs .add (zip_repo_mapping_manifest )
92112
93113def _create_zip (ctx , py_runtime , py_executable , stage2_bootstrap ):
94114 output = ctx .actions .declare_file (ctx .label .name + ".zip" )
@@ -106,8 +126,17 @@ def _create_zip(ctx, py_runtime, py_executable, stage2_bootstrap):
106126
107127 runfiles = runfiles .build (ctx )
108128
109- zip_main = _create_zipapp_main_py (ctx , py_runtime , py_executable , stage2_bootstrap )
110- inputs = _build_manifest (ctx , manifest , runfiles , zip_main )
129+ zip_main = _create_zipapp_main_py (
130+ ctx ,
131+ py_runtime ,
132+ py_executable ,
133+ stage2_bootstrap ,
134+ runfiles ,
135+ )
136+ inputs = builders .DepsetBuilder ()
137+ manifest .add ("regular|0|__main__.py|{}" .format (zip_main .path ))
138+ inputs .add (zip_main )
139+ _build_manifest (ctx , manifest , runfiles , inputs )
111140
112141 zipper_args = ctx .actions .args ()
113142 zipper_args .add (output )
@@ -124,7 +153,7 @@ def _create_zip(ctx, py_runtime, py_executable, stage2_bootstrap):
124153 ctx ,
125154 executable = ctx .attr ._zipper ,
126155 arguments = [manifest , zipper_args ],
127- inputs = depset ( inputs , transitive = [ runfiles . files ] ),
156+ inputs = inputs . build ( ),
128157 outputs = [output ],
129158 mnemonic = "PyZipAppCreateZip" ,
130159 progress_message = "Reticulating zipapp archive: %{label} into %{output}" ,
@@ -315,6 +344,10 @@ Whether the output should be an executable zip file.
315344 "@platforms//os:windows" ,
316345 ],
317346 ),
347+ "_zip_main_maker" : attr .label (
348+ cfg = "exec" ,
349+ default = "//tools/private/zipapp:zip_main_maker" ,
350+ ),
318351 "_zip_shell_template" : attr .label (
319352 default = ":zip_shell_template" ,
320353 allow_single_file = True ,
0 commit comments