Skip to content
This repository has been archived by the owner on Apr 3, 2023. It is now read-only.

Add support for specifying DEVELOPER_DIR as environment variable and env attribute value. #80

Merged
merged 8 commits into from
Sep 21, 2021
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
28 changes: 27 additions & 1 deletion .github/workflows/bazel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,38 @@ jobs:
cd examples/simple
bazelisk test //...

- name: Test Simple Example with Older Xcode
- name: Test Simple Example, Build with Older Xcode
shell: bash
run: |
cd examples/simple
# Default Xcode has SPM 5.4 or later; build with Xcode that has SPM
# less than 5.4.
bazelisk test --xcode_version_config=//:host_xcodes //...

- name: Test Simple Example, Default Xcode is Incompatible, Use DEVELOPER_DIR
shell: bash
run: |
cd examples/simple
current_xcode=$(xcode-select --print-path)
echo "current_xcode: ${current_xcode}"
# Switch default Xcode to SPM 5.3.
sudo xcode-select --switch /Applications/Xcode_12.4.app
# Use DEVELOPER_DIR to specify the current Xcode
export DEVELOPER_DIR="${current_xcode}"
bazelisk test //...
sudo xcode-select --switch "${current_xcode}"

- name: Test Simple Example, Default Xcode is Incompatible, Use env attribute to set DEVELOPER_DIR
shell: bash
run: |
cd examples/simple_with_dev_dir
current_xcode=$(xcode-select --print-path)
# Switch default Xcode to SPM 5.3.
sudo xcode-select --switch /Applications/Xcode_12.4.app
# The DEVELOPER_DIR value is specified as an env attribute on spm_repositories.
bazelisk test //...
sudo xcode-select --switch "${current_xcode}"

- name: Test Simple Example Using Revision
shell: bash
run: |
Expand Down
3 changes: 2 additions & 1 deletion doc/package_descriptions_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Parses the JSON string and returns a dict representing the JSON structure.
## package_descriptions.get

<pre>
package_descriptions.get(<a href="#package_descriptions.get-repository_ctx">repository_ctx</a>, <a href="#package_descriptions.get-working_directory">working_directory</a>)
package_descriptions.get(<a href="#package_descriptions.get-repository_ctx">repository_ctx</a>, <a href="#package_descriptions.get-env">env</a>, <a href="#package_descriptions.get-working_directory">working_directory</a>)
</pre>

Returns a dict representing the merge of a package's description and it's dump (dump-package) information.
Expand All @@ -35,6 +35,7 @@ Returns a dict representing the merge of a package's description and it's dump (
| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="package_descriptions.get-repository_ctx"></a>repository_ctx | A <code>repository_ctx</code>. | none |
| <a id="package_descriptions.get-env"></a>env | A <code>dict</code> of environment variables that will be included in the command execution. | <code>{}</code> |
| <a id="package_descriptions.get-working_directory"></a>working_directory | A <code>string</code> specifying the directory for the SPM package. | <code>""</code> |


Expand Down
25 changes: 25 additions & 0 deletions doc/repository_utils_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,28 @@ Determines if the host is running MacOS.
| <a id="repository_utils.is_macos-repository_ctx"></a>repository_ctx | A <code>repository_ctx</code> instance. | none |


<a id="#repository_utils.exec_spm_command"></a>

## repository_utils.exec_spm_command

<pre>
repository_utils.exec_spm_command(<a href="#repository_utils.exec_spm_command-repository_ctx">repository_ctx</a>, <a href="#repository_utils.exec_spm_command-arguments">arguments</a>, <a href="#repository_utils.exec_spm_command-env">env</a>, <a href="#repository_utils.exec_spm_command-working_directory">working_directory</a>, <a href="#repository_utils.exec_spm_command-err_msg_tpl">err_msg_tpl</a>)
</pre>

Executes a Swift package manager command and returns the stdout.

If the command returns a non-zero return code, this function will fail.


**PARAMETERS**


| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="repository_utils.exec_spm_command-repository_ctx"></a>repository_ctx | A <code>repository_ctx</code> instance. | none |
| <a id="repository_utils.exec_spm_command-arguments"></a>arguments | A <code>list</code> of arguments which will be executed. | none |
| <a id="repository_utils.exec_spm_command-env"></a>env | A <code>dict</code> of environment variables that will be included in the command execution. | <code>{}</code> |
| <a id="repository_utils.exec_spm_command-working_directory"></a>working_directory | Working directory for command execution. Can be relative to the repository root or absolute. | <code>""</code> |
| <a id="repository_utils.exec_spm_command-err_msg_tpl"></a>err_msg_tpl | Optional. A <code>string</code> template which will be formatted with the <code>exec_args</code> and <code>stderr</code> values. | <code>None</code> |


3 changes: 2 additions & 1 deletion doc/spm_versions_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Output: `5.4.0`
## spm_versions.get

<pre>
spm_versions.get(<a href="#spm_versions.get-repository_ctx">repository_ctx</a>)
spm_versions.get(<a href="#spm_versions.get-repository_ctx">repository_ctx</a>, <a href="#spm_versions.get-env">env</a>)
</pre>

Returns the semantic version for Swit Package Manager.
Expand All @@ -43,5 +43,6 @@ the semantic version.
| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="spm_versions.get-repository_ctx"></a>repository_ctx | A <code>repository_ctx</code> instance. | none |
| <a id="spm_versions.get-env"></a>env | A <code>dict</code> of environment variables that are used in the evaluation of the SPM version. | <code>{}</code> |


3 changes: 2 additions & 1 deletion doc/workspace_rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ On this page:
## spm_repositories

<pre>
spm_repositories(<a href="#spm_repositories-name">name</a>, <a href="#spm_repositories-dependencies">dependencies</a>, <a href="#spm_repositories-platforms">platforms</a>, <a href="#spm_repositories-repo_mapping">repo_mapping</a>, <a href="#spm_repositories-swift_version">swift_version</a>)
spm_repositories(<a href="#spm_repositories-name">name</a>, <a href="#spm_repositories-dependencies">dependencies</a>, <a href="#spm_repositories-env">env</a>, <a href="#spm_repositories-platforms">platforms</a>, <a href="#spm_repositories-repo_mapping">repo_mapping</a>, <a href="#spm_repositories-swift_version">swift_version</a>)
</pre>

Used to fetch and prepare external Swift package manager packages for the build.
Expand All @@ -29,6 +29,7 @@ Used to fetch and prepare external Swift package manager packages for the build.
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="spm_repositories-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | |
| <a id="spm_repositories-dependencies"></a>dependencies | List of JSON strings specifying the SPM packages to load. | List of strings | required | |
| <a id="spm_repositories-env"></a>env | Environment variables that will be passed to the execution environments for this repository rule. (e.g. SPM version check, SPM dependency resolution, SPM package description generation) | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
| <a id="spm_repositories-platforms"></a>platforms | The platforms to declare in the placeholder/uber Swift package. (e.g. .macOS(.v10_15)) | List of strings | optional | [] |
| <a id="spm_repositories-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required | |
| <a id="spm_repositories-swift_version"></a>swift_version | The version of Swift that will be declared in the placeholder/uber Swift package. | String | optional | "5.3" |
Expand Down
8 changes: 8 additions & 0 deletions examples/simple_with_dev_dir/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Import Shared settings
import %workspace%/../../shared.bazelrc

# Import CI settings.
import %workspace%/../../ci.bazelrc

# Try to import a local.rc file; typically, written by CI
try-import %workspace%/../../local.bazelrc
17 changes: 17 additions & 0 deletions examples/simple_with_dev_dir/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_binary")

swift_binary(
name = "simple",
srcs = ["main.swift"],
visibility = ["//swift:__subpackages__"],
deps = [
"@swift_pkgs//swift-log:Logging",
],
)

sh_test(
name = "simple_test",
srcs = ["simple_test.sh"],
data = [":simple"],
deps = ["@bazel_tools//tools/bash/runfiles"],
)
6 changes: 6 additions & 0 deletions examples/simple_with_dev_dir/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Simple Example Specifying the Xcode Version Using `env` Attribute

This example demonstrates how to declare a Swift package as a dependency, specify it as a dependency
in a `swift_binary` rule and then import it in a Swift source file. In this case, the client is
specifying the Xcode version by specifying the `DEVELOPER_DIR` as an `env` attribute value in the
`spm_repositories` declaration.
48 changes: 48 additions & 0 deletions examples/simple_with_dev_dir/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
workspace(name = "simple_with_dev_dir_example")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

local_repository(
name = "cgrindel_rules_spm",
path = "../..",
)

load(
"@cgrindel_rules_spm//spm:deps.bzl",
"spm_rules_dependencies",
)

spm_rules_dependencies()

load(
"@build_bazel_rules_swift//swift:repositories.bzl",
"swift_rules_dependencies",
)

swift_rules_dependencies()

load(
"@build_bazel_rules_swift//swift:extras.bzl",
"swift_rules_extra_dependencies",
)

swift_rules_extra_dependencies()

load("@cgrindel_rules_spm//spm:spm.bzl", "spm_pkg", "spm_repositories")

spm_repositories(
name = "swift_pkgs",
dependencies = [
spm_pkg(
"https://github.com/apple/swift-log.git",
from_version = "1.0.0",
products = ["Logging"],
),
],
env = {
# If you are testing this locally, set this value to a valid Xcode
# path. This value is valid for the Github action runner host for
# macos-11.
"DEVELOPER_DIR": "/Applications/Xcode_12.5.1.app",
},
)
4 changes: 4 additions & 0 deletions examples/simple_with_dev_dir/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Logging

let logger = Logger(label: "com.example.main")
logger.info("Hello World!")
24 changes: 24 additions & 0 deletions examples/simple_with_dev_dir/simple_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash

# --- begin runfiles.bash initialization v2 ---
# Copy-pasted from the Bazel Bash runfiles library v2.
set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v2 ---

err_msg() {
local msg="$1"
echo >&2 "${msg}"
exit 1
}

workspace="simple_with_dev_dir_example"
binary="$(rlocation "${workspace}/simple")"

expected="Hello World"
"${binary}" | grep "${expected}" || err_msg "Failed to find expected output. ${expected}"
37 changes: 28 additions & 9 deletions spm/internal/package_descriptions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ JSON as generated by `swift package describe --type json`.\

load(":packages.bzl", "packages")
load(":references.bzl", ref_types = "reference_types", refs = "references")
load(":repository_utils.bzl", "repository_utils")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//lib:sets.bzl", "sets")

Expand Down Expand Up @@ -43,51 +44,69 @@ def _parse_json(json_str):
"""
return json.decode(json_str)

def _retrieve_package_dump(repository_ctx, working_directory = ""):
def _retrieve_package_dump(repository_ctx, env = {}, working_directory = ""):
"""Returns a dict representing the package dump for an SPM package.

Args:
repository_ctx: A `repository_ctx`.
env: A `dict` of environment variables that will be included in the
command execution.
working_directory: A `string` specifying the directory for the SPM package.

Returns:
A `dict` representing an SPM package dump.
"""
describe_result = repository_ctx.execute(
json_str = repository_utils.exec_spm_command(
repository_ctx,
["swift", "package", "dump-package"],
env = env,
working_directory = working_directory,
)
return _parse_json(describe_result.stdout)
return _parse_json(json_str)

def _retrieve_package_description(repository_ctx, working_directory = ""):
def _retrieve_package_description(repository_ctx, env = {}, working_directory = ""):
"""Returns a dict representing the package description for an SPM package.

Args:
repository_ctx: A `repository_ctx`.
env: A `dict` of environment variables that will be included in the
command execution.
working_directory: A `string` specifying the directory for the SPM package.

Returns:
A `dict` representing an SPM package description.
"""
describe_result = repository_ctx.execute(
json_str = repository_utils.exec_spm_command(
repository_ctx,
["swift", "package", "describe", "--type", "json"],
env = env,
working_directory = working_directory,
)
return _parse_json(describe_result.stdout)
return _parse_json(json_str)

def _get_package_description(repository_ctx, working_directory = ""):
def _get_package_description(repository_ctx, env = {}, working_directory = ""):
"""Returns a dict representing the merge of a package's description and it's dump (dump-package) information.

Args:
repository_ctx: A `repository_ctx`.
env: A `dict` of environment variables that will be included in the
command execution.
working_directory: A `string` specifying the directory for the SPM package.

Returns:
A `dict` representing information gathered from an SPM package
description and it's dump data.
"""
pkg_desc = _retrieve_package_description(repository_ctx, working_directory = working_directory)
pkg_dump = _retrieve_package_dump(repository_ctx, working_directory = working_directory)
pkg_desc = _retrieve_package_description(
repository_ctx,
env = env,
working_directory = working_directory,
)
pkg_dump = _retrieve_package_dump(
repository_ctx,
env = env,
working_directory = working_directory,
)

# Collect the dump targets by name
dump_targets_dict = {}
Expand Down
49 changes: 47 additions & 2 deletions spm/internal/repository_utils.bzl
Original file line number Diff line number Diff line change
@@ -1,15 +1,60 @@
def _is_macos(repository_ctx):
"""Determines if the host is running MacOS.

Args:
repository_ctx: A `repository_ctx` instance.

Returns:
A `bool` indicating whether the host is running MacOS.
"""
os_name = repository_ctx.os.name.lower()
return os_name.startswith("mac os")

def _execute_spm_command(
repository_ctx,
arguments,
env = {},
working_directory = "",
err_msg_tpl = None):
"""Executes a Swift package manager command and returns the stdout.

If the command returns a non-zero return code, this function will fail.

Args:
repository_ctx: A `repository_ctx` instance.
arguments: A `list` of arguments which will be executed.
env: A `dict` of environment variables that will be included in the
command execution.
working_directory: Working directory for command execution. Can be
relative to the repository root or absolute.
err_msg_tpl: Optional. A `string` template which will be formatted with
the `exec_args` and `stderr` values.

Returns:
A `string` representing the stdout of the command execution.
"""
exec_args = []
if _is_macos(repository_ctx):
exec_args.append("xcrun")
exec_args.extend(arguments)
exec_result = repository_ctx.execute(
exec_args,
environment = env,
working_directory = working_directory,
)
if exec_result.return_code != 0:
if err_msg_tpl == None:
err_msg_tpl = """\
Failed to execute SPM command. name: {repo_name}, args: {exec_args}\n{stderr}.\
"""
fail(err_msg_tpl.format(
repo_name = repository_ctx.attr.name,
exec_args = exec_args,
stderr = exec_result.stderr,
))
return exec_result.stdout

repository_utils = struct(
is_macos = _is_macos,
exec_spm_command = _execute_spm_command,
)
Loading