Skip to content
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
4 changes: 4 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
exports_files([
"nixpkgs.json",
"nixpkgs.nix",
])
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [Unreleased]

[Unreleased]: https://github.com/tweag/rules_nixpkgs/compare/v0.7.0...HEAD

### Changed

- The values in the `nixopts` attribute to `nixpkgs_package` are now subject to
location expansion. Any instance of `$(location LABEL)` in the `nixopts`
attribute will be expanded to the file path of the file referenced by
`LABEL`. To pass a plain `$` to Nix it must be escaped as `$$`.
See [#132][#132].

[#132]: https://github.com/tweag/rules_nixpkgs/pull/132

## [0.7.0] - 2020-04-20

[0.7.0]: https://github.com/tweag/rules_nixpkgs/compare/v0.6.0...v0.7.0
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,12 @@ filegroup(
<td><code>nixopts</code></td>
<td>
<p><code>String list; optional</code></p>
<p>Extra flags to pass when calling Nix.</p>
<p>
Extra flags to pass when calling Nix. Subject to location
expansion, any instance of <code>$(location LABEL)</code> will be
replaced by the path to the file ferenced by <code>LABEL</code>
relative to the workspace root.
</p>
</td>
</tr>
<tr>
Expand Down
33 changes: 30 additions & 3 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ load(

# For tests

load("@bazel_skylib//lib:unittest.bzl", "register_unittest_toolchains")

register_unittest_toolchains()

nixpkgs_git_repository(
name = "remote_nixpkgs",
remote = "https://github.com/NixOS/nixpkgs",
Expand Down Expand Up @@ -170,6 +174,30 @@ nixpkgs_package(
repository = "@remote_nixpkgs",
)

local_repository(
name = "nixpkgs_location_expansion_test_file",
path = "tests/location_expansion/test_repo",
)

nixpkgs_package(
name = "nixpkgs_location_expansion_test",
build_file_content = "exports_files(glob(['out/**']))",
nix_file = "//tests:location_expansion.nix",
nix_file_deps = [
"//tests:location_expansion/test_file",
"@nixpkgs_location_expansion_test_file//:test_file",
],
nixopts = [
"--arg",
"local_file",
"$(location //tests:location_expansion/test_file)",
"--arg",
"external_file",
"$(location @nixpkgs_location_expansion_test_file//:test_file)",
],
repository = "@remote_nixpkgs",
)

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

http_archive(
Expand Down Expand Up @@ -202,12 +230,11 @@ http_archive(

load(
"//nixpkgs:toolchains/go.bzl",
"nixpkgs_go_configure"
"nixpkgs_go_configure",
)

nixpkgs_go_configure(repository = "@nixpkgs")

load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

go_rules_dependencies()

8 changes: 7 additions & 1 deletion nixpkgs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ exports_files([
"nixpkgs.bzl",
])

filegroup(name = "srcs", srcs = glob(["**"]), visibility = ["//visibility:public"])
filegroup(
name = "srcs",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)

# @bazel_tools//tools does not define a bzl_library itself, instead we are
# supposed to define our own using the @bazel_tools//tools:bzl_srcs filegroup.
Expand All @@ -33,9 +37,11 @@ bzl_library(
name = "nixpkgs",
srcs = [
"nixpkgs.bzl",
"private/location_expansion.bzl",
],
visibility = ["//visibility:public"],
deps = [
":bazel_tools",
"@bazel_skylib//lib:paths",
],
)
2 changes: 1 addition & 1 deletion nixpkgs/constraints/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package(default_visibility = ["//visibility:public"])
constraint_setting(name = "nix")

constraint_value(
name = "support_nix",
name = "support_nix",
constraint_setting = ":nix",
)

Expand Down
19 changes: 15 additions & 4 deletions nixpkgs/nixpkgs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

load("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_autoconf_impl")
load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_cpu_value")
load(":private/location_expansion.bzl", "expand_location")

def _nixpkgs_git_repository_impl(repository_ctx):
repository_ctx.file(
"BUILD",
content = 'filegroup(name = "srcs", srcs = glob(["**"]), visibility = ["//visibility:public"])')
content = 'filegroup(name = "srcs", srcs = glob(["**"]), visibility = ["//visibility:public"])',
)

# Make "@nixpkgs" (syntactic sugar for "@nixpkgs//:nixpkgs") a valid
# label for default.nix.
Expand Down Expand Up @@ -119,8 +121,9 @@ def _nixpkgs_package_impl(repository_ctx):
else:
expr_args = ["-E", "import <nixpkgs> { config = {}; overlays = []; }"]

nix_file_deps = {}
for dep in repository_ctx.attr.nix_file_deps:
_cp(repository_ctx, dep)
nix_file_deps[dep] = _cp(repository_ctx, dep)

expr_args.extend([
"-A",
Expand All @@ -135,7 +138,15 @@ def _nixpkgs_package_impl(repository_ctx):
"bazel-support/nix-out-link",
])

expr_args.extend(repository_ctx.attr.nixopts)
expr_args.extend([
expand_location(
repository_ctx = repository_ctx,
string = opt,
labels = nix_file_deps,
attr = "nixopts",
)
for opt in repository_ctx.attr.nixopts
])

for repo in repositories.keys():
path = str(repository_ctx.path(repo).dirname) + "/nix-file-deps"
Expand Down Expand Up @@ -208,7 +219,7 @@ def _nixpkgs_package_impl(repository_ctx):
if create_build_file_if_needed:
p = repository_ctx.path("BUILD")
if not p.exists:
repository_ctx.template("BUILD", Label("@io_tweag_rules_nixpkgs//nixpkgs:BUILD.pkg"))
repository_ctx.template("BUILD", Label("@io_tweag_rules_nixpkgs//nixpkgs:BUILD.pkg"))

_nixpkgs_package = repository_rule(
implementation = _nixpkgs_package_impl,
Expand Down
128 changes: 128 additions & 0 deletions nixpkgs/private/location_expansion.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
load("@bazel_skylib//lib:paths.bzl", "paths")

def parse_expand_location(string):
"""Parse a string that might contain location expansion commands.

Generates a list of pairs of command and argument.
The command can have the following values:
- `string`: argument is a string, append it to the result.
- `location`: argument is a label, append its location to the result.

Attrs:
string: string, The string to parse.

Returns:
(result, error):
result: The generated list of pairs of command and argument.
error: string or None, This is set if an error occurred.
"""
result = []
offset = 0
len_string = len(string)

# Step through occurrences of `$`. This is bounded by the length of the string.
for _ in range(len_string):
# Find the position of the next `$`.
position = string.find("$", offset)
if position == -1:
position = len_string

# Append the in-between literal string.
if offset < position:
result.append(("string", string[offset:position]))

# Terminate at the end of the string.
if position == len_string:
break

# Parse the `$` command.
if string[position:].startswith("$$"):
# Insert verbatim '$'.
result.append(("string", "$"))
offset = position + 2
elif string[position:].startswith("$("):
# Expand a location command.
group_start = position + 2
group_end = string.find(")", group_start)
if group_end == -1:
return (None, "Unbalanced parentheses in location expansion for '{}'.".format(string[position:]))

group = string[group_start:group_end]
command = None
if group.startswith("location "):
label_str = group[len("location "):]
command = ("location", label_str)
else:
return (None, "Unrecognized location expansion '$({})'.".format(group))

result.append(command)
offset = group_end + 1
else:
return (None, "Unescaped '$' in location expansion at position {} of input.".format(position))

return (result, None)

def resolve_label(label_str, labels):
"""Find the label that corresponds to the given string.

Attr:
label_str: string, String representation of a label.
labels: dict from Label to path: Known label to path mappings.

Returns:
(path, error):
path: path, The path to the resolved label
error: string or None, This is set if an error occurred.
"""
label_candidates = [
(lbl, path)
for (lbl, path) in labels.items()
if lbl.relative(label_str) == lbl
]

if len(label_candidates) == 0:
return (None, "Unknown label '{}' in location expansion.".format(label_str))
elif len(label_candidates) > 1:
return (None, "Ambiguous label '{}' in location expansion. Candidates: {}".format(
label_str,
", ".join([str(lbl) for (lbl, _) in label_candidates]),
))

return (label_candidates[0][1], None)

def expand_location(repository_ctx, string, labels, attr = None):
"""Expand `$(location label)` to a path.

Raises an error on unexpected occurrences of `$`.
Use `$$` to insert a verbatim `$`.

Attrs:
repository_ctx: The repository rule context.
string: string, Replace instances of `$(location )` in this string.
labels: dict from label to path: Known label to path mappings.
attr: string, The rule attribute to use for error reporting.

Returns:
The string with all instances of `$(location )` replaced by paths.
"""
(parsed, error) = parse_expand_location(string)
if error != None:
fail(error, attr)

result = ""
for (command, argument) in parsed:
if command == "string":
result += argument
elif command == "location":
(label, error) = resolve_label(argument, labels)
if error != None:
fail(error, attr)

result += paths.join(".", paths.relativize(
str(repository_ctx.path(label)),
str(repository_ctx.path(".")),
))
else:
fail("Internal error: Unknown location expansion command '{}'.".format(command), attr)

return result
18 changes: 8 additions & 10 deletions nixpkgs/toolchains/go.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ load(
"@io_bazel_rules_go//go:deps.bzl",
"go_wrap_sdk",
)

load(
"//nixpkgs:nixpkgs.bzl",
"nixpkgs_package"
"nixpkgs_package",
)

def nixpkgs_go_configure(
sdk_name = "go_sdk",
repository = None,
repositories = {},
nix_file = None,
nix_file_deps = None,
nix_file_content = None,
nixopts = []):
sdk_name = "go_sdk",
repository = None,
repositories = {},
nix_file = None,
nix_file_deps = None,
nix_file_content = None,
nixopts = []):
"""
Use go toolchain from Nixpkgs. Will fail if not a nix-based platform.

Expand All @@ -41,7 +40,6 @@ def nixpkgs_go_configure(
}
"""


nixpkgs_package(
name = "nixpkgs_go_toolchain",
repository = repository,
Expand Down
Loading