diff options
author | Alyssa Ross <hi@alyssa.is> | 2020-01-22 15:26:58 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2020-01-22 16:56:33 +0000 |
commit | 542f80867c380b0ac79250b6e5358dda8bc49e0d (patch) | |
tree | aa5903f228b2f32c524a9a6e4f6dd94f8c5b869e /nixpkgs/lib | |
parent | f69898c7d5b757342e6ab90d5fcc7c9aea9f5ff4 (diff) | |
parent | 90441b4b47fc7280de6a5bd1a228017caaa0f97f (diff) | |
download | nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.tar nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.tar.gz nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.tar.bz2 nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.tar.lz nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.tar.xz nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.tar.zst nixlib-542f80867c380b0ac79250b6e5358dda8bc49e0d.zip |
Merge commit '90441b4b47fc7280de6a5bd1a228017caaa0f97f'
Diffstat (limited to 'nixpkgs/lib')
-rw-r--r-- | nixpkgs/lib/attrsets.nix | 2 | ||||
-rw-r--r-- | nixpkgs/lib/cli.nix | 56 | ||||
-rw-r--r-- | nixpkgs/lib/default.nix | 4 | ||||
-rw-r--r-- | nixpkgs/lib/modules.nix | 3 | ||||
-rw-r--r-- | nixpkgs/lib/sources.nix | 36 | ||||
-rw-r--r-- | nixpkgs/lib/systems/examples.nix | 16 | ||||
-rw-r--r-- | nixpkgs/lib/tests/misc.nix | 21 | ||||
-rwxr-xr-x | nixpkgs/lib/tests/modules.sh | 3 | ||||
-rw-r--r-- | nixpkgs/lib/trivial.nix | 2 | ||||
-rw-r--r-- | nixpkgs/lib/types.nix | 78 |
10 files changed, 189 insertions, 32 deletions
diff --git a/nixpkgs/lib/attrsets.nix b/nixpkgs/lib/attrsets.nix index 086c3d746fc1..32994432d53d 100644 --- a/nixpkgs/lib/attrsets.nix +++ b/nixpkgs/lib/attrsets.nix @@ -60,7 +60,7 @@ rec { [ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ]; - /* Like `getAttrPath' without a default value. If it doesn't find the + /* Like `attrByPath' without a default value. If it doesn't find the path it will throw. Example: diff --git a/nixpkgs/lib/cli.nix b/nixpkgs/lib/cli.nix new file mode 100644 index 000000000000..f47625d2f537 --- /dev/null +++ b/nixpkgs/lib/cli.nix @@ -0,0 +1,56 @@ +{ lib }: + +rec { + /* Automatically convert an attribute set to command-line options. + + This helps protect against malformed command lines and also to reduce + boilerplate related to command-line construction for simple use cases. + + Example: + encodeGNUCommandLine + { } + { data = builtins.toJSON { id = 0; }; + + X = "PUT"; + + retry = 3; + + retry-delay = null; + + url = [ "https://example.com/foo" "https://example.com/bar" ]; + + silent = false; + + verbose = true; + }; + => "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'" + */ + encodeGNUCommandLine = + options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs); + + toGNUCommandLine = + { renderKey ? + key: if builtins.stringLength key == 1 then "-${key}" else "--${key}" + + , renderOption ? + key: value: + if value == null + then [] + else [ (renderKey key) (builtins.toString value) ] + + , renderBool ? key: value: lib.optional value (renderKey key) + + , renderList ? key: value: lib.concatMap (renderOption key) value + }: + options: + let + render = key: value: + if builtins.isBool value + then renderBool key value + else if builtins.isList value + then renderList key value + else renderOption key value; + + in + builtins.concatLists (lib.mapAttrsToList render options); +} diff --git a/nixpkgs/lib/default.nix b/nixpkgs/lib/default.nix index 9f7a088d792d..5abafe1b2acf 100644 --- a/nixpkgs/lib/default.nix +++ b/nixpkgs/lib/default.nix @@ -39,6 +39,7 @@ let # misc asserts = callLibs ./asserts.nix; + cli = callLibs ./cli.nix; debug = callLibs ./debug.nix; generators = callLibs ./generators.nix; misc = callLibs ./deprecated.nix; @@ -100,7 +101,7 @@ let inherit (sources) pathType pathIsDirectory cleanSourceFilter cleanSource sourceByRegex sourceFilesBySuffices commitIdFromGitRepo cleanSourceWith pathHasContext - canCleanSource; + canCleanSource pathIsRegularFile; inherit (modules) evalModules unifyModuleSyntax applyIfFunction mergeModules mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions @@ -120,6 +121,7 @@ let isOptionType mkOptionType; inherit (asserts) assertMsg assertOneOf; + inherit (cli) encodeGNUCommandLine toGNUCommandLine; inherit (debug) addErrorContextToAttrs traceIf traceVal traceValFn traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq traceValSeqFn traceValSeqN traceValSeqNFn traceShowVal diff --git a/nixpkgs/lib/modules.nix b/nixpkgs/lib/modules.nix index e2315290ff0d..2b1faf4f0c28 100644 --- a/nixpkgs/lib/modules.nix +++ b/nixpkgs/lib/modules.nix @@ -764,12 +764,15 @@ rec { fromOpt = getAttrFromPath from options; toOf = attrByPath to (abort "Renaming error: option `${showOption to}' does not exist."); + toType = let opt = attrByPath to {} options; in opt.type or null; in { options = setAttrByPath from (mkOption { inherit visible; description = "Alias of <option>${showOption to}</option>."; apply = x: use (toOf config); + } // optionalAttrs (toType != null) { + type = toType; }); config = mkMerge [ { diff --git a/nixpkgs/lib/sources.nix b/nixpkgs/lib/sources.nix index 51bcf5559e32..a5765c0fda5b 100644 --- a/nixpkgs/lib/sources.nix +++ b/nixpkgs/lib/sources.nix @@ -9,6 +9,9 @@ rec { # Returns true if the path exists and is a directory, false otherwise pathIsDirectory = p: if builtins.pathExists p then (pathType p) == "directory" else false; + # Returns true if the path exists and is a regular file, false otherwise + pathIsRegularFile = p: if builtins.pathExists p then (pathType p) == "regular" else false; + # Bring in a path as a source, filtering out all Subversion and CVS # directories, as well as backup files (*~). cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! ( @@ -110,24 +113,45 @@ rec { with builtins; let fileName = toString path + "/" + file; packedRefsName = toString path + "/packed-refs"; - in if lib.pathExists fileName + absolutePath = base: path: + if lib.hasPrefix "/" path + then path + else toString (/. + "${base}/${path}"); + in if pathIsRegularFile path + # Resolve git worktrees. See gitrepository-layout(5) + then + let m = match "^gitdir: (.*)$" (lib.fileContents path); + in if m == null + then throw ("File contains no gitdir reference: " + path) + else + let gitDir = absolutePath (dirOf path) (lib.head m); + commonDir' = if pathIsRegularFile "${gitDir}/commondir" + then lib.fileContents "${gitDir}/commondir" + else gitDir; + commonDir = absolutePath gitDir commonDir'; + refFile = lib.removePrefix "${commonDir}/" "${gitDir}/${file}"; + in readCommitFromFile refFile commonDir + + else if pathIsRegularFile fileName + # Sometimes git stores the commitId directly in the file but + # sometimes it stores something like: «ref: refs/heads/branch-name» then let fileContent = lib.fileContents fileName; - # Sometimes git stores the commitId directly in the file but - # sometimes it stores something like: «ref: refs/heads/branch-name» matchRef = match "^ref: (.*)$" fileContent; - in if matchRef == null + in if matchRef == null then fileContent else readCommitFromFile (lib.head matchRef) path + + else if pathIsRegularFile packedRefsName # Sometimes, the file isn't there at all and has been packed away in the # packed-refs file, so we have to grep through it: - else if lib.pathExists packedRefsName then let fileContent = readFile packedRefsName; matchRef = match (".*\n([^\n ]*) " + file + "\n.*") fileContent; - in if matchRef == null + in if matchRef == null then throw ("Could not find " + file + " in " + packedRefsName) else lib.head matchRef + else throw ("Not a .git directory: " + path); in readCommitFromFile "HEAD"; diff --git a/nixpkgs/lib/systems/examples.nix b/nixpkgs/lib/systems/examples.nix index cb8bc3de6c48..19b3790ecbe0 100644 --- a/nixpkgs/lib/systems/examples.nix +++ b/nixpkgs/lib/systems/examples.nix @@ -170,8 +170,8 @@ rec { iphone64 = { config = "aarch64-apple-ios"; # config = "aarch64-apple-darwin14"; - sdkVer = "10.2"; - xcodeVer = "8.2"; + sdkVer = "12.4"; + xcodeVer = "10.3"; xcodePlatform = "iPhoneOS"; useiOSPrebuilt = true; platform = {}; @@ -180,8 +180,8 @@ rec { iphone32 = { config = "armv7a-apple-ios"; # config = "arm-apple-darwin10"; - sdkVer = "10.2"; - xcodeVer = "8.2"; + sdkVer = "12.4"; + xcodeVer = "10.3"; xcodePlatform = "iPhoneOS"; useiOSPrebuilt = true; platform = {}; @@ -190,8 +190,8 @@ rec { iphone64-simulator = { config = "x86_64-apple-ios"; # config = "x86_64-apple-darwin14"; - sdkVer = "10.2"; - xcodeVer = "8.2"; + sdkVer = "12.4"; + xcodeVer = "10.3"; xcodePlatform = "iPhoneSimulator"; useiOSPrebuilt = true; platform = {}; @@ -200,8 +200,8 @@ rec { iphone32-simulator = { config = "i686-apple-ios"; # config = "i386-apple-darwin11"; - sdkVer = "10.2"; - xcodeVer = "8.2"; + sdkVer = "12.4"; + xcodeVer = "10.3"; xcodePlatform = "iPhoneSimulator"; useiOSPrebuilt = true; platform = {}; diff --git a/nixpkgs/lib/tests/misc.nix b/nixpkgs/lib/tests/misc.nix index b064faa1e1ba..e47b48b5017d 100644 --- a/nixpkgs/lib/tests/misc.nix +++ b/nixpkgs/lib/tests/misc.nix @@ -441,4 +441,25 @@ runTests { expected = "«foo»"; }; + testRenderOptions = { + expr = + encodeGNUCommandLine + { } + { data = builtins.toJSON { id = 0; }; + + X = "PUT"; + + retry = 3; + + retry-delay = null; + + url = [ "https://example.com/foo" "https://example.com/bar" ]; + + silent = false; + + verbose = true; + }; + + expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'"; + }; } diff --git a/nixpkgs/lib/tests/modules.sh b/nixpkgs/lib/tests/modules.sh index c8340ff7f157..8cd632a439cd 100755 --- a/nixpkgs/lib/tests/modules.sh +++ b/nixpkgs/lib/tests/modules.sh @@ -174,8 +174,7 @@ checkConfigOutput "true" config.submodule.inner ./declare-submoduleWith-modules. checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules.nix ## Paths should be allowed as values and work as expected -# Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861 -#checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix +checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix # Check that disabledModules works recursively and correctly checkConfigOutput "true" config.enable ./disable-recursive/main.nix diff --git a/nixpkgs/lib/trivial.nix b/nixpkgs/lib/trivial.nix index 3a25e31fb052..940ec1a3d59e 100644 --- a/nixpkgs/lib/trivial.nix +++ b/nixpkgs/lib/trivial.nix @@ -191,7 +191,7 @@ rec { let revisionFile = "${toString ./..}/.git-revision"; gitRepo = "${toString ./..}/.git"; - in if lib.pathIsDirectory gitRepo + in if builtins.pathExists gitRepo then lib.commitIdFromGitRepo gitRepo else if lib.pathExists revisionFile then lib.fileContents revisionFile else default; diff --git a/nixpkgs/lib/types.nix b/nixpkgs/lib/types.nix index e86f6d364761..6fd6de7e1fd9 100644 --- a/nixpkgs/lib/types.nix +++ b/nixpkgs/lib/types.nix @@ -340,29 +340,79 @@ rec { let padWidth = stringLength (toString (length def.value)); unnamed = i: unnamedPrefix + fixedWidthNumber padWidth i; + anyString = placeholder "name"; + nameAttrs = [ + { path = [ "environment" "etc" ]; + name = "target"; + } + { path = [ "containers" anyString "bindMounts" ]; + name = "mountPoint"; + } + { path = [ "programs" "ssh" "knownHosts" ]; + # hostNames is actually a list so we would need to handle it only when singleton + name = "hostNames"; + } + { path = [ "fileSystems" ]; + name = "mountPoint"; + } + { path = [ "boot" "specialFileSystems" ]; + name = "mountPoint"; + } + { path = [ "services" "znapzend" "zetup" ]; + name = "dataset"; + } + { path = [ "services" "znapzend" "zetup" anyString "destinations" ]; + name = "label"; + } + { path = [ "services" "geoclue2" "appConfig" ]; + name = "desktopID"; + } + ]; + matched = let + equals = a: b: b == anyString || a == b; + fallback = { name = "name"; }; + in findFirst ({ path, ... }: all (v: v == true) (zipListsWith equals loc path)) fallback nameAttrs; + nameAttr = matched.name; + nameValueOld = value: + if isList value then + if length value > 0 then + "[ " + concatMapStringsSep " " escapeNixString value + " ]" + else + "[ ]" + else + escapeNixString value; + nameValueNew = value: unnamed: + if isList value then + if length value > 0 then + head value + else + unnamed + else + value; res = { inherit (def) file; value = listToAttrs ( imap1 (elemIdx: elem: - { name = elem.name or (unnamed elemIdx); + { name = nameValueNew (elem.${nameAttr} or (unnamed elemIdx)) (unnamed elemIdx); value = elem; }) def.value); }; option = concatStringsSep "." loc; sample = take 3 def.value; - list = concatMapStrings (x: ''{ name = "${x.name or "unnamed"}"; ...} '') sample; - set = concatMapStrings (x: ''${x.name or "unnamed"} = {...}; '') sample; + more = lib.optionalString (length def.value > 3) "... "; + list = concatMapStrings (x: ''{ ${nameAttr} = ${nameValueOld (x.${nameAttr} or "unnamed")}; ...} '') sample; + set = concatMapStrings (x: ''${nameValueNew (x.${nameAttr} or "unnamed") "unnamed"} = {...}; '') sample; msg = '' In file ${def.file} a list is being assigned to the option config.${option}. This will soon be an error as type loaOf is deprecated. - See https://git.io/fj2zm for more information. + See https://github.com/NixOS/nixpkgs/pull/63103 for more information. Do ${option} = - { ${set}...} + { ${set}${more}} instead of ${option} = - [ ${list}...] + [ ${list}${more}] ''; in lib.warn msg res @@ -430,14 +480,16 @@ rec { else unify (if shorthandOnlyDefinesConfig then { config = value; } else value); allModules = defs: modules ++ imap1 (n: { value, file }: - # Annotate the value with the location of its definition for better error messages - coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value + if isAttrs value || isFunction value then + # Annotate the value with the location of its definition for better error messages + coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value + else value ) defs; in mkOptionType rec { name = "submodule"; - check = x: isAttrs x || isFunction x; + check = x: isAttrs x || isFunction x || path.check x; merge = loc: defs: (evalModules { modules = allModules defs; @@ -538,7 +590,7 @@ rec { tail' = tail ts; in foldl' either head' tail'; - # Either value of type `finalType` or `coercedType`, the latter is + # Either value of type `coercedType` or `finalType`, the former is # converted to `finalType` using `coerceFunc`. coercedTo = coercedType: coerceFunc: finalType: assert lib.assertMsg (coercedType.getSubModules == null) @@ -547,12 +599,12 @@ rec { mkOptionType rec { name = "coercedTo"; description = "${finalType.description} or ${coercedType.description} convertible to it"; - check = x: finalType.check x || (coercedType.check x && finalType.check (coerceFunc x)); + check = x: (coercedType.check x && finalType.check (coerceFunc x)) || finalType.check x; merge = loc: defs: let coerceVal = val: - if finalType.check val then val - else coerceFunc val; + if coercedType.check val then coerceFunc val + else val; in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); emptyValue = finalType.emptyValue; getSubOptions = finalType.getSubOptions; |