Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[install] Use file argument for actions, not template substitution #16252

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ else()
set(BAZEL_ARGS)
endif()

# N.B. If you are testing the CMake API and making changes to `install.py.in`,
# N.B. If you are testing the CMake API and making changes to `installer.py`,
# you can change this target to something more lightweight, such as
# `//tools/install/dummy:install`.
set(BAZEL_TARGETS //:install)
Expand Down
8 changes: 6 additions & 2 deletions tools/install/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ load("//tools/skylark:py.bzl", "py_library")
load("//tools/lint:lint.bzl", "add_lint_tests")
load(
"@drake//tools/skylark:drake_py.bzl",
"drake_py_binary",
"drake_py_unittest",
)

Expand All @@ -15,16 +16,19 @@ py_library(
srcs = ["install_test_helper.py"],
data = ["//:install"],
imports = ["."],
visibility = ["//visibility:public"],
)

exports_files(
[
"install.py.in",
"install_test.py",
],
)

drake_py_binary(
name = "installer",
srcs = ["installer.py"],
)

# Runs `install_test_helper` unit tests.
drake_py_unittest(
name = "install_test_helper_test",
Expand Down
40 changes: 26 additions & 14 deletions tools/install/install.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -483,13 +483,23 @@ def _install_impl(ctx):
"\n src2 = " + repr(src) +
"\n dst = " + repr(a.dst))

# Generate installer manifest.
actions_file = ctx.actions.declare_file(ctx.attr.name + "_actions")
ctx.actions.write(
output = actions_file,
content = "\n".join(script_actions) + "\n",
)

# Generate install script.
# TODO(mwoehlke-kitware): Figure out a better way to generate this and run
# it via Python than `#!/usr/bin/env python3`?
ctx.actions.expand_template(
template = ctx.executable.install_script_template,
ctx.actions.write(
output = ctx.outputs.executable,
substitutions = {"<<actions>>": "\n ".join(script_actions)},
content = "\n".join([
"#!/bin/bash",
"tools/install/installer --actions '{}' \"$@\"".format(
actions_file.short_path,
),
]),
is_executable = True,
)

script_tests = []
Expand All @@ -498,7 +508,7 @@ def _install_impl(ctx):
for i in installed_tests:
script_tests.append(i.cmd)

# Generate test installation script
# Generate test installation script.
if ctx.attr.install_tests_script and not script_tests:
fail("`install_tests_script` is not empty but no `script_tests` were provided.") # noqa
if ctx.attr.install_tests_script:
Expand All @@ -509,9 +519,11 @@ def _install_impl(ctx):
)

# Return actions.
files = ctx.runfiles(
files = [a.src for a in actions if not hasattr(a, "main_class")] +
[i.src for i in installed_tests],
runfiles = (
[a.src for a in actions if not hasattr(a, "main_class")] +
[i.src for i in installed_tests] +
ctx.files._installer +
[actions_file]
)
return [
InstallInfo(
Expand All @@ -520,7 +532,7 @@ def _install_impl(ctx):
installed_files = installed_files,
),
InstalledTestInfo(tests = installed_tests),
DefaultInfo(runfiles = files),
DefaultInfo(runfiles = ctx.runfiles(files = runfiles)),
]

# TODO(mwoehlke-kitware) default guess_data to PACKAGE when we have better
Expand Down Expand Up @@ -560,12 +572,12 @@ _install_rule = rule(
),
"workspace": attr.string(),
"allowed_externals": attr.label_list(allow_files = True),
"install_script_template": attr.label(
allow_files = True,
"_installer": attr.label(
executable = True,
cfg = "target",
default = Label("//tools/install:install.py.in"),
cfg = "host",
default = Label("//tools/install:installer"),
),
"install_script": attr.output(),
"install_tests_script": attr.output(),
},
executable = True,
Expand Down
20 changes: 14 additions & 6 deletions tools/install/install.py.in → tools/install/installer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
"""
Installation script generated from a Bazel `install` target.
"""
Expand Down Expand Up @@ -197,8 +196,8 @@ def fix_rpaths_and_strip():
# dictionary to fixup other library and executable paths.
continue
# Enable write permissions to allow modification.
os.chmod(dst_full, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
os.chmod(dst_full, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
| stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
if sys.platform == "darwin":
# From the manual for BSD `strip`: for dynamic shared libraries,
# the maximum level of stripping is usually -x (to remove all
Expand Down Expand Up @@ -364,8 +363,8 @@ def create_java_launcher(filename, classpath, jvm_flags, main_class):
java {} {} "$@"
""".format(strclasspath, jvm_flags, main_class)
launcher_file.write(content)
os.chmod(filename, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH |
stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
os.chmod(filename, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH
| stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)


def main(args):
Expand All @@ -379,6 +378,9 @@ def main(args):
# Set up options.
parser = argparse.ArgumentParser()
parser.add_argument('prefix', type=str, help='Install prefix')
parser.add_argument(
'--actions', type=str, required=True,
help='file path to installer actions')
parser.add_argument(
'--color', action='store_true', default=False,
help='colorize the output')
Expand Down Expand Up @@ -447,7 +449,13 @@ def main(args):
ansi_color_escape, ansi_reset_escape))

# Execute the install actions.
<<actions>>
# TODO(jwnimmer-tri) Executing arbitrary Python code from the actions file
# is an absurd implementation choice that we've inherited from the original
# installer scripts. We should rework the install.bzl <=> installer.py
# specification format to use something other than open-ended Python code.
with open(args.actions, "r", encoding="utf-8") as f:
actions = f.read()
exec(actions)

# Libraries paths may need to be updated in libraries and executables.
fix_rpaths_and_strip()
Expand Down
2 changes: 1 addition & 1 deletion tools/install/test/install_meta_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests the behavior of targets generated from `install.py.in`."""
"""Tests the behavior of targets that use `installer.py`."""

import os
from os.path import isdir, join, relpath
Expand Down