diff options
author | Vincent Ambo <tazjin@google.com> | 2019-08-03T17·27+0100 |
---|---|---|
committer | Vincent Ambo <github@tazj.in> | 2019-08-03T22·11+0100 |
commit | 20103640fa6ab0678c72d3ba8a3ddc29ac264973 (patch) | |
tree | c9eb3fdfa0a7786a06b39f7731fe7b7a2e60ce2e /tools/nixery/build-registry-image.nix | |
parent | aa260af1fff8a07a34c776e5b4be2b5c63b96826 (diff) |
fix(nix): Support retrieving differently cased top-level attributes
As described in issue #14, the registry API does not allow image names with uppercase-characters in them. However, the Nix package set has several top-level keys with uppercase characters in them which could previously not be retrieved using Nixery. This change implements a method for retrieving those keys, but it is explicitly only working for the top-level package set as nested sets (such as `haskellPackages`) often contain packages that differ in case only.
Diffstat (limited to 'tools/nixery/build-registry-image.nix')
-rw-r--r-- | tools/nixery/build-registry-image.nix | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/tools/nixery/build-registry-image.nix b/tools/nixery/build-registry-image.nix index 20eb6d9e98d4..6a5312b444d0 100644 --- a/tools/nixery/build-registry-image.nix +++ b/tools/nixery/build-registry-image.nix @@ -113,11 +113,36 @@ let # For top-level items, the name of the key yields the result directly. Nested # items are fetched by using dot-syntax, as in Nix itself. # - # For example, `deepFetch pkgs "xorg.xev"` retrieves `pkgs.xorg.xev`. - deepFetch = s: n: - let path = lib.strings.splitString "." n; + # Due to a restriction of the registry API specification it is not possible to + # pass uppercase characters in an image name, however the Nix package set + # makes use of camelCasing repeatedly (for example for `haskellPackages`). + # + # To work around this, if no value is found on the top-level a second lookup + # is done on the package set using lowercase-names. This is not done for + # nested sets, as they often have keys that only differ in case. + # + # For example, `deepFetch pkgs "xorg.xev"` retrieves `pkgs.xorg.xev` and + # `deepFetch haskellpackages.stylish-haskell` retrieves + # `haskellPackages.stylish-haskell`. + deepFetch = with lib; s: n: + let path = splitString "." n; err = { error = "not_found"; pkg = n; }; - in lib.attrsets.attrByPath path err s; + # The most efficient way I've found to do a lookup against + # case-differing versions of an attribute is to first construct a + # mapping of all lowercased attribute names to their differently cased + # equivalents. + # + # This map is then used for a second lookup if the top-level + # (case-sensitive) one does not yield a result. + hasUpper = str: (match ".*[A-Z].*" str) != null; + allUpperKeys = filter hasUpper (attrNames s); + lowercased = listToAttrs (map (k: { + name = toLower k; + value = k; + }) allUpperKeys); + caseAmendedPath = map (v: if hasAttr v lowercased then lowercased."${v}" else v) path; + fetchLower = attrByPath caseAmendedPath err s; + in attrByPath path fetchLower s; # allContents is the combination of all derivations and store paths passed in # directly, as well as packages referred to by name. |