diff --git a/.bazelrc b/.bazelrc index 24676574e6..2545f30f80 100644 --- a/.bazelrc +++ b/.bazelrc @@ -41,3 +41,7 @@ common --incompatible_python_disallow_native_rules common --incompatible_no_implicit_file_export build --lockfile_mode=update + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false diff --git a/BUILD.bazel b/BUILD.bazel index aa2642d43f..7da18ebaa4 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -43,6 +43,7 @@ filegroup( "internal_dev_deps.bzl", "internal_dev_setup.bzl", "version.bzl", + "//command_line_option:distribution", "//python:distribution", "//tools:distribution", ], diff --git a/command_line_option/BUILD.bazel b/command_line_option/BUILD.bazel new file mode 100644 index 0000000000..1488f0b4e1 --- /dev/null +++ b/command_line_option/BUILD.bazel @@ -0,0 +1,28 @@ +# Aliases for Bazel builtin //command_line_option psuedo-targets +# +# These are alias to use with `py_binary.config_settings` that are treated +# as aliases for `//command_line_option:XXX` psuedo-targets. + +package( + default_visibility = ["//visibility:public"], +) + +# todo: add docs, xref with config_settings +# rules_python target, config_setting processing code converts it to the +# Bazel-builtin //command_line_label:build_runfile_links psuedo-target +alias( + name = "build_runfile_links", + actual = "//python:none", +) + +# todo: add docs +alias( + name = "enable_runfiles", + actual = "//python:none", +) + +filegroup( + name = "distribution", + srcs = glob(["**"]), + visibility = ["//:__subpackages__"], +) diff --git a/examples/build_file_generation/.bazelrc b/examples/build_file_generation/.bazelrc index f1ae44fac8..e14ed7c9f6 100644 --- a/examples/build_file_generation/.bazelrc +++ b/examples/build_file_generation/.bazelrc @@ -8,3 +8,7 @@ build --enable_runfiles common --noenable_bzlmod common --enable_workspace common --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/examples/bzlmod/.bazelrc b/examples/bzlmod/.bazelrc index 28a44a7523..a18c7e2551 100644 --- a/examples/bzlmod/.bazelrc +++ b/examples/bzlmod/.bazelrc @@ -24,3 +24,7 @@ test --test_output=errors --enable_runfiles # Windows requires these for multi-python support: build --enable_runfiles common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/examples/multi_python_versions/.bazelrc b/examples/multi_python_versions/.bazelrc index 97a973bd85..39ed55aff4 100644 --- a/examples/multi_python_versions/.bazelrc +++ b/examples/multi_python_versions/.bazelrc @@ -5,3 +5,7 @@ build --enable_runfiles coverage --java_runtime_version=remotejdk_11 common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/examples/pip_parse/.bazelrc b/examples/pip_parse/.bazelrc index f263a1744d..fe7156d840 100644 --- a/examples/pip_parse/.bazelrc +++ b/examples/pip_parse/.bazelrc @@ -1,3 +1,10 @@ # https://docs.bazel.build/versions/main/best-practices.html#using-the-bazelrc-file try-import %workspace%/user.bazelrc common --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false + +# Windows makes use of runfiles for some rules +##common --enable_runfiles diff --git a/examples/pip_parse_vendored/.bazelrc b/examples/pip_parse_vendored/.bazelrc index a6ea2d9138..e846b1ac11 100644 --- a/examples/pip_parse_vendored/.bazelrc +++ b/examples/pip_parse_vendored/.bazelrc @@ -8,3 +8,7 @@ build --enable_runfiles common --noenable_bzlmod common --enable_workspace common --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/examples/pip_repository_annotations/.bazelrc b/examples/pip_repository_annotations/.bazelrc index 9397bd31b8..82c7a1dbd2 100644 --- a/examples/pip_repository_annotations/.bazelrc +++ b/examples/pip_repository_annotations/.bazelrc @@ -7,3 +7,7 @@ common --noenable_bzlmod common --enable_workspace common --legacy_external_runfiles=false common --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/gazelle/.bazelrc b/gazelle/.bazelrc index 9a38133e9d..0f46b5b584 100644 --- a/gazelle/.bazelrc +++ b/gazelle/.bazelrc @@ -16,3 +16,7 @@ build --@rules_python//python/config_settings:incompatible_default_to_explicit_i build --enable_runfiles common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/gazelle/examples/bzlmod_build_file_generation/.bazelrc b/gazelle/examples/bzlmod_build_file_generation/.bazelrc index 31097b41de..5ab484ee67 100644 --- a/gazelle/examples/bzlmod_build_file_generation/.bazelrc +++ b/gazelle/examples/bzlmod_build_file_generation/.bazelrc @@ -14,3 +14,7 @@ common:bazel7.x --incompatible_python_disallow_native_rules # rules_python code. In the BCR presubmits, this override is removed # and the bazel_dep version of rules_python is used. common --override_module=rules_python=../../../ + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel index 70f7f86413..13951bf417 100644 --- a/python/private/BUILD.bazel +++ b/python/private/BUILD.bazel @@ -831,6 +831,14 @@ config_setting( }, ) +alias( + name = "what_os", + actual = select({ + "@platforms//os:windows": "@platforms//os:windows", + "//conditions:default": "@platforms//os:linux", + }), +) + alias( name = "debugger_if_target_config", actual = select({ diff --git a/python/private/attributes.bzl b/python/private/attributes.bzl index 362eee8f2e..665eadd24a 100644 --- a/python/private/attributes.bzl +++ b/python/private/attributes.bzl @@ -400,6 +400,18 @@ particular CPU, or defining a custom setting that `select()` uses elsewhere to pick between `pip.parse` hubs. See the [How to guide on multiple versions of a library] for a more concrete example. +:::{important} +Labels with package `command_line_option` are handled specially: they are treated +as aliases for the Bazel-builtin `//command_line_option:` psuedo-targets. + +e.g. `@foo//command_line_option:NAME` will attempt to transition +the Bazel-builtin `//command_line_option:NAME` setting. + +See the {obj}`@rules_python//command_line_option` package for some predefined +aliases, or define your own by putting them in your own `command_line_option` +directory. +::: + :::{note} These values are transitioned on, so will affect the analysis graph and the associated memory overhead. The more unique configurations in your overall @@ -426,7 +438,11 @@ def apply_config_settings_attr(settings, attr): {type}`dict[str, object]` the input `settings` value. """ for key, value in attr.config_settings.items(): - settings[str(key)] = value + if key.package == "command_line_option": + str_key = "//command_line_option:" + key.name + else: + str_key = str(key) + settings[str_key] = value return settings AGNOSTIC_EXECUTABLE_ATTRS = dicts.add( diff --git a/python/private/build_data_writer.ps1 b/python/private/build_data_writer.ps1 index db7a48e676..846399f194 100644 --- a/python/private/build_data_writer.ps1 +++ b/python/private/build_data_writer.ps1 @@ -1,17 +1,29 @@ $OutputPath = $env:OUTPUT - -Add-Content -Path $OutputPath -Value "TARGET $env:TARGET" -Add-Content -Path $OutputPath -Value "CONFIG_MODE $env:CONFIG_MODE" -Add-Content -Path $OutputPath -Value "STAMPED $env:STAMPED" +$Lines = @( + "TARGET $env:TARGET", + "CONFIG_MODE $env:CONFIG_MODE", + "STAMPED $env:STAMPED" +) $VersionFilePath = $env:VERSION_FILE -if (-not [string]::IsNullOrEmpty($VersionFilePath)) { - Get-Content -Path $VersionFilePath | Add-Content -Path $OutputPath +if (-not [string]::IsNullOrEmpty($VersionFilePath) -and (Test-Path $VersionFilePath)) { + $Lines += Get-Content -Path $VersionFilePath } $InfoFilePath = $env:INFO_FILE -if (-not [string]::IsNullOrEmpty($InfoFilePath)) { - Get-Content -Path $InfoFilePath | Add-Content -Path $OutputPath +if (-not [string]::IsNullOrEmpty($InfoFilePath) -and (Test-Path $InfoFilePath)) { + $Lines += Get-Content -Path $InfoFilePath } +# Use .NET to write file to avoid PowerShell encoding/locking quirks +# We use UTF8 without BOM for compatibility with how the bash script writes (and +# what consumers expect). +$Utf8NoBom = New-Object System.Text.UTF8Encoding $False +[System.IO.File]::WriteAllLines($OutputPath, $Lines, $Utf8NoBom) + +$Acl = Get-Acl $OutputPath +$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone", "Read", "Allow") +$Acl.SetAccessRule($AccessRule) +Set-Acl $OutputPath $Acl + exit 0 diff --git a/python/private/common_labels.bzl b/python/private/common_labels.bzl index 9c21198a62..b6594cf0b9 100644 --- a/python/private/common_labels.bzl +++ b/python/private/common_labels.bzl @@ -8,15 +8,20 @@ labels = struct( ADD_SRCS_TO_RUNFILES = str(Label("//python/config_settings:add_srcs_to_runfiles")), BOOTSTRAP_IMPL = str(Label("//python/config_settings:bootstrap_impl")), BUILD_PYTHON_ZIP = str(Label("//python/config_settings:build_python_zip")), + # NOTE: Special target; see definition for details. + BUILD_RUNFILE_LINKS = str(Label("//command_line_option:build_runfile_links")), DEBUGGER = str(Label("//python/config_settings:debugger")), + # NOTE: Special target; see definition for details. + ENABLE_RUNFILES = str(Label("//command_line_option:enable_runfiles")), EXEC_TOOLS_TOOLCHAIN = str(Label("//python/config_settings:exec_tools_toolchain")), - PIP_ENV_MARKER_CONFIG = str(Label("//python/config_settings:pip_env_marker_config")), NONE = str(Label("//python:none")), + PIP_ENV_MARKER_CONFIG = str(Label("//python/config_settings:pip_env_marker_config")), PIP_WHL = str(Label("//python/config_settings:pip_whl")), PIP_WHL_GLIBC_VERSION = str(Label("//python/config_settings:pip_whl_glibc_version")), PIP_WHL_MUSLC_VERSION = str(Label("//python/config_settings:pip_whl_muslc_version")), PIP_WHL_OSX_ARCH = str(Label("//python/config_settings:pip_whl_osx_arch")), PIP_WHL_OSX_VERSION = str(Label("//python/config_settings:pip_whl_osx_version")), + PLATFORMS_OS_WINDOWS = str(Label("@platforms//os:windows")), PRECOMPILE = str(Label("//python/config_settings:precompile")), PRECOMPILE_SOURCE_RETENTION = str(Label("//python/config_settings:precompile_source_retention")), PYC_COLLECTION = str(Label("//python/config_settings:pyc_collection")), diff --git a/python/private/py_binary_macro.bzl b/python/private/py_binary_macro.bzl index fa10f2e8a3..6a8268ccf3 100644 --- a/python/private/py_binary_macro.bzl +++ b/python/private/py_binary_macro.bzl @@ -14,11 +14,13 @@ """Implementation of macro-half of py_binary rule.""" load(":py_binary_rule.bzl", py_binary_rule = "py_binary") -load(":py_executable.bzl", "convert_legacy_create_init_to_int") +load(":py_executable.bzl", "common_executable_macro_kwargs_setup") + +_PLATFORMS_OS_WINDOWS = str(Label("@platforms//os:windows")) def py_binary(**kwargs): py_binary_macro(py_binary_rule, **kwargs) def py_binary_macro(py_rule, **kwargs): - convert_legacy_create_init_to_int(kwargs) + common_executable_macro_kwargs_setup(kwargs) py_rule(**kwargs) diff --git a/python/private/py_console_script_gen.bzl b/python/private/py_console_script_gen.bzl index de016036b2..528ef8c4fb 100644 --- a/python/private/py_console_script_gen.bzl +++ b/python/private/py_console_script_gen.bzl @@ -55,6 +55,9 @@ def _py_console_script_gen_impl(ctx): mnemonic = "PyConsoleScriptBinaryGen", progress_message = "Generating py_console_script_binary main: %{label}", executable = ctx.executable._tool, + env = { + "RULES_PYTHON_BOOTSTRAP_VERBOSE": "1", + }, ) return [DefaultInfo( diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 7ff6278e02..0fc9dcc715 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -768,10 +768,7 @@ def _create_stage1_bootstrap( } if stage2_bootstrap: - subs["%stage2_bootstrap%"] = "{}/{}".format( - ctx.workspace_name, - stage2_bootstrap.short_path, - ) + subs["%stage2_bootstrap%"] = runfiles_root_path(ctx, stage2_bootstrap.short_path) template = runtime.bootstrap_template subs["%shebang%"] = runtime.stub_shebang elif not ctx.files.srcs: @@ -1771,6 +1768,30 @@ def _create_run_environment_info(ctx, inherited_environment): inherited_environment = inherited_environment, ) +def add_config_setting_default_build_runfiles_links(kwargs): + config_settings = kwargs.get("config_settings", None) + if config_settings == None: + config_settings = {} + + # NOTE: This code runs in loading phase within the context of the caller. + # Label() must be used to resolve repo names within rules_python's + # context to avoid unknown repo name errors. + default = select({ + labels.PLATFORMS_OS_WINDOWS: { + labels.BUILD_RUNFILE_LINKS: "true", + labels.ENABLE_RUNFILES: "true", + }, + "//conditions:default": { + labels.BUILD_RUNFILE_LINKS: "true", + }, + }) + config_settings = default | config_settings + kwargs["config_settings"] = config_settings + +def common_executable_macro_kwargs_setup(kwargs): + convert_legacy_create_init_to_int(kwargs) + add_config_setting_default_build_runfiles_links(kwargs) + def _transition_executable_impl(settings, attr): settings = dict(settings) apply_config_settings_attr(settings, attr) @@ -1780,6 +1801,7 @@ def _transition_executable_impl(settings, attr): if attr.stamp != -1: settings["//command_line_option:stamp"] = str(attr.stamp) + return settings def create_executable_rule(*, attrs, **kwargs): @@ -1833,10 +1855,14 @@ def create_executable_rule_builder(implementation, **kwargs): inputs = TRANSITION_LABELS + [ labels.PYTHON_VERSION, "//command_line_option:stamp", + "//command_line_option:build_runfile_links", + "//command_line_option:enable_runfiles", ], outputs = TRANSITION_LABELS + [ labels.PYTHON_VERSION, "//command_line_option:stamp", + "//command_line_option:build_runfile_links", + "//command_line_option:enable_runfiles", ], ), **kwargs diff --git a/python/private/py_test_macro.bzl b/python/private/py_test_macro.bzl index 028dee6678..bc58f859f8 100644 --- a/python/private/py_test_macro.bzl +++ b/python/private/py_test_macro.bzl @@ -13,12 +13,12 @@ # limitations under the License. """Implementation of macro-half of py_test rule.""" -load(":py_executable.bzl", "convert_legacy_create_init_to_int") +load(":py_executable.bzl", "common_executable_macro_kwargs_setup") load(":py_test_rule.bzl", py_test_rule = "py_test") def py_test(**kwargs): py_test_macro(py_test_rule, **kwargs) def py_test_macro(py_rule, **kwargs): - convert_legacy_create_init_to_int(kwargs) + common_executable_macro_kwargs_setup(kwargs) py_rule(**kwargs) diff --git a/python/private/python_bootstrap_template.txt b/python/private/python_bootstrap_template.txt index f2d5a42fda..95fd1116eb 100644 --- a/python/private/python_bootstrap_template.txt +++ b/python/private/python_bootstrap_template.txt @@ -10,13 +10,13 @@ import sys import os import subprocess import uuid -# runfiles-relative path # NOTE: The sentinel strings are split (e.g., "%stage2" + "_bootstrap%") so that # the substitution logic won't replace them. This allows runtime detection of # unsubstituted placeholders, which occurs when native py_binary is used in # external repositories. In that case, we fall back to %main% which Bazel's # native rule does substitute. _STAGE2_BOOTSTRAP_SENTINEL = "%stage2" + "_bootstrap%" +# runfiles-root-relative path STAGE2_BOOTSTRAP="%stage2_bootstrap%" # NOTE: The fallback logic from stage2_bootstrap to main is only present @@ -165,6 +165,29 @@ def print_verbose(*args, mapping=None, values=None): else: print("bootstrap: stage 1:", *args, file=sys.stderr, flush=True) +def maybe_find_in_manifest(rf_root_path, show_lines=False): + if not os.environ.get("RUNFILES_MANIFEST_FILE"): + return None + if not os.path.exists(os.environ["RUNFILES_MANIFEST_FILE"]): + return None + manifest_path = os.environ["RUNFILES_MANIFEST_FILE"] + print_verbose("search manifest for:", rf_root_path) + + # Add trailing space to avoid suffix-string matching + search_for_prefix = rf_root_path.encode("utf8") + b" " + # Use binary to avoid BOM issues on Windows + with open(manifest_path, 'rb') as fp: + for line in fp: + if show_lines: + print_verbose("manifest line:", repr(line)) + # NOTE: This doesn't handle escaped manifest lines + if line.startswith(search_for_prefix): + _, _, main_filename = line.partition(b" ") + return main_filename.strip().decode("utf8") + + return None + + def FindBinary(module_space, bin_name): """Finds the real binary if it's not a normal absolute path.""" if not bin_name: @@ -180,7 +203,13 @@ def FindBinary(module_space, bin_name): # Use normpath() to convert slashes to os.sep on Windows. elif os.sep in os.path.normpath(bin_name): # Case 3: Path is relative to the repo root. - return os.path.join(module_space, bin_name) + full_path = os.path.join(module_space, bin_name) + if os.path.exists(full_path): + return full_path + full_path = maybe_find_in_manifest(bin_name, True) + if not full_path: + raise AssertionError(f"Unable to find Python: {bin_name}") + return full_path else: # Case 4: Path has to be looked up in the search path. return SearchPath(bin_name) @@ -233,6 +262,19 @@ def FindModuleSpace(main_rel_path): raise AssertionError('Cannot find .runfiles directory for %s' % sys.argv[0]) +def find_main_file(module_space, main_rel_path): + main_filename = os.path.join(module_space, main_rel_path) + main_filename = GetWindowsPathWithUNCPrefix(main_filename) + + if os.path.exists(main_filename): + return main_filename + + main_filename = maybe_find_in_manifest(STAGE2_BOOTSTRAP) + if main_filename: + return main_filename + raise AssertionError(f"Cannot find main filename: {main_rel_path}") + + def ExtractZip(zip_path, dest_dir): """Extracts the contents of a zip file, preserving the unix file mode bits. @@ -381,6 +423,13 @@ def Main(): print_verbose("initial cwd:", os.getcwd()) print_verbose("initial environ:", mapping=os.environ) print_verbose("initial sys.path:", values=sys.path) + print_verbose("STAGE2_BOOTSTRAP:", STAGE2_BOOTSTRAP) + print_verbose("PYTHON_BINARY:", PYTHON_BINARY) + print_verbose("PYTHON_BINARY_ACTUAL:", PYTHON_BINARY_ACTUAL) + print_verbose("IS_ZIPFILE:", IS_ZIPFILE) + print_verbose("RECREATE_VENV_AT_RUNTIME:", RECREATE_VENV_AT_RUNTIME) + print_verbose("WORKSPACE_NAME :", WORKSPACE_NAME ) + args = sys.argv[1:] new_env = {} @@ -391,6 +440,7 @@ def Main(): # matters if `_main` doesn't exist (which can occur if a binary # is packaged and needs no artifacts from the main repo) main_rel_path = os.path.normpath(STAGE2_BOOTSTRAP) + print_verbose("main_rel_path:", main_rel_path) if IsRunningFromZip(): module_space = CreateModuleSpace() @@ -399,6 +449,8 @@ def Main(): module_space = FindModuleSpace(main_rel_path) delete_module_space = False + print_verbose("runfiles root:", module_space) + if os.environ.get("RULES_PYTHON_TESTING_TELL_MODULE_SPACE"): new_env["RULES_PYTHON_TESTING_MODULE_SPACE"] = module_space @@ -410,8 +462,7 @@ def Main(): # See: https://docs.python.org/3.11/using/cmdline.html#envvar-PYTHONSAFEPATH new_env['PYTHONSAFEPATH'] = '1' - main_filename = os.path.join(module_space, main_rel_path) - main_filename = GetWindowsPathWithUNCPrefix(main_filename) + main_filename = find_main_file(module_space, main_rel_path) assert os.path.exists(main_filename), \ 'Cannot exec() %r: file not found.' % main_filename assert os.access(main_filename, os.R_OK), \ @@ -419,7 +470,10 @@ def Main(): program = python_program = FindPythonBinary(module_space) if python_program is None: - raise AssertionError('Could not find python binary: ' + repr(PYTHON_BINARY)) + raise AssertionError("Could not find python binary: {} or {}".format( + repr(PYTHON_BINARY), + repr(PYTHON_BINARY_ACTUAL) + )) # Some older Python versions on macOS (namely Python 3.7) may unintentionally # leave this environment variable set after starting the interpreter, which diff --git a/python/private/stage2_bootstrap_template.py b/python/private/stage2_bootstrap_template.py index 959e631ad1..016b5fa7cb 100644 --- a/python/private/stage2_bootstrap_template.py +++ b/python/private/stage2_bootstrap_template.py @@ -48,6 +48,7 @@ COVERAGE_INSTRUMENTED = "%coverage_instrumented%" == "1" # runfiles-root-relative path to a file with binary-specific build information +# It uses forward slashes, so must be converted for proper usage on Windows. BUILD_DATA_FILE = "%build_data_file%" # ===== Template substitutions end ===== @@ -64,9 +65,23 @@ def get_build_data(self): import runfiles except ImportError: from python.runfiles import runfiles - path = runfiles.Create().Rlocation(self.BUILD_DATA_FILE) - with open(path) as fp: - return fp.read() + rlocation_path = self.BUILD_DATA_FILE + if is_windows(): + rlocation_path = rlocation_path.replace("/", "\\") + path = runfiles.Create().Rlocation(rlocation_path) + if is_windows(): + path = os.path.normpath(path) + try: + # Use utf-8-sig to handle Windows BOM + with open(path, encoding='utf-8-sig') as fp: + return fp.read() + except Exception as exc: + if hasattr(exc, "add_note"): + exc.add_note(f"runfiles lookup path: {rlocation_path}") + exc.add_note(f"exists: {os.path.exists(path)}") + can_read = os.access(path, os.R_OK) + exc.add_note(f"readable: {can_read}") + raise sys.modules["bazel_binary_info"] = BazelBinaryInfoModule("bazel_binary_info") @@ -194,6 +209,9 @@ def find_runfiles_root(main_rel_path): else: stub_filename = os.path.join(os.path.dirname(stub_filename), target) + # todo: this can happen if --enable_runfiles=false, which is the default + # on windows. + # To work around this, return None, then have callers handle the case raise AssertionError("Cannot find .runfiles directory for %s" % sys.argv[0]) @@ -439,6 +457,7 @@ def main(): else: runfiles_root = find_runfiles_root("") + # todo: handle missing runfiles root site_packages = os.path.join(runfiles_root, VENV_ROOT, VENV_SITE_PACKAGES) if site_packages not in sys.path and os.path.exists(site_packages): # This can happen in a few situations: @@ -458,6 +477,7 @@ def main(): print_verbose("runfiles root:", runfiles_root) + # todo: handle missing runfiles root runfiles_envkey, runfiles_envvalue = runfiles_envvar(runfiles_root) if runfiles_envkey: os.environ[runfiles_envkey] = runfiles_envvalue @@ -488,6 +508,7 @@ def main(): else: prepend_path_entries = [] + # todo: look in manifest if runfiles_root is None main_filename = os.path.join(runfiles_root, main_rel_path) main_filename = get_windows_path_with_unc_prefix(main_filename) assert os.path.exists(main_filename), ( diff --git a/tests/bootstrap_impls/BUILD.bazel b/tests/bootstrap_impls/BUILD.bazel index e1f60f5b40..d9cfa665ae 100644 --- a/tests/bootstrap_impls/BUILD.bazel +++ b/tests/bootstrap_impls/BUILD.bazel @@ -13,6 +13,8 @@ # limitations under the License. load("@rules_pkg//pkg:tar.bzl", "pkg_tar") load("@rules_shell//shell:sh_test.bzl", "sh_test") +load("//python:py_binary.bzl", "py_binary") +load("//python:py_test.bzl", "py_test") load("//tests/support:py_reconfig.bzl", "py_reconfig_binary", "py_reconfig_test") load("//tests/support:sh_py_run_test.bzl", "sh_py_run_test") load("//tests/support:support.bzl", "SUPPORTS_BOOTSTRAP_SCRIPT") @@ -190,4 +192,13 @@ sh_test( }), ) +py_test( + name = "system_python_nodeps_test", + srcs = ["system_python_nodeps_test.py"], + config_settings = { + "//python/config_settings:bootstrap_impl": "system_python", + ##"//command_line_option:build_runfile_links": "false", + }, +) + relative_path_test_suite(name = "relative_path_tests") diff --git a/tests/bootstrap_impls/system_python_nodeps_test.py b/tests/bootstrap_impls/system_python_nodeps_test.py new file mode 100644 index 0000000000..cde2bcef38 --- /dev/null +++ b/tests/bootstrap_impls/system_python_nodeps_test.py @@ -0,0 +1,5 @@ +import os + +print("Hello, world") +for k, v in sorted(os.environ.items()): + print(k, v) diff --git a/tests/build_data/BUILD.bazel b/tests/build_data/BUILD.bazel index 64db005f51..599e04b875 100644 --- a/tests/build_data/BUILD.bazel +++ b/tests/build_data/BUILD.bazel @@ -21,5 +21,6 @@ genrule( name = "tool_build_data", outs = ["tool_build_data.txt"], cmd = "$(location :print_build_data) > $(OUTS)", + tags = ["manual"], tools = [":print_build_data"], ) diff --git a/tests/integration/compile_pip_requirements/.bazelrc b/tests/integration/compile_pip_requirements/.bazelrc index b85f03bcb6..be2ceedf66 100644 --- a/tests/integration/compile_pip_requirements/.bazelrc +++ b/tests/integration/compile_pip_requirements/.bazelrc @@ -3,3 +3,7 @@ test --test_output=errors # Windows requires these for multi-python support: build --enable_runfiles common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc b/tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc index ab10c8caf7..80d2b0d97d 100644 --- a/tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc +++ b/tests/integration/compile_pip_requirements_test_from_external_repo/.bazelrc @@ -1,2 +1,6 @@ test --test_output=errors common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/tests/integration/local_toolchains/.bazelrc b/tests/integration/local_toolchains/.bazelrc index aed08b0790..6a920b180c 100644 --- a/tests/integration/local_toolchains/.bazelrc +++ b/tests/integration/local_toolchains/.bazelrc @@ -6,3 +6,7 @@ build --enable_runfiles common:bazel7.x --incompatible_python_disallow_native_rules build --//:py=local common --announce_rc + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/tests/integration/pip_parse/.bazelrc b/tests/integration/pip_parse/.bazelrc index a74909297d..3d3d8bd67f 100644 --- a/tests/integration/pip_parse/.bazelrc +++ b/tests/integration/pip_parse/.bazelrc @@ -6,3 +6,7 @@ build --enable_runfiles try-import %workspace%/user.bazelrc common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/tests/integration/py_cc_toolchain_registered/.bazelrc b/tests/integration/py_cc_toolchain_registered/.bazelrc index fb31561892..e5a95490e6 100644 --- a/tests/integration/py_cc_toolchain_registered/.bazelrc +++ b/tests/integration/py_cc_toolchain_registered/.bazelrc @@ -1,3 +1,7 @@ # This aids debugging on failure build --toolchain_resolution_debug=python common:bazel7.x --incompatible_python_disallow_native_rules + +# See issue 3567. Disable implicit python zip creation. +common --build_python_zip=false +common --@rules_python//python/config_settings:build_python_zip=false \ No newline at end of file diff --git a/tests/pypi/whl_installer/wheel_installer_test.py b/tests/pypi/whl_installer/wheel_installer_test.py index 7040b0cfd8..91adddf15a 100644 --- a/tests/pypi/whl_installer/wheel_installer_test.py +++ b/tests/pypi/whl_installer/wheel_installer_test.py @@ -63,7 +63,9 @@ def setUp(self) -> None: shutil.copy(os.path.join("examples", "wheel", self.wheel_name), self.wheel_dir) def tearDown(self): - shutil.rmtree(self.wheel_dir) + # On windows, the wheel file remains open, so gives an error upon + # deletion for some reason. + shutil.rmtree(self.wheel_dir, ignore_errors=True) def test_wheel_exists(self) -> None: wheel_installer._extract_wheel( diff --git a/tests/support/py_reconfig.bzl b/tests/support/py_reconfig.bzl index d0cb968466..9bbfdb1104 100644 --- a/tests/support/py_reconfig.bzl +++ b/tests/support/py_reconfig.bzl @@ -47,8 +47,6 @@ def _perform_transition_impl(input_settings, attr, base_impl): settings[labels.VENVS_USE_DECLARE_SYMLINK] = attr.venvs_use_declare_symlink if attr.venvs_site_packages: settings[labels.VENVS_SITE_PACKAGES] = attr.venvs_site_packages - for key, value in attr.config_settings.items(): - settings[str(key)] = value return settings _BUILTIN_BUILD_PYTHON_ZIP = [] if config.bazel_10_or_later else [ @@ -56,7 +54,9 @@ _BUILTIN_BUILD_PYTHON_ZIP = [] if config.bazel_10_or_later else [ ] _RECONFIG_INPUTS = [ + "//command_line_option:build_runfile_links", "//command_line_option:extra_toolchains", + "//command_line_option:stamp", CUSTOM_RUNTIME, labels.BOOTSTRAP_IMPL, labels.PYTHON_SRC,