diff --git a/experimental/examples/wheel/BUILD b/experimental/examples/wheel/BUILD index d7ed5da49c..5c3bff6690 100644 --- a/experimental/examples/wheel/BUILD +++ b/experimental/examples/wheel/BUILD @@ -85,6 +85,51 @@ py_wheel( deps = [":example_pkg"], ) +# An example of how to change the wheel package root directory using 'strip_path_prefixes'. +py_wheel( + name = "custom_package_root", + # Package data. We're building "custom_package_root-0.0.1-py3-none-any.whl" + distribution = "example_custom_package_root", + python_tag = "py3", + version = "0.0.1", + deps = [ + ":example_pkg" + ], + strip_path_prefixes = [ + "experimental" + ] +) + +py_wheel( + name = "custom_package_root_multi_prefix", + # Package data. We're building "custom_custom_package_root_multi_prefix-0.0.1-py3-none-any.whl" + distribution = "example_custom_package_root_multi_prefix", + python_tag = "py3", + version = "0.0.1", + deps = [ + ":example_pkg" + ], + strip_path_prefixes = [ + "experimental/examples/wheel/lib", + "experimental/examples/wheel" + ] +) + +py_wheel( + name = "custom_package_root_multi_prefix_reverse_order", + # Package data. We're building "custom_custom_package_root_multi_prefix_reverse_order-0.0.1-py3-none-any.whl" + distribution = "example_custom_package_root_multi_prefix_reverse_order", + python_tag = "py3", + version = "0.0.1", + deps = [ + ":example_pkg" + ], + strip_path_prefixes = [ + "experimental/examples/wheel" , + "experimental/examples/wheel/lib" # this is not effective, because the first prefix takes priority + ] +) + py_test( name = "wheel_test", srcs = ["wheel_test.py"], @@ -92,5 +137,8 @@ py_test( ":customized", ":minimal_with_py_library", ":minimal_with_py_package", - ], + ":custom_package_root", + ":custom_package_root_multi_prefix", + ":custom_package_root_multi_prefix_reverse_order" + ] ) diff --git a/experimental/examples/wheel/wheel_test.py b/experimental/examples/wheel/wheel_test.py index 278f00726a..d7bb8b6b4e 100644 --- a/experimental/examples/wheel/wheel_test.py +++ b/experimental/examples/wheel/wheel_test.py @@ -102,6 +102,57 @@ def test_customized_wheel(self): This is a sample description of a wheel. """) + def test_custom_package_root_wheel(self): + filename = os.path.join(os.environ['TEST_SRCDIR'], + 'io_bazel_rules_python', 'experimental', + 'examples', 'wheel', + 'example_custom_package_root-0.0.1-py3-none-any.whl') + + with zipfile.ZipFile(filename) as zf: + self.assertEquals( + zf.namelist(), + ['examples/wheel/lib/data.txt', + 'examples/wheel/lib/module_with_data.py', + 'examples/wheel/lib/simple_module.py', + 'examples/wheel/main.py', + 'example_custom_package_root-0.0.1.dist-info/WHEEL', + 'example_custom_package_root-0.0.1.dist-info/METADATA', + 'example_custom_package_root-0.0.1.dist-info/RECORD']) + + def test_custom_package_root_multi_prefix_wheel(self): + filename = os.path.join(os.environ['TEST_SRCDIR'], + 'io_bazel_rules_python', 'experimental', + 'examples', 'wheel', + 'example_custom_package_root_multi_prefix-0.0.1-py3-none-any.whl') + + with zipfile.ZipFile(filename) as zf: + self.assertEquals( + zf.namelist(), + ['data.txt', + 'module_with_data.py', + 'simple_module.py', + 'main.py', + 'example_custom_package_root_multi_prefix-0.0.1.dist-info/WHEEL', + 'example_custom_package_root_multi_prefix-0.0.1.dist-info/METADATA', + 'example_custom_package_root_multi_prefix-0.0.1.dist-info/RECORD']) + + def test_custom_package_root_multi_prefix_reverse_order_wheel(self): + filename = os.path.join(os.environ['TEST_SRCDIR'], + 'io_bazel_rules_python', 'experimental', + 'examples', 'wheel', + 'example_custom_package_root_multi_prefix_reverse_order-0.0.1-py3-none-any.whl') + + with zipfile.ZipFile(filename) as zf: + self.assertEquals( + zf.namelist(), + ['lib/data.txt', + 'lib/module_with_data.py', + 'lib/simple_module.py', + 'main.py', + 'example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/WHEEL', + 'example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/METADATA', + 'example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/RECORD']) + if __name__ == '__main__': unittest.main() diff --git a/experimental/python/wheel.bzl b/experimental/python/wheel.bzl index 75c4711d6d..1c43409cd5 100644 --- a/experimental/python/wheel.bzl +++ b/experimental/python/wheel.bzl @@ -102,6 +102,7 @@ def _py_wheel_impl(ctx): args.add("--abi", ctx.attr.abi) args.add("--platform", ctx.attr.platform) args.add("--out", outfile.path) + args.add_all(ctx.attr.strip_path_prefixes, format_each = "--strip_path_prefix=%s") args.add_all(inputs_to_package, format_each = "--input_file=%s", map_each = _input_file_to_arg) @@ -242,6 +243,10 @@ to refer to the package in other packages' dependencies. "license": attr.string(default = ""), "classifiers": attr.string_list(), "description_file": attr.label(allow_single_file = True), + "strip_path_prefixes": attr.string_list( + default = [], + doc = "path prefixes to strip from files added to the generated package", + ), # Requirements "requires": attr.string_list( doc = "List of requirements for this package", diff --git a/experimental/rules_python/wheelmaker.py b/experimental/rules_python/wheelmaker.py index 7a50ae4a20..ca3279f3ff 100644 --- a/experimental/rules_python/wheelmaker.py +++ b/experimental/rules_python/wheelmaker.py @@ -15,9 +15,7 @@ import argparse import base64 import collections -import csv import hashlib -import io import os import os.path import sys @@ -35,7 +33,7 @@ def commonpath(path1, path2): class WheelMaker(object): def __init__(self, name, version, build_tag, python_tag, abi, platform, - outfile=None): + outfile=None, strip_path_prefixes=None): self._name = name self._version = version self._build_tag = build_tag @@ -43,6 +41,7 @@ def __init__(self, name, version, build_tag, python_tag, abi, platform, self._abi = abi self._platform = platform self._outfile = outfile + self._strip_path_prefixes = strip_path_prefixes if strip_path_prefixes is not None else [] self._zipfile = None self._record = [] @@ -93,8 +92,17 @@ def add_string(self, filename, contents): def add_file(self, package_filename, real_filename): """Add given file to the distribution.""" - # Always use unix path separators. - arcname = package_filename.replace(os.path.sep, '/') + def arcname_from(name): + # Always use unix path separators. + normalized_arcname = name.replace(os.path.sep, '/') + for prefix in self._strip_path_prefixes: + if normalized_arcname.startswith(prefix): + return normalized_arcname[len(prefix):] + + return normalized_arcname + + arcname = arcname_from(package_filename) + self._zipfile.write(real_filename, arcname=arcname) # Find the hash and length hash = hashlib.sha256() @@ -208,6 +216,15 @@ def main(): output_group.add_argument('--out', type=str, default=None, help="Override name of ouptut file") + output_group.add_argument('--strip_path_prefix', + type=str, + action="append", + default=[], + help="Path prefix to be stripped from input package files' path. " + "Can be supplied multiple times. " + "Evaluated in order." + ) + wheel_group = parser.add_argument_group("Wheel metadata") wheel_group.add_argument( '--header', action='append', @@ -248,13 +265,17 @@ def main(): # Sort the files for reproducible order in the archive. all_files = sorted(all_files.items()) + strip_prefixes = [p for p in arguments.strip_path_prefix] + with WheelMaker(name=arguments.name, version=arguments.version, build_tag=arguments.build_tag, python_tag=arguments.python_tag, abi=arguments.abi, platform=arguments.platform, - outfile=arguments.out) as maker: + outfile=arguments.out, + strip_path_prefixes=strip_prefixes + ) as maker: for package_filename, real_filename in all_files: maker.add_file(package_filename, real_filename) maker.add_wheelfile()