From ca3ba210ee6ac673246cdbc35d30b6ed5f80e39b Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Tue, 23 Nov 2021 22:10:44 +0100 Subject: [PATCH] Work around Bazel launcher issues on Windows. --- elisp/process.cc | 19 ++++++++++++++++++- elisp/run_binary.py | 10 ++++++++-- elisp/run_emacs.py | 10 ++++++++-- elisp/run_test.py | 10 ++++++++-- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/elisp/process.cc b/elisp/process.cc index 8668d897..0d02cfd1 100644 --- a/elisp/process.cc +++ b/elisp/process.cc @@ -396,9 +396,26 @@ absl::StatusOr Run(std::string binary, absl::StatusOr resolved_binary = runfiles.Resolve(binary); if (!resolved_binary.ok()) return resolved_binary.status(); std::vector final_args{*resolved_binary}; - final_args.insert(final_args.end(), args.begin(), args.end()); absl::StatusOr map = runfiles.Environment(); if (!map.ok()) return map.status(); + std::vector runfiles_args; + // Pass the runfiles environment variables as separate arguments. This is + // necessary because the binary launcher unconditionally sets the runfiles + // environment variables based on its own argv[0]; see + // https://github.com/bazelbuild/bazel/blob/6.0.0-pre.20211110.1/src/tools/launcher/launcher.cc. + // We also can’t set argv[0] to this binary because the launcher uses it to + // find and its own binary; see + // https://github.com/bazelbuild/bazel/blob/6.0.0-pre.20211110.1/src/tools/launcher/launcher_main.cc. + for (const auto& p : *map) { + runfiles_args.push_back(PHST_RULES_ELISP_NATIVE_LITERAL("--runfiles_env=") + + p.first + PHST_RULES_ELISP_NATIVE_LITERAL('=') + + p.second); + } + // Sort entries for hermeticity. + absl::c_sort(runfiles_args); + final_args.insert(final_args.end(), runfiles_args.begin(), + runfiles_args.end()); + final_args.insert(final_args.end(), args.begin(), args.end()); map->insert(orig_env.begin(), orig_env.end()); std::vector final_env; for (const auto& p : *map) { diff --git a/elisp/run_binary.py b/elisp/run_binary.py index 17db6f41..af61b5cb 100644 --- a/elisp/run_binary.py +++ b/elisp/run_binary.py @@ -23,7 +23,7 @@ import pathlib import subprocess import sys -from typing import Iterable, Mapping, Optional, Sequence +from typing import Iterable, Mapping, Optional, Sequence, Tuple from phst_rules_elisp.elisp import load from phst_rules_elisp.elisp import manifest @@ -32,6 +32,8 @@ def main() -> None: """Main function.""" parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument('--runfiles_env', action='append', type=_env_var, + default=[]) parser.add_argument('--wrapper', type=pathlib.PurePosixPath, required=True) parser.add_argument('--mode', choices=('direct', 'wrap'), required=True) parser.add_argument('--rule-tag', action='append', default=[]) @@ -46,7 +48,7 @@ def main() -> None: parser.add_argument('argv', nargs='+') opts = parser.parse_args() orig_env = dict(os.environ) - run_files = runfiles.Runfiles() + run_files = runfiles.Runfiles(dict(opts.runfiles_env)) emacs = run_files.resolve(opts.wrapper) args = [opts.argv[0]] with manifest.add(opts.mode, args) as manifest_file: @@ -103,5 +105,9 @@ def _arg_files(argv: Sequence[str], root: pathlib.Path, result.append(file) return tuple(result) +def _env_var(arg: str) -> Tuple[str, str]: + key, _, value = arg.partition('=') + return key, value + if __name__ == '__main__': main() diff --git a/elisp/run_emacs.py b/elisp/run_emacs.py index 3aeab3c8..1c603dc8 100644 --- a/elisp/run_emacs.py +++ b/elisp/run_emacs.py @@ -26,20 +26,22 @@ import subprocess import sys import tempfile -from typing import Iterable +from typing import Iterable, Tuple from phst_rules_elisp.elisp import runfiles def main() -> None: """Main function.""" parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument('--runfiles_env', action='append', type=_env_var, + default=[]) parser.add_argument('--install', type=pathlib.PurePosixPath, required=True) parser.add_argument('--archive', type=pathlib.PurePosixPath, required=True) parser.add_argument('--dump-mode', choices=('portable', 'unexec'), required=True) parser.add_argument('argv', nargs='+') opts = parser.parse_args() - run_files = runfiles.Runfiles() + run_files = runfiles.Runfiles(dict(opts.runfiles_env)) try: install = run_files.resolve(opts.install) remove = False @@ -99,5 +101,9 @@ def _check_codepage(description: str, values: Iterable[str]) -> None: raise ValueError( f'can’t encode {description} “{value}” for Windows') from ex +def _env_var(arg: str) -> Tuple[str, str]: + key, _, value = arg.partition('=') + return key, value + if __name__ == '__main__': main() diff --git a/elisp/run_test.py b/elisp/run_test.py index 3193e065..1162f109 100644 --- a/elisp/run_test.py +++ b/elisp/run_test.py @@ -23,7 +23,7 @@ import pathlib import subprocess import sys -from typing import List +from typing import List, Tuple import urllib.parse import warnings @@ -34,6 +34,8 @@ def main() -> None: """Main function.""" parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument('--runfiles_env', action='append', type=_env_var, + default=[]) parser.add_argument('--wrapper', type=pathlib.PurePosixPath, required=True) parser.add_argument('--mode', choices=('direct', 'wrap'), required=True) parser.add_argument('--rule-tag', action='append', default=[]) @@ -48,7 +50,7 @@ def main() -> None: parser.add_argument('argv', nargs='+') opts = parser.parse_args() orig_env = dict(os.environ) - run_files = runfiles.Runfiles() + run_files = runfiles.Runfiles(dict(opts.runfiles_env)) emacs = run_files.resolve(opts.wrapper) args = [opts.argv[0]] with manifest.add(opts.mode, args) as manifest_file: @@ -124,6 +126,10 @@ def _fix_coverage_manifest(manifest_file: pathlib.Path, for file in files: stream.write(file + '\n') +def _env_var(arg: str) -> Tuple[str, str]: + key, _, value = arg.partition('=') + return key, value + _WINDOWS = os.name == 'nt' if __name__ == '__main__':