Skip to content

Commit

Permalink
Factor out location expansion
Browse files Browse the repository at this point in the history
Addressing review comment
#132 (comment)
  • Loading branch information
aherrmann committed Jul 29, 2020
1 parent f2e898b commit f568e71
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 70 deletions.
1 change: 1 addition & 0 deletions nixpkgs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ bzl_library(
name = "nixpkgs",
srcs = [
"nixpkgs.bzl",
"private/location_expansion.bzl",
],
visibility = ["//visibility:public"],
deps = [
Expand Down
72 changes: 2 additions & 70 deletions nixpkgs/nixpkgs.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Rules for importing Nixpkgs packages."""

load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//lib:sets.bzl", "sets")
load("@bazel_skylib//lib:versions.bzl", "versions")
load("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_autoconf_impl")
Expand All @@ -11,6 +10,7 @@ load(
"write_builtin_include_directory_paths",
)
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load(":private/location_expansion.bzl", "expand_location")

def _nixpkgs_git_repository_impl(repository_ctx):
repository_ctx.file(
Expand Down Expand Up @@ -82,74 +82,6 @@ nixpkgs_local_repository = repository_rule(
def _is_supported_platform(repository_ctx):
return repository_ctx.which("nix-build") != 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.
"""
result = ""
offset = 0

# Step through occurrences of `$`. This is bounded by the length of the string.
for _ in range(len(string)):
start = string.find("$", offset)
if start == -1:
result += string[offset:]
break
else:
result += string[offset:start]
if start + 1 == len(string):
fail("Unescaped '$' in location expansion at end of input", attr)
elif string[start + 1] == "$":
# Insert verbatim '$'.
result += "$"
offset = start + 2
elif string[start + 1] == "(":
group_start = start + 2
group_end = string.find(")", group_start)
if group_end == -1:
fail("Unbalanced parentheses in location expansion for '{}'.".format(string[start:]), attr)
group = string[group_start:group_end]
if group.startswith("location "):
label_str = group[len("location "):]
label_candidates = [
(lbl, path)
for (lbl, path) in labels.items()
if lbl.relative(label_str) == lbl
]
if len(label_candidates) == 0:
fail("Unknown label '{}' in location expansion for '{}'.".format(label_str, string), attr)
elif len(label_candidates) > 1:
fail(
"Ambiguous label '{}' in location expansion for '{}'. Candidates: {}".format(
label_str,
string,
", ".join([str(lbl) for lbl in label_candidates]),
),
attr,
)
location = paths.join(".", paths.relativize(
str(repository_ctx.path(label_candidates[0][1])),
str(repository_ctx.path(".")),
))
result += location
else:
fail("Unrecognized location expansion '$({})'.".format(group), attr)
offset = group_end + 1
else:
fail("Unescaped '$' in location expansion at position {} of input.".format(start), attr)
return result

def _nixpkgs_package_impl(repository_ctx):
repository = repository_ctx.attr.repository
repositories = repository_ctx.attr.repositories
Expand Down Expand Up @@ -215,7 +147,7 @@ def _nixpkgs_package_impl(repository_ctx):
])

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

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

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.
"""
result = ""
offset = 0

# Step through occurrences of `$`. This is bounded by the length of the string.
for _ in range(len(string)):
start = string.find("$", offset)
if start == -1:
result += string[offset:]
break
else:
result += string[offset:start]
if start + 1 == len(string):
fail("Unescaped '$' in location expansion at end of input", attr)
elif string[start + 1] == "$":
# Insert verbatim '$'.
result += "$"
offset = start + 2
elif string[start + 1] == "(":
group_start = start + 2
group_end = string.find(")", group_start)
if group_end == -1:
fail("Unbalanced parentheses in location expansion for '{}'.".format(string[start:]), attr)
group = string[group_start:group_end]
if group.startswith("location "):
label_str = group[len("location "):]
label_candidates = [
(lbl, path)
for (lbl, path) in labels.items()
if lbl.relative(label_str) == lbl
]
if len(label_candidates) == 0:
fail("Unknown label '{}' in location expansion for '{}'.".format(label_str, string), attr)
elif len(label_candidates) > 1:
fail(
"Ambiguous label '{}' in location expansion for '{}'. Candidates: {}".format(
label_str,
string,
", ".join([str(lbl) for lbl in label_candidates]),
),
attr,
)
location = paths.join(".", paths.relativize(
str(repository_ctx.path(label_candidates[0][1])),
str(repository_ctx.path(".")),
))
result += location
else:
fail("Unrecognized location expansion '$({})'.".format(group), attr)
offset = group_end + 1
else:
fail("Unescaped '$' in location expansion at position {} of input.".format(start), attr)
return result

0 comments on commit f568e71

Please sign in to comment.