Skip to content

Commit

Permalink
Added stamp attribute to py_wheel
Browse files Browse the repository at this point in the history
  • Loading branch information
UebelAndre committed Oct 22, 2021
1 parent 77e4a70 commit 5439a0f
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 16 deletions.
9 changes: 9 additions & 0 deletions docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ bzl_library(
],
)

bzl_library(
name = "packaging_bzl",
srcs = [
"//python:packaging.bzl",
"//python/private:stamp.bzl",
],
)

stardoc(
name = "core-docs",
out = "python.md_",
Expand Down Expand Up @@ -103,6 +111,7 @@ stardoc(
name = "packaging-docs",
out = "packaging.md_",
input = "//python:packaging.bzl",
deps = [":packaging_bzl"],
)

[
Expand Down
24 changes: 22 additions & 2 deletions docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ This rule is intended to be used as data dependency to py_wheel rule
<pre>
py_wheel(<a href="#py_wheel-name">name</a>, <a href="#py_wheel-abi">abi</a>, <a href="#py_wheel-author">author</a>, <a href="#py_wheel-author_email">author_email</a>, <a href="#py_wheel-classifiers">classifiers</a>, <a href="#py_wheel-console_scripts">console_scripts</a>, <a href="#py_wheel-deps">deps</a>, <a href="#py_wheel-description_file">description_file</a>,
<a href="#py_wheel-distribution">distribution</a>, <a href="#py_wheel-entry_points">entry_points</a>, <a href="#py_wheel-extra_requires">extra_requires</a>, <a href="#py_wheel-homepage">homepage</a>, <a href="#py_wheel-license">license</a>, <a href="#py_wheel-platform">platform</a>, <a href="#py_wheel-python_requires">python_requires</a>,
<a href="#py_wheel-python_tag">python_tag</a>, <a href="#py_wheel-requires">requires</a>, <a href="#py_wheel-strip_path_prefixes">strip_path_prefixes</a>, <a href="#py_wheel-version">version</a>)
<a href="#py_wheel-python_tag">python_tag</a>, <a href="#py_wheel-requires">requires</a>, <a href="#py_wheel-stamp">stamp</a>, <a href="#py_wheel-strip_path_prefixes">strip_path_prefixes</a>, <a href="#py_wheel-version">version</a>)
</pre>


Expand Down Expand Up @@ -101,7 +101,27 @@ py_wheel(
| python_requires | A string specifying what other distributions need to be installed when this one is. See the section on [Declaring required dependency](https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html#declaring-dependencies) for details and examples of the format of this argument. | String | optional | "" |
| python_tag | Supported Python version(s), eg <code>py3</code>, <code>cp35.cp36</code>, etc | String | optional | "py3" |
| requires | List of requirements for this package | List of strings | optional | [] |
| stamp | Whether to encode build information into the wheel. Possible values:<br><br>- <code>stamp = 1</code>: Always stamp the build information into the wheel, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it potentially kills remote caching for the target and any downstream actions that depend on it.<br><br>- <code>stamp = 0</code>: Always replace build information by constant values. This gives good build result caching.<br><br>- <code>stamp = -1</code>: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.<br><br>Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | -1 |
| strip_path_prefixes | path prefixes to strip from files added to the generated package | List of strings | optional | [] |
| version | Version number of the package | String | required | |
| version | Version number of the package. Note that this attribute suppots stamp format strings. Eg <code>1.2.3-{BUILD_TIMESTAMP}</code> | String | required | |


<a name="#PyWheelInfo"></a>

## PyWheelInfo

<pre>
PyWheelInfo(<a href="#PyWheelInfo-name_file">name_file</a>, <a href="#PyWheelInfo-wheel">wheel</a>)
</pre>

Information about a wheel produced by `py_wheel`

**FIELDS**


| Name | Description |
| :-------------: | :-------------: |
| name_file | File: A file containing the canonical name of the wheel (after stamping, if enabled). |
| wheel | File: The wheel file itself. |


14 changes: 14 additions & 0 deletions examples/wheel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ py_wheel(
],
)

# Package just a specific py_libraries, without their dependencies
py_wheel(
name = "minimal_with_py_library_with_stamp",
# Package data. We're building "example_minimal_library-0.0.1-py3-none-any.whl"
distribution = "example_minimal_library",
python_tag = "py3",
stamp = 1,
version = "0.1.{BUILD_TIMESTAMP}",
deps = [
"//examples/wheel/lib:module_with_data",
"//examples/wheel/lib:simple_module",
],
)

# Use py_package to collect all transitive dependencies of a target,
# selecting just the files within a specific python package.
py_package(
Expand Down
67 changes: 60 additions & 7 deletions python/packaging.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@

"""Rules for building wheels."""

load("//python/private:stamp.bzl", "is_stamping_enabled")

PyWheelInfo = provider(
doc = "Information about a wheel produced by `py_wheel`",
fields = {
"name_file": (
"File: A file containing the canonical name of the wheel (after " +
"stamping, if enabled)."
),
"wheel": "File: The wheel file itself.",
},
)

def _path_inside_wheel(input_file):
# input_file.short_path is sometimes relative ("../${repository_root}/foobar")
# which is not a valid path within a zip file. Fix that.
Expand Down Expand Up @@ -110,6 +123,8 @@ def _py_wheel_impl(ctx):
_escape_filename_segment(ctx.attr.platform),
]) + ".whl")

name_file = ctx.actions.declare_file(ctx.label.name + ".name")

inputs_to_package = depset(
direct = ctx.files.deps,
)
Expand All @@ -133,9 +148,15 @@ def _py_wheel_impl(ctx):
args.add("--python_requires", ctx.attr.python_requires)
args.add("--abi", ctx.attr.abi)
args.add("--platform", ctx.attr.platform)
args.add("--out", outfile.path)
args.add("--out", outfile)
args.add("--name_file", name_file)
args.add_all(ctx.attr.strip_path_prefixes, format_each = "--strip_path_prefix=%s")

# Pass workspace status files if stamping is enabled
if is_stamping_enabled(ctx.attr):
args.add("--volatile_status_file", ctx.version_file)
other_inputs.append(ctx.version_file)

args.add("--input_file_list", packageinputfile)

extra_headers = []
Expand Down Expand Up @@ -193,15 +214,21 @@ def _py_wheel_impl(ctx):

ctx.actions.run(
inputs = depset(direct = other_inputs, transitive = [inputs_to_package]),
outputs = [outfile],
outputs = [outfile, name_file],
arguments = [args],
executable = ctx.executable._wheelmaker,
progress_message = "Building wheel",
)
return [DefaultInfo(
files = depset([outfile]),
data_runfiles = ctx.runfiles(files = [outfile]),
)]
return [
DefaultInfo(
files = depset([outfile]),
runfiles = ctx.runfiles(files = [outfile]),
),
PyWheelInfo(
wheel = outfile,
name_file = name_file,
),
]

def _concat_dicts(*dicts):
result = {}
Expand Down Expand Up @@ -247,9 +274,35 @@ platform = select({
default = "py3",
doc = "Supported Python version(s), eg `py3`, `cp35.cp36`, etc",
),
"stamp": attr.int(
doc = """\
Whether to encode build information into the wheel. Possible values:
- `stamp = 1`: Always stamp the build information into the wheel, even in \
[--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. \
This setting should be avoided, since it potentially kills remote caching for the target and \
any downstream actions that depend on it.
- `stamp = 0`: Always replace build information by constant values. This gives good build result caching.
- `stamp = -1`: Embedding of build information is controlled by the \
[--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.
Stamped targets are not rebuilt unless their dependencies change.
""",
default = -1,
values = [1, 0, -1],
),
"version": attr.string(
mandatory = True,
doc = "Version number of the package",
doc = (
"Version number of the package. Note that this attribute " +
"suppots stamp format strings. Eg `1.2.3-{BUILD_TIMESTAMP}`"
),
),
"_stamp_flag": attr.label(
doc = "A setting used to determine whether or not the `--stamp` flag is enabled",
default = Label("//python/private:stamp"),
),
}

Expand Down
5 changes: 5 additions & 0 deletions python/private/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

load(":stamp.bzl", "stamp_build_setting")

licenses(["notice"]) # Apache 2.0

filegroup(
Expand Down Expand Up @@ -39,3 +41,6 @@ exports_files(
],
visibility = ["//docs:__pkg__"],
)

# Used to determine the use of `--stamp` in Starlark rules
stamp_build_setting(name = "stamp")
73 changes: 73 additions & 0 deletions python/private/stamp.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""A small utility module dedicated to detecting whether or not the `--stamp` flag is enabled
This module can be removed likely after the following PRs ar addressed:
- https://github.com/bazelbuild/bazel/issues/11164
"""

StampSettingInfo = provider(
doc = "Information about the `--stamp` command line flag",
fields = {
"value": "bool: Whether or not the `--stamp` flag was enabled",
},
)

def _stamp_build_setting_impl(ctx):
return StampSettingInfo(value = ctx.attr.value)

_stamp_build_setting = rule(
doc = """\
Whether to encode build information into the binary. Possible values:
- stamp = 1: Always stamp the build information into the binary, even in [--nostamp][stamp] builds. \
This setting should be avoided, since it potentially kills remote caching for the binary and \
any downstream actions that depend on it.
- stamp = 0: Always replace build information by constant values. This gives good build result caching.
- stamp = -1: Embedding of build information is controlled by the [--[no]stamp][stamp] flag.
Stamped binaries are not rebuilt unless their dependencies change.
[stamp]: https://docs.bazel.build/versions/main/user-manual.html#flag--stamp
""",
implementation = _stamp_build_setting_impl,
attrs = {
"value": attr.bool(
doc = "The default value of the stamp build flag",
mandatory = True,
),
},
)

def stamp_build_setting(name, visibility = ["//visibility:public"]):
native.config_setting(
name = "stamp_detect",
values = {"stamp": "1"},
visibility = visibility,
)

_stamp_build_setting(
name = name,
value = select({
":stamp_detect": True,
"//conditions:default": False,
}),
visibility = visibility,
)

def is_stamping_enabled(attr):
"""Determine whether or not build staming is enabled
Args:
attr (struct): A rule's struct of attributes (`ctx.attr`)
Returns:
bool: The stamp value
"""
stamp_num = getattr(attr, "stamp", -1)
if stamp_num == 1:
return True
elif stamp_num == 0:
return False
elif stamp_num == -1:
stamp_flag = getattr(attr, "_stamp_flag", None)
return stamp_flag[StampSettingInfo].value if stamp_flag else False
else:
fail("Unexpected `stamp` value: {}".format(stamp_num))
Loading

0 comments on commit 5439a0f

Please sign in to comment.