diff --git a/nixpkgs/BUILD.bazel b/nixpkgs/BUILD.bazel index 04c7c172..18f32ded 100644 --- a/nixpkgs/BUILD.bazel +++ b/nixpkgs/BUILD.bazel @@ -37,6 +37,7 @@ bzl_library( name = "nixpkgs", srcs = [ "nixpkgs.bzl", + "private/location_expansion.bzl", ], visibility = ["//visibility:public"], deps = [ diff --git a/nixpkgs/nixpkgs.bzl b/nixpkgs/nixpkgs.bzl index 93f1d84d..74a50bc4 100644 --- a/nixpkgs/nixpkgs.bzl +++ b/nixpkgs/nixpkgs.bzl @@ -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") @@ -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( @@ -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 @@ -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 ]) diff --git a/nixpkgs/private/location_expansion.bzl b/nixpkgs/private/location_expansion.bzl new file mode 100644 index 00000000..20b23700 --- /dev/null +++ b/nixpkgs/private/location_expansion.bzl @@ -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