From 5bec48ef8abf8b2b6f34f664ae1cd69633eb1a60 Mon Sep 17 00:00:00 2001 From: Jake Hamilton Date: Sun, 30 Mar 2025 04:24:37 -0700 Subject: [PATCH] chore(lib): remove lib from labs --- README.md | 1 - foundation/default.nix | 3 +- foundation/flake.lock | 23 +- foundation/flake.nix | 13 +- foundation/npins/default.nix | 80 ++ foundation/npins/sources.json | 16 + lib/LICENSE | 24 - lib/README.md | 132 --- lib/default.nix | 1 - lib/default.test.nix | 100 -- lib/flake.nix | 5 - lib/src/attrs/default.nix | 216 ----- lib/src/attrs/default.test.nix | 342 ------- lib/src/bools/default.nix | 48 - lib/src/bools/default.test.nix | 190 ---- lib/src/dag/default.nix | 155 ---- lib/src/dag/default.test.nix | 169 ---- lib/src/default.nix | 84 -- lib/src/default.test.nix | 22 - lib/src/errors/default.nix | 10 - lib/src/errors/default.test.nix | 4 - lib/src/fp/default.nix | 64 -- lib/src/fp/default.test.nix | 165 ---- lib/src/generators/default.nix | 152 --- lib/src/generators/default.test.nix | 111 --- lib/src/importers/default.nix | 15 - lib/src/importers/default.test.nix | 4 - lib/src/licenses/all.nix | 1268 ------------------------- lib/src/licenses/default.nix | 29 - lib/src/lists/default.nix | 234 ----- lib/src/lists/default.test.nix | 345 ------- lib/src/math/default.nix | 13 - lib/src/math/default.test.nix | 22 - lib/src/modules/default.nix | 702 -------------- lib/src/modules/default.test.nix | 709 -------------- lib/src/numbers/default.nix | 72 -- lib/src/numbers/default.test.nix | 67 -- lib/src/options/default.nix | 348 ------- lib/src/options/default.test.nix | 4 - lib/src/packages/default.nix | 52 -- lib/src/packages/default.test.nix | 4 - lib/src/paths/default.nix | 67 -- lib/src/paths/default.test.nix | 4 - lib/src/points/default.nix | 54 -- lib/src/points/default.test.nix | 52 -- lib/src/strings/alphabet.nix | 59 -- lib/src/strings/ascii.nix | 97 -- lib/src/strings/default.nix | 342 ------- lib/src/strings/default.test.nix | 4 - lib/src/types/default.nix | 1333 --------------------------- lib/src/types/default.test.nix | 55 -- lib/src/versions/default.nix | 58 -- lib/src/versions/default.test.nix | 4 - lib/test.sh | 18 - tidepool/default.nix | 4 +- tidepool/flake.lock | 34 +- tidepool/flake.nix | 5 - tidepool/npins/default.nix | 80 ++ tidepool/npins/sources.json | 16 + 59 files changed, 208 insertions(+), 8096 deletions(-) create mode 100644 foundation/npins/default.nix create mode 100644 foundation/npins/sources.json delete mode 100644 lib/LICENSE delete mode 100644 lib/README.md delete mode 100644 lib/default.nix delete mode 100644 lib/default.test.nix delete mode 100644 lib/flake.nix delete mode 100644 lib/src/attrs/default.nix delete mode 100644 lib/src/attrs/default.test.nix delete mode 100644 lib/src/bools/default.nix delete mode 100644 lib/src/bools/default.test.nix delete mode 100644 lib/src/dag/default.nix delete mode 100644 lib/src/dag/default.test.nix delete mode 100644 lib/src/default.nix delete mode 100644 lib/src/default.test.nix delete mode 100644 lib/src/errors/default.nix delete mode 100644 lib/src/errors/default.test.nix delete mode 100644 lib/src/fp/default.nix delete mode 100644 lib/src/fp/default.test.nix delete mode 100644 lib/src/generators/default.nix delete mode 100644 lib/src/generators/default.test.nix delete mode 100644 lib/src/importers/default.nix delete mode 100644 lib/src/importers/default.test.nix delete mode 100644 lib/src/licenses/all.nix delete mode 100644 lib/src/licenses/default.nix delete mode 100644 lib/src/lists/default.nix delete mode 100644 lib/src/lists/default.test.nix delete mode 100644 lib/src/math/default.nix delete mode 100644 lib/src/math/default.test.nix delete mode 100644 lib/src/modules/default.nix delete mode 100644 lib/src/modules/default.test.nix delete mode 100644 lib/src/numbers/default.nix delete mode 100644 lib/src/numbers/default.test.nix delete mode 100644 lib/src/options/default.nix delete mode 100644 lib/src/options/default.test.nix delete mode 100644 lib/src/packages/default.nix delete mode 100644 lib/src/packages/default.test.nix delete mode 100644 lib/src/paths/default.nix delete mode 100644 lib/src/paths/default.test.nix delete mode 100644 lib/src/points/default.nix delete mode 100644 lib/src/points/default.test.nix delete mode 100644 lib/src/strings/alphabet.nix delete mode 100644 lib/src/strings/ascii.nix delete mode 100644 lib/src/strings/default.nix delete mode 100644 lib/src/strings/default.test.nix delete mode 100644 lib/src/types/default.nix delete mode 100644 lib/src/types/default.test.nix delete mode 100644 lib/src/versions/default.nix delete mode 100644 lib/src/versions/default.test.nix delete mode 100755 lib/test.sh create mode 100644 tidepool/npins/default.nix create mode 100644 tidepool/npins/sources.json diff --git a/README.md b/README.md index 915cf3d..c931a63 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,5 @@ may collaborate. | Name | Phase | Description | | ------------------------------ | --------- | ------------------------------------------------------------------------------------ | -| [Aux Lib](./lib) | Iteration | A library of common functions used in the Aux ecosystem. | | [Aux Foundation](./foundation) | Iteration | Foundational packages which allow for bootstrapping a greater package set. | | [Aux Tidepool](./tidepool) | Idea | An initial package set built on top of Aux Foundation using Aux Lib's module system. | diff --git a/foundation/default.nix b/foundation/default.nix index e80393f..c43ed7f 100644 --- a/foundation/default.nix +++ b/foundation/default.nix @@ -2,7 +2,8 @@ system ? builtins.currentSystem, }: let - lib = import ./../lib; + pins = import ./npins; + lib = import pins.lib; modules = import ./src; diff --git a/foundation/flake.lock b/foundation/flake.lock index f58668e..5999137 100644 --- a/foundation/flake.lock +++ b/foundation/flake.lock @@ -1,27 +1,6 @@ { "nodes": { - "lib": { - "locked": { - "dir": "lib", - "lastModified": 1723737980, - "narHash": "sha256-1WnFatW5kSuO2jjt62hvSbH84TSYyO+VmvkJ0d5e/ZY=", - "ref": "master", - "rev": "cadfaabc853d20f2bc20bad794fcbe520ea48f13", - "revCount": 82, - "type": "git", - "url": "file:../" - }, - "original": { - "dir": "lib", - "type": "git", - "url": "file:../" - } - }, - "root": { - "inputs": { - "lib": "lib" - } - } + "root": {} }, "root": "root", "version": 7 diff --git a/foundation/flake.nix b/foundation/flake.nix index abe9dc7..a59da8d 100644 --- a/foundation/flake.nix +++ b/foundation/flake.nix @@ -1,16 +1,13 @@ { description = "A set of foundational packages required for bootstrapping a larger package set."; - inputs = { - lib = { - url = "git+file:../?dir=lib"; - }; - }; + inputs = { }; outputs = - inputs: + _: let - inherit (inputs.lib) lib; + pins = import ./npins; + lib = import pins.lib; modules = import ./src; @@ -27,7 +24,7 @@ system: let result = lib.modules.run { - modules = (builtins.attrValues modules) ++ [ { config.aux.system = system; } ]; + modules = (builtins.attrValues modules) ++ [{ config.aux.system = system; }]; }; in result.config.exports.resolved.packages diff --git a/foundation/npins/default.nix b/foundation/npins/default.nix new file mode 100644 index 0000000..5e7d086 --- /dev/null +++ b/foundation/npins/default.nix @@ -0,0 +1,80 @@ +# Generated by npins. Do not modify; will be overwritten regularly +let + data = builtins.fromJSON (builtins.readFile ./sources.json); + version = data.version; + + mkSource = + spec: + assert spec ? type; + let + path = + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else + builtins.throw "Unknown source type ${spec.type}"; + in + spec // { outPath = path; }; + + mkGitSource = + { + repository, + revision, + url ? null, + hash, + branch ? null, + ... + }: + assert repository ? type; + # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository + # In the latter case, there we will always be an url to the tarball + if url != null then + (builtins.fetchTarball { + inherit url; + sha256 = hash; # FIXME: check nix version & use SRI hashes + }) + else + assert repository.type == "Git"; + let + urlToName = + url: rev: + let + matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url; + + short = builtins.substring 0 7 rev; + + appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else ""; + in + "${if matched == null then "source" else builtins.head matched}${appendShort}"; + name = urlToName repository.url revision; + in + builtins.fetchGit { + url = repository.url; + rev = revision; + inherit name; + # hash = hash; + }; + + mkPyPiSource = + { url, hash, ... }: + builtins.fetchurl { + inherit url; + sha256 = hash; + }; + + mkChannelSource = + { url, hash, ... }: + builtins.fetchTarball { + inherit url; + sha256 = hash; + }; +in +if version == 3 then + builtins.mapAttrs (_: mkSource) data.pins +else + throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/foundation/npins/sources.json b/foundation/npins/sources.json new file mode 100644 index 0000000..99ec39b --- /dev/null +++ b/foundation/npins/sources.json @@ -0,0 +1,16 @@ +{ + "pins": { + "lib": { + "type": "Git", + "repository": { + "type": "Git", + "url": "git+ssh://forgejo@git.auxolotl.org/auxolotl/lib.git" + }, + "branch": "main", + "revision": "7552ab48bb394d59d2bf1f7a558d28ce59da524d", + "url": null, + "hash": "0705fm00k9f95b6idf5qnfvqm4qf1a0cv966ghgd48kd1qy4il5c" + } + }, + "version": 3 +} \ No newline at end of file diff --git a/lib/LICENSE b/lib/LICENSE deleted file mode 100644 index 46376b6..0000000 --- a/lib/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -MIT License -Copyright (c) 2003-2023 Eelco Dolstra and the Nixpkgs/NixOS contributors -Copyright (c) 2017-2023 Home Manager contributors -Copyright (c) 2024 Aux Contributors - -Permission is hereby granted, free -of charge, to any person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice -(including the next paragraph) shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index f8b92fc..0000000 --- a/lib/README.md +++ /dev/null @@ -1,132 +0,0 @@ -# Aux Lib - -Aux Lib is intended to be a replacement for NixPkg's `lib` with stronger constraints around naming, -organization, and inclusion of functions. In addition to replacing library functions, Aux Lib also -defines a revamped version of the NixOS Module system intended to make it easier, more approachable, -and intuitive. - -## Usage - -The library can be imported both with and without Nix Flakes. To import the library using Nix Flakes, -add this repository as an input. - -```nix -inputs.lib.url = "https://git.auxolotl.org/auxolotl/labs/archive/main.tar.gz?dir=lib"; -``` - -To import the library without using Nix Flakes, you will need to use `fetchTarball` and import the -library entrypoint. - -```nix -let - labs = builtins.fetchTarball { - url = "https://git.auxolotl.org/auxolotl/labs/archive/main.tar.gz"; - sha256 = ""; - }; - lib = import "${labs}/lib"; -in - # ... -``` - -## Development - -To contribute to the project, we accept pull requests to this repository. Please see the following -sections for information on the appropriate practices and required steps for working on Aux Lib. - -### Documentation - -We want our code to survive in the world, but without proper documentation that won't happen. In -order to not lose knowledge and also make it easier for others to begin participating in the -project we require that every function have an appropriate documentation comment. The format for -these comments is as follows: - -```nix -let - ## This is a description of what the function does. Any necessary information can be added - ## here. After this point comes a gap before a Hindley-Milner style type signature. Note - ## that these types are not actually checked, but serve as a helpful addition for the user - ## in addition to being provided in generated documentation. - ## - ## @type Int -> String - func = x: builtins.toString x; -in - # ... -``` - -### Testing - -All functions that are added to the project should include tests. The test suites are located -next to their implementation in files ending in `.test.nix`. These tests should ensure that -the library behaves as expected. The typical structure of these test suites is: - -```nix -let - lib = import ./../default.nix; -in -{ - "my function" = { - "test 1" = let - expected = 1; - input = {}; - actual = lib.myFunction input; - in - actual == expected; - }; -} -``` - -Successful tests will return `true` while failing test will resolve with `false`. You can run -all tests with the following command: - -```shell -./test.sh -``` - -If you want to run a specific test suite, you can run the command, specifying the directory -to the tests file: - -```shell -./test.sh $namespace -``` - -For example, to run the tests for only `attrs`, use the following command: - -```shell -./test.sh attrs -``` - -### Formatting - -> **Note:** To keep this flake light and keep its inputs empty we do not include a package -> set which would provide a formatter. Instead please run `nix run nixpkgs#nixfmt-rfc-style` -> until an improved solution is available. - -All code in this project must be formatted using the provided formatter in the `flake.nix` -file. You can run this formatter using the command `nix fmt` (not currently available). - -### Code Quality - -In order to keep the project approachable and easy to maintain, certain patterns are not allowed. -In particular, the use of `with` and `rec` are not allowed. Additionally, you should prefer the -fully qualified name of a variable rather than creating intermediate ones using `inherit`. - -### Adding Functionality - -Before adding new features to the library, submit an issue or talk the idea over with one or -more of the project maintainers. We want to make sure that the library does not become bloated -with tools that aren't used. Some features may be better handled in a separate project. If you -do get the go-ahead to begin working on your feature, please place it in the library structure -similarly to how existing features are. For example, things dealing with strings should go in -`src/strings/default.nix`. - -Additionally, you should prefer to group things in attribute sets for like-functionality. More -broad categories such as `strings` and `lists` are helpful, but scoped groups for things like -`into`, `from`, and `validate` also make the library more discoverable. Having all of the -different parts of the library mirroring this organizational structure makes building intuition -for working with the library much easier. To know when to group new things, consider the -following: - -- Would your function name be multiple words like `fromString`? -- Are there multiple variants of this function? -- Would it be easier to find in a group? -- Would grouping help avoid name collisions or confusion? diff --git a/lib/default.nix b/lib/default.nix deleted file mode 100644 index 76840e2..0000000 --- a/lib/default.nix +++ /dev/null @@ -1 +0,0 @@ -import ./src diff --git a/lib/default.test.nix b/lib/default.test.nix deleted file mode 100644 index 0decee6..0000000 --- a/lib/default.test.nix +++ /dev/null @@ -1,100 +0,0 @@ -let - lib = import ./default.nix; - - root = ./.; - - files = [ - ./src/default.test.nix - ./src/attrs/default.test.nix - ./src/bools/default.test.nix - ./src/dag/default.test.nix - ./src/errors/default.test.nix - ./src/fp/default.test.nix - ./src/generators/default.test.nix - ./src/importers/default.test.nix - ./src/lists/default.test.nix - ./src/math/default.test.nix - ./src/modules/default.test.nix - ./src/numbers/default.test.nix - ./src/options/default.test.nix - ./src/packages/default.test.nix - ./src/paths/default.test.nix - ./src/points/default.test.nix - ./src/strings/default.test.nix - ./src/types/default.test.nix - ./src/versions/default.test.nix - ]; - - resolve = - file: - let - imported = import file; - value = if builtins.isFunction imported then imported { inherit lib; } else imported; - relative = lib.strings.removePrefix (builtins.toString root) (builtins.toString file); - in - { - inherit file value; - relative = if lib.strings.hasPrefix "/" relative then "." + relative else relative; - namespace = getNamespace file; - }; - - resolved = builtins.map resolve files; - - getNamespace = - path: - let - relative = lib.strings.removePrefix (builtins.toString root) (builtins.toString path); - parts = lib.strings.split "/" relative; - in - if builtins.length parts > 2 then builtins.elemAt parts 2 else relative; - - results = - let - getTests = - file: prefix: suite: - let - nested = lib.attrs.mapToList (name: value: getTests file (prefix ++ [ name ]) value) suite; - relative = lib.strings.removePrefix (builtins.toString root) (builtins.toString file); - in - if builtins.isAttrs suite then - builtins.concatLists nested - else - [ - { - inherit prefix file; - name = builtins.concatStringsSep " > " prefix; - value = suite; - relative = if lib.strings.hasPrefix "/" relative then "." + relative else relative; - } - ]; - - base = builtins.map (entry: getTests entry.file [ entry.namespace ] entry.value) resolved; - in - builtins.concatLists base; - - successes = builtins.filter (test: test.value) results; - failures = builtins.filter (test: !test.value) results; - - total = "${builtins.toString (builtins.length successes)} / ${builtins.toString (builtins.length results)}"; -in -if failures == [ ] then - let - message = lib.strings.concatMapSep "\n" (test: "✅ ${test.name}") successes; - in - '' - SUCCESS (${total}) - - ${message} - '' -else - let - successMessage = lib.strings.concatMapSep "\n" (test: "✅ ${test.name}") successes; - failureMessage = lib.strings.concatMapSep "\n\n" ( - test: "❎ ${test.name}\n" + " -> ${test.relative}" - ) failures; - in - '' - FAILURE (${total}) - - ${failureMessage} - '' diff --git a/lib/flake.nix b/lib/flake.nix deleted file mode 100644 index 749d2de..0000000 --- a/lib/flake.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - description = "A NixPkgs library replacement containing helper functions and a module system."; - - outputs = _: { lib = import ./src; }; -} diff --git a/lib/src/attrs/default.nix b/lib/src/attrs/default.nix deleted file mode 100644 index 87cc52c..0000000 --- a/lib/src/attrs/default.nix +++ /dev/null @@ -1,216 +0,0 @@ -lib: { - attrs = { - ## Merge two attribute sets at the base level. - ## - ## @type Attrs a b c => a -> b -> c - merge = x: y: x // y; - - ## Merge two attribute sets recursively until a given predicate returns true. - ## Any values that are _not_ attribute sets will be overridden with the value - ## from `y` first if it exists and then `x` otherwise. - ## - ## @type Attrs a b c => (String -> Any -> Any -> Bool) -> a -> b -> c - mergeRecursiveUntil = - predicate: x: y: - let - process = - path: - builtins.zipAttrsWith ( - name: values: - let - currentPath = path ++ [ name ]; - isSingleValue = builtins.length values == 1; - isComplete = predicate currentPath (builtins.elemAt values 1) (builtins.elemAt values 0); - in - if isSingleValue then - builtins.elemAt values 0 - else if isComplete then - builtins.elemAt values 1 - else - process currentPath values - ); - in - process - [ ] - [ - x - y - ]; - - ## Merge two attribute sets recursively. Any values that are _not_ attribute sets - ## will be overridden with the value from `y` first if it exists and then `x` - ## otherwise. - ## - ## @type Attrs a b c => a -> b -> c - mergeRecursive = lib.attrs.mergeRecursiveUntil ( - path: x: y: - !(builtins.isAttrs x && builtins.isAttrs y) - ); - - ## Get a value from an attribute set by a path. If the path does not exist, - ## a fallback value will be returned instead. - ## - ## @type (List String) -> a -> Attrs -> a | b - select = - path: fallback: target: - let - name = builtins.head path; - rest = builtins.tail path; - in - if path == [ ] then - target - else if target ? ${name} then - lib.attrs.select rest fallback target.${name} - else - fallback; - - ## Get a value from an attribute set by a path. If the path does not exist, - ## an error will be thrown. - ## - ## @type (List String) -> Attrs -> a - selectOrThrow = - path: target: - let - pathAsString = builtins.concatStringsSep "." path; - error = builtins.throw "Path not found in attribute set: ${pathAsString}"; - in - if lib.attrs.has path target then lib.attrs.select path null target else error; - - ## Zip specific attributes from a list of attribute sets. - ## - ## @type List String -> (List Any -> Any) -> List Attrs -> Attrs - zipWithNames = - names: f: list: - let - transform = name: { - inherit name; - value = f name (builtins.catAttrs name list); - }; - results = builtins.map transform names; - in - builtins.listToAttrs results; - - ## Match an attribute set against a pattern. - ## - ## @type Attrs -> Attrs -> Bool - match = - pattern: value: - let - process = - name: values: - let - first = builtins.elemAt values 0; - second = builtins.elemAt values 1; - in - if builtins.length values == 1 then - false - else if builtins.isAttrs first then - builtins.isAttrs second && lib.attrs.match first second - else - first == second; - - result = lib.attrs.zipWithNames (builtins.attrNames pattern) process [ - pattern - value - ]; - in - assert lib.errors.trace (builtins.isAttrs pattern) "Pattern must be an attribute set"; - assert lib.errors.trace (builtins.isAttrs value) "Value must be an attribute set"; - builtins.all lib.fp.id (builtins.attrValues result); - - ## Create a nested attribute set with a value as the leaf node. - ## - ## @type (List String) -> a -> Attrs - set = - path: value: - let - length = builtins.length path; - process = - depth: if depth == length then value else { ${builtins.elemAt path depth} = process (depth + 1); }; - in - process 0; - - ## Check if a path exists in an attribute set. - ## - ## @type (List String) -> Attrs -> Bool - has = - path: target: - let - name = builtins.head path; - rest = builtins.tail path; - in - if path == [ ] then - true - else if target ? ${name} then - lib.attrs.has rest target.${name} - else - false; - - ## Depending on a given condition, either use the given value or an empty - ## attribute set. - ## - ## @type Attrs a b => Bool -> a -> a | b - when = condition: value: if condition then value else { }; - - ## Map an attribute set's names and values to a list. - ## - ## @type Any a => (String -> Any -> a) -> Attrs -> List a - mapToList = f: target: builtins.map (name: f name target.${name}) (builtins.attrNames target); - - ## Map an attribute set recursively. Only non-set leaf nodes will be mapped. - ## - ## @type (List String -> Any -> Any) -> Attrs -> Attrs - mapRecursive = f: target: lib.attrs.mapRecursiveWhen (lib.fp.const true) f target; - - ## Map an attribute set recursively when a given predicate returns true. - ## Only leaf nodes according to the predicate will be mapped. - ## - ## @type (Attrs -> Bool) -> (List String -> Any -> Any) -> Attrs -> Attrs - mapRecursiveWhen = - predicate: f: target: - let - process = - path: - builtins.mapAttrs ( - name: value: - if builtins.isAttrs value && predicate value then - process (path ++ [ name ]) value - else - f (path ++ [ name ]) value - ); - in - process [ ] target; - - ## Filter an attribute set by a given predicate. The filter is only performed - ## on the base level of the attribute set. - ## - ## @type (String -> Any -> Bool) -> Attrs -> Attrs - filter = - predicate: target: - let - names = builtins.attrNames target; - process = - name: - let - value = target.${name}; - in - if predicate name value then [ { inherit name value; } ] else [ ]; - valid = builtins.concatMap process names; - in - builtins.listToAttrs valid; - - ## Generate an attribute set from a list of names and a function that is - ## applied to each name. - ## - ## @type (List String) -> (String -> Any) -> Attrs - generate = - names: f: - let - pairs = builtins.map (name: { - inherit name; - value = f name; - }) names; - in - builtins.listToAttrs pairs; - }; -} diff --git a/lib/src/attrs/default.test.nix b/lib/src/attrs/default.test.nix deleted file mode 100644 index 31f8a3e..0000000 --- a/lib/src/attrs/default.test.nix +++ /dev/null @@ -1,342 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "merge" = { - "merges two shallow sets" = - let - expected = { - x = 1; - y = 2; - }; - - actual = lib.attrs.merge { x = 1; } { y = 2; }; - in - expected == actual; - - "overwrites values from the first set" = - let - expected = { - x = 2; - }; - actual = lib.attrs.merge { x = 1; } { x = 2; }; - in - actual == expected; - - "does not merge nested sets" = - let - expected = { - x.y = 2; - }; - actual = lib.attrs.merge { x.z = 1; } { x.y = 2; }; - in - actual == expected; - }; - - "mergeRecursiveUntil" = { - "merges with predicate" = - let - expected = { - x.y.z = 1; - }; - actual = lib.attrs.mergeRecursiveUntil ( - path: x: y: - lib.lists.last path == "z" - ) { x.y.z = 2; } { x.y.z = 1; }; - in - actual == expected; - - "handles shallow merges" = - let - expected = { - x.y.z = 1; - }; - actual = - lib.attrs.mergeRecursiveUntil - ( - path: x: y: - true - ) - { - x = { - y.z = 2; - - a = false; - }; - } - { x.y.z = 1; }; - in - actual == expected; - }; - - "mergeRecursive" = { - "merges two sets deeply" = - let - expected = { - x.y.z = 1; - }; - actual = lib.attrs.mergeRecursive { x.y.z = 2; } { x.y.z = 1; }; - in - actual == expected; - }; - - "select" = { - "selects a nested value" = - let - expected = "value"; - actual = lib.attrs.select [ - "x" - "y" - "z" - ] null { x.y.z = expected; }; - in - actual == expected; - - "handles empty path" = - let - expected = { - x = { - y = { - z = 1; - }; - }; - }; - actual = lib.attrs.select [ ] null { - x = { - y = { - z = 1; - }; - }; - }; - in - actual == expected; - - "handles fallback value" = - let - expected = "fallback"; - actual = lib.attrs.select [ - "x" - "y" - "z" - ] expected { }; - in - actual == expected; - }; - - "selectOrThrow" = { - "selects a nested value" = - let - expected = "value"; - actual = lib.attrs.selectOrThrow [ - "x" - "y" - "z" - ] { x.y.z = expected; }; - in - actual == expected; - - "handles empty path" = - let - expected = { - x = { - y = { - z = 1; - }; - }; - }; - actual = lib.attrs.selectOrThrow [ ] { - x = { - y = { - z = 1; - }; - }; - }; - in - actual == expected; - - "throws on nonexistent path" = - let - actual = lib.attrs.selectOrThrow [ - "x" - "y" - "z" - ] { }; - - evaluated = builtins.tryEval (builtins.deepSeq actual actual); - in - !evaluated.success; - }; - - "set" = { - "creates a nested set" = - let - expected = { - x = { - y = { - z = 1; - }; - }; - }; - actual = lib.attrs.set [ - "x" - "y" - "z" - ] 1; - in - actual == expected; - - "handles empty path" = - let - expected = 1; - actual = lib.attrs.set [ ] 1; - in - actual == expected; - }; - - "has" = { - "returns true for a nested value" = - let - exists = lib.attrs.has [ - "x" - "y" - "z" - ] { x.y.z = 1; }; - in - exists; - - "returns false for a nonexistent value" = - let - exists = lib.attrs.has [ - "x" - "y" - "z" - ] { }; - in - !exists; - - "handles empty path" = - let - exists = lib.attrs.has [ ] { }; - in - exists; - }; - - "when" = { - "returns the value when condition is true" = - let - expected = "value"; - actual = lib.attrs.when true expected; - in - actual == expected; - - "returns an empty set when condition is false" = - let - expected = { }; - actual = lib.attrs.when false "value"; - in - actual == expected; - }; - - "mapToList" = { - "converts a set to a list" = - let - expected = [ - { - name = "x"; - value = 1; - } - { - name = "y"; - value = 2; - } - ]; - actual = lib.attrs.mapToList (name: value: { inherit name value; }) { - x = 1; - y = 2; - }; - in - actual == expected; - }; - - "mapRecursiveWhen" = { - "maps a set recursively" = - let - expected = { - x = { - y = { - z = 2; - }; - }; - }; - actual = lib.attrs.mapRecursiveWhen (value: true) (path: value: value + 1) { - x = { - y = { - z = 1; - }; - }; - }; - in - actual == expected; - - "maps a set given a condition" = - let - expected = { - x = { - y = { - z = 1; - }; - }; - }; - actual = - lib.attrs.mapRecursiveWhen (value: !(value ? z)) - ( - path: value: - # We map before we get to a non-set value - if builtins.isAttrs value then value else value + 1 - ) - { - x = { - y = { - z = 1; - }; - }; - }; - in - actual == expected; - }; - - "mapRecursive" = { - "maps a set recursively" = - let - expected = { - x = { - y = { - z = 2; - }; - }; - }; - actual = lib.attrs.mapRecursive (path: value: value + 1) { - x = { - y = { - z = 1; - }; - }; - }; - in - actual == expected; - }; - - "filter" = { - "filters a set" = - let - expected = { - y = 2; - }; - actual = lib.attrs.filter (name: value: name == "y") { - x = 1; - y = 2; - }; - in - actual == expected; - }; -} diff --git a/lib/src/bools/default.nix b/lib/src/bools/default.nix deleted file mode 100644 index 7f4a7a3..0000000 --- a/lib/src/bools/default.nix +++ /dev/null @@ -1,48 +0,0 @@ -lib: { - bools = { - into = { - ## Convert a boolean value into a string. - ## - ## @type Bool -> String - string = value: if value then "true" else "false"; - - ## Convert a boolean into either the string "yes" or "no". - ## - ## @type Bool -> String - yesno = value: if value then "yes" else "no"; - }; - - ## Choose between two values based on a condition. When true, the first value - ## is returned, otherwise the second value is returned. - ## - ## @type Bool -> a -> b -> a | b - when = - condition: x: y: - if condition then x else y; - - ## Perform a logical AND operation on two values. - ## - ## @type Bool -> Bool -> Bool - and = a: b: a && b; - - ## Perform a logical AND operation on two functions being applied to a value. - ## - ## @type (a -> Bool) -> (a -> Bool) -> a -> Bool - and' = f: g: (x: (f x) && (g x)); - - ## Perform a logical OR operation on two values. - ## - ## @type Bool -> Bool -> Bool - or = a: b: a || b; - - ## Perform a logical OR operation on two functions being applied to a value. - ## - ## @type (a -> Bool) -> (a -> Bool) -> a -> Bool - or' = f: g: (x: (f x) || (g x)); - - ## Perform a logical NOT operation on a value. - ## - ## @type Bool -> Bool - not = a: !a; - }; -} diff --git a/lib/src/bools/default.test.nix b/lib/src/bools/default.test.nix deleted file mode 100644 index 1f9c924..0000000 --- a/lib/src/bools/default.test.nix +++ /dev/null @@ -1,190 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "into" = { - "string" = { - "handles true" = - let - expected = "true"; - actual = lib.bools.into.string true; - in - actual == expected; - - "handles false" = - let - expected = "false"; - actual = lib.bools.into.string false; - in - actual == expected; - }; - - "yesno" = { - "handles true" = - let - expected = "yes"; - actual = lib.bools.into.yesno true; - in - actual == expected; - "handles false" = - let - expected = "no"; - actual = lib.bools.into.yesno false; - in - actual == expected; - }; - }; - - "when" = { - "returns first value when true" = - let - expected = "foo"; - actual = lib.bools.when true expected "bar"; - in - actual == expected; - - "returns second value when false" = - let - expected = "bar"; - actual = lib.bools.when false "foo" expected; - in - actual == expected; - }; - - "and" = { - "returns true when both are true" = - let - expected = true; - actual = lib.bools.and true true; - in - actual == expected; - "returns false when first is false" = - let - expected = false; - actual = lib.bools.and false true; - in - actual == expected; - "returns false when second is false" = - let - expected = false; - actual = lib.bools.and true false; - in - actual == expected; - "returns false when both are false" = - let - expected = false; - actual = lib.bools.and false false; - in - actual == expected; - }; - - "and'" = - let - getTrue = _: true; - getFalse = _: false; - in - { - "returns true when both are true" = - let - expected = true; - actual = lib.bools.and' getTrue getTrue null; - in - actual == expected; - - "returns false when first is false" = - let - expected = false; - actual = lib.bools.and' getFalse getTrue null; - in - actual == expected; - - "returns false when second is false" = - let - expected = false; - actual = lib.bools.and' getTrue getFalse null; - in - actual == expected; - - "returns false when both are false" = - let - expected = false; - actual = lib.bools.and' getFalse getFalse null; - in - actual == expected; - }; - - "or" = { - "returns true when both are true" = - let - expected = true; - actual = lib.bools.or true true; - in - actual == expected; - "returns true when first is true" = - let - expected = true; - actual = lib.bools.or true false; - in - actual == expected; - "returns true when second is true" = - let - expected = true; - actual = lib.bools.or false true; - in - actual == expected; - "returns false when both are false" = - let - expected = false; - actual = lib.bools.or false false; - in - actual == expected; - }; - - "or'" = - let - getTrue = _: true; - getFalse = _: false; - in - { - "returns true when both are true" = - let - expected = true; - actual = lib.bools.or' getTrue getTrue null; - in - actual == expected; - "returns true when first is true" = - let - expected = true; - actual = lib.bools.or' getTrue getFalse null; - in - actual == expected; - "returns true when second is true" = - let - expected = true; - actual = lib.bools.or' getFalse getTrue null; - in - actual == expected; - "returns false when both are false" = - let - expected = false; - actual = lib.bools.or' getFalse getFalse null; - in - actual == expected; - }; - - "not" = { - "returns false when true" = - let - expected = false; - actual = lib.bools.not true; - in - actual == expected; - - "returns true when false" = - let - expected = true; - actual = lib.bools.not false; - in - actual == expected; - }; -} diff --git a/lib/src/dag/default.nix b/lib/src/dag/default.nix deleted file mode 100644 index 87f2275..0000000 --- a/lib/src/dag/default.nix +++ /dev/null @@ -1,155 +0,0 @@ -lib: { - dag = { - validate = { - ## Check that a value is a DAG entry. - ## - ## @type a -> Bool - entry = value: (value ? value) && (value ? before) && (value ? after); - - ## Check that a value is a DAG. - ## - ## @type a -> Bool - graph = - value: - let - isContentsValid = builtins.all lib.dag.validate.entry (builtins.attrValues value); - in - builtins.isAttrs value && isContentsValid; - }; - - sort = { - ## Apply a topological sort to a DAG. - ## - ## @type Dag a -> { result :: List a } | { cycle :: List a, loops :: List a } - topological = - graph: - let - getEntriesBefore = - graph: name: - let - before = lib.attrs.filter (key: value: builtins.elem name value.before) graph; - in - builtins.attrNames before; - - normalize = name: value: { - inherit name; - value = value.value; - after = value.after ++ (getEntriesBefore graph name); - }; - - normalized = builtins.mapAttrs normalize graph; - - entries = builtins.attrValues normalized; - - isBefore = a: b: builtins.elem a.name b.after; - - sorted = lib.lists.sort.topological isBefore entries; - in - if sorted ? result then - { - result = builtins.map (value: { - name = value.name; - value = value.value; - }) sorted.result; - } - else - sorted; - }; - - apply = { - ## Apply a set of defaults to a graph. This will ensure that missing entries are added - ## and any entries that do exist are given the appropriate `before` and `after` values. - ## - ## @type Dag a -> Dag a -> Dag a - defaults = - graph: defaults: - let - result = builtins.mapAttrs ( - name: entry: - if defaults ? ${name} then - if builtins.isString entry then - { - value = entry; - before = defaults.${name}.before or [ ]; - after = defaults.${name}.after or [ ]; - } - else - entry - // { - before = (entry.before or [ ]) ++ (defaults.${name}.before or [ ]); - after = (entry.after or [ ]) ++ (defaults.${name}.after or [ ]); - } - else - entry - ) graph; - in - defaults // result; - }; - - ## Map over the entries in a DAG and modify their values. - ## - ## @type (String -> a -> b) -> Dag a -> Dag b - map = f: builtins.mapAttrs (name: value: value // { value = f name value.value; }); - - entry = { - ## Create a new DAG entry. - ## - ## @type List String -> List String -> a -> { before :: List String, after :: List String, value :: a } - between = after: before: value: { inherit before after value; }; - - ## Create a new DAG entry with no dependencies. - ## - ## @type a -> { before :: List String, after :: List String, value :: a } - anywhere = lib.dag.entry.between [ ] [ ]; - - ## Create a new DAG entry that occurs before other entries. - ## - ## @type List String -> a -> { before :: List String, after :: List String, value :: a } - before = before: lib.dag.entry.between [ ] before; - - ## Create a new DAG entry that occurs after other entries. - ## - ## @type List String -> a -> { before :: List String, after :: List String, value :: a } - after = after: lib.dag.entry.between after [ ]; - }; - - entries = { - ## Create a DAG from a list of entries, prefixed with a tag. - ## - ## @type String -> List String -> List String -> List a -> Dag a - between = - tag: - let - process = - i: after: before: entries: - let - name = "${tag}-${builtins.toString i}"; - entry = builtins.head entries; - rest = builtins.tail entries; - in - if builtins.length entries == 0 then - { } - else if builtins.length entries == 1 then - { "${name}" = lib.dag.entry.between after before entry; } - else - { "${name}" = lib.dag.entry.after after entry; } // (process (i + 1) before [ name ] rest); - in - process 0; - - ## Create a DAG from a list of entries, prefixed with a tag, that can occur anywhere. - ## - ## @type String -> List a -> Dag a - anywhere = tag: lib.dag.entries.between tag [ ] [ ]; - - ## Create a DAG from a list of entries, prefixed with a tag, that occurs before other entries. - ## - ## @type String -> List String -> List a -> Dag a - before = tag: before: lib.dag.entries.between tag [ ] before; - - ## Create a DAG from a list of entries, prefixed with a tag, that occurs after other entries. - ## - ## @type String -> List String -> List a -> Dag a - after = tag: after: lib.dag.entries.between tag after [ ]; - }; - }; -} diff --git a/lib/src/dag/default.test.nix b/lib/src/dag/default.test.nix deleted file mode 100644 index 1474878..0000000 --- a/lib/src/dag/default.test.nix +++ /dev/null @@ -1,169 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "validate" = { - "entry" = { - "invalid value" = - let - expected = false; - actual = lib.dag.validate.entry { }; - in - actual == expected; - - "a manually created value" = - let - expected = true; - actual = lib.dag.validate.entry { - value = null; - before = [ ]; - after = [ ]; - }; - in - actual == expected; - - "entry.between" = - let - expected = true; - actual = lib.dag.validate.entry (lib.dag.entry.between [ ] [ ] null); - in - actual == expected; - - "entry.anywhere" = - let - expected = true; - actual = lib.dag.validate.entry (lib.dag.entry.anywhere null); - in - actual == expected; - - "entry.before" = - let - expected = true; - actual = lib.dag.validate.entry (lib.dag.entry.before [ ] null); - in - actual == expected; - - "entry.after" = - let - expected = true; - actual = lib.dag.validate.entry (lib.dag.entry.after [ ] null); - in - actual == expected; - }; - - "graph" = { - "invalid value" = - let - expected = false; - actual = lib.dag.validate.graph { x = { }; }; - in - actual == expected; - - "a manually created value" = - let - expected = true; - actual = lib.dag.validate.graph { - x = { - value = null; - before = [ ]; - after = [ ]; - }; - }; - in - actual == expected; - - "entries.between" = - let - expected = true; - graph = - lib.dag.entries.between "example" [ ] - [ ] - [ - null - null - ]; - actual = lib.dag.validate.graph graph; - in - actual == expected; - - "entries.anywhere" = - let - expected = true; - graph = lib.dag.entries.anywhere "example" [ - null - null - ]; - actual = lib.dag.validate.graph graph; - in - actual == expected; - - "entries.before" = - let - expected = true; - graph = - lib.dag.entries.before "example" - [ ] - [ - null - null - ]; - actual = lib.dag.validate.graph graph; - in - actual == expected; - - "entries.after" = - let - expected = true; - graph = - lib.dag.entries.after "example" - [ ] - [ - null - null - ]; - actual = lib.dag.validate.graph graph; - in - actual == expected; - }; - }; - - "sort" = { - "topological" = { - "handles an empty graph" = - let - expected = [ ]; - actual = lib.dag.sort.topological { }; - in - actual.result == expected; - - "sorts a graph" = - let - expected = [ - { - name = "a"; - value = "a"; - } - { - name = "b"; - value = "b"; - } - { - name = "c"; - value = "c"; - } - { - name = "d"; - value = "d"; - } - ]; - actual = lib.dag.sort.topological { - a = lib.dag.entry.anywhere "a"; - b = lib.dag.entry.between [ "a" ] [ "c" ] "b"; - c = lib.dag.entry.before [ "c" ] "c"; - d = lib.dag.entry.after [ "c" ] "d"; - }; - in - actual.result == expected; - }; - }; -} diff --git a/lib/src/default.nix b/lib/src/default.nix deleted file mode 100644 index e2f7ae9..0000000 --- a/lib/src/default.nix +++ /dev/null @@ -1,84 +0,0 @@ -let - files = [ - ./attrs - ./bools - ./dag - ./errors - ./fp - ./generators - ./importers - ./licenses - ./lists - ./math - ./modules - ./numbers - ./options - ./packages - ./paths - ./points - ./strings - ./types - ./versions - ]; - - libs = builtins.map (f: import f) files; - - ## Calculate the fixed point of a function. This will evaluate the function `f` - ## until its result settles (or Nix's recursion limit is reached). This allows - ## us to define recursive functions without worrying about the order of their - ## definitions. - ## - ## @type (a -> a) -> a - fix = - f: - let - x = f x; - in - x; - - ## Merge two attribute sets recursively until a given predicate returns true. - ## Any values that are _not_ attribute sets will be overridden with the value - ## from `y` first if it exists and then `x` otherwise. - ## - ## @type Attrs a b c => (String -> Any -> Any -> Bool) -> a -> b -> c - mergeAttrsRecursiveUntil = - predicate: x: y: - let - process = - path: - builtins.zipAttrsWith ( - name: values: - let - currentPath = path ++ [ name ]; - isSingleValue = builtins.length values == 1; - isComplete = predicate currentPath (builtins.elemAt values 1) (builtins.elemAt values 0); - in - if isSingleValue || isComplete then builtins.elemAt values 0 else process currentPath values - ); - in - process - [ ] - [ - x - y - ]; - - ## Merge two attribute sets recursively. Any values that are _not_ attribute sets - ## will be overridden with the value from `y` first if it exists and then `x` - ## otherwise. - ## - ## @type Attrs a b c => a -> b -> c - mergeAttrsRecursive = mergeAttrsRecursiveUntil ( - path: x: y: - !(builtins.isAttrs x && builtins.isAttrs y) - ); - - lib = fix ( - self: - let - merge = acc: create: mergeAttrsRecursive acc (create self); - in - builtins.foldl' merge { } libs - ); -in -lib.points.withExtend (lib.fp.const lib) diff --git a/lib/src/default.test.nix b/lib/src/default.test.nix deleted file mode 100644 index fc43a08..0000000 --- a/lib/src/default.test.nix +++ /dev/null @@ -1,22 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "extend" = { - "lib is extensible" = - let - result = lib.extend ( - final: prev: - prev - // { - __injected__ = true; - - fp = prev.fp // { - __injected__ = true; - }; - } - ); - in - result ? __injected__ && result.fp ? __injected__ && result.fp ? const; - }; -} diff --git a/lib/src/errors/default.nix b/lib/src/errors/default.nix deleted file mode 100644 index 322f0bf..0000000 --- a/lib/src/errors/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -lib: { - errors = { - ## Prints a message if the condition is not met. The result of - ## the condition is returned. - ## - ## @notest - ## @type Bool -> String -> Bool - trace = condition: message: if condition then true else builtins.trace message false; - }; -} diff --git a/lib/src/errors/default.test.nix b/lib/src/errors/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/errors/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/src/fp/default.nix b/lib/src/fp/default.nix deleted file mode 100644 index 23b39b3..0000000 --- a/lib/src/fp/default.nix +++ /dev/null @@ -1,64 +0,0 @@ -lib: { - fp = { - ## A function that returns its argument. - ## - ## @type a -> a - id = x: x; - - ## Create a function that ignores its argument and returns a constant value. - ## - ## @type a -> b -> a - const = x: (_: x); - - ## Compose two functions to produce a new function that applies them both - ## from right to left. - ## - ## @type Function f g => (b -> c) -> (a -> b) -> a -> c - compose = f: g: (x: f (g x)); - - ## Process a value with a series of functions. Functions are applied in the - ## order they are provided. - ## - ## @type (List (Any -> Any)) -> Any -> Any - pipe = fs: (x: builtins.foldl' (value: f: f value) x fs); - - ## Reverse the order of arguments to a function that has two parameters. - ## - ## @type (a -> b -> c) -> b -> a -> c - flip2 = - f: a: b: - f b a; - ## Reverse the order of arguments to a function that has three parameters. - ## - ## @type (a -> b -> c -> d) -> c -> b -> a -> d - flip3 = - f: a: b: c: - f c b a; - ## Reverse the order of arguments to a function that has four parameters. - ## - ## @type (a -> b -> c -> d -> e) -> d -> c -> b -> a -> e - flip4 = - f: a: b: c: d: - f d c b a; - - ## Get the arguments of a function or functor. - ## An attribute set is returned with the arguments as keys. The values - ## are `true` when the argument has a default value specified and `false` - ## when it does not. - ## - ## @type Function -> Attrs - args = - f: if f ? __functor then f.__args__ or (lib.fp.args (f.__functor f)) else builtins.functionArgs f; - - ## Create a function that is called with only the arguments it specifies. - ## - ## @type Attrs a => (a -> b) -> a -> b - withDynamicArgs = - f: args: - let - fArgs = lib.fp.args f; - common = builtins.intersectAttrs fArgs args; - in - if builtins.isAttrs args then if fArgs == { } then f args else f common else f args; - }; -} diff --git a/lib/src/fp/default.test.nix b/lib/src/fp/default.test.nix deleted file mode 100644 index 62fe7d4..0000000 --- a/lib/src/fp/default.test.nix +++ /dev/null @@ -1,165 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "id" = { - "returns its argument" = - let - expected = "foo"; - actual = lib.fp.id expected; - in - actual == expected; - }; - - "const" = { - "creates a function that returns its argument" = - let - expected = "foo"; - actual = lib.fp.const expected "bar"; - in - actual == expected; - }; - - "compose" = { - "composes two functions" = - let - f = x: x + 1; - g = x: x * 2; - expected = 5; - actual = lib.fp.compose f g 2; - in - actual == expected; - }; - - "pipe" = { - "pipes two functions" = - let - f = x: x + 1; - g = x: x * 2; - expected = 5; - actual = lib.fp.pipe [ - g - f - ] 2; - in - actual == expected; - }; - - "flip2" = { - "flips the arguments of a binary function" = - let - f = a: b: a - b; - expected = 1; - actual = lib.fp.flip2 f 1 2; - in - actual == expected; - }; - - "flip3" = { - "flips the arguments of a ternary function" = - let - f = - a: b: c: - a - b - c; - expected = 0; - actual = lib.fp.flip3 f 1 2 3; - in - actual == expected; - }; - - "flip4" = { - "flips the arguments of a quaternary function" = - let - f = - a: b: c: d: - a - b - c - d; - expected = -2; - actual = lib.fp.flip4 f 1 2 3 4; - in - actual == expected; - }; - - "args" = { - "gets a functions attr set arguments" = - let - expected = { - x = false; - y = true; - }; - actual = lib.fp.args ( - { - x, - y ? null, - }: - null - ); - in - actual == expected; - - "returns an empty set if the function has no attrs arguments" = - let - expected = { }; - actual = lib.fp.args (args: null); - in - actual == expected; - - "supports functors" = - let - expected = { - x = false; - y = true; - }; - - actual = lib.fp.args { - __functor = - self: - { - x, - y ? null, - }: - null; - }; - in - actual == expected; - - "supports cached functor arguments" = - let - expected = { - x = false; - y = true; - }; - actual = lib.fp.args { - __args__ = { - x = false; - y = true; - }; - __functor = self: args: null; - }; - in - actual == expected; - }; - - "withDynamicArgs" = { - "applies a function with dynamic arguments" = - let - expected = { - x = true; - }; - actual = lib.fp.withDynamicArgs (args@{ x }: args) { - x = true; - y = true; - }; - in - actual == expected; - - "applies all arguments if none are specified" = - let - expected = { - x = true; - y = true; - }; - actual = lib.fp.withDynamicArgs (args: args) expected; - in - actual == expected; - }; -} diff --git a/lib/src/generators/default.nix b/lib/src/generators/default.nix deleted file mode 100644 index 6627e43..0000000 --- a/lib/src/generators/default.nix +++ /dev/null @@ -1,152 +0,0 @@ -lib: { - generators = { - ## Limit evaluation of a valud to a certain depth. - ## - ## @type { limit? :: Int | Null, throw? :: Bool } -> a -> a - withRecursion = - { - limit ? null, - throw ? true, - }: - assert builtins.isInt limit; - let - special = [ - "__functor" - "__functionArgs" - "__toString" - "__pretty__" - ]; - attr = next: name: if builtins.elem name special then lib.fp.id else next; - transform = - depth: - if limit != null && depth > limit then - if throw then - builtins.throw "Exceeded maximum eval-depth limit of ${builtins.toString limit} while trying to evaluate with `lib.generators.withRecursion'!" - else - lib.fp.const "" - else - lib.fp.id; - process = - depth: value: - let - next = x: process (depth + 1) (transform (depth + 1) x); - in - if builtins.isAttrs value then - builtins.mapAttrs (attr next) value - else if builtins.isList value then - builtins.map next value - else - transform (depth + 1) value; - in - process 0; - - ## Create a pretty printer for Nix values. - ## - ## @type { indent? :: String, multiline? :: Bool, allowCustomPrettifiers? :: Bool } -> a -> string - pretty = - { - indent ? "", - multiline ? true, - allowCustomPrettifiers ? false, - }: - let - process = - indent: value: - let - prefix = if multiline then "\n${indent} " else " "; - suffix = if multiline then "\n${indent}" else " "; - - prettyNull = "null"; - prettyNumber = lib.numbers.into.string value; - prettyBool = lib.bools.into.string value; - prettyPath = builtins.toString value; - - prettyString = - let - lines = builtins.filter (x: !builtins.isList x) (builtins.split "\n" value); - escapeSingleline = lib.strings.escape.any [ - "\\" - "\"" - "\${" - ]; - escapeMultiline = - builtins.replaceStrings - [ - "\${" - "''" - ] - [ - "''\${" - "'''" - ]; - singlelineResult = "\"" + lib.strings.concatMapSep "\\n" escapeSingleline lines + "\""; - multilineResult = - let - escapedLines = builtins.map escapeMultiline lines; - # The last line gets a special treatment: if it's empty, '' is on its own line at the "outer" - # indentation level. Otherwise, '' is appended to the last line. - lastLine = lib.lists.last escapedLines; - contents = builtins.concatStringsSep prefix (lib.lists.init escapedLines); - contentsSuffix = if lastLine == "" then suffix else prefix + lastLine; - in - "''" + prefix + contents + contentsSuffix + "''"; - in - if multiline && builtins.length lines > 1 then multilineResult else singlelineResult; - - prettyList = - let - contents = lib.strings.concatMapSep prefix (process (indent + " ")) value; - in - if builtins.length value == 0 then "[ ]" else "[${prefix}${contents}${suffix}]"; - - prettyFunction = - let - args = lib.fp.args value; - markArgOptional = name: default: if default then name + "?" else name; - argsWithDefaults = lib.attrs.mapToList markArgOptional args; - serializedArgs = builtins.concatStringsSep ", " argsWithDefaults; - in - if args == { } then "" else ""; - - prettyAttrs = - let - contents = builtins.concatStringsSep prefix ( - lib.attrs.mapToList ( - name: value: - "${lib.strings.escape.nix.identifier name} = ${ - builtins.addErrorContext "while evaluating an attribute `${name}`" (process (indent + " ") value) - };" - ) value - ); - in - if allowCustomPrettifiers && value ? __pretty__ && value ? value then - value.__pretty__ value.value - else if value == { } then - "{ }" - else if lib.packages.isDerivation value then - "" - else - "{${prefix}${contents}${suffix}}"; - in - if null == value then - prettyNull - else if builtins.isInt value || builtins.isFloat value then - prettyNumber - else if builtins.isBool value then - prettyBool - else if builtins.isString value then - prettyString - else if builtins.isPath value then - prettyPath - else if builtins.isList value then - prettyList - else if builtins.isFunction value then - prettyFunction - else if builtins.isAttrs value then - prettyAttrs - else - builtins.abort "lib.generators.pretty: should never happen (value = ${value})"; - in - process indent; - }; -} diff --git a/lib/src/generators/default.test.nix b/lib/src/generators/default.test.nix deleted file mode 100644 index 46ffd04..0000000 --- a/lib/src/generators/default.test.nix +++ /dev/null @@ -1,111 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "withRecursion" = { - "evaluates within a given limit" = - let - expected = { - x = 1; - }; - actual = lib.generators.withRecursion { limit = 100; } expected; - in - expected == actual; - - "fails when the limit is reached" = - let - expected = { - x = 1; - }; - actual = lib.generators.withRecursion { limit = -1; } expected; - evaluated = builtins.tryEval (builtins.deepSeq actual actual); - in - !evaluated.success; - - "does not fail when throw is disabled" = - let - expected = { - x = ""; - }; - actual = lib.generators.withRecursion { - limit = -1; - throw = false; - } { x = 1; }; - evaluated = builtins.tryEval (builtins.deepSeq actual actual); - in - evaluated.success && evaluated.value == expected; - }; - - "pretty" = { - "formats with defaults" = - let - expected = '' - { - attrs = { }; - bool = true; - float = 0.0; - function = ; - int = 0; - list = [ ]; - string = "string"; - }''; - actual = lib.generators.pretty { } { - attrs = { }; - bool = true; - float = 0.0; - function = x: x; - int = 0; - list = [ ]; - string = "string"; - # NOTE: We are not testing `path` types because they can return out of store - # values which are not deterministic. - # path = ./.; - }; - in - actual == expected; - - "formats with custom prettifiers" = - let - expected = '' - { - attrs = { }; - bool = true; - custom = ; - float = 0.0; - function = ; - int = 0; - list = [ ]; - string = "string"; - }''; - actual = lib.generators.pretty { allowCustomPrettifiers = true; } { - attrs = { }; - bool = true; - float = 0.0; - function = x: x; - int = 0; - list = [ ]; - string = "string"; - custom = { - value = 0; - __pretty__ = value: ""; - }; - }; - in - actual == expected; - - "formats with multiline disabled" = - let - expected = "{ attrs = { }; bool = true; float = 0.0; function = ; int = 0; list = [ ]; string = \"string\"; }"; - actual = lib.generators.pretty { multiline = false; } { - attrs = { }; - bool = true; - float = 0.0; - function = x: x; - int = 0; - list = [ ]; - string = "string"; - }; - in - actual == expected; - }; -} diff --git a/lib/src/importers/default.nix b/lib/src/importers/default.nix deleted file mode 100644 index 8fe0967..0000000 --- a/lib/src/importers/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -lib: { - importers = { - ## Import a JSON file as a Nix value. - ## - ## @notest - ## @type Path -> a - json = file: builtins.fromJSON (builtins.readFile file); - - ## Import a TOML file as a Nix value. - ## - ## @notest - ## @type Path -> a - toml = file: builtins.fromTOML (builtins.readFile file); - }; -} diff --git a/lib/src/importers/default.test.nix b/lib/src/importers/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/importers/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/src/licenses/all.nix b/lib/src/licenses/all.nix deleted file mode 100644 index 98740f0..0000000 --- a/lib/src/licenses/all.nix +++ /dev/null @@ -1,1268 +0,0 @@ -{ - abstyles = { - spdxId = "Abstyles"; - fullName = "Abstyles License"; - }; - - acsl14 = { - fullName = "Anti-Capitalist Software License v1.4"; - url = "https://anticapitalist.software/"; - # restrictions on corporations apply for both use and redistribution - free = false; - redistributable = false; - }; - - activision = { - # https://doomwiki.org/wiki/Raven_source_code_licensing - fullName = "Activision EULA"; - url = "https://www.doomworld.com/eternity/activision_eula.txt"; - free = false; - }; - - afl20 = { - spdxId = "AFL-2.0"; - fullName = "Academic Free License v2.0"; - }; - - afl21 = { - spdxId = "AFL-2.1"; - fullName = "Academic Free License v2.1"; - }; - - afl3 = { - spdxId = "AFL-3.0"; - fullName = "Academic Free License v3.0"; - }; - - agpl3Only = { - spdxId = "AGPL-3.0-only"; - fullName = "GNU Affero General Public License v3.0 only"; - }; - - agpl3Plus = { - spdxId = "AGPL-3.0-or-later"; - fullName = "GNU Affero General Public License v3.0 or later"; - }; - - aladdin = { - spdxId = "Aladdin"; - fullName = "Aladdin Free Public License"; - free = false; - }; - - amazonsl = { - fullName = "Amazon Software License"; - url = "https://aws.amazon.com/asl/"; - free = false; - }; - - amd = { - fullName = "AMD License Agreement"; - url = "https://developer.amd.com/amd-license-agreement/"; - free = false; - }; - - aom = { - fullName = "Alliance for Open Media Patent License 1.0"; - url = "https://aomedia.org/license/patent-license/"; - }; - - apple-psl10 = { - spdxId = "APSL-1.0"; - fullName = "Apple Public Source License 1.0"; - }; - - apple-psl20 = { - spdxId = "APSL-2.0"; - fullName = "Apple Public Source License 2.0"; - }; - - arphicpl = { - spdxId = "Arphic-1999"; - fullName = "Arphic Public License"; - url = "https://www.freedesktop.org/wiki/Arphic_Public_License/"; - }; - - artistic1 = { - spdxId = "Artistic-1.0"; - fullName = "Artistic License 1.0"; - }; - - artistic1-cl8 = { - spdxId = "Artistic-1.0-cl8"; - fullName = "Artistic License 1.0 w/clause 8"; - }; - - artistic2 = { - spdxId = "Artistic-2.0"; - fullName = "Artistic License 2.0"; - }; - - asl20 = { - spdxId = "Apache-2.0"; - fullName = "Apache License 2.0"; - }; - - asl20-llvm = { - spdxId = "Apache-2.0 WITH LLVM-exception"; - fullName = "Apache License 2.0 with LLVM Exceptions"; - }; - - bitstreamVera = { - spdxId = "Bitstream-Vera"; - fullName = "Bitstream Vera Font License"; - }; - - bitTorrent10 = { - spdxId = "BitTorrent-1.0"; - fullName = " BitTorrent Open Source License v1.0"; - }; - - bitTorrent11 = { - spdxId = "BitTorrent-1.1"; - fullName = " BitTorrent Open Source License v1.1"; - }; - - bola11 = { - url = "https://blitiri.com.ar/p/bola/"; - fullName = "Buena Onda License Agreement 1.1"; - }; - - boost = { - spdxId = "BSL-1.0"; - fullName = "Boost Software License 1.0"; - }; - - beerware = { - spdxId = "Beerware"; - fullName = "Beerware License"; - }; - - blueOak100 = { - spdxId = "BlueOak-1.0.0"; - fullName = "Blue Oak Model License 1.0.0"; - }; - - bsd0 = { - spdxId = "0BSD"; - fullName = "BSD Zero Clause License"; - }; - - bsd1 = { - spdxId = "BSD-1-Clause"; - fullName = "BSD 1-Clause License"; - }; - - bsd2 = { - spdxId = "BSD-2-Clause"; - fullName = ''BSD 2-clause "Simplified" License''; - }; - - bsd2Patent = { - spdxId = "BSD-2-Clause-Patent"; - fullName = "BSD-2-Clause Plus Patent License"; - }; - - bsd2WithViews = { - spdxId = "BSD-2-Clause-Views"; - fullName = "BSD 2-Clause with views sentence"; - }; - - bsd3 = { - spdxId = "BSD-3-Clause"; - fullName = ''BSD 3-clause "New" or "Revised" License''; - }; - - bsd3Clear = { - spdxId = "BSD-3-Clause-Clear"; - fullName = "BSD 3-Clause Clear License"; - }; - - bsdOriginal = { - spdxId = "BSD-4-Clause"; - fullName = ''BSD 4-clause "Original" or "Old" License''; - }; - - bsdOriginalShortened = { - spdxId = "BSD-4-Clause-Shortened"; - fullName = "BSD 4 Clause Shortened"; - }; - - bsdOriginalUC = { - spdxId = "BSD-4-Clause-UC"; - fullName = "BSD 4-Clause University of California-Specific"; - }; - - bsdProtection = { - spdxId = "BSD-Protection"; - fullName = "BSD Protection License"; - }; - - bsl11 = { - fullName = "Business Source License 1.1"; - url = "https://mariadb.com/bsl11"; - free = false; - redistributable = true; - }; - - caossl = { - fullName = "Computer Associates Open Source Licence Version 1.0"; - url = "http://jxplorer.org/licence.html"; - }; - - cal10 = { - spdxId = "CAL-1.0"; - fullName = "Cryptographic Autonomy License version 1.0 (CAL-1.0)"; - url = "https://opensource.org/licenses/CAL-1.0"; - }; - - caldera = { - spdxId = "Caldera"; - fullName = "Caldera License"; - url = "http://www.lemis.com/grog/UNIX/ancient-source-all.pdf"; - }; - - capec = { - fullName = "Common Attack Pattern Enumeration and Classification"; - url = "https://capec.mitre.org/about/termsofuse.html"; - }; - - clArtistic = { - spdxId = "ClArtistic"; - fullName = "Clarified Artistic License"; - }; - - cc0 = { - spdxId = "CC0-1.0"; - fullName = "Creative Commons Zero v1.0 Universal"; - }; - - cc-by-nc-nd-30 = { - spdxId = "CC-BY-NC-ND-3.0"; - fullName = "Creative Commons Attribution Non Commercial No Derivative Works 3.0 Unported"; - free = false; - }; - - cc-by-nc-nd-40 = { - spdxId = "CC-BY-NC-ND-4.0"; - fullName = "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International"; - free = false; - }; - - cc-by-nc-sa-20 = { - spdxId = "CC-BY-NC-SA-2.0"; - fullName = "Creative Commons Attribution Non Commercial Share Alike 2.0"; - free = false; - }; - - cc-by-nc-sa-25 = { - spdxId = "CC-BY-NC-SA-2.5"; - fullName = "Creative Commons Attribution Non Commercial Share Alike 2.5"; - free = false; - }; - - cc-by-nc-sa-30 = { - spdxId = "CC-BY-NC-SA-3.0"; - fullName = "Creative Commons Attribution Non Commercial Share Alike 3.0"; - free = false; - }; - - cc-by-nc-sa-40 = { - spdxId = "CC-BY-NC-SA-4.0"; - fullName = "Creative Commons Attribution Non Commercial Share Alike 4.0"; - free = false; - }; - - cc-by-nc-30 = { - spdxId = "CC-BY-NC-3.0"; - fullName = "Creative Commons Attribution Non Commercial 3.0 Unported"; - free = false; - }; - - cc-by-nc-40 = { - spdxId = "CC-BY-NC-4.0"; - fullName = "Creative Commons Attribution Non Commercial 4.0 International"; - free = false; - }; - - cc-by-nd-30 = { - spdxId = "CC-BY-ND-3.0"; - fullName = "Creative Commons Attribution-No Derivative Works v3.00"; - free = false; - }; - - cc-by-sa-10 = { - spdxId = "CC-BY-SA-1.0"; - fullName = "Creative Commons Attribution Share Alike 1.0"; - }; - - cc-by-sa-20 = { - spdxId = "CC-BY-SA-2.0"; - fullName = "Creative Commons Attribution Share Alike 2.0"; - }; - - cc-by-sa-25 = { - spdxId = "CC-BY-SA-2.5"; - fullName = "Creative Commons Attribution Share Alike 2.5"; - }; - - cc-by-10 = { - spdxId = "CC-BY-1.0"; - fullName = "Creative Commons Attribution 1.0"; - }; - - cc-by-20 = { - spdxId = "CC-BY-2.0"; - fullName = "Creative Commons Attribution 2.0"; - }; - - cc-by-30 = { - spdxId = "CC-BY-3.0"; - fullName = "Creative Commons Attribution 3.0"; - }; - - cc-by-sa-30 = { - spdxId = "CC-BY-SA-3.0"; - fullName = "Creative Commons Attribution Share Alike 3.0"; - }; - - cc-by-40 = { - spdxId = "CC-BY-4.0"; - fullName = "Creative Commons Attribution 4.0"; - }; - - cc-by-sa-40 = { - spdxId = "CC-BY-SA-4.0"; - fullName = "Creative Commons Attribution Share Alike 4.0"; - }; - - cddl = { - spdxId = "CDDL-1.0"; - fullName = "Common Development and Distribution License 1.0"; - }; - - cecill20 = { - spdxId = "CECILL-2.0"; - fullName = "CeCILL Free Software License Agreement v2.0"; - }; - - cecill21 = { - spdxId = "CECILL-2.1"; - fullName = "CeCILL Free Software License Agreement v2.1"; - }; - - cecill-b = { - spdxId = "CECILL-B"; - fullName = "CeCILL-B Free Software License Agreement"; - }; - - cecill-c = { - spdxId = "CECILL-C"; - fullName = "CeCILL-C Free Software License Agreement"; - }; - - cpal10 = { - spdxId = "CPAL-1.0"; - fullName = "Common Public Attribution License 1.0"; - }; - - commons-clause = { - fullName = "Commons Clause License"; - url = "https://commonsclause.com/"; - free = false; - }; - - cpl10 = { - spdxId = "CPL-1.0"; - fullName = "Common Public License 1.0"; - }; - - curl = { - spdxId = "curl"; - fullName = "curl License"; - }; - - doc = { - spdxId = "DOC"; - fullName = "DOC License"; - }; - - drl10 = { - spdxId = "DRL-1.0"; - fullName = "Detection Rule License 1.0"; - }; - - dtoa = { - spdxId = "dtoa"; - fullName = "dtoa License"; - }; - - eapl = { - fullName = "EPSON AVASYS PUBLIC LICENSE"; - url = "https://avasys.jp/hp/menu000000700/hpg000000603.htm"; - free = false; - }; - - ecl20 = { - fullName = "Educational Community License, Version 2.0"; - url = "https://opensource.org/licenses/ECL-2.0"; - shortName = "ECL 2.0"; - spdxId = "ECL-2.0"; - }; - - efl10 = { - spdxId = "EFL-1.0"; - fullName = "Eiffel Forum License v1.0"; - }; - - efl20 = { - spdxId = "EFL-2.0"; - fullName = "Eiffel Forum License v2.0"; - }; - - elastic20 = { - spdxId = "Elastic-2.0"; - fullName = "Elastic License 2.0"; - url = "https://github.com/elastic/elasticsearch/blob/main/licenses/ELASTIC-LICENSE-2.0.txt"; - free = false; - }; - - epl10 = { - spdxId = "EPL-1.0"; - fullName = "Eclipse Public License 1.0"; - }; - - epl20 = { - spdxId = "EPL-2.0"; - fullName = "Eclipse Public License 2.0"; - }; - - epson = { - fullName = "Seiko Epson Corporation Software License Agreement for Linux"; - url = "https://download.ebz.epson.net/dsc/du/02/eula/global/LINUX_EN.html"; - free = false; - }; - - eupl11 = { - spdxId = "EUPL-1.1"; - fullName = "European Union Public License 1.1"; - }; - - eupl12 = { - spdxId = "EUPL-1.2"; - fullName = "European Union Public License 1.2"; - }; - - fdl11Only = { - spdxId = "GFDL-1.1-only"; - fullName = "GNU Free Documentation License v1.1 only"; - }; - - fdl11Plus = { - spdxId = "GFDL-1.1-or-later"; - fullName = "GNU Free Documentation License v1.1 or later"; - }; - - fdl12Only = { - spdxId = "GFDL-1.2-only"; - fullName = "GNU Free Documentation License v1.2 only"; - }; - - fdl12Plus = { - spdxId = "GFDL-1.2-or-later"; - fullName = "GNU Free Documentation License v1.2 or later"; - }; - - fdl13Only = { - spdxId = "GFDL-1.3-only"; - fullName = "GNU Free Documentation License v1.3 only"; - }; - - fdl13Plus = { - spdxId = "GFDL-1.3-or-later"; - fullName = "GNU Free Documentation License v1.3 or later"; - }; - - ffsl = { - fullName = "Floodgap Free Software License"; - url = "https://www.floodgap.com/software/ffsl/license.html"; - free = false; - }; - - fraunhofer-fdk = { - fullName = "Fraunhofer FDK AAC Codec Library"; - spdxId = "FDK-AAC"; - }; - - free = { - fullName = "Unspecified free software license"; - }; - - ftl = { - spdxId = "FTL"; - fullName = "Freetype Project License"; - }; - - g4sl = { - fullName = "Geant4 Software License"; - url = "https://geant4.web.cern.ch/geant4/license/LICENSE.html"; - }; - - geogebra = { - fullName = "GeoGebra Non-Commercial License Agreement"; - url = "https://www.geogebra.org/license"; - free = false; - }; - - generaluser = { - fullName = "GeneralUser GS License v2.0"; - url = "https://www.schristiancollins.com/generaluser.php"; # license included in sources - }; - - gfl = { - fullName = "GUST Font License"; - url = "https://www.gust.org.pl/projects/e-foundry/licenses/GUST-FONT-LICENSE.txt"; - }; - - gfsl = { - fullName = "GUST Font Source License"; - url = "https://www.gust.org.pl/projects/e-foundry/licenses/GUST-FONT-SOURCE-LICENSE.txt"; - }; - - gpl1Only = { - spdxId = "GPL-1.0-only"; - fullName = "GNU General Public License v1.0 only"; - }; - - gpl1Plus = { - spdxId = "GPL-1.0-or-later"; - fullName = "GNU General Public License v1.0 or later"; - }; - - gpl2Only = { - spdxId = "GPL-2.0-only"; - fullName = "GNU General Public License v2.0 only"; - }; - - gpl2Classpath = { - spdxId = "GPL-2.0-with-classpath-exception"; - fullName = "GNU General Public License v2.0 only (with Classpath exception)"; - }; - - gpl2ClasspathPlus = { - fullName = "GNU General Public License v2.0 or later (with Classpath exception)"; - url = "https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception"; - }; - - gpl2Oss = { - fullName = "GNU General Public License version 2 only (with OSI approved licenses linking exception)"; - url = "https://www.mysql.com/about/legal/licensing/foss-exception"; - }; - - gpl2Plus = { - spdxId = "GPL-2.0-or-later"; - fullName = "GNU General Public License v2.0 or later"; - }; - - gpl3Only = { - spdxId = "GPL-3.0-only"; - fullName = "GNU General Public License v3.0 only"; - }; - - gpl3Plus = { - spdxId = "GPL-3.0-or-later"; - fullName = "GNU General Public License v3.0 or later"; - }; - - gpl3ClasspathPlus = { - fullName = "GNU General Public License v3.0 or later (with Classpath exception)"; - url = "https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception"; - }; - - giftware = { - spdxId = "Giftware"; - fullName = "Giftware License"; - }; - - hpnd = { - spdxId = "HPND"; - fullName = "Historic Permission Notice and Disclaimer"; - }; - - hpndSellVariant = { - fullName = "Historical Permission Notice and Disclaimer - sell variant"; - spdxId = "HPND-sell-variant"; - }; - - hpndUc = { - spdxId = "HPND-UC"; - fullName = "Historical Permission Notice and Disclaimer - University of California variant"; - }; - - # Intel's license, seems free - iasl = { - spdxId = "Intel-ACPI"; - fullName = "iASL"; - url = "https://old.calculate-linux.org/packages/licenses/iASL"; - }; - - icu = { - spdxId = "ICU"; - fullName = "ICU"; - }; - - ijg = { - spdxId = "IJG"; - fullName = "Independent JPEG Group License"; - }; - - imagemagick = { - fullName = "ImageMagick License"; - spdxId = "ImageMagick"; - }; - - imlib2 = { - spdxId = "Imlib2"; - fullName = "Imlib2 License"; - }; - - info-zip = { - spdxId = "Info-ZIP"; - fullName = "Info-ZIP License"; - url = "https://infozip.sourceforge.net/license.html"; - }; - - inria-compcert = { - fullName = "INRIA Non-Commercial License Agreement for the CompCert verified compiler"; - url = "https://compcert.org/doc/LICENSE.txt"; - free = false; - }; - - inria-icesl = { - fullName = "End User License Agreement for IceSL Software"; - url = "https://icesl.loria.fr/assets/pdf/EULA_IceSL_binary.pdf"; - free = false; - }; - - inria-zelus = { - fullName = "INRIA Non-Commercial License Agreement for the Zélus compiler"; - url = "https://github.com/INRIA/zelus/raw/829f2b97cba93b0543a9ca0272269e6b8fdad356/LICENSE"; - free = false; - }; - - ipa = { - spdxId = "IPA"; - fullName = "IPA Font License"; - }; - - ipl10 = { - spdxId = "IPL-1.0"; - fullName = "IBM Public License v1.0"; - }; - - isc = { - spdxId = "ISC"; - fullName = "ISC License"; - }; - - # Proprietary binaries; free to redistribute without modification. - databricks = { - fullName = "Databricks Proprietary License"; - url = "https://pypi.org/project/databricks-connect"; - free = false; - }; - - databricks-dbx = { - fullName = "DataBricks eXtensions aka dbx License"; - url = "https://github.com/databrickslabs/dbx/blob/743b579a4ac44531f764c6e522dbe5a81a7dc0e4/LICENSE"; - free = false; - redistributable = false; - }; - - fair = { - fullName = "Fair License"; - spdxId = "Fair"; - free = true; - }; - - fairsource09 = { - fullName = "Fair Source License, version 0.9"; - url = "https://fair.io/v0.9.txt"; - free = false; - redistributable = true; - }; - - hl3 = { - fullName = "Hippocratic License v3.0"; - url = "https://firstdonoharm.dev/version/3/0/core.txt"; - free = false; - redistributable = true; - }; - - issl = { - fullName = "Intel Simplified Software License"; - url = "https://software.intel.com/en-us/license/intel-simplified-software-license"; - free = false; - }; - - knuth = { - fullName = "Knuth CTAN License"; - spdxId = "Knuth-CTAN"; - }; - - lal12 = { - spdxId = "LAL-1.2"; - fullName = "Licence Art Libre 1.2"; - }; - - lal13 = { - spdxId = "LAL-1.3"; - fullName = "Licence Art Libre 1.3"; - }; - - lens = { - fullName = "Lens Terms of Service Agreement"; - url = "https://k8slens.dev/licenses/tos"; - free = false; - }; - - lgpl2Only = { - spdxId = "LGPL-2.0-only"; - fullName = "GNU Library General Public License v2 only"; - }; - - lgpl2Plus = { - spdxId = "LGPL-2.0-or-later"; - fullName = "GNU Library General Public License v2 or later"; - }; - - lgpl21Only = { - spdxId = "LGPL-2.1-only"; - fullName = "GNU Lesser General Public License v2.1 only"; - }; - - lgpl21Plus = { - spdxId = "LGPL-2.1-or-later"; - fullName = "GNU Lesser General Public License v2.1 or later"; - }; - - lgpl3Only = { - spdxId = "LGPL-3.0-only"; - fullName = "GNU Lesser General Public License v3.0 only"; - }; - - lgpl3Plus = { - spdxId = "LGPL-3.0-or-later"; - fullName = "GNU Lesser General Public License v3.0 or later"; - }; - - lgpllr = { - spdxId = "LGPLLR"; - fullName = "Lesser General Public License For Linguistic Resources"; - }; - - libpng = { - spdxId = "Libpng"; - fullName = "libpng License"; - }; - - libpng2 = { - spdxId = "libpng-2.0"; # Used since libpng 1.6.36. - fullName = "PNG Reference Library version 2"; - }; - - libssh2 = { - fullName = "libssh2 License"; - url = "https://www.libssh2.org/license.html"; - }; - - libtiff = { - spdxId = "libtiff"; - fullName = "libtiff License"; - }; - - llgpl21 = { - fullName = "Lisp LGPL; GNU Lesser General Public License version 2.1 with Franz Inc. preamble for clarification of LGPL terms in context of Lisp"; - url = "https://opensource.franz.com/preamble.html"; - }; - - lppl1 = { - spdxId = "LPPL-1.0"; - fullName = "LaTeX Project Public License v1.0"; - }; - - lppl12 = { - spdxId = "LPPL-1.2"; - fullName = "LaTeX Project Public License v1.2"; - }; - - lppl13a = { - spdxId = "LPPL-1.3a"; - fullName = "LaTeX Project Public License v1.3a"; - }; - - lppl13c = { - spdxId = "LPPL-1.3c"; - fullName = "LaTeX Project Public License v1.3c"; - }; - - lpl-102 = { - spdxId = "LPL-1.02"; - fullName = "Lucent Public License v1.02"; - }; - - miros = { - spdxId = "MirOS"; - fullName = "MirOS License"; - url = "https://opensource.org/licenses/MirOS"; - }; - - # spdx.org does not (yet) differentiate between the X11 and Expat versions - # for details see https://en.wikipedia.org/wiki/MIT_License#Various_versions - mit = { - spdxId = "MIT"; - fullName = "MIT License"; - }; - # https://spdx.org/licenses/MIT-feh.html - mit-feh = { - spdxId = "MIT-feh"; - fullName = "feh License"; - }; - - mitAdvertising = { - spdxId = "MIT-advertising"; - fullName = "Enlightenment License (e16)"; - }; - - mit0 = { - spdxId = "MIT-0"; - fullName = "MIT No Attribution"; - }; - - mpl10 = { - spdxId = "MPL-1.0"; - fullName = "Mozilla Public License 1.0"; - }; - - mpl11 = { - spdxId = "MPL-1.1"; - fullName = "Mozilla Public License 1.1"; - }; - - mpl20 = { - spdxId = "MPL-2.0"; - fullName = "Mozilla Public License 2.0"; - }; - - mplus = { - spdxId = "mplus"; - fullName = "M+ Font License"; - }; - - mspl = { - spdxId = "MS-PL"; - fullName = "Microsoft Public License"; - }; - - mulan-psl2 = { - spdxId = "MulanPSL-2.0"; - fullName = "Mulan Permissive Software License, Version 2"; - url = "https://license.coscl.org.cn/MulanPSL2"; - }; - - nasa13 = { - spdxId = "NASA-1.3"; - fullName = "NASA Open Source Agreement 1.3"; - free = false; - }; - - ncbiPd = { - spdxId = "NCBI-PD"; - fullname = "NCBI Public Domain Notice"; - # Due to United States copyright law, anything with this "license" does not have a copyright in the - # jurisdiction of the United States. However, other jurisdictions may assign the United States - # government copyright to the work, and the license explicitly states that in such a case, no license - # is granted. This is nonfree and nonredistributable in most jurisdictions other than the United States. - free = false; - redistributable = false; - }; - - ncsa = { - spdxId = "NCSA"; - fullName = "University of Illinois/NCSA Open Source License"; - }; - - ncul1 = { - spdxId = "NCUL1"; - fullName = "Netdata Cloud UI License v1.0"; - free = false; - redistributable = true; # Only if used in Netdata products. - url = "https://raw.githubusercontent.com/netdata/netdata/master/web/gui/v2/LICENSE.md"; - }; - - nistSoftware = { - spdxId = "NIST-Software"; - fullName = "NIST Software License"; - }; - - nlpl = { - spdxId = "NLPL"; - fullName = "No Limit Public License"; - }; - - nposl3 = { - spdxId = "NPOSL-3.0"; - fullName = "Non-Profit Open Software License 3.0"; - }; - - nvidiaCuda = { - shortName = "CUDA EULA"; - fullName = "CUDA Toolkit End User License Agreement (EULA)"; - url = "https://docs.nvidia.com/cuda/eula/index.html#cuda-toolkit-supplement-license-agreement"; - free = false; - }; - - nvidiaCudaRedist = { - shortName = "CUDA EULA"; - fullName = "CUDA Toolkit End User License Agreement (EULA)"; - url = "https://docs.nvidia.com/cuda/eula/index.html#cuda-toolkit-supplement-license-agreement"; - free = false; - redistributable = true; - }; - - obsidian = { - fullName = "Obsidian End User Agreement"; - url = "https://obsidian.md/eula"; - free = false; - }; - - ocamlLgplLinkingException = { - spdxId = "OCaml-LGPL-linking-exception"; - fullName = "OCaml LGPL Linking Exception"; - }; - - ocamlpro_nc = { - fullName = "OCamlPro Non Commercial license version 1"; - url = "https://alt-ergo.ocamlpro.com/http/alt-ergo-2.2.0/OCamlPro-Non-Commercial-License.pdf"; - free = false; - }; - - odbl = { - spdxId = "ODbL-1.0"; - fullName = "Open Data Commons Open Database License v1.0"; - }; - - ofl = { - spdxId = "OFL-1.1"; - fullName = "SIL Open Font License 1.1"; - }; - - oml = { - spdxId = "OML"; - fullName = "Open Market License"; - }; - - openldap = { - spdxId = "OLDAP-2.8"; - fullName = "Open LDAP Public License v2.8"; - }; - - openssl = { - spdxId = "OpenSSL"; - fullName = "OpenSSL License"; - }; - - opubl = { - spdxId = "OPUBL-1.0"; - fullName = "Open Publication License v1.0"; - }; - - osl2 = { - spdxId = "OSL-2.0"; - fullName = "Open Software License 2.0"; - }; - - osl21 = { - spdxId = "OSL-2.1"; - fullName = "Open Software License 2.1"; - }; - - osl3 = { - spdxId = "OSL-3.0"; - fullName = "Open Software License 3.0"; - }; - - parity70 = { - spdxId = "Parity-7.0.0"; - fullName = "Parity Public License 7.0.0"; - url = "https://paritylicense.com/versions/7.0.0.html"; - }; - - php301 = { - spdxId = "PHP-3.01"; - fullName = "PHP License v3.01"; - }; - - postgresql = { - spdxId = "PostgreSQL"; - fullName = "PostgreSQL License"; - }; - - postman = { - fullName = "Postman EULA"; - url = "https://www.getpostman.com/licenses/postman_base_app"; - free = false; - }; - - psfl = { - spdxId = "Python-2.0"; - fullName = "Python Software Foundation License version 2"; - url = "https://docs.python.org/license.html"; - }; - - publicDomain = { - fullName = "Public Domain"; - }; - - purdueBsd = { - fullName = " Purdue BSD-Style License"; # also know as lsof license - url = "https://enterprise.dejacode.com/licenses/public/purdue-bsd"; - }; - - prosperity30 = { - fullName = "Prosperity-3.0.0"; - free = false; - url = "https://prosperitylicense.com/versions/3.0.0.html"; - }; - - qhull = { - spdxId = "Qhull"; - fullName = "Qhull License"; - }; - - qpl = { - spdxId = "QPL-1.0"; - fullName = "Q Public License 1.0"; - }; - - qwt = { - fullName = "Qwt License, Version 1.0"; - url = "https://qwt.sourceforge.io/qwtlicense.html"; - }; - - ruby = { - spdxId = "Ruby"; - fullName = "Ruby License"; - }; - - sendmail = { - spdxId = "Sendmail"; - fullName = "Sendmail License"; - }; - - sgi-b-20 = { - spdxId = "SGI-B-2.0"; - fullName = "SGI Free Software License B v2.0"; - }; - - # Gentoo seems to treat it as a license: - # https://gitweb.gentoo.org/repo/gentoo.git/tree/licenses/SGMLUG?id=7d999af4a47bf55e53e54713d98d145f935935c1 - sgmlug = { - fullName = "SGML UG SGML Parser Materials license"; - }; - - sleepycat = { - spdxId = "Sleepycat"; - fullName = "Sleepycat License"; - }; - - smail = { - shortName = "smail"; - fullName = "SMAIL General Public License"; - url = "https://sources.debian.org/copyright/license/debianutils/4.9.1/"; - }; - - smlnj = { - spdxId = "SMLNJ"; - fullName = "Standard ML of New Jersey License"; - }; - - sspl = { - shortName = "SSPL"; - fullName = "Server Side Public License"; - url = "https://www.mongodb.com/licensing/server-side-public-license"; - free = false; - # NOTE Debatable. - # The license a slightly modified AGPL but still considered unfree by the - # OSI for what seem like political reasons - redistributable = true; # Definitely redistributable though, it's an AGPL derivative - }; - - stk = { - shortName = "stk"; - fullName = "Synthesis Tool Kit 4.3"; - url = "https://github.com/thestk/stk/blob/master/LICENSE"; - }; - - sudo = { - shortName = "sudo"; - fullName = "Sudo License (ISC-style)"; - url = "https://www.sudo.ws/about/license/"; - }; - - sustainableUse = { - shortName = "sustainable"; - fullName = "Sustainable Use License"; - url = "https://github.com/n8n-io/n8n/blob/master/LICENSE.md"; - free = false; - redistributable = false; # only free to redistribute "for non-commercial purposes" - }; - - tsl = { - shortName = "TSL"; - fullName = "Timescale License Agreegment"; - url = "https://github.com/timescale/timescaledb/blob/main/tsl/LICENSE-TIMESCALE"; - unfree = true; - }; - - tcltk = { - spdxId = "TCL"; - fullName = "TCL/TK License"; - }; - - ucd = { - fullName = "Unicode Character Database License"; - url = "https://fedoraproject.org/wiki/Licensing:UCD"; - }; - - ufl = { - fullName = "Ubuntu Font License 1.0"; - url = "https://ubuntu.com/legal/font-licence"; - }; - - unfree = { - fullName = "Unfree"; - free = false; - }; - - unfreeRedistributable = { - fullName = "Unfree redistributable"; - free = false; - redistributable = true; - }; - - unfreeRedistributableFirmware = { - fullName = "Unfree redistributable firmware"; - redistributable = true; - # Note: we currently consider these "free" for inclusion in the - # channel and NixOS images. - }; - - unicode-30 = { - spdxId = "Unicode-3.0"; - fullName = "Unicode License v3"; - }; - - unicode-dfs-2015 = { - spdxId = "Unicode-DFS-2015"; - fullName = "Unicode License Agreement - Data Files and Software (2015)"; - }; - - unicode-dfs-2016 = { - spdxId = "Unicode-DFS-2016"; - fullName = "Unicode License Agreement - Data Files and Software (2016)"; - }; - - unlicense = { - spdxId = "Unlicense"; - fullName = "The Unlicense"; - }; - - upl = { - spdxId = "UPL-1.0"; - fullName = "Universal Permissive License"; - url = "https://oss.oracle.com/licenses/upl/"; - }; - - vim = { - spdxId = "Vim"; - fullName = "Vim License"; - }; - - virtualbox-puel = { - fullName = "Oracle VM VirtualBox Extension Pack Personal Use and Evaluation License (PUEL)"; - url = "https://www.virtualbox.org/wiki/VirtualBox_PUEL"; - free = false; - }; - - vol-sl = { - fullName = "Volatility Software License, Version 1.0"; - url = "https://www.volatilityfoundation.org/license/vsl-v1.0"; - }; - - vsl10 = { - spdxId = "VSL-1.0"; - fullName = "Vovida Software License v1.0"; - }; - - watcom = { - spdxId = "Watcom-1.0"; - fullName = "Sybase Open Watcom Public License 1.0"; - }; - - w3c = { - spdxId = "W3C"; - fullName = "W3C Software Notice and License"; - }; - - wadalab = { - fullName = "Wadalab Font License"; - url = "https://fedoraproject.org/wiki/Licensing:Wadalab?rd=Licensing/Wadalab"; - }; - - wtfpl = { - spdxId = "WTFPL"; - fullName = "Do What The F*ck You Want To Public License"; - }; - - wxWindows = { - spdxId = "wxWindows"; - fullName = "wxWindows Library Licence, Version 3.1"; - }; - - x11 = { - spdxId = "X11"; - fullName = "X11 License"; - }; - - xfig = { - spdxId = "Xfig"; - fullName = "xfig"; - url = "https://mcj.sourceforge.net/authors.html#xfig"; - }; - - xinetd = { - spdxId = "xinetd"; - fullName = "xinetd License"; - }; - - zlib = { - spdxId = "Zlib"; - fullName = "zlib License"; - }; - - zpl20 = { - spdxId = "ZPL-2.0"; - fullName = "Zope Public License 2.0"; - }; - - zpl21 = { - spdxId = "ZPL-2.1"; - fullName = "Zope Public License 2.1"; - }; - - xskat = { - spdxId = "XSkat"; - fullName = "XSkat License"; - }; -} diff --git a/lib/src/licenses/default.nix b/lib/src/licenses/default.nix deleted file mode 100644 index 9821a71..0000000 --- a/lib/src/licenses/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -lib: { - licenses = - let - raw = import ./all.nix; - - defaults = name: { - inherit name; - free = true; - }; - - withDefaults = name: license: (defaults name) // license; - withSpdx = - license: - if license ? spdx then - license // { url = "https://spdx.org/licenses/${license.spdx}.html"; } - else - license; - withRedistributable = license: { redistributable = license.free; } // license; - - normalize = - name: - lib.fp.pipe [ - (withDefaults name) - withSpdx - withRedistributable - ]; - in - builtins.mapAttrs normalize raw; -} diff --git a/lib/src/lists/default.nix b/lib/src/lists/default.nix deleted file mode 100644 index 7cd6f10..0000000 --- a/lib/src/lists/default.nix +++ /dev/null @@ -1,234 +0,0 @@ -lib: { - lists = { - from = { - ## Convert a value to a list. If the value is already a list, - ## it will be returned as-is. If the value is not a list, it - ## will be wrapped in a list. - ## - ## @type a | (List a) -> List a - any = value: if builtins.isList value then value else [ value ]; - }; - - sort = { - ## Perform a natural sort on a list of strings. - ## - ## @type List String -> List String - natural = - list: - let - vectorize = - string: - let - serialize = part: if builtins.isList part then lib.strings.into.int (builtins.head part) else part; - parts = lib.strings.split "(0|[1-9][0-9]*)" string; - in - builtins.map serialize parts; - prepared = builtins.map (value: [ - (vectorize value) - value - ]) list; - isLess = a: b: (lib.lists.compare lib.numbers.compare (builtins.head a) (builtins.head b)) < 0; - in - builtins.map (x: builtins.elemAt x 1) (builtins.sort isLess prepared); - - ## Perform a topological sort on a list of items. The predicate function determines whether - ## its first argument comes before the second argument. - ## - ## @type (a -> a -> Bool) -> List a -> List a - topological = - predicate: list: - let - searched = lib.lists.search.depthFirst true predicate list; - results = lib.lists.sort.topological predicate (searched.visited ++ searched.rest); - in - if builtins.length list < 2 then - { result = list; } - else if searched ? cycle then - { - loops = searched.loops; - cycle = lib.lists.reverse ([ searched.cycle ] ++ searched.visited); - } - else if results ? cycle then - results - else - { result = [ searched.minimal ] ++ results.result; }; - }; - - search = { - ## Perform a depth first search on a list. The supplied predicate function determines whether - ## its first argument comes before the second argument. - ## - ## @type Bool -> (a -> a -> Bool) -> List a - depthFirst = - isAcyclical: predicate: list: - let - process = - current: visited: rest: - let - loops = builtins.filter (value: predicate value current) visited; - partitioned = builtins.partition (value: predicate value current) rest; - in - if isAcyclical && (builtins.length loops > 0) then - { - cycle = current; - inherit loops visited rest; - } - else if builtins.length partitioned.right == 0 then - { - minimal = current; - inherit visited rest; - } - else - process (builtins.head partitioned.right) ([ current ] ++ visited) ( - builtins.tail partitioned.right ++ partitioned.wrong - ); - in - process (builtins.head list) [ ] (builtins.tail list); - }; - - ## Map a list using both the index and value of each item. The - ## index starts at 0. - ## - ## @type (Int -> a -> b) -> List a -> List b - mapWithIndex = f: list: builtins.genList (i: f i (builtins.elemAt list i)) (builtins.length list); - - ## Map a list using both the index and value of each item. The - ## index starts at 1. - ## - ## @type (Int -> a -> b) -> List a -> List b - mapWithIndex1 = - f: list: builtins.genList (i: f (i + 1) (builtins.elemAt list i)) (builtins.length list); - - ## Compare two lists using a custom compare function. The compare - ## function is called for each element in the lists that need to - ## be compared. - ## - ## @type (a -> b -> -1 | 0 | 1) -> List a -> List b -> Int - compare = - compare: a: b: - let - result = compare (builtins.head a) (builtins.head b); - in - if a == [ ] then - if b == [ ] then 0 else -1 - else if b == [ ] then - 1 - else if result == 0 then - lib.lists.compare compare (builtins.tail a) (builtins.tail b) - else - result; - - ## Get the last element of a list. - ## - ## @type List a -> a - last = - list: - assert lib.errors.trace (list != [ ]) "List cannot be empty"; - builtins.elemAt list (builtins.length list - 1); - - ## Slice part of a list to create a new list. - ## - ## @type Int -> Int -> List -> List - slice = - start: count: list: - let - listLength = builtins.length list; - resultLength = - if start >= listLength then - 0 - else if start + count > listLength then - listLength - start - else - count; - in - builtins.genList (i: builtins.elemAt list (start + i)) resultLength; - - ## Take the first n elements of a list. - ## - ## @type Int -> List -> List - take = lib.lists.slice 0; - - ## Drop the first n elements of a list. - ## - ## @type Int -> List -> List - drop = - count: list: - let - listLength = builtins.length list; - in - lib.lists.slice count listLength list; - - ## Take all but the last element of a list. - ## - ## @type List -> List - init = - list: - assert lib.errors.trace (builtins.length list != 0) "lib.lists.init: list must not be empty."; - lib.lists.take (builtins.length list - 1) list; - - ## Reverse a list. - ## - ## @type List -> List - reverse = - list: - let - length = builtins.length list; - create = i: builtins.elemAt list (length - i - 1); - in - builtins.genList create length; - - ## Interleave a list with a separator. - ## - ## @type Separator -> List -> List - intersperse = - separator: list: - let - length = builtins.length list; - in - if length < 2 then - list - else - builtins.tail ( - builtins.concatMap (part: [ - separator - part - ]) list - ); - - ## Create a list of integers from a starting number to an ending - ## number. This *includes* the ending number as well. - ## - ## @type Int -> Int -> List - range = start: end: if start > end then [ ] else builtins.genList (i: start + i) (end - start + 1); - - ## Depending on a given condition, either use the given value (as - ## a list) or an empty list. - ## - ## @type Attrs a b => Bool -> a -> a | b - when = - condition: value: if condition then if builtins.isList value then value else [ value ] else [ ]; - - ## Count the number of items in a list that satisfy a given predicate. - ## - ## @type (a -> Bool) -> List a -> Int - count = - predicate: list: - builtins.foldl' (total: value: if predicate value then total + 1 else total) 0 list; - - ## Remove duplicate items from a list. - ## - ## @type List -> List - unique = - list: - let - filter = result: value: if builtins.elem value result then result else result ++ [ value ]; - in - builtins.foldl' filter [ ] list; - - ## Flatten a list of lists into a single list. - ## - ## @type List (List a) -> List a - flatten = - value: if builtins.isList value then builtins.concatMap lib.lists.flatten value else [ value ]; - }; -} diff --git a/lib/src/lists/default.test.nix b/lib/src/lists/default.test.nix deleted file mode 100644 index fa7440f..0000000 --- a/lib/src/lists/default.test.nix +++ /dev/null @@ -1,345 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "from" = { - "any" = { - "returns a list containing the value" = - let - expected = [ 1 ]; - actual = lib.lists.from.any 1; - in - actual == expected; - - "returns the value if the value was already a list" = - let - expected = [ 1 ]; - actual = lib.lists.from.any expected; - in - actual == expected; - }; - }; - - "sort" = { - "natural" = { - "sorts a list of strings" = - let - expected = [ - "1" - "a" - "a0" - "a1" - "b" - "c" - ]; - actual = lib.lists.sort.natural [ - "c" - "a" - "b" - "a1" - "a0" - "1" - ]; - in - actual == expected; - }; - }; - - "mapWithIndex" = { - "maps a list using index 0" = - let - expected = [ - "0: a" - "1: b" - "2: c" - ]; - actual = lib.lists.mapWithIndex (i: v: "${builtins.toString i}: ${v}") [ - "a" - "b" - "c" - ]; - in - actual == expected; - }; - - "mapWithIndex1" = { - "maps a list using index 1" = - let - expected = [ - "1: a" - "2: b" - "3: c" - ]; - actual = lib.lists.mapWithIndex1 (i: v: "${builtins.toString i}: ${v}") [ - "a" - "b" - "c" - ]; - in - actual == expected; - }; - - "compare" = { - "compares two lists" = { - "returns -1 if the first list is smaller" = - let - expected = -1; - actual = - lib.lists.compare lib.numbers.compare - [ - 1 - 2 - 3 - ] - [ - 1 - 2 - 4 - ]; - in - actual == expected; - "returns 1 if the first list is larger" = - let - expected = 1; - actual = - lib.lists.compare lib.numbers.compare - [ - 1 - 2 - 4 - ] - [ - 1 - 2 - 3 - ]; - in - actual == expected; - "returns 0 if the lists are equal" = - let - expected = 0; - actual = - lib.lists.compare lib.numbers.compare - [ - 1 - 2 - 3 - ] - [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - }; - - "last" = { - "returns the last element of a list" = - let - expected = 3; - actual = lib.lists.last [ - 1 - 2 - 3 - ]; - in - actual == expected; - - "fails if the list is empty" = - let - actual = lib.lists.last [ ]; - evaluated = builtins.tryEval actual; - in - !evaluated.success; - }; - - "slice" = { - "slices a list" = { - "slices a list from the start" = - let - expected = [ - 1 - 2 - ]; - actual = lib.lists.slice 0 2 [ - 1 - 2 - 3 - ]; - in - actual == expected; - "slices a list from the end" = - let - expected = [ - 2 - 3 - ]; - actual = lib.lists.slice 1 3 [ - 1 - 2 - 3 - ]; - in - actual == expected; - "slices a list from the middle" = - let - expected = [ 2 ]; - actual = lib.lists.slice 1 1 [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - }; - - "take" = { - "takes the first n elements" = - let - expected = [ - 1 - 2 - ]; - actual = lib.lists.take 2 [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - - "drop" = { - "drops the first n elements" = - let - expected = [ 3 ]; - actual = lib.lists.drop 2 [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - - "reverse" = { - "reverses a list" = - let - expected = [ - 3 - 2 - 1 - ]; - actual = lib.lists.reverse [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - - "intersperse" = { - "intersperses a list with a separator" = - let - expected = [ - 1 - "-" - 2 - "-" - 3 - ]; - actual = lib.lists.intersperse "-" [ - 1 - 2 - 3 - ]; - in - actual == expected; - - "handles lists with less than 2 elements" = - let - expected = [ 1 ]; - actual = lib.lists.intersperse "-" [ 1 ]; - in - actual == expected; - }; - - "range" = { - "returns a range of numbers" = - let - expected = [ - 1 - 2 - 3 - 4 - 5 - ]; - actual = lib.lists.range 1 5; - in - actual == expected; - }; - - "when" = { - "returns the list if the condition is true" = - let - expected = [ - 1 - 2 - 3 - ]; - actual = lib.lists.when true [ - 1 - 2 - 3 - ]; - in - actual == expected; - "returns an empty list if the condition is false" = - let - expected = [ ]; - actual = lib.lists.when false [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - - "count" = { - "counts the number of elements in a list" = - let - expected = 2; - actual = lib.lists.count (value: value < 3) [ - 1 - 2 - 3 - ]; - in - actual == expected; - }; - - "unique" = { - "removes duplicate elements" = - let - expected = [ - 1 - 2 - 3 - ]; - actual = lib.lists.unique [ - 1 - 2 - 3 - 1 - 2 - 3 - ]; - in - actual == expected; - }; -} diff --git a/lib/src/math/default.nix b/lib/src/math/default.nix deleted file mode 100644 index 96f38c1..0000000 --- a/lib/src/math/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -lib: { - math = { - ## Return the smaller of two numbers. - ## - ## @type Int -> Int -> Int - min = x: y: if x < y then x else y; - - ## Return the larger of two numbers. - ## - ## @type Int -> Int -> Int - max = x: y: if x > y then x else y; - }; -} diff --git a/lib/src/math/default.test.nix b/lib/src/math/default.test.nix deleted file mode 100644 index 57b08bc..0000000 --- a/lib/src/math/default.test.nix +++ /dev/null @@ -1,22 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "min" = { - "returns the smaller number" = - let - expected = 1; - actual = lib.math.min 1 2; - in - actual == expected; - }; - - "max" = { - "returns the larger number" = - let - expected = 2; - actual = lib.math.max 1 2; - in - actual == expected; - }; -} diff --git a/lib/src/modules/default.nix b/lib/src/modules/default.nix deleted file mode 100644 index 6d7d97d..0000000 --- a/lib/src/modules/default.nix +++ /dev/null @@ -1,702 +0,0 @@ -lib: { - modules = { - from = { - ## Create a module from a JSON file. - ## - ## @notest - ## @type Path -> Module - json = file: { - __file__ = file; - config = lib.importers.json file; - }; - - ## Create a module from a TOML file. - ## - ## @notest - ## @type Path -> Module - toml = file: { - __file__ = file; - config = lib.importers.toml file; - }; - }; - - apply = { - ## Apply custom definitions such as `merge` and `when` to a definition. - ## Note that this function does not perform actiosn like `merge`, but - ## instead pulls out the merge contents to be processed by the module - ## system. - ## - ## @type Definition -> List (Definition | (List Definition)) - properties = - definition: - if lib.types.is "merge" definition then - builtins.concatMap lib.modules.apply.properties definition.content - else if lib.types.is "when" definition then - if !(builtins.isBool definition.condition) then - builtins.throw "lib.modules.when called with a non-boolean condition" - else if definition.condition then - lib.modules.apply.properties definition.content - else - [ ] - else - [ definition ]; - - ## Apply overrides for a definition. This uses the priority system - ## to determine which definition to use. The most important (lowest - ## priority) choice will be used. - ## - ## @type List Definition -> { highestPriority :: Int, values :: List (Definition | (List Definition)) } - overrides = - definitions: - let - getPriority = - definition: - if lib.types.is "override" definition.value then - definition.value.priority - else - lib.modules.DEFAULT_PRIORITY; - normalize = - definition: - if lib.types.is "override" definition.value then - definition // { value = definition.value.content; } - else - definition; - highestPriority = builtins.foldl' ( - priority: definition: lib.math.min priority (getPriority definition) - ) 9999 definitions; - in - { - inherit highestPriority; - values = builtins.concatMap ( - definition: if getPriority definition == highestPriority then [ (normalize definition) ] else [ ] - ) definitions; - }; - - ## Apply ordering for prioritized definitions. - ## - ## @type List Definition -> List Definition - order = - definitions: - let - normalize = - definition: - if lib.types.is "order" definition then - definition - // { - value = definition.value.content; - priority = definition.value.priority; - } - else - definition; - normalized = builtins.map normalize definitions; - compare = - a: b: (a.priority or lib.modules.DEFAULT_PRIORITY) < (b.priority or lib.modules.DEFAULT_PRIORITY); - in - builtins.sort compare normalized; - - ## Normalize the type of an option. This will set a default type if none - ## was provided. - ## - ## @type List String -> Option -> Option - fixup = - location: option: - if option.type.submodules or null == null then - option // { type = option.type or lib.types.unspecified; } - else - option - // { - type = option.type.withSubModules option.options; - options = [ ]; - }; - - ## Invert the structure of `merge`, `when`, and `override` definitions so - ## that they apply to each individual attribute in their respective sets. - ## Note that this function _only_ supports attribute sets within specialized - ## definitions such as `when` and `override`. Other values like lists will - ## throw a type error. - ## - ## @type Definition -> List Definition - invert = - config: - if lib.types.is "merge" config then - builtins.concatMap lib.modules.apply.invert config.content - else if lib.types.is "when" config then - builtins.map (builtins.mapAttrs (name: value: lib.modules.when config.condition value)) ( - lib.modules.apply.invert config.content - ) - else if lib.types.is "override" config then - builtins.map (builtins.mapAttrs (name: value: lib.modules.override config.priority value)) ( - lib.modules.apply.invert config.content - ) - else - [ config ]; - }; - - validate = { - ## Check that a module only specifies supported attributes. - ## - ## @type Attrs -> Bool - keys = - module: - let - invalid = builtins.removeAttrs module lib.modules.VALID_KEYS; - in - invalid == { }; - }; - - ## Modules only support certain keys at the root level. This list determines - ## the valid attributes that users can supply. - ## - ## @type List String - VALID_KEYS = [ - "__file__" - "__key__" - "includes" - "excludes" - "options" - "config" - "freeform" - "meta" - ]; - - ## Normalize a module to a standard structure. All other information will be - ## lost in the conversion. - ## - ## @type String -> String -> Attrs -> Module - normalize = - file: key: module: - let - invalid = builtins.removeAttrs module lib.modules.VALID_KEYS; - invalidKeys = builtins.concatStringsSep ", " (builtins.attrNames invalid); - in - if lib.modules.validate.keys module then - { - __file__ = builtins.toString module.__file__ or file; - __key__ = builtins.toString module.__key__ or key; - includes = module.includes or [ ]; - excludes = module.excludes or [ ]; - options = module.options or { }; - config = - let - base = module.config or { }; - withMeta = - config: - if module ? meta then - lib.modules.merge [ - config - { meta = module.meta; } - ] - else - config; - withFreeform = - config: - if module ? freeform then - lib.modules.merge [ - config - { __module__.freeform = module.freeform; } - ] - else - config; - in - withFreeform (withMeta base); - } - else - builtins.throw "Module `${key}` (${file}) has unsupported attribute(s): ${invalidKeys}"; - - ## Convert a module that is either a function or an attribute set into - ## a resolved attribute set. If the module was a function then it will - ## be evaluated and the result will be returned. - ## - ## @type String -> Attrs | (Attrs -> Attrs) -> Attrs -> Attrs - resolve = - key: module: args: - let - dynamicArgs = builtins.mapAttrs ( - name: value: - builtins.addErrorContext "while evaluating the module argument `${name}` in `${key}`" ( - # The base case here is the set of static arguments supplied in the - # call to `lib.modules.run`. - args.${name} - # Then, any other arguments must be created dynamically from within - # the modules being evaluated. - or args.config.__module__.args.dynamic.${name} - ) - ) (lib.fp.args module); - in - if builtins.isFunction module then lib.fp.withDynamicArgs module (args // dynamicArgs) else module; - - ## The default priority to set for values that do not have one provided. - ## - ## @type Int - DEFAULT_PRIORITY = 100; - - ## Allow for sorting the values provided to a module by priority. The - ## most important value will be used. - ## - ## @notest - ## @type Int -> a -> Attrs - order = priority: value: { - __type__ = "order"; - inherit priority value; - }; - - orders = { - ## Order a value before others. - ## - ## @notest - ## @type a -> Attrs - before = lib.modules.order 500; - - ## Use the default ordering for a value. - ## - ## @notest - ## @type a -> Attrs - default = lib.modules.order 1000; - - ## Order a value after others. - ## - ## @notest - ## @type a -> Attrs - after = lib.modules.order 1500; - }; - - ## Extract a list of files from a list of modules. - ## - ## @type List Module -> List (String | Path) - getFiles = builtins.map (module: module.__file__); - - ## Create a conditional value which is only used when the condition's - ## value is `true`. - ## - ## @notest - ## @type Bool -> a -> When a - when = condition: content: { - __type__ = "when"; - inherit condition content; - }; - - ## Merge module attribute sets when evaluated in the module system. - ## - ## @notest - ## @type List Attrs -> Attrs - merge = content: { - __type__ = "merge"; - inherit content; - }; - - ## Create a value override which can replace other definitions if it - ## has the higher priority. - ## - ## @notest - ## @type Int -> a -> Attrs - override = priority: content: { - __type__ = "override"; - inherit priority content; - }; - - overrides = { - ## Create an override used for setting the `default.value` from an - ## option. This uses the lowest priority of all predefined overrides. - ## - ## @notest - ## @type a -> Attrs - option = lib.modules.override 1500; - - ## Create a default override for a value. This uses a very low priority - ## so that it can easily be overridden. - ## - ## @notest - ## @type a -> Attrs - default = lib.modules.override 1000; - - ## Create a high priority override for a value. This is not the highest - ## priority possible, but it will override nearly everything else except - ## for very explicit cases. - ## - ## @notest - ## @type a -> Attrs - force = lib.modules.override 50; - - ## Create a high priority override intended to be used only for VM targets. - ## This allows for forcing certain values even if a user has otherwise - ## specified `lib.modules.overrides.force`. - ## - ## @notest - ## @type a -> Attrs - vm = lib.modules.override 10; - }; - - ## Create alias definitions for a given option. - ## - ## @type Option -> Attrs - alias = lib.modules.aliasWith lib.fp.id; - - ## Create alias definitions for a given option. - ## - ## @type (Attrs -> Attrs) -> Option -> Attrs - aliasWith = - f: option: - let - exists = lib.types.is "option" option && option.isDefined; - value = f (lib.modules.merge option.definitions); - in - lib.modules.when exists value; - - ## Combine multiple modules together. - ## - ## @type List String -> List Module -> { matched :: Attrs, unmatched :: List Definition } - combine = - prefix: modules: - let - getConfig = - module: - builtins.map (config: { - __file__ = module.__file__; - inherit config; - }) (lib.modules.apply.invert module.config); - - configs = builtins.concatMap getConfig modules; - - process = - prefix: options: configs: - let - byName = - attr: f: modules: - builtins.zipAttrsWith (key: value: builtins.concatLists value) ( - builtins.map ( - module: - let - subtree = module.${attr}; - in - if builtins.isAttrs subtree then - builtins.mapAttrs (name: f module) subtree - else - builtins.throw "Value for `${builtins.concatStringsSep "." prefix}` is of type `${builtins.typeOf subtree}` but an attribute set was expected." - ) modules - ); - - declarationsByName = byName "options" (module: option: [ - { - __file__ = module.__file__; - options = option; - } - ]) options; - - definitionsByName = byName "config" ( - module: value: - builtins.map (config: { - __file__ = module.__file__; - inherit config; - }) (lib.modules.apply.invert value) - ) configs; - - definitionsByName' = byName "config" (module: value: [ - { - __file__ = module.__file__; - inherit value; - } - ]) configs; - - getOptionFromDeclaration = - declaration: - if lib.types.is "option" declaration.options then - declaration - else - declaration - // { - options = lib.options.create { type = lib.types.submodule [ { options = declaration.options; } ]; }; - }; - - resultsByName = builtins.mapAttrs ( - name: declarations: - let - location = prefix ++ [ name ]; - definitions = definitionsByName.${name} or [ ]; - definitions' = definitionsByName'.${name} or [ ]; - optionDeclarations = builtins.filter ( - declaration: lib.types.is "option" declaration.options - ) declarations; - in - if builtins.length optionDeclarations == builtins.length declarations then - let - option = lib.modules.apply.fixup location (lib.options.merge.declarations location declarations); - in - { - matched = lib.options.run location option definitions'; - unmatched = [ ]; - } - else if optionDeclarations != [ ] then - if builtins.all (declaration: declaration.options.type.name == "Submodule") optionDeclarations then - let - option = lib.modules.apply.fixup location ( - lib.options.merge.declarations location (builtins.map getOptionFromDeclaration declarations) - ); - in - { - matched = lib.options.run location option definitions'; - unmatched = [ ]; - } - else - builtins.throw "The option `${lib.options.getIdentifier location}` in module `${(builtins.head optionDeclarations).__file__}` would be a parent of the following options, but its type `${ - (builtins.head optionDeclarations).options.type.description or "" - }` does not support nested options." - else - process location declarations definitions - ) declarationsByName; - - matched = builtins.mapAttrs (key: value: value.matched) resultsByName; - - unmatched = - builtins.mapAttrs (name: value: value.unmatched) resultsByName - // builtins.removeAttrs definitionsByName' (builtins.attrNames matched); - in - { - inherit matched; - - unmatched = - if configs == [ ] then - [ ] - else - builtins.concatLists ( - lib.attrs.mapToList ( - name: definitions: - builtins.map ( - definition: definition // { prefix = [ name ] ++ (definition.prefix or [ ]); } - ) definitions - ) unmatched - ); - }; - in - process prefix modules configs; - - ## Run a set of modules. Custom arguments can also be supplied which will - ## be provided to all modules statically as they are not modifiable. - ## - ## @type { modules? :: List (Attrs | (Attrs -> Attrs)), args? :: Attrs, prefix? :: List String } -> { type :: Module, extend :: lib.modules.run, options :: Attrs, config :: Attrs, __module__ :: Attrs } - run = - settings@{ - modules ? [ ], - args ? { }, - prefix ? [ ], - }: - let - type = lib.types.submodules.of { inherit modules args; }; - - extend = - extensions@{ - modules ? [ ], - args ? { }, - prefix ? [ ], - }: - lib.modules.run { - modules = (settings.modules or [ ]) ++ (extensions.modules or [ ]); - args = (settings.args or { }) // (extensions.args or { }); - prefix = extensions.prefix or settings.prefix or [ ]; - }; - - collect = - let - load = - args: file: key: module: - let - moduleFromValue = lib.modules.normalize file key (lib.modules.resolve key module args); - moduleFromPath = lib.modules.normalize (builtins.toString module) (builtins.toString module) ( - lib.modules.resolve (builtins.toString module) (import module) args - ); - in - if builtins.isAttrs module || builtins.isFunction module then - moduleFromValue - else if builtins.isString module || builtins.isPath module then - moduleFromPath - else - builtins.throw "The provided module must be either an attribute set, function, or path but got ${builtins.typeOf module}"; - - normalize = - parentFile: parentKey: modules: args: - let - normalized = lib.lists.mapWithIndex1 ( - i: value: - let - module = load args parentFile "${parentKey}:unknown-${builtins.toString i}" value; - tree = normalize module.__file__ module.__key__ module.includes args; - in - { - inherit module; - key = module.__key__; - modules = tree.modules; - excludes = module.excludes ++ tree.excludes; - } - ) modules; - in - { - modules = normalized; - excludes = builtins.concatLists (builtins.catAttrs "excludes" normalized); - }; - - withExclusions = - path: - { modules, excludes }: - let - getKey = - module: - if builtins.isString module && (builtins.substring 0 1 module != "/") then - (builtins.toString path) + "/" + module - else - builtins.toString module; - excludedKeys = builtins.map getKey excludes; - removeExcludes = builtins.filter (value: !(builtins.elem value.key excludedKeys)); - in - builtins.map (value: value.module) ( - builtins.genericClosure { - startSet = removeExcludes modules; - operator = value: removeExcludes value.modules; - } - ); - - process = - path: modules: args: - withExclusions path (normalize "" "" modules args); - in - process; - - internal = { - __file__ = "virtual:aux/internal"; - __key__ = "virtual:aux/internal"; - - options = { - __module__ = { - args = { - static = lib.options.create { - type = lib.types.attrs.lazy lib.types.raw; - writable = false; - internal = false; - description = "Static arguments provided to lib.modules.run which cannot be changed."; - }; - - dynamic = lib.options.create { - type = lib.types.attrs.lazy lib.types.raw; - - ${if prefix == [ ] then null else "internal"} = true; - - visible = false; - - description = "Additional arguments pased to each module."; - }; - }; - - check = lib.options.create { - type = lib.types.bool; - default.value = true; - internal = true; - description = "Whether to perform checks on option definitions."; - }; - - freeform = lib.options.create { - type = lib.types.nullish lib.types.type; - default.value = null; - internal = true; - description = "If set, all options that don't have a declared type will be merged using this type."; - }; - }; - }; - - config = { - __module__ = { - args = { - static = args; - - dynamic = { - meta = { - inherit extend type; - }; - }; - }; - }; - }; - }; - - merged = - let - collected = collect (args.path or "") ([ internal ] ++ modules) ( - { - inherit options config; - - # The library does not include `extend` out of the box to avoid infinite recursion - # in most cases. Instead, we supply an estensible version here for modules to consume. - # This is only something that affects internal use of `lib`, the properly exported - # `lib` is augmented with an `extend` method. - lib = lib.points.withExtend (lib.fp.const lib); - } - // args - ); - in - lib.modules.combine prefix (lib.lists.reverse collected); - - options = merged.matched; - - config = - let - declared = lib.attrs.mapRecursiveWhen (value: !(lib.types.is "option" value)) ( - name: value: value.value - ) options; - - freeform = - let - definitions = builtins.map (definition: { - __file__ = definition.__file__; - value = lib.attrs.set definition.prefix definition.value; - }) merged.unmatched; - in - if definitions == [ ] then { } else declared.__module__.freeform.merge prefix definitions; - in - if declared.__module__.freeform == null then - declared - else - lib.attrs.mergeRecursive freeform declared; - - checked = - if config.__module__.check && config.__module__.freeform == null && merged.unmatched != [ ] then - let - first = builtins.head merged.unmatched; - - identifier = lib.options.getIdentifier (prefix ++ first.prefix); - definitions = - builtins.addErrorContext - "while evaluating the error message for definitions of non-existent option `${identifier}`" - ( - builtins.addErrorContext "while evaluating a definition from `${first.__file__}`" ( - lib.options.getDefinitions [ first ] - ) - ); - - message = "The option `${identifier}` does not exist. Definitions:${definitions}"; - in - if builtins.attrNames options == [ "__module__" ] then - if lib.options.getIdentifier prefix == "" then - builtins.throw '' - ${message} - - You are trying to declare options in `config` rather than `options`. - '' - else - builtins.throw '' - ${message} - - There are no options defined in `${lib.options.getIdentifier prefix}`. - Are you sure you declared your options correctly? - '' - else - builtins.throw message - else - null; - - withCheck = builtins.seq checked; - in - { - inherit type extend; - options = withCheck options; - config = withCheck (builtins.removeAttrs config [ "__module__" ]); - __module__ = withCheck config.__module__; - }; - }; -} diff --git a/lib/src/modules/default.test.nix b/lib/src/modules/default.test.nix deleted file mode 100644 index 4467af5..0000000 --- a/lib/src/modules/default.test.nix +++ /dev/null @@ -1,709 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "apply" = { - "properties" = { - "handles normal values" = - let - expected = [ { } ]; - actual = lib.modules.apply.properties { }; - in - actual == expected; - - "handles merge" = - let - expected = [ - { x = 1; } - { x = 2; } - ]; - actual = lib.modules.apply.properties ( - lib.modules.merge [ - { x = 1; } - { x = 2; } - ] - ); - in - actual == expected; - - "handles when" = - let - expected = [ [ { x = 1; } ] ]; - actual = lib.modules.apply.properties (lib.modules.when true [ { x = 1; } ]); - in - actual == expected; - }; - - "overrides" = { - "handles normal values" = - let - expected = { - highestPriority = 100; - values = [ { value = 1; } ]; - }; - actual = lib.modules.apply.overrides [ { value = 1; } ]; - in - actual == expected; - - "handles overrides" = - let - expected = { - highestPriority = 100; - values = [ { value = "world"; } ]; - }; - actual = lib.modules.apply.overrides [ - { value = "world"; } - { value = lib.modules.override 101 "hello"; } - ]; - in - actual == expected; - }; - - "order" = { - "handles normal values" = - let - expected = [ { } ]; - actual = lib.modules.apply.order [ { } ]; - in - actual == expected; - - "handles priority" = - let - expected = [ - { - value = 1; - priority = 10; - } - { - value = 3; - priority = 50; - } - { value = 2; } - ]; - actual = lib.modules.apply.order [ - { - value = 1; - priority = 10; - } - { value = 2; } - { - value = 3; - priority = 50; - } - ]; - in - actual == expected; - }; - - "fixup" = { - "sets default type for option" = - let - actual = lib.modules.apply.fixup [ ] (lib.options.create { }); - in - actual.type.name == "Unspecified"; - }; - - "invert" = { - "inverts merge" = - let - expected = [ - { x = 1; } - { x = 2; } - ]; - actual = lib.modules.apply.invert ( - lib.modules.merge [ - { x = 1; } - { x = 2; } - ] - ); - in - actual == expected; - - "inverts when" = - let - expected = [ - { - x = { - __type__ = "when"; - condition = true; - content = 1; - }; - y = { - __type__ = "when"; - condition = true; - content = 2; - }; - } - ]; - actual = lib.modules.apply.invert ( - lib.modules.when true { - x = 1; - y = 2; - } - ); - in - actual == expected; - - "inverts overrides" = - let - expected = [ - { - x = { - __type__ = "override"; - priority = 100; - content = 1; - }; - y = { - __type__ = "override"; - priority = 100; - content = 2; - }; - } - ]; - actual = lib.modules.apply.invert ( - lib.modules.override 100 { - x = 1; - y = 2; - } - ); - in - actual == expected; - }; - }; - - "validate" = { - "keys" = { - "handles an empty set" = - let - value = lib.modules.validate.keys { }; - in - value; - - "handles a valid module" = - let - value = lib.modules.validate.keys { - __file__ = "virtual:aux/example"; - __key__ = "aux/example"; - includes = [ ]; - excludes = [ ]; - options = { }; - config = { }; - freeform = null; - meta = { }; - }; - in - value; - - "handles an invalid module" = - let - value = lib.modules.validate.keys { invalid = null; }; - in - !value; - }; - }; - - "normalize" = { - "handles an empty set" = - let - expected = { - __file__ = "/aux/example.nix"; - __key__ = "example"; - config = { }; - excludes = [ ]; - includes = [ ]; - options = { }; - }; - actual = lib.modules.normalize "/aux/example.nix" "example" { }; - in - actual == expected; - - "handles an example module" = - let - expected = { - __file__ = "myfile.nix"; - __key__ = "mykey"; - config = { - x = true; - }; - excludes = [ ]; - includes = [ ]; - options = { }; - }; - actual = lib.modules.normalize "/aux/example.nix" "example" { - __file__ = "myfile.nix"; - __key__ = "mykey"; - config.x = true; - }; - in - actual == expected; - }; - - "resolve" = { - "handles an attribute set" = - let - expected = { - config.x = 1; - }; - actual = lib.modules.resolve "example" { config.x = 1; } { }; - in - actual == expected; - - "handles a function" = - let - expected = { - config.x = 1; - }; - actual = lib.modules.resolve "example" (lib.fp.const { config.x = 1; }) { }; - in - actual == expected; - - "handles a function with arguments" = - let - expected = { - config.x = 1; - }; - actual = lib.modules.resolve "example" (args: { config.x = args.x; }) { x = 1; }; - in - actual == expected; - }; - - "getFiles" = { - "gets the files for a list of modules" = - let - expected = [ "/aux/example.nix" ]; - actual = lib.modules.getFiles [ { __file__ = "/aux/example.nix"; } ]; - in - actual == expected; - }; - - "combine" = { - "handles empty modules" = - let - expected = { - matched = { }; - unmatched = [ ]; - }; - actual = lib.modules.combine [ ] [ (lib.modules.normalize "/aux/example.nix" "example" { }) ]; - in - actual == expected; - - "handles a single module" = - let - expected = { - matched = { }; - unmatched = [ - { - __file__ = "/aux/example.nix"; - prefix = [ "x" ]; - value = 1; - } - ]; - }; - actual = - lib.modules.combine - [ ] - [ - (lib.modules.normalize "/aux/example.nix" "example" { - config = { - x = 1; - }; - }) - ]; - in - actual == expected; - - "handles multiple modules" = - let - unmatched = [ - { - __file__ = "/aux/example2.nix"; - prefix = [ "y" ]; - value = 2; - } - ]; - actual = - lib.modules.combine - [ ] - [ - (lib.modules.normalize "/aux/example1.nix" "example2" { - options = { - x = lib.options.create { }; - }; - - config = { - x = 1; - }; - }) - (lib.modules.normalize "/aux/example2.nix" "example2" { - config = { - y = 2; - }; - }) - ]; - in - (actual.unmatched == unmatched) && actual.matched ? x; - }; - - "run" = { - "empty" = - let - evaluated = lib.modules.run { - modules = [ - { - options.aux = { - message = lib.options.create { type = lib.types.string; }; - }; - - config = { - aux.message = "Hello, World!"; - }; - } - ]; - }; - in - evaluated ? config; - - "hello world" = - let - expected = "Hello, World!"; - - evaluated = lib.modules.run { - modules = [ - { - options.aux = { - message = lib.options.create { type = lib.types.string; }; - }; - - config = { - aux.message = "Hello, World!"; - }; - } - ]; - }; - - actual = evaluated.config.aux.message; - in - actual == expected; - - "recursive" = - let - expected = "Hello, World!"; - - evaluated = lib.modules.run { - modules = [ - ( - { config }: - { - options.aux = { - message = lib.options.create { type = lib.types.string; }; - - proxy = lib.options.create { type = lib.types.string; }; - }; - - config = { - aux = { - proxy = "Hello, World!"; - message = config.aux.proxy; - }; - }; - } - ) - ]; - }; - - actual = evaluated.config.aux.message; - in - actual == expected; - - "conditional" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options.aux = { - message = lib.options.create { type = lib.types.string; }; - }; - config = { - aux = { - message = lib.modules.when true expected; - }; - }; - } - ]; - }; - in - evaluated.config.aux.message == expected; - - "conditional list" = - let - expected = [ "Hello, World!" ]; - evaluated = lib.modules.run { - modules = [ - { - options.aux = { - message = lib.options.create { type = lib.types.list.of lib.types.string; }; - }; - config = { - aux = { - message = lib.modules.when true expected; - }; - }; - } - ]; - }; - in - evaluated.config.aux.message == expected; - - "submodules" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - default.value = { - message = "hi"; - }; - type = lib.types.attrs.of ( - lib.types.submodule ( - { name }: - { - # freeform = lib.types.any; - options.message = lib.options.create { type = lib.types.string; }; - } - ) - ); - }; - }; - config = { - aux = { - x = { - message = "Hello, World!"; - }; - }; - }; - } - ]; - }; - in - evaluated.config.aux.x.message == expected; - - "submodules without shorthand" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodules.of { - shorthand = false; - modules = [ { options.message = lib.options.create { type = lib.types.string; }; } ]; - }; - }; - }; - config = { - aux = { - options = { - message2 = lib.options.create { type = lib.types.string; }; - }; - - config = { - message = expected; - message2 = expected; - }; - }; - }; - } - ]; - }; - in - evaluated.config.aux.message == evaluated.config.aux.message2; - - "function submodules" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodules.of { - shorthand = false; - modules = [ { options.message = lib.options.create { type = lib.types.string; }; } ]; - }; - }; - }; - config = { - aux = args: { config.message = expected; }; - }; - } - ]; - }; - in - evaluated.config.aux.message == expected; - - "merges submodules" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodules.of { - shorthand = false; - modules = [ { options.message = lib.options.create { type = lib.types.string; }; } ]; - }; - }; - }; - config = { - aux = args: { - options.message2 = lib.options.create { type = lib.types.string; }; - - config.message = expected; - }; - }; - } - { - config = { - aux.config.message2 = expected; - }; - } - ]; - }; - in - evaluated.config.aux.message == evaluated.config.aux.message2; - - "flexible shorthand" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodules.of { - shorthand = true; - modules = [ { options.message = lib.options.create { type = lib.types.string; }; } ]; - }; - }; - }; - config = { - aux = args: { - options.message2 = lib.options.create { type = lib.types.string; }; - - config.message = expected; - }; - }; - } - { - config = { - aux.message2 = expected; - }; - } - ]; - }; - in - evaluated.config.aux.message == evaluated.config.aux.message2; - - "base level submodule" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodule { options.message = lib.options.create { type = lib.types.string; }; }; - }; - }; - config = { - aux = args: { - options.message2 = lib.options.create { type = lib.types.string; }; - - config.message = expected; - }; - }; - } - { - config = { - aux.message2 = expected; - }; - } - ]; - }; - in - evaluated.config.aux.message == evaluated.config.aux.message2; - - "base level submodule (freeform)" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodule { - freeform = lib.types.any; - - options.message = lib.options.create { type = lib.types.string; }; - }; - }; - }; - config = { - aux = args: { - options.message2 = lib.options.create { type = lib.types.string; }; - - config.message = expected; - }; - }; - } - { - config = { - aux.exists = true; - aux.message2 = expected; - }; - } - ]; - }; - in - (evaluated.config.aux.message == evaluated.config.aux.message2) && evaluated.config.aux.exists; - - "nested submodules" = - let - expected = "Hello, World!"; - evaluated = lib.modules.run { - modules = [ - { - options = { - aux = lib.options.create { - type = lib.types.submodule { - freeform = lib.types.any; - - options.message = lib.options.create { type = lib.types.string; }; - }; - }; - }; - config = { - aux = args: { - options.message2 = lib.options.create { type = lib.types.string; }; - - config.message = expected; - }; - }; - } - { - config = { - aux.exists = true; - aux.message2 = expected; - }; - } - ]; - }; - in - (evaluated.config.aux.message == evaluated.config.aux.message2) && evaluated.config.aux.exists; - }; -} diff --git a/lib/src/numbers/default.nix b/lib/src/numbers/default.nix deleted file mode 100644 index 0df6ebb..0000000 --- a/lib/src/numbers/default.nix +++ /dev/null @@ -1,72 +0,0 @@ -lib: { - numbers = { - into = { - ## Convert a number into a string. - ## - ## @type Int | Float -> String - string = value: if builtins.isInt value then builtins.toString value else builtins.toJSON value; - - ## Convert a number into a list of digits in the given base. - ## - ## @type Int -> Int -> List Int - base = - base: target: - let - process = - value: - let - r = value - ((value / base) * base); - q = (value - r) / base; - in - if value < base then [ value ] else [ r ] ++ process q; - result = process target; - in - assert lib.errors.trace (builtins.isInt base) "Base must be an integer."; - assert lib.errors.trace (builtins.isInt target) "Target must be an integer."; - assert lib.errors.trace (base >= 2) "Base must be at least 2."; - assert lib.errors.trace (target >= 0) "Target cannot be negative."; - lib.lists.reverse result; - - ## Convert a number into a hexadecimal string. - ## - ## @type Int -> String - hex = - value: - let - serialize = - part: - if part < 10 then - builtins.toString part - else if part == 10 then - "A" - else if part == 11 then - "B" - else if part == 12 then - "C" - else if part == 13 then - "D" - else if part == 14 then - "E" - else if part == 15 then - "F" - else - builtins.throw "Invalid hex digit."; - in - lib.strings.concatMap serialize (lib.numbers.into.base 16 value); - }; - - ## Compare two numbers. When the first number is less than the second, -1 - ## is returned. When the first number is greater than the second, 1 is - ## returned. When the numbers are equal, 0 is returned. - ## - ## @type Int -> Int -> Int - compare = - a: b: - if a < b then - -1 - else if a > b then - 1 - else - 0; - }; -} diff --git a/lib/src/numbers/default.test.nix b/lib/src/numbers/default.test.nix deleted file mode 100644 index 9b858fc..0000000 --- a/lib/src/numbers/default.test.nix +++ /dev/null @@ -1,67 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "into" = { - "string" = { - "converts an int into a string" = - let - expected = "1"; - actual = lib.numbers.into.string 1; - in - actual == expected; - - "converts a float into a string" = - let - expected = "1.0"; - actual = lib.numbers.into.string 1.0; - in - actual == expected; - }; - - "base" = { - "converts a number into a given base" = - let - expected = [ - 1 - 0 - 0 - ]; - actual = lib.numbers.into.base 2 4; - in - actual == expected; - }; - - "hex" = { - "converts a number into a hex string" = - let - expected = "64"; - actual = lib.numbers.into.hex 100; - in - actual == expected; - }; - }; - - "compare" = { - "returns -1 when first is less than second" = - let - expected = -1; - actual = lib.numbers.compare 1 2; - in - actual == expected; - - "returns 0 when first is equal to second" = - let - expected = 0; - actual = lib.numbers.compare 1 1; - in - actual == expected; - - "returns 1 when first is greater than second" = - let - expected = 1; - actual = lib.numbers.compare 2 1; - in - actual == expected; - }; -} diff --git a/lib/src/options/default.nix b/lib/src/options/default.nix deleted file mode 100644 index 63cb69a..0000000 --- a/lib/src/options/default.nix +++ /dev/null @@ -1,348 +0,0 @@ -lib: { - options = { - merge = { - ## Merge a list of option definitions into a single value. - ## - ## @type Location -> List Definition -> Any - default = - location: definitions: - let - values = lib.options.getDefinitionValues definitions; - first = builtins.elemAt values 0; - mergedFunctions = x: lib.options.mergeDefault location (builtins.map (f: f x) values); - mergedLists = builtins.concatLists values; - mergedAttrs = builtins.foldl' lib.attrs.merge { } values; - mergedBools = builtins.any lib.bools.or false values; - mergedStrings = lib.strings.concat values; - in - if builtins.length values == 1 then - builtins.elemAt values 0 - else if builtins.all builtins.isFunction values then - mergedFunctions - else if builtins.all builtins.isList values then - mergedLists - else if builtins.all builtins.isAttrs values then - mergedAttrs - else if builtins.all builtins.isBool values then - mergedBools - else if builtins.all lib.strings.isString values then - mergedStrings - else if builtins.all builtins.isInt values && builtins.all (x: x == first) values then - first - # TODO: Improve this error message to show the location and definitions for the option. - else - builtins.throw "Cannot merge definitions."; - - ## Merge multiple option definitions together. - ## - ## @type Location -> Type -> List Definition - definitions = - location: type: definitions: - let - identifier = lib.options.getIdentifier location; - resolve = - definition: - let - properties = builtins.addErrorContext "while evaluating definitions from `${definition.__file__ or ""}`:" ( - lib.modules.apply.properties definition.value - ); - normalize = value: { - __file__ = definition.__file__ or ""; - inherit value; - }; - in - builtins.map normalize properties; - - resolved = builtins.concatMap resolve definitions; - overridden = lib.modules.apply.overrides resolved; - - values = - if builtins.any (definition: lib.types.is "order" definition.value) overridden.values then - lib.modules.apply.order overridden.values - else - overridden.values; - - isDefined = values != [ ]; - - invalid = builtins.filter (definition: !(type.check definition.value)) values; - - merged = - if isDefined then - if builtins.all (definition: type.check definition.value) values then - type.merge location values - else - builtins.throw "A definition for `${identifier}` is not of type `${type.description}`. Definition values:${lib.options.getDefinitions invalid}" - else - builtins.throw "The option `${identifier}` is used but not defined."; - - optional = if isDefined then { value = merged; } else { }; - in - { - inherit - isDefined - values - merged - optional - ; - - raw = { - inherit values; - inherit (overridden) highestPriority; - }; - }; - - ## Merge multiple option declarations together. - ## - ## @type Location -> List Option - declarations = - location: options: - let - merge = - result: option: - let - mergedType = result.type.mergeType option.options.type.functor; - isTypeMergeable = mergedType != null; - shared = name: option.options ? ${name} && result ? ${name}; - typeSet = lib.attrs.when ((shared "type") && isTypeMergeable) { type = mergedType; }; - files = result.declarations; - serializedFiles = builtins.concatStringsSep " and " files; - typeSubmodules = option.options.type.submodules or null; - submodules = - if typeSubmodules != null then - builtins.map (module: { - __file__ = option.__file__; - includes = [ module ]; - }) typeSubmodules - ++ result.options - else - result.options; - in - if - shared "default" - || shared "example" - || shared "description" - || shared "apply" - || (shared "type" && !isTypeMergeable) - then - builtins.throw "The option `${lib.options.getIdentifier location}` in `${option.__file__}` is already declared in ${serializedFiles}" - else - option.options - // result - // { - declarations = result.declarations ++ [ option.__file__ ]; - options = submodules; - } - // typeSet; - in - builtins.foldl' merge { - inherit location; - declarations = [ ]; - options = [ ]; - } options; - - ## Merge an option, only supporting a single unique definition. - ## - ## @type String -> Location -> List Definition -> Any - unique = - message: location: definitions: - let - identifier = lib.options.getIdentifier location; - total = builtins.length definitions; - first = builtins.elemAt definitions 0; - in - if total == 1 then - first.value - else if total == 0 then - builtins.throw "Cannot merge unused option `${identifier}`.\n${message}" - else - builtins.throw "The option `${identifier}` is defined multiple times, but must be unique.\n${message}\nDefinitions:${lib.options.getDefinitions definitions}"; - - ## Merge a single instance of an option. - ## - ## @type Location -> List Definition -> Any - one = lib.options.merge.unique ""; - - equal = - location: definitions: - let - identifier = lib.options.getIdentifier location; - first = builtins.elemAt definitions 0; - rest = builtins.tail definitions; - merge = - x: y: - if x != y then - builtins.throw "The option `${identifier}` has conflicting definitions:${lib.options.getDefinitions definitions}" - else - x; - merged = builtins.foldl' merge first rest; - in - if builtins.length definitions == 0 then - builtins.throw "Cannot merge unused option `${identifier}`." - else if builtins.length definitions == 1 then - first.value - else - merged.value; - }; - - ## Check whether a value is an option. - ## - ## @type Attrs -> Bool - is = lib.types.is "option"; - - ## Create an option. - ## - ## @type { type? :: String | Null, apply? :: (a -> b) | Null, default? :: { value :: a, text :: String }, example? :: String | Null, visible? :: Bool | Null, internal? :: Bool | Null, writable? :: Bool | Null, description? :: String | Null } -> Option a - create = - settings@{ - type ? lib.types.unspecified, - apply ? null, - default ? { }, - example ? null, - visible ? null, - internal ? null, - writable ? null, - description ? null, - }: - { - __type__ = "option"; - inherit - type - apply - default - example - visible - internal - writable - description - ; - }; - - ## Create a sink option. - ## - ## @type @alias lib.options.create - sink = - settings: - let - defaults = { - internal = true; - visible = false; - default = false; - description = "A sink option for unused definitions"; - type = lib.types.create { - name = "sink"; - check = lib.fp.const true; - merge = lib.fp.const (lib.fp.const false); - }; - apply = value: builtins.throw "Cannot read the value of a Sink option."; - }; - in - lib.options.create (defaults // settings); - - ## Get the definition values from a list of options definitions. - ## - ## @type List Definition -> Any - getDefinitionValues = definitions: builtins.map (definition: definition.value) definitions; - - ## Convert a list of option identifiers into a single identifier. - ## - ## @type List String -> String - getIdentifier = - location: - let - special = [ - # lib.types.attrs.of (lib.types.submodule {}) - "" - # lib.types.list.of (submodule {}) - "*" - # lib.types.function - "" - ]; - escape = part: if builtins.elem part special then part else lib.strings.escape.nix.identifier part; - in - lib.strings.concatMapSep "." escape location; - - ## Get a string message of the definitions for an option. - ## - ## @type List Definition -> String - getDefinitions = - definitions: - let - serialize = - definition: - let - valueWithRecursionLimit = lib.generators.withRecursion { - limit = 10; - throw = false; - } definition.value; - - eval = builtins.tryEval (lib.generators.pretty { } valueWithRecursionLimit); - - lines = lib.strings.split "\n" eval.value; - linesLength = builtins.length lines; - firstFiveLines = lib.lists.take 5 lines; - - ellipsis = lib.lists.when (linesLength > 5) "..."; - - value = builtins.concatStringsSep "\n " (firstFiveLines ++ ellipsis); - - result = - if !eval.success then - "" - else if linesLength > 1 then - ":\n " + value - else - ": " + value; - in - "\n- In `${definition.__file__}`${result}"; - in - lib.strings.concatMap serialize definitions; - - ## Run a set of definitions, calculating the resolved value and associated information. - ## - ## @type Location -> Option -> List Definition -> String & { value :: Any, highestPriority :: Int, isDefined :: Bool, files :: List String, definitions :: List Any, definitionsWithLocations :: List Definition } - run = - location: option: definitions: - let - identifier = lib.options.getIdentifier location; - - definitionsWithDefault = - if option ? default && option.default ? value then - [ - { - __file__ = builtins.head option.declarations; - value = lib.modules.overrides.option option.default.value; - } - ] - ++ definitions - else - definitions; - - merged = - if option.writable or null == false && builtins.length definitionsWithDefault > 1 then - let - separatedDefinitions = builtins.map ( - definition: - definition - // { - value = (lib.options.merge.definitions location option.type [ definition ]).merged; - } - ) definitionsWithDefault; - in - builtins.throw "The option `${identifier}` is not writable, but is set more than once:${lib.options.getDefinitions separatedDefinitions}" - else - lib.options.merge.definitions location option.type definitionsWithDefault; - - value = if option.apply or null != null then option.apply merged.merged else merged.merged; - in - option - // { - value = builtins.addErrorContext "while evaluating the option `${identifier}`:" value; - highestPriority = merged.raw.highestPriority; - isDefined = merged.isDefined; - files = builtins.map (definition: definition.__file__) merged.values; - definitions = lib.options.getDefinitionValues merged.values; - definitionsWithLocations = merged.values; - __toString = identifier; - }; - }; -} diff --git a/lib/src/options/default.test.nix b/lib/src/options/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/options/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/src/packages/default.nix b/lib/src/packages/default.nix deleted file mode 100644 index 40f7f3c..0000000 --- a/lib/src/packages/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -lib: { - packages = { - ## Check whether a value is a derivation. Note that this will also return true - ## for "fake" derivations which are constructed by helpers such as - ## `lib.paths.into.drv` for convenience. - ## - ## @type a -> Bool - isDerivation = value: value.type or null == "derivation"; - - ## Sanitize a string to produce a valid name for a derivation. - ## - ## @type String -> String - sanitizeDerivationName = - let - validate = builtins.match "[[:alnum:]+_?=-][[:alnum:]+._?=-]*"; - in - value: - # First detect the common case of already valid strings, to speed those up - if builtins.stringLength value <= 207 && validate value != null then - builtins.unsafeDiscardStringContext value - else - lib.fp.pipe [ - # Get rid of string context. This is safe under the assumption that the - # resulting string is only used as a derivation name - builtins.unsafeDiscardStringContext - - # Strip all leading "." - (x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) - - (lib.strings.split "[^[:alnum:]+._?=-]+") - - # Replace invalid character ranges with a "-" - (lib.strings.concatMap (x: if builtins.isList x then "-" else x)) - - # Limit to 211 characters (minus 4 chars for ".drv") - (x: builtins.substring (lib.math.max (builtins.stringLength x - 207) 0) (-1) x) - - # If the result is empty, replace it with "unknown" - (x: if builtins.stringLength x == 0 then "unknown" else x) - ] value; - - ## Get an output of a derivation. - ## - ## @type String -> Derivation -> String - getOutput = - output: package: - if !package ? outputSpecified || !package.outputSpecified then - package.${output} or package.out or package - else - package; - }; -} diff --git a/lib/src/packages/default.test.nix b/lib/src/packages/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/packages/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/src/paths/default.nix b/lib/src/paths/default.nix deleted file mode 100644 index 9279985..0000000 --- a/lib/src/paths/default.nix +++ /dev/null @@ -1,67 +0,0 @@ -lib: { - paths = { - into = { - ## Convert a path into a derivation. - ## - ## @type Path -> Derivation - drv = - value: - let - path = builtins.storePath value; - result = { - type = "derivation"; - name = lib.packages.sanitizeDerivationName (builtins.substring 33 (-1) (builtins.baseNameOf path)); - outPath = path; - outputs = [ "out" ]; - outputName = "out"; - out = result; - }; - in - result; - }; - - validate = { - ## Check whether a path is contained within the Nix store. - ## - ## @type Path -> Bool - store = - value: - if lib.strings.validate.stringifiable value then - builtins.substring 0 1 (builtins.toString value) == "/" - && builtins.dirOf (builtins.toString value) == builtins.storeDir - else - false; - }; - - ## Create a search path from a list of paths. - ## - ## @type String -> [String] -> String - search = - target: paths: - lib.strings.concatMapSep ":" (path: path + "/" + target) ( - builtins.filter (value: value != null) paths - ); - - ## Create a search path from a list of packages. - ## - ## @type String -> [Derivation] -> String - searchFromOutput = - output: target: packages: - lib.paths.search target (builtins.map (lib.packages.getOutput output) packages); - - ## Create a search path for the binary output of a package. - ## - ## @type [Derivation] -> String - bin = lib.paths.searchFromOutput "bin" "bin"; - - ## Create a search path for the library output of a package. - ## - ## @type [Derivation] -> String - lib = lib.paths.searchFromOutput "lib" "lib"; - - ## Create a search path for the include output of a package. - ## - ## @type [Derivation] -> String - include = lib.paths.searchFromOutput "dev" "include"; - }; -} diff --git a/lib/src/paths/default.test.nix b/lib/src/paths/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/paths/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/src/points/default.nix b/lib/src/points/default.nix deleted file mode 100644 index 99bae5f..0000000 --- a/lib/src/points/default.nix +++ /dev/null @@ -1,54 +0,0 @@ -lib: { - points = { - ## Calculate the fixed point of a function. This will evaluate the function `f` - ## until its result settles (or Nix's recursion limit is reached). This allows - ## us to define recursive functions without worrying about the order of their - ## definitions. - ## - ## @type (a -> a) -> a - fix = - f: - let - x = f x; - in - x; - - ## Calculate the fixed point of a function. This will evaluate the function `f` - ## until its result settles (or Nix's recursion limit is reached). This allows - ## us to define recursive functions without worrying about the order of their - ## definitions. Unlike `fix`, the resulting value is also given a `__unfix__` - ## attribute that is set to the original function passed to `fix'`. - ## - ## @type (a -> a) -> a & { __unfix__ :: (a -> a) } - fix' = - f: - let - x = f x // { - __unfix__ = f; - }; - in - x; - - ## Extend a function's output with an additional function. This is the basis for - ## features like overlays. - ## - ## @type (a -> b -> c) -> (a -> b) -> a -> b & c - extends = - g: f: self: - let - previous = f self; - next = g self previous; - in - previous // next; - - ## Add an `extend` method to the result of a function. - ## - ## @type (a -> b) -> b & { extend :: (a -> b -> c) -> b & c } - withExtend = - f: - let - create = self: (f self) // { extend = g: lib.points.withExtend (lib.points.extends g f); }; - in - lib.points.fix' create; - }; -} diff --git a/lib/src/points/default.test.nix b/lib/src/points/default.test.nix deleted file mode 100644 index 1eeb20d..0000000 --- a/lib/src/points/default.test.nix +++ /dev/null @@ -1,52 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "fix" = { - "calculates a fixed point" = - let - expected = { - original = 0; - calculated = 1; - }; - actual = lib.points.fix (self: { - original = 0; - calculated = self.original + 1; - }); - in - actual == expected; - }; - - "fix'" = { - "allows unfixing a fixed point" = - let - expected = { - original = 0; - calculated = 6; - }; - result = lib.points.fix' (self: { - original = 0; - calculated = self.original + 1; - }); - actual = result.__unfix__ { original = 5; }; - in - actual == expected; - }; - - "extends" = { - "overlays two functions' return values" = - let - first = self: previous: { z = 3; }; - - second = self: { y = 2; }; - - expected = { - y = 2; - z = 3; - }; - - actual = lib.points.extends first second { x = 1; }; - in - actual == expected; - }; -} diff --git a/lib/src/strings/alphabet.nix b/lib/src/strings/alphabet.nix deleted file mode 100644 index 145dc34..0000000 --- a/lib/src/strings/alphabet.nix +++ /dev/null @@ -1,59 +0,0 @@ -{ - upper = [ - "A" - "B" - "C" - "D" - "E" - "F" - "G" - "H" - "I" - "J" - "K" - "L" - "M" - "N" - "O" - "P" - "Q" - "R" - "S" - "T" - "U" - "V" - "W" - "X" - "Y" - "Z" - ]; - - lower = [ - "a" - "b" - "c" - "d" - "e" - "f" - "g" - "h" - "i" - "j" - "k" - "l" - "m" - "n" - "o" - "p" - "q" - "r" - "s" - "t" - "u" - "v" - "w" - "x" - "y" - "z" - ]; -} diff --git a/lib/src/strings/ascii.nix b/lib/src/strings/ascii.nix deleted file mode 100644 index d7c95a8..0000000 --- a/lib/src/strings/ascii.nix +++ /dev/null @@ -1,97 +0,0 @@ -{ - " " = 32; - "!" = 33; - "\"" = 34; - "#" = 35; - "$" = 36; - "%" = 37; - "&" = 38; - "'" = 39; - "(" = 40; - ")" = 41; - "*" = 42; - "+" = 43; - "," = 44; - "-" = 45; - "." = 46; - "/" = 47; - "0" = 48; - "1" = 49; - "2" = 50; - "3" = 51; - "4" = 52; - "5" = 53; - "6" = 54; - "7" = 55; - "8" = 56; - "9" = 57; - ":" = 58; - ";" = 59; - "<" = 60; - "=" = 61; - ">" = 62; - "?" = 63; - "@" = 64; - "A" = 65; - "B" = 66; - "C" = 67; - "D" = 68; - "E" = 69; - "F" = 70; - "G" = 71; - "H" = 72; - "I" = 73; - "J" = 74; - "K" = 75; - "L" = 76; - "M" = 77; - "N" = 78; - "O" = 79; - "P" = 80; - "Q" = 81; - "R" = 82; - "S" = 83; - "T" = 84; - "U" = 85; - "V" = 86; - "W" = 87; - "X" = 88; - "Y" = 89; - "Z" = 90; - "[" = 91; - "\\" = 92; - "]" = 93; - "^" = 94; - "_" = 95; - "`" = 96; - "a" = 97; - "b" = 98; - "c" = 99; - "d" = 100; - "e" = 101; - "f" = 102; - "g" = 103; - "h" = 104; - "i" = 105; - "j" = 106; - "k" = 107; - "l" = 108; - "m" = 109; - "n" = 110; - "o" = 111; - "p" = 112; - "q" = 113; - "r" = 114; - "s" = 115; - "t" = 116; - "u" = 117; - "v" = 118; - "w" = 119; - "x" = 120; - "y" = 121; - "z" = 122; - "{" = 123; - "|" = 124; - "}" = 125; - "~" = 126; -} diff --git a/lib/src/strings/default.nix b/lib/src/strings/default.nix deleted file mode 100644 index fb558a2..0000000 --- a/lib/src/strings/default.nix +++ /dev/null @@ -1,342 +0,0 @@ -lib: { - strings = { - into = { - ## Convert a character to an integer. - ## - ## @type String -> Integer - int = char: builtins.getAttr char lib.strings.ascii; - - ## Convert a string into a list of characters. - ## - ## @type String -> List String - chars = - value: - let - range = lib.lists.range 0 (builtins.stringLength value - 1); - pick = index: builtins.substring index 1 value; - in - builtins.map pick range; - - shell = { - ## Convert a value into a shell variable. - ## - ## @type String -> Any -> String - var = - name: target: - let - baseVar = "${name}=${lib.strings.escape.shell.arg target}"; - listVar = "declare -a ${name}=(${lib.strings.escape.shell.args target})"; - attrsVar = "declare -A ${name}=(${ - builtins.concatStringsSep " " ( - lib.attrs.mapToList ( - k: v: "[${lib.strings.escape.shell.arg k}]=${lib.strings.escape.shell.arg v}" - ) target - ) - })"; - in - assert lib.errors.trace (lib.strings.validate.posix name) "Invalid shell variable name: ${name}"; - if builtins.isAttrs target && !lib.strings.validate.stringifiable target then - attrsVar - else if builtins.isList target then - listVar - else - baseVar; - - ## Create shell variables for a map of values. - ## - ## @type Attrs -> String - vars = - target: builtins.concatStringsSep "\n" (lib.attrs.mapToList lib.strings.into.shell.var target); - }; - }; - - escape = { - ## Escape parts of a string. - ## - ## @type List String -> String -> String - any = - patterns: source: - let - escaped = builtins.map (x: "\\${x}") patterns; - replacer = builtins.replaceStrings patterns escaped; - in - replacer source; - - ## Escape a given set of characters in a string using their - ## ASCII code prefixed with "\x". - ## - ## @type List String -> String - c = - list: - let - serialize = - char: - let - hex = lib.numbers.into.hex (lib.strings.into.int char); - in - "\\x${lib.strings.lower hex}"; - in - builtins.replaceStrings list (builtins.map serialize list); - - nix = { - ## Escape a string of Nix code. - ## - ## @type String -> String - value = value: lib.strings.escape.any [ "$" ] (builtins.toJSON value); - - ## Escape a string for use as a Nix identifier. - ## - ## @type String -> String - identifier = - value: - if builtins.match "[a-zA-Z_][a-zA-Z0-9_'-]*" value != null then - value - else - lib.strings.escape.nix.value value; - }; - - ## Escape a string for use in a regular expression. - ## - ## @type String -> String - regex = lib.strings.escape.any (lib.strings.into.chars "\\[{()^$?*+|."); - - ## Escape a string for use in XML. - ## - ## @type String -> String - xml = - builtins.replaceStrings - [ - "\"" - "'" - "<" - ">" - "&" - ] - [ - """ - "'" - "<" - ">" - "&" - ]; - - shell = { - ## Escape a string for use as a shell argument. - ## - ## @type String -> String - arg = value: "'${builtins.replaceStrings [ "'" ] [ "'\\''" ] (builtins.toString value)}'"; - - ## Escape multiple strings for use as shell arguments. - ## - ## @type List String -> String - args = lib.strings.concatMapSep " " lib.strings.escape.shell.arg; - }; - }; - - validate = { - ## Check if a string is a valid POSIX identifier. - ## - ## @type String -> Bool - posix = name: builtins.match "[a-zA-Z_][a-zA-Z0-9_]*" name != null; - - ## Check if a value can be used as a string. - ## - ## @type Any -> Bool - stringifiable = - value: builtins.isString value || builtins.isPath value || value ? outPath || value ? __toString; - - ## Check whether a string is empty. This includes strings that - ## only contain whitespace. - ## - ## @type String -> Bool - empty = value: builtins.match "[ \t\n]*" value != null; - }; - - order = { - ## Create an ordered string that will be placed anywhere. - ## - ## @type String -> OrderedString - anywhere = value: { - inherit value; - deps = [ ]; - }; - - ## Create an ordered string that will be placed before its dependencies. - ## - ## @type String -> List String -> OrderedString - after = deps: value: { inherit deps value; }; - - ## Apply the order for a list of ordered strings. This function also supports - ## plain strings in the list so long as they have an accompanying static definition - ## provided. - ## - ## @type Attrs -> List (OrderedString | String) - apply = - static: items: - let - process = - complete: remaining: - let - next = builtins.head remaining; - - before = process complete next.deps; - after = process before.complete (builtins.tail remaining); - in - if builtins.length remaining == 0 then - { - inherit complete; - result = [ ]; - } - else if builtins.isAttrs next then - { - inherit complete; - result = before.result ++ [ next.value ] ++ after.result; - } - else - process (complete // { "${next}" = true; }) ([ static.${next} ] ++ builtins.tail remaining); - - processed = process { } items; - in - processed.result; - }; - - ## Return a given string if a condition is true, otherwise return - ## an empty string. - ## - ## @type Bool -> String -> String - when = condition: value: if condition then value else ""; - - ## A table of ASCII characters mapped to their integer character code. - ## - ## @type Attrs - ascii = import ./ascii.nix; - - ## Lists of both upper and lower case ASCII characters. - ## - ## @type { upper :: List String, lower :: List String } - alphabet = import ./alphabet.nix; - - ## Concatenate a list of strings together. - ## - ## @type List String -> String - concat = builtins.concatStringsSep ""; - - ## Concatenate and map a list of strings together. - ## - ## @type List String -> String - concatMap = lib.strings.concatMapSep ""; - - ## Concatenate and map a list of strings together with a separator. - ## - ## @type String -> (a -> String) -> List a -> String - concatMapSep = - separator: f: list: - builtins.concatStringsSep separator (builtins.map f list); - - ## Change a string to uppercase. - ## - ## @type String -> String - upper = builtins.replaceStrings lib.strings.alphabet.lower lib.strings.alphabet.upper; - - ## Change a string to lowercase. - ## - ## @type String -> String - lower = builtins.replaceStrings lib.strings.alphabet.upper lib.strings.alphabet.lower; - - ## Add the context of one string to another. - ## - ## @type String -> String -> String - withContext = context: value: builtins.substring 0 0 context + value; - - ## Split a string by a separator. - ## - ## @type String -> String -> List String - split = - separator: value: - let - escaped = lib.strings.escape.regex (builtins.toString separator); - raw = builtins.split escaped (builtins.toString value); - parts = builtins.filter builtins.isString raw; - in - builtins.map (lib.strings.withContext value) parts; - - ## Check if a string starts with a given prefix. - ## - ## @type String -> String -> Bool - hasPrefix = - prefix: value: - let - text = builtins.substring 0 (builtins.stringLength prefix) value; - in - text == prefix; - - ## Check if a string ends with a given suffix. - ## - ## @type String -> String -> Bool - hasSuffix = - suffix: value: - let - valueLength = builtins.stringLength value; - suffixLength = builtins.stringLength suffix; - text = builtins.substring (valueLength - suffixLength) valueLength value; - in - (valueLength >= suffixLength) && text == suffix; - - ## Check if a string contains a given infix. - ## - ## @type String -> String -> Bool - hasInfix = infix: value: builtins.match ".*${lib.strings.escape.regex infix}.*" "${value}" != null; - - ## Remove a prefix from a string if it exists. - ## - ## @type String -> String -> String - removePrefix = - prefix: value: - let - prefixLength = builtins.stringLength prefix; - valueLength = builtins.stringLength value; - in - if lib.strings.hasPrefix prefix value then - builtins.substring prefixLength (valueLength - prefixLength) value - else - value; - - ## Remove a suffix from a string if it exists. - ## - ## @type String -> String -> String - removeSuffix = - suffix: value: - let - suffixLength = builtins.stringLength suffix; - valueLength = builtins.stringLength value; - in - if lib.strings.hasSuffix suffix value then - builtins.substring 0 (valueLength - suffixLength) value - else - value; - - ## Pad the start of a string with a character until it reaches - ## a given length. - ## - ## @type Integer -> String -> String - padStart = - length: char: value: - let - valueLength = builtins.stringLength value; - padding = builtins.genList (_: char) (length - valueLength); - in - if valueLength < length then (builtins.concatStringsSep "" padding) + value else value; - - ## Pad the end of a string with a character until it reaches - ## a given length. - ## - ## @type Integer -> String -> String - padEnd = - length: char: value: - let - valueLength = builtins.stringLength value; - padding = builtins.genList (_: char) (length - valueLength); - in - if valueLength < length then value + (builtins.concatStringsSep "" padding) else value; - }; -} diff --git a/lib/src/strings/default.test.nix b/lib/src/strings/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/strings/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/src/types/default.nix b/lib/src/types/default.nix deleted file mode 100644 index 5cf67a6..0000000 --- a/lib/src/types/default.nix +++ /dev/null @@ -1,1333 +0,0 @@ -lib: { - types = { - ## Determine whether a given value is a certain type. Note that this is *not* - ## the same as primitive Nix types. Types created with `lib.type` are attribute - ## sets with a `__type__` symbol. - ## - ## @type String -> Attrs -> Bool - is = name: value: value.__type__ or null == name; - - ## Assign a type to an attribute set. - ## - ## @type String -> Attrs -> Attrs - set = name: value: value // { __type__ = name; }; - - ## Create a default functor for a type. This handles merging of type values - ## by referencing wrapped and payload values. See the types implemented below - ## such as `lib.types.any` for examples. - ## - ## @type String -> Attrs - functor = name: { - inherit name; - type = lib.attrs.select (lib.strings.split "." name) null lib.types; - wrapped = null; - payload = null; - merge = null; - }; - - ## Merge two types. - ## - ## @type Attrs -> Attrs -> Attrs - merge = - f: g: - let - wrapped = f.wrapped.mergeType g.wrapped.functor; - payload = f.merge f.payload g.payload; - in - if f.name != g.name then - null - else if f.wrapped == null && g.wrapped == null && f.payload == null && g.payload == null then - f.type - else if f.wrapped != null && g.wrapped != null && wrapped != null then - f.type wrapped - else if f.payload != null && g.payload != null && payload != null then - f.type payload - else - null; - - ## Create a new type. - ## - ## @type Attrs -> Attrs - create = - settings@{ - name, - description ? name, - fallback ? { }, - check ? lib.fp.const true, - merge ? lib.options.merge.default, - functor ? lib.types.functor name, - mergeType ? lib.types.merge functor, - getSubOptions ? lib.fp.const { }, - submodules ? null, - withSubModules ? lib.fp.const null, - children ? { }, - }: - { - __type__ = "type"; - inherit - name - description - fallback - check - merge - functor - mergeType - getSubOptions - submodules - withSubModules - children - ; - }; - - ## Add a check to a type. - ## - ## @type Attrs -> (Any -> Bool) -> Attrs - withCheck = type: check: type // { check = value: type.check value && check value; }; - - ## A type that allows any value and will only use a single definition. - ## - ## @type Attrs - raw = lib.types.create { - name = "Raw"; - description = "raw value"; - check = lib.fp.const true; - merge = lib.options.merge.one; - }; - - ## A type that allows any value and will merge the definitions depending on - ## their data type. - ## - ## @type Attrs - any = lib.types.create { - name = "Any"; - description = "any"; - check = lib.fp.const true; - merge = - location: definitions: - let - identifier = lib.options.getIdentifier location; - first = builtins.elemAt definitions 0; - - files = lib.modules.getFiles definitions; - serializedFiles = builtins.concatStringsSep " and " files; - - getType = - value: - if builtins.isAttrs value && lib.strings.validate.stringifiable value then - "StringifiableAttrs" - else - builtins.typeOf value; - - commonType = builtins.foldl' ( - type: definition: - if getType definition.value != type then - builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}" - else - type - ) (getType first.value) definitions; - - mergeStringifiableAttrs = lib.options.merge.one; - - mergeSet = (lib.types.attrs.of lib.types.any).merge; - - mergeList = - if builtins.length definitions > 1 then - builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}" - else - (lib.types.list.of lib.types.any).merge; - - mergeLambda = - location: definitions: x: - let - resolvedLocation = location ++ [ "" ]; - resolvedDefinitions = builtins.map (definition: { - __file__ = definition.__file__; - value = definition.value x; - }) definitions; - in - lib.types.any.merge resolvedLocation resolvedDefinitions; - - merge = - if commonType == "set" then - mergeSet - else if commonType == "list" then - mergeList - else if commonType == "StringifiableAttrs" then - mergeStringifiableAttrs - else if commonType == "lambda" then - mergeLambda - else - lib.options.merge.equal; - in - merge location definitions; - }; - - ## A fallback type that is used when a type is not specified for an option. - ## - ## @type Attrs - unspecified = lib.types.create { - name = "Unspecified"; - description = "unspecified type"; - }; - - ## A type that allows a boolean value. The merged definitions must all be - ## the same. - ## - ## @type Attrs - bool = lib.types.create { - name = "Bool"; - description = "boolean"; - check = builtins.isBool; - merge = lib.options.merge.equal; - }; - - ## A type that allows an integer value. The merged definitions must all be - ## the same. - ## - ## @type Attrs - int = lib.types.create { - name = "Int"; - description = "signed integer"; - check = builtins.isInt; - merge = lib.options.merge.equal; - }; - - ints = - let - description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; - ## Create a type that allows an integer value between a given range. - ## - ## @type Int -> Int -> Attrs - between = - start: end: - assert lib.errors.trace ( - start <= end - ) "lib.types.ints.between start must be less than or equal to end"; - lib.types.withCheck lib.types.int (value: value >= start && value <= end) - // { - name = "IntBetween"; - description = "integer between ${description start end}"; - }; - - ## Create a type that allows an integer value between a given range with a specific - ## number of bits. - ## - ## @type Int -> Int -> Attrs - sign = - bits: range: - let - start = 0 - (range / 2); - end = range / 2 - 1; - in - between start end - // { - name = "IntSigned${builtins.toString bits}"; - description = "${builtins.toString bits} bit signed integer between ${description start end}"; - }; - - ## Create a type that allows an unsigned integer value between a given range with a specific - ## number of bits. - ## - ## @type Int -> Int -> Attrs - unsign = - bits: range: - let - start = 0; - end = range - 1; - in - between start end - // { - name = "IntUnsigned${builtins.toString bits}"; - description = "${builtins.toString bits} bit unsigned integer between ${description start end}"; - }; - in - { - inherit between; - - ## A type that allows a positive integer value. - ## - ## @type Attrs - positive = lib.types.withCheck lib.types.int (value: value > 0) // { - name = "IntPositive"; - description = "positive integer"; - }; - - ## A type that allows a positive integer value or zero. - ## - ## @type Attrs - unsigned = lib.types.withCheck lib.types.int (value: value >= 0) // { - name = "IntUnsigned"; - description = "unsigned integer"; - }; - - ## A type that allows an 8bit unsigned integer. - ## - ## @type Attrs - u8 = unsign 8 256; - - ## A type that allows a 16bit unsigned integer. - ## - ## @type Attrs - u16 = unsign 16 65536; - - ## A type that allows a 32bit unsigned integer. - ## - ## @type Attrs - u32 = unsign 32 4294967296; - - # u64 = unsign 64 18446744073709551616; - - ## A type that allows an 8bit signed integer. - ## - ## @type Attrs - s8 = sign 8 256; - - ## A type that allows a 16bit signed integer. - ## - ## @type Attrs - s16 = sign 16 65536; - - ## A type that allows a 32bit signed integer. - ## - ## @type Attrs - s32 = sign 32 4294967296; - }; - - ## A type that allows a floating point value. The merged definitions must all be - ## the same. - ## - ## @type Attrs - float = lib.types.create { - name = "Float"; - description = "floating point number"; - check = builtins.isFloat; - merge = lib.options.merge.equal; - }; - - ## A type that allows a number value. This can be either an integer or a float. - ## - ## @type Attrs - number = lib.types.either lib.types.int lib.types.float; - - numbers = - let - description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; - ## Create a type that allows a number value between a given range. - ## - ## @type Int -> Int -> Attrs - between = - start: end: - assert lib.errors.trace ( - start <= end - ) "lib.types.numbers.between start must be less than or equal to end"; - lib.types.withCheck lib.types.number (value: value >= start && value <= end) - // { - name = "NumberBetween"; - description = "numbereger between ${description start end}"; - }; - in - { - inherit between; - - ## A type that allows a positive number value. - ## - ## @type Attrs - positive = lib.types.withCheck lib.types.int (value: value > 0) // { - name = "NumberPositive"; - description = "positive number"; - }; - - ## A type that allows a positive number value or zero. - ## - ## @type Attrs - positiveOrZero = lib.types.withCheck lib.types.int (value: value >= 0) // { - name = "NumberPositiveOrZero"; - description = "number that is zero or greater"; - }; - }; - - ## A type that allows a port value. This values an unsigned 16bit integer. - ## - ## @type Attrs - port = lib.types.ints.u16; - - ## A type that allows a string value specifying a version number. - ## - ## @type Attrs - version = lib.types.create { - name = "Version"; - description = "version"; - check = - value: - let - parts = builtins.splitVersion value; - in - builtins.isString value && builtins.length parts > 0; - merge = lib.options.merge.equal; - }; - - ## A type that allows a string value. The merged definitions must all be - ## the same. - ## - ## @type Attrs - string = lib.types.create { - name = "String"; - description = "string"; - check = builtins.isString; - merge = lib.options.merge.equal; - }; - - strings = { - ## A type that allows a non-empty string value. The merged definitions must all be - ## the same. - ## - ## @type Attrs - required = lib.types.create { - name = "StringNonEmpty"; - description = "non-empty string"; - check = value: lib.types.string.check value && !(lib.strings.validate.empty value); - merge = lib.options.merge.equal; - }; - - ## Create a type that allows a string value that matches a given pattern. The merged - ## definitions must all be the same. - ## - ## @type String -> Attrs - matching = - pattern: - lib.types.create { - name = "StringMatching ${pattern}"; - description = "string matching the pattern ${pattern}"; - check = value: lib.types.string.check value && builtins.match pattern value != null; - merge = lib.options.merge.equal; - }; - - ## Create a type that allows a string value joined by a separator. The merged - ## definitions must all be the same. - ## - ## @type String -> Attrs - concat = - separator: - lib.types.create { - name = "StringConcat"; - description = - if separator == "" then - "concatenated string" - else - "string concatenated with ${builtins.toJSON separator}"; - check = value: lib.types.string.check value; - merge = - location: definitions: - builtins.concatStringsSep separator (lib.options.getDefinitionValues definitions); - functor = lib.types.functor "strings.concat" // { - payload = separator; - merge = x: y: if x == y then x else null; - }; - }; - - ## A type that allows a string value that is a single line with an optional new line - ## at the end. - ## - ## @type Attrs - line = - let - matcher = lib.types.strings.matching "[^\n\r]*\n?"; - in - lib.types.create { - name = "StringLine"; - description = "single line string with an optional new line at the end"; - check = matcher.check; - merge = location: definitions: lib.strings.removeSuffix "\n" (matcher.merge location definitions); - }; - - ## A type that allows a string value joined by new lines. - ## - ## @type Attrs - lines = lib.types.strings.concat "\n"; - }; - - attrs = { - ## A type that allows an attribute set containing any type of value. - ## - ## @type Attrs - any = lib.types.create { - name = "Attrs"; - description = "attribute set"; - fallback = { - value = { }; - }; - check = builtins.isAttrs; - merge = - location: definitions: - builtins.foldl' (result: definition: result // definition.value) { } definitions; - }; - - ## Create a type that allows an attribute set containing a specific type of value. - ## - ## @type Attrs -> Attrs - of = - type: - lib.types.create { - name = "AttrsOf"; - description = "AttrsOf (${type.name})"; - fallback = { - value = { }; - }; - check = builtins.isAttrs; - merge = - location: definitions: - let - normalize = - definition: - builtins.mapAttrs (name: value: { - __file__ = definition.__file__; - value = value; - }) definition.value; - normalized = builtins.map normalize definitions; - zipper = - name: definitions: (lib.options.merge.definitions (location ++ [ name ]) type definitions).optional; - filtered = lib.attrs.filter (name: value: value ? value) (builtins.zipAttrsWith zipper normalized); - in - builtins.mapAttrs (name: value: value.value) filtered; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); - submodules = type.submodules; - withSubModules = modules: lib.types.attrs.of (type.withSubModules modules); - functor = lib.types.functor "attrs.of" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - - ## Create a type that allows an attribute set containing a specific type of value. - ## However, unlike `lib.types.attrs.of` this variant is lazily evaluated and does - ## not support certain properties like `lib.modules.when`. - ## - ## @type Attrs -> Attrs - lazy = - type: - lib.types.create { - name = "LazyAttrsOf"; - description = "LazyAttrsOf (${type.name})"; - fallback = { - value = { }; - }; - check = builtins.isAttrs; - merge = - location: definitions: - let - normalize = - definition: - builtins.mapAttrs (name: value: { - __file__ = definition.__file__; - value = value; - }) definition.value; - normalized = builtins.map normalize definitions; - zipper = - name: definitions: - let - merged = lib.options.merge.definitions (location ++ [ name ]) type definitions; - in - merged.optional.value or type.fallback.value or merged.merged; - in - builtins.zipAttrsWith zipper normalized; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); - submodules = type.submodules; - withSubModules = modules: lib.types.attrs.lazy (type.withSubModules modules); - functor = lib.types.functor "attrs.lazy" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - }; - - ## A type that allows a derivation (or store path). - ## - ## @type Attrs - derivation = lib.types.create { - name = "Derivation"; - description = "derivation"; - check = value: lib.packages.isDerivation value || lib.paths.validate.store value; - merge = - location: definitions: - let - merged = lib.options.merge.one location definitions; - in - if builtins.isPath merged || (builtins.isString merged && !(builtins.hasContext merged)) then - lib.paths.into.drv merged - else - merged; - }; - - derivations = { - ## A type that allows a shell derivation. This is a derivation with an accompanying - ## `shellPath` attribute. - ## - ## @type Attrs - shell = lib.types.derivation // { - check = value: lib.packages.isDerivation value && builtins.hasAttr "shellPath" value; - }; - }; - - ## A type that allows a path value. The merged definitions must all be the same. - ## - ## @type Attrs - path = lib.types.create { - name = "Path"; - description = "path"; - check = - value: - lib.strings.validate.stringifiable value && builtins.substring 0 1 (builtins.toString value) == "/"; - merge = lib.options.merge.equal; - }; - - list = { - ## A type that allows a list containing any value. - ## - ## @type Attrs - any = lib.types.list.of lib.types.any; - - ## Create a type that allows a list containing a specific type of value. - ## - ## @type Attrs -> Attrs - of = - type: - lib.types.create { - name = "ListOf"; - description = "ListOf (${type.name})"; - fallback = { - value = [ ]; - }; - check = builtins.isList; - merge = - location: definitions: - let - result = lib.lists.mapWithIndex1 ( - i: definition: - lib.lists.mapWithIndex1 ( - j: value: - let - resolved = - lib.options.merge.definitions - (location ++ [ "[definition ${builtins.toString i}-entry ${builtins.toString j}]" ]) - type - [ - { - file = definition.file; - value = value; - } - ]; - in - resolved.optional - ) definition.value - ) definitions; - - merged = lib.lists.flatten result; - filtered = builtins.filter (definition: definition ? value) merged; - values = lib.options.getDefinitionValues filtered; - in - values; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "*" ]); - submodules = type.submodules; - withSubModules = modules: lib.types.list.of (type.withSubModules modules); - functor = lib.types.functor "list.of" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - - ## A type that allows a non-empty list containing a specific type of value. - ## - ## @type Attrs -> Attrs - required = - type: - lib.types.withCheck (lib.types.list.of type) (value: value != [ ]) - // { - description = "non-empty list of ${type.description}"; - fallback = { }; - }; - }; - - ## Create a type that must be a unique value. - ## - ## @type String -> Attrs -> Attrs - unique = - message: type: - lib.types.create { - name = "Unique"; - description = type.description; - fallback = type.fallback; - check = type.check; - merge = lib.options.merge.unique message; - getSubOptions = type.getSubOptions; - submodules = type.submodules; - withSubModules = modules: lib.types.unique message (type.withSubModules modules); - functor = lib.types.functor "unique" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - - ## Create a type that must be a single value. Unlike `lib.types.unique`, this type - ## does not merge the definitions. - ## - ## @type Attrs -> Attrs - single = - type: - lib.types.create { - name = "Single"; - description = type.description; - fallback = type.fallback; - check = type.check; - merge = lib.options.merge.one; - getSubOptions = type.getSubOptions; - submodules = type.submodules; - withSubModules = modules: lib.types.single (type.withSubModules modules); - functor = lib.types.functor "unique" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - - ## Create a type that may be either a given type or null. - ## - ## @type Attrs -> Attrs - nullish = - type: - lib.types.create { - name = "Nullish"; - description = "null or ${type.description}"; - fallback = { - value = null; - }; - check = value: value == null || type.check value; - merge = - location: definitions: - let - identifier = lib.options.getIdentifier location; - files = builtins.map lib.modules.getFiles definitions; - serializedFiles = builtins.concatStringsSep " and " files; - totalNulls = lib.lists.count (definition: definition == null) definitions; - in - if totalNulls == builtins.length definitions then - null - else if totalNulls != 0 then - builtins.throw "The option `${identifier}` is defined as both null and not null in ${serializedFiles}" - else - type.merge location definitions; - getSubOptions = type.getSubOptions; - submodules = type.submodules; - withSubModules = modules: lib.types.nullish (type.withSubModules modules); - functor = lib.types.functor "nullish" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - - ## Create a type that allows a function which returns a given type. - ## - ## @type Attrs -> Attrs - function = - type: - lib.types.create { - name = "Function"; - description = "function that returns ${type.description}"; - check = builtins.isFunction; - merge = - location: definitions: args: - let - normalize = definition: { - __file__ = definition.__file__; - value = definition.value args; - }; - normalized = builtins.map normalize definitions; - merged = lib.options.merge.definitions (location ++ [ "" ]) type normalized; - in - merged.merged; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); - submodules = type.submodules; - withSubModules = modules: lib.types.function (type.withSubModules modules); - functor = lib.types.functor "function" // { - wrapped = type; - }; - children = { - element = type; - }; - }; - - ## Create a submodule from a list of modules (or a module directly). - ## - ## @type (Module | (List Module)) -> Attrs - submodule = modules: lib.types.submodules.of { modules = lib.lists.from.any modules; }; - - submodules = { - ## Create a type from a list of submodules. This is particularly useful for use - ## with helpers like `lib.types.attrs.of` in order to produce more complex, - ## dynamic types. - ## - ## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs - of = - settings@{ - modules, - args ? { }, - description ? null, - shorthand ? true, - }: - let - getModules = builtins.map ( - definition: - if shorthand && builtins.isAttrs definition.value then - let - # TODO: Figure out if we can apply additional attributes to the generated module. - # Currently this causes issues to do with redefined options. - rest = builtins.removeAttrs (lib.attrs.filter ( - name: value: builtins.elem name lib.modules.VALID_KEYS - ) definition.value) [ "freeform" ]; - in - if definition.value ? config then - rest - // { - __file__ = definition.__file__; - config = definition.value.config; - } - else - let - config = builtins.removeAttrs definition.value lib.modules.VALID_KEYS; - in - rest - // { - __file__ = definition.__file__; - config = config; - } - else - { - __file__ = definition.__file__; - includes = [ definition.value ]; - } - ); - - base = lib.modules.run { - inherit args; - - modules = [ - { config.__module__.args.dynamic.name = lib.modules.overrides.default ""; } - ] ++ modules; - }; - - freeform = base.__module__.freeform; - name = "Submodule"; - in - lib.types.create { - inherit name; - description = if description != null then description else freeform.description or name; - fallback = { - value = { }; - }; - check = value: builtins.isAttrs value || builtins.isFunction value || lib.types.path.check value; - merge = - location: definitions: - let - result = base.extend { - prefix = location; - modules = [ - { config.__module__.args.dynamic.name = lib.lists.last location; } - ] ++ getModules definitions; - }; - in - result.config; - getSubOptions = - prefix: - let - result = base.extend { inherit prefix; }; - in - result.options - // lib.attrs.when (freeform != null) { __freeformOptions__ = freeform.getSubOptions prefix; }; - submodules = modules; - withSubModules = - modules: - lib.types.submodules.of { - inherit - args - description - modules - shorthand - ; - }; - children = lib.attrs.when (freeform != null) { inherit freeform; }; - functor = lib.types.functor "submodule" // { - type = lib.types.submodules.of; - payload = { - inherit - modules - args - description - shorthand - ; - }; - merge = x: y: { - modules = x.modules ++ y.modules; - - args = - let - intersection = builtins.intersectAttrs x.args y.args; - in - if intersection == { } then - x.args // y.args - else - builtins.throw "A submodule option is declared multiple times with the same args: ${builtins.toString (builtins.attrNames intersection)}"; - - description = - if x.description == null then - y.description - else if y.description == null then - x.description - else if x.description == y.description then - x.description - else - builtins.throw "A submodule description is declared multiple times with conflicting values"; - }; - }; - }; - - ## Create a type from a submodule which can be used in multiple parts of the configuration. - ## - ## @type { module :: Module, name? :: String, description? :: String } -> Attrs - portable = - { - name ? "PortableSubmodule", - description ? "portable submodule", - module, - }: - let - normalize = - value: - if builtins.isFunction value || builtins.isList value then - value - else if value ? __modules__ then - value.__modules__ - else - { config = value; }; - - initial = lib.types.create { - name = "PortableSubmoduleInitial"; - description = "initial portable submodule value"; - check = value: builtins.isFunction value || builtins.isAttrs value || builtins.isList value; - merge = - location: definitions: - let - normalized = builtins.map (definition: lib.lists.from.any (normalize definition.value)) definitions; - in - builtins.concatLists normalized; - }; - - base = - { config }: - { - includes = [ - { config.__module__.args.dynamic.name = lib.modules.overrides.default ""; } - ]; - - options = { - __modules__ = lib.options.create { - description = "User specified modules to be evaluated."; - type = lib.types.list.of (initial // { merge = lib.options.merge.one; }); - internal = true; - default.value = [ ]; - }; - - extend = lib.options.create { - description = "Extend the submodule configuration."; - type = lib.types.function lib.types.raw; - internal = true; - writable = false; - default.value = - module: - let - normalized = - if builtins.isList module then - module - else if builtins.isFunction module || module ? config then - [ module ] - else - [ { config = module; } ]; - - modules = config.__modules__ ++ normalized; - - result = lib.modules.run { - modules = [ - module - base - { config.__modules__ = modules; } - { config.__module__.args.dynamic.name = config.__module__.args.dynamic.name; } - ] ++ modules; - }; - in - result.config; - }; - }; - }; - - transform = - location: value: - let - modules = lib.lists.from.any (normalize value); - - result = lib.modules.run { - prefix = location; - modules = [ - module - base - { config.__modules__ = modules; } - { config.__module__.args.dynamic.name = lib.lists.last location; } - ] ++ modules; - }; - in - result.config; - - final = lib.types.raw // { - merge = - location: definitions: - let - modules = lib.lists.flatten (builtins.map (definition: normalize definition.value) definitions); - - result = lib.modules.run { - prefix = location; - modules = [ - module - base - { config.__modules__ = modules; } - { config.__module__.args.dynamic.name = lib.lists.last location; } - ] ++ modules; - }; - in - result.config; - }; - - type = lib.types.coerceWithLocation initial transform final; - in - type - // { - inherit name description; - children = type.children // { - inherit module base; - }; - }; - }; - - deferred = { - ## A module that is imported in another part of the configuration. - ## - ## @type Attrs - default = lib.types.deferred.of { modules = [ ]; }; - - ## Create a submodule type from a list of modules which will be imported in - ## another part of the configuration. - ## - ## @type { modules :: List Module } -> Attrs - of = - settings@{ modules }: - let - submodule = lib.types.submodule modules; - in - lib.types.create { - name = "Deferred"; - description = "module"; - check = value: builtins.isAttrs value || builtins.isFunction value || lib.types.path.check value; - merge = location: definitions: { - includes = - modules - ++ builtins.map (definition: { - __file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}"; - includes = [ definition.value ]; - }) definitions; - }; - getSubOptions = submodule.getSubOptions; - submodules = submodule.submodules; - withSubModules = modules: lib.types.deferred.of { modules = modules; }; - functor = lib.types.functor "deferred.of" // { - type = lib.types.deferred.of; - payload = { - inherit modules; - }; - merge = x: y: { modules = x.modules ++ y.modules; }; - }; - }; - }; - - ## A type that allows a Type. - ## - ## @type Attrs - type = lib.types.create { - name = "Type"; - description = "type"; - check = lib.types.is "type"; - merge = lib.options.merge.one; - }; - - ## A type that allows an Option. - ## - ## @type Attrs - option = lib.types.create { - name = "Option"; - description = "option"; - check = lib.types.is "option"; - merge = - location: definitions: - let - first = builtins.elemAt definitions 0; - modules = builtins.map (definition: { - __file__ = definition.__file__; - options = lib.options.create { type = definition.value; }; - }) definitions; - merged = lib.modules.fixup location (lib.options.merge.declarations location modules); - in - if builtins.length definitions == 1 then first.value else merged.type; - }; - - ## Create a type that allows a specific primitive value from a given list. - ## - ## @type List Any -> Attrs - enum = - values: - let - serialize = - value: - if builtins.isString value then - ''"${value}"'' - else if builtins.isInt value then - builtins.toString value - else if builtins.isBool value then - lib.bools.into.string value - else - ''<${builtins.typeOf value}>''; - in - lib.types.create { - name = "Enum"; - description = - if values == [ ] then - "empty enum" - else if builtins.length values == 1 then - "value ${serialize (builtins.elemAt values 0)} (singular enum)" - else - "one of ${lib.strings.concatMapSep ", " serialize values}"; - check = value: builtins.elem value values; - merge = lib.options.merge.equal; - functor = lib.types.functor "enum" // { - payload = values; - merge = x: y: lib.lists.unique (x ++ y); - }; - }; - - ## Create a type that allows either of two types. - ## - ## @type Attrs -> Attrs -> Attrs - either = - left: right: - let - name = "Either"; - functor = lib.types.functor name // { - wrapped = [ - left - right - ]; - }; - in - lib.types.create { - inherit name functor; - description = "${left.description} or ${right.description}"; - check = value: left.check value || right.check value; - merge = - location: definitions: - let - values = lib.options.getDefinitionValues definitions; - isLeft = builtins.all left.check values; - isRight = builtins.all right.check values; - in - if isLeft then - left.merge location definitions - else if isRight then - right.merge location definitions - else - lib.options.merge.one location definitions; - mergeType = - f: - let - mergedLeft = left.mergeType (builtins.elemAt f.wrapped 0).functor; - mergedRight = right.mergeType (builtins.elemAt f.wrapped 1).functor; - in - if (f.name == name) && (mergedLeft != null) && (mergedRight != null) then - functor.type mergedLeft mergedRight - else - null; - children = { - inherit left right; - }; - }; - - ## Create a type that allows a value of one of the given types. - ## - ## @type List Attrs -> Attrs - one = - types: - let - first = builtins.elemAt types 0; - rest = builtins.tail types; - in - if types == [ ] then - builtins.throw "lib.types.one must be given at least one type" - else - builtins.foldl' lib.types.either first rest; - - ## Create a type that allows a value which is either the final type or is transformable - ## to the final type. - ## - ## @type Attrs -> (Any -> Any) -> Attrs -> Attrs - coerce = - initial: transform: final: - let - in - if initial.submodules != null then - builtins.throw "lib.types.coerce's first argument may not have submodules, but got ${initial.description}" - else - lib.types.create { - name = "Coerce"; - description = "${initial.description} that is transformed to ${final.description}"; - fallback = final.fallback; - check = value: final.check value || (initial.check value && final.check (transform value)); - merge = - location: definitions: - let - process = value: if initial.check value then transform value else value; - normalize = definition: definition // { value = process definition.value; }; - normalized = builtins.map normalize definitions; - in - final.merge location normalized; - getSubOptions = final.getSubOptions; - submodules = final.submodules; - withSubModules = modules: lib.types.coerce initial transform (final.withSubModules modules); - mergeType = x: y: null; - functor = lib.types.functor "coerce" // { - wrapped = final; - }; - children = { - inherit initial final; - }; - }; - - ## Create a type that allows a value which is either the final type or is transformable - ## to the final type. - ## - ## @type Attrs -> (Any -> Any) -> Attrs -> Attrs - coerceWithLocation = - initial: transform: final: - let - in - if initial.submodules != null then - builtins.throw "lib.types.coerceWithLocation's first argument may not have submodules, but got ${initial.description}" - else - lib.types.create { - name = "Coerce"; - description = "${initial.description} that is transformed to ${final.description}"; - fallback = final.fallback; - check = value: final.check value || (initial.check value && final.check (transform [ ] value)); - merge = - location: definitions: - let - process = value: if initial.check value then transform location value else value; - normalize = definition: definition // { value = process definition.value; }; - normalized = builtins.map normalize definitions; - in - final.merge location normalized; - getSubOptions = final.getSubOptions; - submodules = final.submodules; - withSubModules = - modules: lib.types.coerceWithLocation initial transform (final.withSubModules modules); - mergeType = x: y: null; - functor = lib.types.functor "coerceWithLocation" // { - wrapped = final; - }; - children = { - inherit initial final; - }; - }; - - dag = { - ## Create a type that allows a DAG (Directed Acyclic Graph) of a given type. - ## - ## @type Attrs -> Attrs - of = - type: - let - resolved = lib.types.attrs.of (lib.types.dag.entry type); - in - lib.types.create { - name = "Dag"; - description = "Dag of ${type.description}"; - check = resolved.check; - merge = resolved.merge; - fallback = resolved.fallback; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); - submodules = type.submodules; - withSubModules = modules: lib.types.dag.of (type.withSubModules modules); - functor = lib.types.functor "dag.of" // { - wrapped = type; - }; - children = { - element = type; - resolved = resolved; - }; - }; - - ## Create a type that allows a DAG entry of a given type. - ## - ## @type Attrs -> Attrs - entry = - type: - let - submodule = lib.types.submodule ( - { name }: - { - options = { - value = lib.options.create { type = type; }; - before = lib.options.create { type = lib.types.list.of lib.types.string; }; - after = lib.options.create { type = lib.types.list.of lib.types.string; }; - }; - } - ); - normalize = - definition: - let - value = - if definition ? priority then - lib.modules.order definition.priority definition.value - else - definition.value; - in - if lib.dag.validate.entry definition.value then definition.value else lib.dag.entry.anywhere value; - in - lib.types.create { - name = "DagEntry"; - description = "DagEntry (${type.description})"; - merge = - location: definitions: - submodule.merge location ( - builtins.map (definition: { - __file__ = definition.__file__; - value = normalize definition; - }) definitions - ); - }; - }; - }; -} diff --git a/lib/src/types/default.test.nix b/lib/src/types/default.test.nix deleted file mode 100644 index 6062b5e..0000000 --- a/lib/src/types/default.test.nix +++ /dev/null @@ -1,55 +0,0 @@ -let - lib = import ./../default.nix; -in -{ - "PortableSubmodule" = { - "is portable" = - let - submodule = - { config }: - { - options = { - primitive = lib.options.create { - type = lib.types.string; - default.value = ""; - }; - - computed = lib.options.create { - type = lib.types.string; - default.value = "computed: ${config.primitive}"; - }; - }; - }; - - option = lib.options.create { - default.value = { }; - type = lib.types.submodules.portable { - module = submodule; - }; - }; - - moduleA = { - options.a = option; - }; - moduleB = - { config }: - { - options.b = option; - - config.b = config.a; - }; - moduleC = { - config.b.primitive = "custom"; - }; - - result = lib.modules.run { - modules = [ - moduleA - moduleB - moduleC - ]; - }; - in - result.config.b.computed == "computed: custom"; - }; -} diff --git a/lib/src/versions/default.nix b/lib/src/versions/default.nix deleted file mode 100644 index e58e213..0000000 --- a/lib/src/versions/default.nix +++ /dev/null @@ -1,58 +0,0 @@ -lib: { - versions = { - ## Check if a version is greater than another. - ## - ## @type String -> String -> Bool - gt = first: second: builtins.compareVersions first second == -1; - - ## Check if a version is greater than or equal to another. - ## - ## @type String -> String -> Bool - gte = first: second: builtins.compareVersions first second != 1; - - ## Check if a version is less than another. - ## - ## @type String -> String -> Bool - lt = first: second: builtins.compareVersions first second == 1; - - ## Check if a version is less than or equal to another. - ## - ## @type String -> String -> Bool - lte = first: second: builtins.compareVersions first second != -1; - - ## Check if a version is equal to another. - ## - ## @type String -> String -> Bool - eq = first: second: builtins.compareVersions first second == 0; - - ## Get the major version from a version string. - ## - ## @type String -> String - major = - version: - let - parts = builtins.splitVersion version; - in - builtins.elemAt parts 0; - - ## Get the minor version from a version string. - ## - ## @type String -> String - minor = - version: - let - parts = builtins.splitVersion version; - in - builtins.elemAt parts 1; - - ## Get the patch version from a version string. - ## - ## @type String -> String - patch = - version: - let - parts = builtins.splitVersion version; - in - builtins.elemAt parts 2; - }; -} diff --git a/lib/src/versions/default.test.nix b/lib/src/versions/default.test.nix deleted file mode 100644 index 2c21ad2..0000000 --- a/lib/src/versions/default.test.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - lib = import ./../default.nix; -in -{ } diff --git a/lib/test.sh b/lib/test.sh deleted file mode 100755 index b6e1592..0000000 --- a/lib/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -i bash -p jq - -set -euo pipefail - -namespace=${1:-} - -if [ -z "$namespace" ]; then - nix eval -f ./default.test.nix --show-trace --raw -else - if [ -d "./src/$namespace" ]; then - nix eval -f "./src/$namespace/default.test.nix" --show-trace --json | jq - else - echo "Namespace $namespace not found" - exit 1 - fi -fi - diff --git a/tidepool/default.nix b/tidepool/default.nix index 8c6436e..d9dcc28 100644 --- a/tidepool/default.nix +++ b/tidepool/default.nix @@ -1,8 +1,10 @@ { - lib ? import ./../lib, foundation ? import ./../foundation { system = "i686-linux"; }, }: let + pins = import ./npins; + lib = import pins.lib; + modules = import ./src/modules.nix; result = lib.modules.run { diff --git a/tidepool/flake.lock b/tidepool/flake.lock index 746a587..e0cb1bb 100644 --- a/tidepool/flake.lock +++ b/tidepool/flake.lock @@ -1,18 +1,12 @@ { "nodes": { "foundation": { - "inputs": { - "lib": [ - "lib" - ] - }, "locked": { "dir": "foundation", - "lastModified": 1724190751, - "narHash": "sha256-e8sOmeXS9YWuQqjW6gvtS3PIueazkf4S1iiJ/94eXv4=", - "ref": "master", - "rev": "4b36a5a0133f5481840bdfaf693c971215a7ef1f", - "revCount": 84, + "dirtyRev": "c30f94972c84c5c758b705e4363f624e75560916-dirty", + "dirtyShortRev": "c30f949-dirty", + "lastModified": 1742785479, + "narHash": "sha256-jYjvytd4Ut1z3izUuGCfq2KKjHLgWYvhMtPtyRh4FR8=", "type": "git", "url": "file:../" }, @@ -22,27 +16,9 @@ "url": "file:../" } }, - "lib": { - "locked": { - "dir": "lib", - "lastModified": 1724190751, - "narHash": "sha256-e8sOmeXS9YWuQqjW6gvtS3PIueazkf4S1iiJ/94eXv4=", - "ref": "master", - "rev": "4b36a5a0133f5481840bdfaf693c971215a7ef1f", - "revCount": 84, - "type": "git", - "url": "file:../" - }, - "original": { - "dir": "lib", - "type": "git", - "url": "file:../" - } - }, "root": { "inputs": { - "foundation": "foundation", - "lib": "lib" + "foundation": "foundation" } } }, diff --git a/tidepool/flake.nix b/tidepool/flake.nix index 213cd18..0b009ef 100644 --- a/tidepool/flake.nix +++ b/tidepool/flake.nix @@ -1,11 +1,7 @@ { inputs = { - lib = { - url = "git+file:../?dir=lib"; - }; foundation = { url = "git+file:../?dir=foundation"; - inputs.lib.follows = "lib"; }; }; @@ -13,7 +9,6 @@ inputs: let exports = import ./default.nix { - lib = inputs.lib.lib; foundation = inputs.foundation.packages.i686-linux; }; in diff --git a/tidepool/npins/default.nix b/tidepool/npins/default.nix new file mode 100644 index 0000000..5e7d086 --- /dev/null +++ b/tidepool/npins/default.nix @@ -0,0 +1,80 @@ +# Generated by npins. Do not modify; will be overwritten regularly +let + data = builtins.fromJSON (builtins.readFile ./sources.json); + version = data.version; + + mkSource = + spec: + assert spec ? type; + let + path = + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else + builtins.throw "Unknown source type ${spec.type}"; + in + spec // { outPath = path; }; + + mkGitSource = + { + repository, + revision, + url ? null, + hash, + branch ? null, + ... + }: + assert repository ? type; + # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository + # In the latter case, there we will always be an url to the tarball + if url != null then + (builtins.fetchTarball { + inherit url; + sha256 = hash; # FIXME: check nix version & use SRI hashes + }) + else + assert repository.type == "Git"; + let + urlToName = + url: rev: + let + matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url; + + short = builtins.substring 0 7 rev; + + appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else ""; + in + "${if matched == null then "source" else builtins.head matched}${appendShort}"; + name = urlToName repository.url revision; + in + builtins.fetchGit { + url = repository.url; + rev = revision; + inherit name; + # hash = hash; + }; + + mkPyPiSource = + { url, hash, ... }: + builtins.fetchurl { + inherit url; + sha256 = hash; + }; + + mkChannelSource = + { url, hash, ... }: + builtins.fetchTarball { + inherit url; + sha256 = hash; + }; +in +if version == 3 then + builtins.mapAttrs (_: mkSource) data.pins +else + throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/tidepool/npins/sources.json b/tidepool/npins/sources.json new file mode 100644 index 0000000..99ec39b --- /dev/null +++ b/tidepool/npins/sources.json @@ -0,0 +1,16 @@ +{ + "pins": { + "lib": { + "type": "Git", + "repository": { + "type": "Git", + "url": "git+ssh://forgejo@git.auxolotl.org/auxolotl/lib.git" + }, + "branch": "main", + "revision": "7552ab48bb394d59d2bf1f7a558d28ce59da524d", + "url": null, + "hash": "0705fm00k9f95b6idf5qnfvqm4qf1a0cv966ghgd48kd1qy4il5c" + } + }, + "version": 3 +} \ No newline at end of file