fix: run executable zip action with execution Python to better support windows building (#3890) The legacy self-executable zip action invokes `cat` through `run_shell`. The action does not declare `cat`, and a Windows-hosted Bazel invocation cannot use that action reliably when the selected execution platform is Linux. Run the existing `exe_zip_maker` through `actions_run` instead. This selects the helper and Python runtime from the execution configuration, preserves the prelude-plus-zip output format, and removes the ambient shell utility dependency. A news entry documents the fix. The Bazel integration that motivated this fix is [bazelbuild/bazel#30121](https://github.com/bazelbuild/bazel/pull/30121). --------- Co-authored-by: Richard Levasseur <richardlev@gmail.com> (cherry picked from commit 1d99f70e5967da59ecd948c0e6775e1e6424d889) Work towards #3867
diff --git a/CHANGELOG.md b/CHANGELOG.md index d585ce8..5819796 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -46,6 +46,8 @@ * Fixed a flaky error on Windows 2022 when looking up the win32 version during site initialization by retrying the lookup ([#3721](https://github.com/bazel-contrib/rules_python/issues/3721)). +* (binaries) Fixed building of legacy zipapps on Windows execution platforms by +using a hermetic tool instead of host `cat`. * (bootstrap) Fixed stage 1 bootstrap imports when target outputs shadow standard library modules. * (coverage) Skip lcov report when no data was collected. @@ -78,6 +80,7 @@ + {#v2-1-0} ## [2.1.0] - 2026-06-17
diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 11246ec..b15d1d2 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl
@@ -38,6 +38,7 @@ load( ":common.bzl", "ExplicitSymlink", + "actions_run", "collect_cc_info", "collect_deps", "collect_imports", @@ -218,6 +219,10 @@ default = "//python/private:debugger_if_target_config", providers = [PyInfo], ), + "_exe_zip_maker": lambda: attrb.Label( + cfg = "exec", + default = "//tools/private/zipapp:exe_zip_maker", + ), "_launcher": lambda: attrb.Label( cfg = "target", # NOTE: This is an executable, but is only used for Windows. It @@ -1094,15 +1099,16 @@ else: ctx.actions.write(prelude, "#!/usr/bin/env python3\n") - ctx.actions.run_shell( - command = "cat {prelude} {zip} > {output}".format( - prelude = prelude.path, - zip = zip_file.path, - output = output.path, - ), - inputs = [prelude, zip_file], + args = ctx.actions.args() + args.add(prelude) + args.add(zip_file) + args.add(output) + actions_run( + ctx, + executable = ctx.attr._exe_zip_maker, + arguments = [args], + inputs = depset([prelude, zip_file]), outputs = [output], - use_default_shell_env = True, mnemonic = "PyBuildExecutableZip", progress_message = "Build Python zip executable: %{label}", )