diff --git a/lib/apple_support.bzl b/lib/apple_support.bzl index a518e15..28839b1 100644 --- a/lib/apple_support.bzl +++ b/lib/apple_support.bzl @@ -100,7 +100,23 @@ def _validate_attribute_present(ctx, attribute_name): ])) def _action_required_attrs(): - """Returns a dictionary with required attributes for registering actions on Apple platforms.""" + """Returns a dictionary with required attributes for registering actions on Apple platforms. + + This method adds private attributes which should not be used outside of the apple_support + codebase. It also adds the following attributes which are considered to be public for rule + maintainers to use: + + * _xcode_config: Attribute that references a target containing the single + apple_common.XcodeVersionConfig provider. This provider can be used to inspect Xcode-related + properties about the Xcode being used for the build, as specified with the `--xcode_version` + Bazel flag. The most common way to retrieve this provider is: + `ctx.attr._xcode_config[apple_common.XcodeVersionConfig]`. + + The returned `dict` can be added to the rule's attributes using Skylib's `dicts.add()` method. + + Returns: + A `dict` object containing attributes to be added to rule implementations. + """ return { "_xcode_config": attr.label( default = configuration_field( diff --git a/lib/xcode_support.bzl b/lib/xcode_support.bzl new file mode 100644 index 0000000..00824a4 --- /dev/null +++ b/lib/xcode_support.bzl @@ -0,0 +1,43 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Support functions for working with Xcode configurations.""" + +def _is_xcode_at_least_version(xcode_config, version): + """Returns True if Xcode version is at least a given version. + + This method takes as input an `XcodeVersionConfig` provider, which can be obtained from the + `_xcode_config` attribute (e.g. `ctx.attr._xcode_config[apple_common.XcodeVersionConfig]`). This + provider should contain the Xcode version parameters with which this rule is being built with. + If you need to add this attribute to your rule implementation, please refer to + `apple_support.action_required_attrs`. + + Args: + xcode_config: The XcodeVersionConfig provider from the _xcode_config attribute's value. + version: The minimum desired Xcode version, as a dotted version string. + Returns: + True if the given xcode_config version at least as high as the requested version. + """ + current_version = xcode_config.xcode_version() + if not current_version: + fail("Could not determine Xcode version at all. This likely means Xcode isn't available; " + + "if you think this is a mistake, please file an issue.") + + desired_version = apple_common.dotted_version(version) + return current_version >= desired_version + +# Define the loadable module that lists the exported symbols in this file. +xcode_support = struct( + is_xcode_at_least_version = _is_xcode_at_least_version, +) diff --git a/test/BUILD b/test/BUILD index befdd3d..d89094f 100644 --- a/test/BUILD +++ b/test/BUILD @@ -1,5 +1,25 @@ +load("@build_bazel_apple_support//rules:apple_genrule.bzl", "apple_genrule") load(":apple_support_test.bzl", "apple_support_test") +load(":xcode_support_test.bzl", "xcode_support_test") licenses(["notice"]) -apple_support_test(name = "test") +# Custom rules that test rule-context APIs. Check their implementations for more details. +apple_support_test(name = "apple_support_test") + +xcode_support_test(name = "xcode_support_test") + +# Test to ensure the environment variable contract of apple_genrule. +sh_test( + name = "apple_genrule_test", + size = "small", + srcs = ["apple_genrule_test.sh"], + args = ["$(location simple_genrule.txt)"], + data = ["simple_genrule.txt"], +) + +apple_genrule( + name = "simple_genrule", + outs = ["simple_genrule.txt"], + cmd = "printenv | grep \"^\\(DEVELOPER_DIR\\|SDKROOT\\)\" > $(@)", +) diff --git a/test/apple_genrule_test.sh b/test/apple_genrule_test.sh new file mode 100755 index 0000000..34d6523 --- /dev/null +++ b/test/apple_genrule_test.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu + +# Integration test for apple_genrule. + +# This test checks that the first argument contains a file that contains +# Xcode environment variables. Since the file was generated using an +# apple_genrule using `printenv`, we enforce that the contract of providing the +# DEVELOPER_DIR and SDKROOT environment variables is maintained. + +INPUT_FILE="$1" + +if ! grep -Fq DEVELOPER_DIR "$INPUT_FILE"; then + echo "FAILURE: DEVELOPER_DIR not found." + exit 1 +fi + +if ! grep -Fq SDKROOT "$INPUT_FILE"; then + echo "FAILURE: SDKROOT not found." + exit 1 +fi diff --git a/test/xcode_support_test.bzl b/test/xcode_support_test.bzl new file mode 100644 index 0000000..27deeba --- /dev/null +++ b/test/xcode_support_test.bzl @@ -0,0 +1,59 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Definition of a test rule to test xcode_support.""" + +load( + "@build_bazel_apple_support//lib:apple_support.bzl", + "apple_support", +) +load( + "@build_bazel_apple_support//lib:xcode_support.bzl", + "xcode_support", +) + +# Template for the test script used to validate that the action outputs contain the expected +# values. +_TEST_SCRIPT_CONTENTS = """ +#!/bin/bash + +set -eu + +if [[ "{past_version_is_true}" != "True" ]]; then + echo "FAILURE: 'past_version_is_true' should be True, but it's {past_version_is_true}." + exit 1 +fi + +if [[ "{future_version_is_false}" != "False" ]]; then + echo "FAILURE: 'future_version_is_false' should be False, but it's {future_version_is_false}." + exit 1 +fi +""" + +def _xcode_support_test_impl(ctx): + """Implementation of the xcode_support_test rule.""" + + test_script = ctx.actions.declare_file("{}_test_script".format(ctx.label.name)) + xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] + ctx.actions.write(test_script, _TEST_SCRIPT_CONTENTS.format( + past_version_is_true = str(xcode_support.is_xcode_at_least_version(xcode_config, "1.0")), + future_version_is_false = str(xcode_support.is_xcode_at_least_version(xcode_config, "999")), + ), is_executable = True) + + return [DefaultInfo(executable = test_script)] + +xcode_support_test = rule( + implementation = _xcode_support_test_impl, + attrs = apple_support.action_required_attrs(), + test = True, +)