diff --git a/lib/README.md b/lib/README.md index a886cf5bfb55..1cf10670ecb2 100644 --- a/lib/README.md +++ b/lib/README.md @@ -36,6 +36,69 @@ The [module system](https://nixos.org/manual/nixpkgs/#module-system) spans multi - [`options.nix`](options.nix): `lib.options` for anything relating to option definitions - [`types.nix`](types.nix): `lib.types` for module system types +## PR Guidelines + +Follow these guidelines for proposing a change to the interface of `lib`. + +### Provide a Motivation + +Clearly describe why the change is necessary and its use cases. + +Make sure that the change benefits the user more than the added mental effort of looking it up and keeping track of its definition. +If the same can reasonably be done with the existing interface, +consider just updating the documentation with more examples and links. +This is also known as the [Fairbairn Threshold](https://wiki.haskell.org/Fairbairn_threshold). + +Through this principle we avoid the human cost of duplicated functionality in an overly large library. + +### Make one PR for each change + +Don't have multiple changes in one PR, instead split it up into multiple ones. + +This keeps the conversation focused and has a higher chance of getting merged. + +### Name the interface appropriately + +When introducing new names to the interface, such as new function, or new function attributes, +make sure to name it appropriately. + +Names should be self-explanatory and consistent with the rest of `lib`. +If there's no obvious best name, include the alternatives you considered. + +### Write documentation + +Update the [reference documentation](#reference-documentation) to reflect the change. + +Be generous with links to related functionality. + +### Write tests + +Add good test coverage for the change, including: + +- Tests for edge cases, such as empty values or lists. +- Tests for tricky inputs, such as a string with string context or a path that doesn't exist. +- Test all code paths, such as `if-then-else` branches and returned attributes. +- If the tests for the sub-library are written in bash, + test messages of custom errors, such as `throw` or `abortMsg`, + + At the time this is only not necessary for sub-libraries tested with [`tests/misc.nix`](./tests/misc.nix). + +See [running tests](#running-tests) for more details on the test suites. + +### Write tidy code + +Name variables well, even if they're internal. +The code should be as self-explanatory as possible. +Be generous with code comments when appropriate. + +As a baseline, follow the [Nixpkgs code conventions](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#code-conventions). + +### Write efficient code + +Nix generally does not have free abstractions. +Be aware that seemingly straightforward changes can cause more allocations and a decrease in performance. +That said, don't optimise prematurely, especially in new code. + ## Reference documentation Reference documentation for library functions is written above each function as a multi-line comment. diff --git a/lib/default.nix b/lib/default.nix index 35e31af364d8..f6c94ae91634 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -120,7 +120,8 @@ let inherit (self.meta) addMetaAttrs dontDistribute setName updateName appendToName mapDerivationAttrset setPrio lowPrio lowPrioSet hiPrio hiPrioSet getLicenseFromSpdxId getExe getExe'; - inherit (self.filesystem) pathType pathIsDirectory pathIsRegularFile; + inherit (self.filesystem) pathType pathIsDirectory pathIsRegularFile + packagesFromDirectoryRecursive; inherit (self.sources) cleanSourceFilter cleanSource sourceByRegex sourceFilesBySuffices commitIdFromGitRepo cleanSourceWith pathHasContext diff --git a/lib/fileset/default.nix b/lib/fileset/default.nix index 18acb9a980ca..c007b60def0a 100644 --- a/lib/fileset/default.nix +++ b/lib/fileset/default.nix @@ -763,6 +763,12 @@ in { Create a file set containing all [Git-tracked files](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) in a repository. The first argument allows configuration with an attribute set, while the second argument is the path to the Git working tree. + + `gitTrackedWith` does not perform any filtering when the path is a [Nix store path](https://nixos.org/manual/nix/stable/store/store-path.html#store-path) and not a repository. + In this way, it accommodates the use case where the expression that makes the `gitTracked` call does not reside in an actual git repository anymore, + and has presumably already been fetched in a way that excludes untracked files. + Fetchers with such equivalent behavior include `builtins.fetchGit`, `builtins.fetchTree` (experimental), and `pkgs.fetchgit` when used without `leaveDotGit`. + If you don't need the configuration, you can use [`gitTracked`](#function-library-lib.fileset.gitTracked) instead. diff --git a/lib/fileset/internal.nix b/lib/fileset/internal.nix index 9de5590d3eff..4059d2e24426 100644 --- a/lib/fileset/internal.nix +++ b/lib/fileset/internal.nix @@ -41,6 +41,8 @@ let inherit (lib.path) append splitRoot + hasStorePathPrefix + splitStorePath ; inherit (lib.path.subpath) @@ -861,28 +863,56 @@ rec { # Type: String -> String -> Path -> Attrs -> FileSet _fromFetchGit = function: argument: path: extraFetchGitAttrs: let - # This imports the files unnecessarily, which currently can't be avoided - # because `builtins.fetchGit` is the only function exposing which files are tracked by Git. - # With the [lazy trees PR](https://github.com/NixOS/nix/pull/6530), - # the unnecessarily import could be avoided. - # However a simpler alternative still would be [a builtins.gitLsFiles](https://github.com/NixOS/nix/issues/2944). - fetchResult = fetchGit ({ - url = path; - } // extraFetchGitAttrs); + # The code path for when isStorePath is true + tryStorePath = + if pathExists (path + "/.git") then + # If there is a `.git` directory in the path, + # it means that the path was imported unfiltered into the Nix store. + # This function should throw in such a case, because + # - `fetchGit` doesn't generally work with `.git` directories in store paths + # - Importing the entire path could include Git-tracked files + throw '' + lib.fileset.${function}: The ${argument} (${toString path}) is a store path within a working tree of a Git repository. + This indicates that a source directory was imported into the store using a method such as `import "''${./.}"` or `path:.`. + This function currently does not support such a use case, since it currently relies on `builtins.fetchGit`. + You could make this work by using a fetcher such as `fetchGit` instead of copying the whole repository. + If you can't avoid copying the repo to the store, see https://github.com/NixOS/nix/issues/9292.'' + else + # Otherwise we're going to assume that the path was a Git directory originally, + # but it was fetched using a method that already removed files not tracked by Git, + # such as `builtins.fetchGit`, `pkgs.fetchgit` or others. + # So we can just import the path in its entirety. + _singleton path; + + # The code path for when isStorePath is false + tryFetchGit = + let + # This imports the files unnecessarily, which currently can't be avoided + # because `builtins.fetchGit` is the only function exposing which files are tracked by Git. + # With the [lazy trees PR](https://github.com/NixOS/nix/pull/6530), + # the unnecessarily import could be avoided. + # However a simpler alternative still would be [a builtins.gitLsFiles](https://github.com/NixOS/nix/issues/2944). + fetchResult = fetchGit ({ + url = path; + } // extraFetchGitAttrs); + in + # We can identify local working directories by checking for .git, + # see https://git-scm.com/docs/gitrepository-layout#_description. + # Note that `builtins.fetchGit` _does_ work for bare repositories (where there's no `.git`), + # even though `git ls-files` wouldn't return any files in that case. + if ! pathExists (path + "/.git") then + throw "lib.fileset.${function}: Expected the ${argument} (${toString path}) to point to a local working tree of a Git repository, but it's not." + else + _mirrorStorePath path fetchResult.outPath; + in - if inPureEvalMode then - throw "lib.fileset.${function}: This function is currently not supported in pure evaluation mode, since it currently relies on `builtins.fetchGit`. See https://github.com/NixOS/nix/issues/9292." - else if ! isPath path then + if ! isPath path then throw "lib.fileset.${function}: Expected the ${argument} to be a path, but it's a ${typeOf path} instead." else if pathType path != "directory" then throw "lib.fileset.${function}: Expected the ${argument} (${toString path}) to be a directory, but it's a file instead." - # We can identify local working directories by checking for .git, - # see https://git-scm.com/docs/gitrepository-layout#_description. - # Note that `builtins.fetchGit` _does_ work for bare repositories (where there's no `.git`), - # even though `git ls-files` wouldn't return any files in that case. - else if ! pathExists (path + "/.git") then - throw "lib.fileset.${function}: Expected the ${argument} (${toString path}) to point to a local working tree of a Git repository, but it's not." + else if hasStorePathPrefix path then + tryStorePath else - _mirrorStorePath path fetchResult.outPath; + tryFetchGit; } diff --git a/lib/fileset/tests.sh b/lib/fileset/tests.sh index d55c4fbfdbeb..e809aef6935a 100755 --- a/lib/fileset/tests.sh +++ b/lib/fileset/tests.sh @@ -43,29 +43,17 @@ crudeUnquoteJSON() { cut -d \" -f2 } -prefixExpression() { - echo 'let - lib = - (import ) - ' - if [[ "${1:-}" == "--simulate-pure-eval" ]]; then - echo ' - .extend (final: prev: { - trivial = prev.trivial // { - inPureEvalMode = true; - }; - })' - fi - echo ' - ; - internal = import { - inherit lib; - }; - in - with lib; - with internal; - with lib.fileset;' -} +prefixExpression=' + let + lib = import ; + internal = import { + inherit lib; + }; + in + with lib; + with internal; + with lib.fileset; +' # Check that two nix expression successfully evaluate to the same value. # The expressions have `lib.fileset` in scope. @@ -74,7 +62,7 @@ expectEqual() { local actualExpr=$1 local expectedExpr=$2 if actualResult=$(nix-instantiate --eval --strict --show-trace 2>"$tmp"/actualStderr \ - --expr "$(prefixExpression) ($actualExpr)"); then + --expr "$prefixExpression ($actualExpr)"); then actualExitCode=$? else actualExitCode=$? @@ -82,7 +70,7 @@ expectEqual() { actualStderr=$(< "$tmp"/actualStderr) if expectedResult=$(nix-instantiate --eval --strict --show-trace 2>"$tmp"/expectedStderr \ - --expr "$(prefixExpression) ($expectedExpr)"); then + --expr "$prefixExpression ($expectedExpr)"); then expectedExitCode=$? else expectedExitCode=$? @@ -110,7 +98,7 @@ expectEqual() { expectStorePath() { local expr=$1 if ! result=$(nix-instantiate --eval --strict --json --read-write-mode --show-trace 2>"$tmp"/stderr \ - --expr "$(prefixExpression) ($expr)"); then + --expr "$prefixExpression ($expr)"); then cat "$tmp/stderr" >&2 die "$expr failed to evaluate, but it was expected to succeed" fi @@ -123,16 +111,10 @@ expectStorePath() { # The expression has `lib.fileset` in scope. # Usage: expectFailure NIX REGEX expectFailure() { - if [[ "$1" == "--simulate-pure-eval" ]]; then - maybePure="--simulate-pure-eval" - shift - else - maybePure="" - fi local expr=$1 local expectedErrorRegex=$2 if result=$(nix-instantiate --eval --strict --read-write-mode --show-trace 2>"$tmp/stderr" \ - --expr "$(prefixExpression $maybePure) $expr"); then + --expr "$prefixExpression $expr"); then die "$expr evaluated successfully to $result, but it was expected to fail" fi stderr=$(<"$tmp/stderr") @@ -149,12 +131,12 @@ expectTrace() { local expectedTrace=$2 nix-instantiate --eval --show-trace >/dev/null 2>"$tmp"/stderrTrace \ - --expr "$(prefixExpression) trace ($expr)" || true + --expr "$prefixExpression trace ($expr)" || true actualTrace=$(sed -n 's/^trace: //p' "$tmp/stderrTrace") nix-instantiate --eval --show-trace >/dev/null 2>"$tmp"/stderrTraceVal \ - --expr "$(prefixExpression) traceVal ($expr)" || true + --expr "$prefixExpression traceVal ($expr)" || true actualTraceVal=$(sed -n 's/^trace: //p' "$tmp/stderrTraceVal") @@ -1331,7 +1313,7 @@ expectFailure 'gitTrackedWith {} ./.' 'lib.fileset.gitTrackedWith: Expected the expectFailure 'gitTrackedWith { recurseSubmodules = null; } ./.' 'lib.fileset.gitTrackedWith: Expected the attribute `recurseSubmodules` of the first argument to be a boolean, but it'\''s a null instead.' # recurseSubmodules = true is not supported on all Nix versions -if [[ "$(nix-instantiate --eval --expr "$(prefixExpression) (versionAtLeast builtins.nixVersion _fetchGitSubmodulesMinver)")" == true ]]; then +if [[ "$(nix-instantiate --eval --expr "$prefixExpression (versionAtLeast builtins.nixVersion _fetchGitSubmodulesMinver)")" == true ]]; then fetchGitSupportsSubmodules=1 else fetchGitSupportsSubmodules= @@ -1401,10 +1383,60 @@ createGitRepo() { git -C "$1" commit -q --allow-empty -m "Empty commit" } -# Check the error message for pure eval mode +# Check that gitTracked[With] works as expected when evaluated out-of-tree + +## First we create a git repositories (and a subrepository) with `default.nix` files referring to their local paths +## Simulating how it would be used in the wild createGitRepo . -expectFailure --simulate-pure-eval 'toSource { root = ./.; fileset = gitTracked ./.; }' 'lib.fileset.gitTracked: This function is currently not supported in pure evaluation mode, since it currently relies on `builtins.fetchGit`. See https://github.com/NixOS/nix/issues/9292.' -expectFailure --simulate-pure-eval 'toSource { root = ./.; fileset = gitTrackedWith {} ./.; }' 'lib.fileset.gitTrackedWith: This function is currently not supported in pure evaluation mode, since it currently relies on `builtins.fetchGit`. See https://github.com/NixOS/nix/issues/9292.' +echo '{ fs }: fs.toSource { root = ./.; fileset = fs.gitTracked ./.; }' > default.nix +git add . + +## We can evaluate it locally just fine, `fetchGit` is used underneath to filter git-tracked files +expectEqual '(import ./. { fs = lib.fileset; }).outPath' '(builtins.fetchGit ./.).outPath' + +## We can also evaluate when importing from fetched store paths +storePath=$(expectStorePath 'builtins.fetchGit ./.') +expectEqual '(import '"$storePath"' { fs = lib.fileset; }).outPath' \""$storePath"\" + +## But it fails if the path is imported with a fetcher that doesn't remove .git (like just using "${./.}") +expectFailure 'import "${./.}" { fs = lib.fileset; }' 'lib.fileset.gitTracked: The argument \(.*\) is a store path within a working tree of a Git repository. +\s*This indicates that a source directory was imported into the store using a method such as `import "\$\{./.\}"` or `path:.`. +\s*This function currently does not support such a use case, since it currently relies on `builtins.fetchGit`. +\s*You could make this work by using a fetcher such as `fetchGit` instead of copying the whole repository. +\s*If you can'\''t avoid copying the repo to the store, see https://github.com/NixOS/nix/issues/9292.' + +## Even with submodules +if [[ -n "$fetchGitSupportsSubmodules" ]]; then + ## Both the main repo with the submodule + echo '{ fs }: fs.toSource { root = ./.; fileset = fs.gitTrackedWith { recurseSubmodules = true; } ./.; }' > default.nix + createGitRepo sub + git submodule add ./sub sub >/dev/null + ## But also the submodule itself + echo '{ fs }: fs.toSource { root = ./.; fileset = fs.gitTracked ./.; }' > sub/default.nix + git -C sub add . + + ## We can evaluate it locally just fine, `fetchGit` is used underneath to filter git-tracked files + expectEqual '(import ./. { fs = lib.fileset; }).outPath' '(builtins.fetchGit { url = ./.; submodules = true; }).outPath' + expectEqual '(import ./sub { fs = lib.fileset; }).outPath' '(builtins.fetchGit ./sub).outPath' + + ## We can also evaluate when importing from fetched store paths + storePathWithSub=$(expectStorePath 'builtins.fetchGit { url = ./.; submodules = true; }') + expectEqual '(import '"$storePathWithSub"' { fs = lib.fileset; }).outPath' \""$storePathWithSub"\" + storePathSub=$(expectStorePath 'builtins.fetchGit ./sub') + expectEqual '(import '"$storePathSub"' { fs = lib.fileset; }).outPath' \""$storePathSub"\" + + ## But it fails if the path is imported with a fetcher that doesn't remove .git (like just using "${./.}") + expectFailure 'import "${./.}" { fs = lib.fileset; }' 'lib.fileset.gitTrackedWith: The second argument \(.*\) is a store path within a working tree of a Git repository. + \s*This indicates that a source directory was imported into the store using a method such as `import "\$\{./.\}"` or `path:.`. + \s*This function currently does not support such a use case, since it currently relies on `builtins.fetchGit`. + \s*You could make this work by using a fetcher such as `fetchGit` instead of copying the whole repository. + \s*If you can'\''t avoid copying the repo to the store, see https://github.com/NixOS/nix/issues/9292.' + expectFailure 'import "${./.}/sub" { fs = lib.fileset; }' 'lib.fileset.gitTracked: The argument \(.*/sub\) is a store path within a working tree of a Git repository. + \s*This indicates that a source directory was imported into the store using a method such as `import "\$\{./.\}"` or `path:.`. + \s*This function currently does not support such a use case, since it currently relies on `builtins.fetchGit`. + \s*You could make this work by using a fetcher such as `fetchGit` instead of copying the whole repository. + \s*If you can'\''t avoid copying the repo to the store, see https://github.com/NixOS/nix/issues/9292.' +fi rm -rf -- * # Go through all stages of Git files diff --git a/lib/filesystem.nix b/lib/filesystem.nix index 5569b8ac80fd..c416db02eb57 100644 --- a/lib/filesystem.nix +++ b/lib/filesystem.nix @@ -9,11 +9,22 @@ let inherit (builtins) readDir pathExists + toString + ; + + inherit (lib.attrsets) + mapAttrs' + filterAttrs ; inherit (lib.filesystem) pathType ; + + inherit (lib.strings) + hasSuffix + removeSuffix + ; in { @@ -154,4 +165,147 @@ in dir + "/${name}" ) (builtins.readDir dir)); + /* + Transform a directory tree containing package files suitable for + `callPackage` into a matching nested attribute set of derivations. + + For a directory tree like this: + + ``` + my-packages + ├── a.nix + ├── b.nix + ├── c + │ ├── my-extra-feature.patch + │ ├── package.nix + │ └── support-definitions.nix + └── my-namespace + ├── d.nix + ├── e.nix + └── f + └── package.nix + ``` + + `packagesFromDirectoryRecursive` will produce an attribute set like this: + + ```nix + # packagesFromDirectoryRecursive { + # callPackage = pkgs.callPackage; + # directory = ./my-packages; + # } + { + a = pkgs.callPackage ./my-packages/a.nix { }; + b = pkgs.callPackage ./my-packages/b.nix { }; + c = pkgs.callPackage ./my-packages/c/package.nix { }; + my-namespace = { + d = pkgs.callPackage ./my-packages/my-namespace/d.nix { }; + e = pkgs.callPackage ./my-packages/my-namespace/e.nix { }; + f = pkgs.callPackage ./my-packages/my-namespace/f/package.nix { }; + }; + } + ``` + + In particular: + - If the input directory contains a `package.nix` file, then + `callPackage /package.nix { }` is returned. + - Otherwise, the input directory's contents are listed and transformed into + an attribute set. + - If a file name has the `.nix` extension, it is turned into attribute + where: + - The attribute name is the file name without the `.nix` extension + - The attribute value is `callPackage { }` + - Other files are ignored. + - Directories are turned into an attribute where: + - The attribute name is the name of the directory + - The attribute value is the result of calling + `packagesFromDirectoryRecursive { ... }` on the directory. + + As a result, directories with no `.nix` files (including empty + directories) will be transformed into empty attribute sets. + + Example: + packagesFromDirectoryRecursive { + inherit (pkgs) callPackage; + directory = ./my-packages; + } + => { ... } + + lib.makeScope pkgs.newScope ( + self: packagesFromDirectoryRecursive { + callPackage = self.callPackage; + directory = ./my-packages; + } + ) + => { ... } + + Type: + packagesFromDirectoryRecursive :: AttrSet -> AttrSet + */ + packagesFromDirectoryRecursive = + # Options. + { + /* + `pkgs.callPackage` + + Type: + Path -> AttrSet -> a + */ + callPackage, + /* + The directory to read package files from + + Type: + Path + */ + directory, + ... + }: + let + # Determine if a directory entry from `readDir` indicates a package or + # directory of packages. + directoryEntryIsPackage = basename: type: + type == "directory" || hasSuffix ".nix" basename; + + # List directory entries that indicate packages in the given `path`. + packageDirectoryEntries = path: + filterAttrs directoryEntryIsPackage (readDir path); + + # Transform a directory entry (a `basename` and `type` pair) into a + # package. + directoryEntryToAttrPair = subdirectory: basename: type: + let + path = subdirectory + "/${basename}"; + in + if type == "regular" + then + { + name = removeSuffix ".nix" basename; + value = callPackage path { }; + } + else + if type == "directory" + then + { + name = basename; + value = packagesFromDirectory path; + } + else + throw + '' + lib.filesystem.packagesFromDirectoryRecursive: Unsupported file type ${type} at path ${toString subdirectory} + ''; + + # Transform a directory into a package (if there's a `package.nix`) or + # set of packages (otherwise). + packagesFromDirectory = path: + let + defaultPackagePath = path + "/package.nix"; + in + if pathExists defaultPackagePath + then callPackage defaultPackagePath { } + else mapAttrs' + (directoryEntryToAttrPair path) + (packageDirectoryEntries path); + in + packagesFromDirectory directory; } diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 2884e880e13a..cf7fa9f2e284 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -2055,4 +2055,37 @@ runTests { expr = meta.platformMatch { } "x86_64-linux"; expected = false; }; + + testPackagesFromDirectoryRecursive = { + expr = packagesFromDirectoryRecursive { + callPackage = path: overrides: import path overrides; + directory = ./packages-from-directory; + }; + expected = { + a = "a"; + b = "b"; + # Note: Other files/directories in `./test-data/c/` are ignored and can be + # used by `package.nix`. + c = "c"; + my-namespace = { + d = "d"; + e = "e"; + f = "f"; + my-sub-namespace = { + g = "g"; + h = "h"; + }; + }; + }; + }; + + # Check that `packagesFromDirectoryRecursive` can process a directory with a + # top-level `package.nix` file into a single package. + testPackagesFromDirectoryRecursiveTopLevelPackageNix = { + expr = packagesFromDirectoryRecursive { + callPackage = path: overrides: import path overrides; + directory = ./packages-from-directory/c; + }; + expected = "c"; + }; } diff --git a/lib/tests/packages-from-directory/a.nix b/lib/tests/packages-from-directory/a.nix new file mode 100644 index 000000000000..54f9eafd8e87 --- /dev/null +++ b/lib/tests/packages-from-directory/a.nix @@ -0,0 +1,2 @@ +{ }: +"a" diff --git a/lib/tests/packages-from-directory/b.nix b/lib/tests/packages-from-directory/b.nix new file mode 100644 index 000000000000..345b3c25fa2a --- /dev/null +++ b/lib/tests/packages-from-directory/b.nix @@ -0,0 +1,2 @@ +{ }: +"b" diff --git a/lib/tests/packages-from-directory/c/my-extra-feature.patch b/lib/tests/packages-from-directory/c/my-extra-feature.patch new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/tests/packages-from-directory/c/not-a-namespace/not-a-package.nix b/lib/tests/packages-from-directory/c/not-a-namespace/not-a-package.nix new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/tests/packages-from-directory/c/package.nix b/lib/tests/packages-from-directory/c/package.nix new file mode 100644 index 000000000000..c1203cdde960 --- /dev/null +++ b/lib/tests/packages-from-directory/c/package.nix @@ -0,0 +1,2 @@ +{ }: +"c" diff --git a/lib/tests/packages-from-directory/c/support-definitions.nix b/lib/tests/packages-from-directory/c/support-definitions.nix new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/tests/packages-from-directory/my-namespace/d.nix b/lib/tests/packages-from-directory/my-namespace/d.nix new file mode 100644 index 000000000000..6e5eaa09e995 --- /dev/null +++ b/lib/tests/packages-from-directory/my-namespace/d.nix @@ -0,0 +1,2 @@ +{ }: +"d" diff --git a/lib/tests/packages-from-directory/my-namespace/e.nix b/lib/tests/packages-from-directory/my-namespace/e.nix new file mode 100644 index 000000000000..50bd742f800c --- /dev/null +++ b/lib/tests/packages-from-directory/my-namespace/e.nix @@ -0,0 +1,2 @@ +{ }: +"e" diff --git a/lib/tests/packages-from-directory/my-namespace/f/package.nix b/lib/tests/packages-from-directory/my-namespace/f/package.nix new file mode 100644 index 000000000000..c9a66c2eb120 --- /dev/null +++ b/lib/tests/packages-from-directory/my-namespace/f/package.nix @@ -0,0 +1,2 @@ +{ }: +"f" diff --git a/lib/tests/packages-from-directory/my-namespace/my-sub-namespace/g.nix b/lib/tests/packages-from-directory/my-namespace/my-sub-namespace/g.nix new file mode 100644 index 000000000000..4ecaffbf1dc7 --- /dev/null +++ b/lib/tests/packages-from-directory/my-namespace/my-sub-namespace/g.nix @@ -0,0 +1,2 @@ +{ }: +"g" diff --git a/lib/tests/packages-from-directory/my-namespace/my-sub-namespace/h.nix b/lib/tests/packages-from-directory/my-namespace/my-sub-namespace/h.nix new file mode 100644 index 000000000000..3756275ba752 --- /dev/null +++ b/lib/tests/packages-from-directory/my-namespace/my-sub-namespace/h.nix @@ -0,0 +1,2 @@ +{ }: +"h" diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix index 7b00ce35eb1a..40219edcd447 100644 --- a/nixos/modules/services/web-apps/mastodon.nix +++ b/nixos/modules/services/web-apps/mastodon.nix @@ -711,31 +711,28 @@ in { systemd.services.mastodon-init-db = lib.mkIf cfg.automaticMigrations { script = lib.optionalString (!databaseActuallyCreateLocally) '' umask 077 - - export PGPASSFILE - PGPASSFILE=$(mktemp) - cat > $PGPASSFILE <espanso" "${placeholder "out"}/Applications/Espanso.app/Contents/MacOS/espanso" diff --git a/pkgs/applications/science/biology/last/default.nix b/pkgs/applications/science/biology/last/default.nix index 607b1ee51cc5..ed8690cd9c85 100644 --- a/pkgs/applications/science/biology/last/default.nix +++ b/pkgs/applications/science/biology/last/default.nix @@ -9,13 +9,13 @@ stdenv.mkDerivation rec { pname = "last"; - version = "1518"; + version = "1519"; src = fetchFromGitLab { owner = "mcfrith"; repo = "last"; rev = "refs/tags/${version}"; - hash = "sha256-a6i5BfJhVHkXTLd7SVFxISEB+Kwl7BhjUUkF8ItMOak="; + hash = "sha256-659YiC7NA6ottOR41jo3ayh4lwReWj46NKMhMPuebF4="; }; nativeBuildInputs = [ diff --git a/pkgs/development/embedded/platformio/core.nix b/pkgs/development/embedded/platformio/core.nix index 82ccfa41c2f0..aa4e8e9600f6 100644 --- a/pkgs/development/embedded/platformio/core.nix +++ b/pkgs/development/embedded/platformio/core.nix @@ -2,6 +2,7 @@ , python3Packages , fetchFromGitHub , fetchpatch +, installShellFiles , git , spdx-license-list-data , substituteAll @@ -43,6 +44,7 @@ with python3Packages; buildPythonApplication rec { ]; nativeBuildInputs = [ + installShellFiles pythonRelaxDepsHook setuptools ]; @@ -88,6 +90,16 @@ with python3Packages; buildPythonApplication rec { postInstall = '' mkdir -p $udev/lib/udev/rules.d cp platformio/assets/system/99-platformio-udev.rules $udev/lib/udev/rules.d/99-platformio-udev.rules + + installShellCompletion --cmd platformio \ + --bash <(_PLATFORMIO_COMPLETE=bash_source $out/bin/platformio) \ + --zsh <(_PLATFORMIO_COMPLETE=zsh_source $out/bin/platformio) \ + --fish <(_PLATFORMIO_COMPLETE=fish_source $out/bin/platformio) + + installShellCompletion --cmd pio \ + --bash <(_PIO_COMPLETE=bash_source $out/bin/pio) \ + --zsh <(_PIO_COMPLETE=zsh_source $out/bin/pio) \ + --fish <(_PIO_COMPLETE=fish_source $out/bin/pio) ''; disabledTestPaths = [ @@ -186,5 +198,6 @@ with python3Packages; buildPythonApplication rec { homepage = "https://platformio.org"; license = licenses.asl20; maintainers = with maintainers; [ mog makefu ]; + mainProgram = "platformio"; }; } diff --git a/pkgs/development/python-modules/anova-wifi/default.nix b/pkgs/development/python-modules/anova-wifi/default.nix new file mode 100644 index 000000000000..b6f885daf619 --- /dev/null +++ b/pkgs/development/python-modules/anova-wifi/default.nix @@ -0,0 +1,59 @@ +{ lib +, buildPythonPackage +, fetchFromGitHub +, pythonOlder +, poetry-core +, aiohttp +, sensor-state-data +, pytestCheckHook +, pytest-asyncio +}: + +buildPythonPackage rec { + pname = "anova-wifi"; + version = "0.10.3"; + pyproject = true; + + disabled = pythonOlder "3.10"; + + src = fetchFromGitHub { + owner = "Lash-L"; + repo = "anova_wifi"; + rev = "refs/tags/v${version}"; + hash = "sha256-tCmvp29KSCkc+g0w0odcB7vGjtDx6evac7XsHEF0syM="; + }; + + postPatch = '' + substituteInPlace pyproject.toml \ + --replace "--cov=anova_wifi --cov-report=term-missing:skip-covered" "" + ''; + + nativeBuildInputs = [ + poetry-core + ]; + + propagatedBuildInputs = [ + aiohttp + sensor-state-data + ]; + + nativeCheckInputs = [ + pytestCheckHook + pytest-asyncio + ]; + + disabledTests = [ + # Makes network calls + "test_async_data_1" + ]; + + pythonImportsCheck = [ "anova_wifi" ]; + + meta = with lib; { + description = "A Python package for reading anova sous vide api data"; + homepage = "https://github.com/Lash-L/anova_wifi"; + changelog = "https://github.com/Lash-L/anova_wifi/releases/tag/v${version}"; + maintainers = with maintainers; [ jamiemagee ]; + license = licenses.mit; + }; +} diff --git a/pkgs/development/python-modules/asyncssh/default.nix b/pkgs/development/python-modules/asyncssh/default.nix index f499adc7bb1e..735e831c0324 100644 --- a/pkgs/development/python-modules/asyncssh/default.nix +++ b/pkgs/development/python-modules/asyncssh/default.nix @@ -20,14 +20,14 @@ buildPythonPackage rec { pname = "asyncssh"; - version = "2.14.1"; + version = "2.14.2"; format = "setuptools"; disabled = pythonOlder "3.6"; src = fetchPypi { inherit pname version; - hash = "sha256-GsMcMzoNg8iIMVIyRVAMqoFFA0I3QbDkZTOe9tpbXik="; + hash = "sha256-6Va/iYjQega6MwX2YE4mH0ygFMSiMvCHPxx2kvvjz8I="; }; propagatedBuildInputs = [ diff --git a/pkgs/development/python-modules/findpython/default.nix b/pkgs/development/python-modules/findpython/default.nix index 9a9bd93fc745..7ada2d813dd4 100644 --- a/pkgs/development/python-modules/findpython/default.nix +++ b/pkgs/development/python-modules/findpython/default.nix @@ -15,7 +15,7 @@ let pname = "findpython"; - version = "0.4.0"; + version = "0.4.1"; in buildPythonPackage { inherit pname version; @@ -25,7 +25,7 @@ buildPythonPackage { src = fetchPypi { inherit pname version; - hash = "sha256-GLFNEVZ42hiuku4i1wAcwwkV6lMQU/dwEO4Fo5aA9Dg="; + hash = "sha256-19AUVYaBs3YdV6WyNCpxOovzAvbB/J2Z+Budi9FoGwQ="; }; nativeBuildInputs = [ diff --git a/pkgs/development/python-modules/fschat/default.nix b/pkgs/development/python-modules/fschat/default.nix index 44420ae6c61f..1d99fcd3e4cc 100644 --- a/pkgs/development/python-modules/fschat/default.nix +++ b/pkgs/development/python-modules/fschat/default.nix @@ -29,7 +29,7 @@ , protobuf }: let - version = "0.2.33"; + version = "0.2.34"; in buildPythonPackage { pname = "fschat"; @@ -40,7 +40,7 @@ buildPythonPackage { owner = "lm-sys"; repo = "FastChat"; rev = "refs/tags/v${version}"; - hash = "sha256-tfFgiYJBuVt71qHOmkDoSrZ2tvXStjubmkw7sexkGZg="; + hash = "sha256-4dnKrLQYkd2uQh2K2yaQ7EgrkgX8bO4QXfjIOqpzCE8="; }; nativeBuildInputs = [ diff --git a/pkgs/development/python-modules/icalevents/default.nix b/pkgs/development/python-modules/icalevents/default.nix new file mode 100644 index 000000000000..f8f211b65993 --- /dev/null +++ b/pkgs/development/python-modules/icalevents/default.nix @@ -0,0 +1,59 @@ +{ lib +, buildPythonPackage +, fetchFromGitHub +, pythonOlder +, pytestCheckHook +, poetry-core +, datetime +, httplib2 +, icalendar +, python-dateutil +, pytz +}: + +buildPythonPackage rec { + pname = "icalevents"; + version = "0.1.27"; + pyproject = true; + + disabled = pythonOlder "3.9"; + + src = fetchFromGitHub { + owner = "jazzband"; + repo = pname; + rev = "refs/tags/v${version}"; + hash = "sha256-vSYQEJFBjXUF4WwEAtkLtcO3y/am00jGS+8Vj+JMMqQ="; + }; + + nativeBuildInputs = [ + poetry-core + ]; + + propagatedBuildInputs = [ + datetime + httplib2 + icalendar + python-dateutil + pytz + ]; + + nativeCheckInputs = [ + pytestCheckHook + ]; + + disabledTests = [ + # Makes HTTP calls + "test_events_url" + "test_events_async_url" + ]; + + pythonImportsCheck = [ "icalevents" ]; + + meta = with lib; { + changelog = "https://github.com/jazzband/icalevents/releases/tag/v${version}"; + description = "Python module for iCal URL/file parsing and querying"; + homepage = "https://github.com/jazzband/icalevents"; + maintainers = with maintainers; [ jamiemagee ]; + license = licenses.mit; + }; +} diff --git a/pkgs/development/python-modules/python-didl-lite/default.nix b/pkgs/development/python-modules/python-didl-lite/default.nix index bd19b5f827c6..aaa546730844 100644 --- a/pkgs/development/python-modules/python-didl-lite/default.nix +++ b/pkgs/development/python-modules/python-didl-lite/default.nix @@ -4,21 +4,27 @@ , pythonOlder , defusedxml , pytestCheckHook +, setuptools }: buildPythonPackage rec { pname = "python-didl-lite"; - version = "1.3.2"; - format = "setuptools"; - disabled = pythonOlder "3.5.3"; + version = "1.4.0"; + pyroject = true; + + disabled = pythonOlder "3.8"; src = fetchFromGitHub { owner = "StevenLooman"; - repo = pname; - rev = version; - hash = "sha256-laKmWGDEzlBVJCUSKxekjPEXVlAz4MIzM7dNJfta/ek="; + repo = "python-didl-lite"; + rev = "refs/tags/${version}"; + hash = "sha256-A+G97T/udyL/yRqykq1sEGDEI6ZwtDBc5xUNFiJp0UQ="; }; + nativeBuildInputs = [ + setuptools + ]; + propagatedBuildInputs = [ defusedxml ]; @@ -27,11 +33,14 @@ buildPythonPackage rec { pytestCheckHook ]; - pythonImportsCheck = [ "didl_lite" ]; + pythonImportsCheck = [ + "didl_lite" + ]; meta = with lib; { description = "DIDL-Lite (Digital Item Declaration Language) tools for Python"; homepage = "https://github.com/StevenLooman/python-didl-lite"; + changelog = "https://github.com/StevenLooman/python-didl-lite/blob/${version}/CHANGES.rst"; license = licenses.asl20; maintainers = with maintainers; [ hexa ]; }; diff --git a/pkgs/development/r-modules/default.nix b/pkgs/development/r-modules/default.nix index 4f7bdd92477e..a7489afd30a0 100644 --- a/pkgs/development/r-modules/default.nix +++ b/pkgs/development/r-modules/default.nix @@ -1387,6 +1387,13 @@ let ''; }); + tesseract = old.tesseract.overrideAttrs (_: { + preConfigure = '' + substituteInPlace configure \ + --replace 'PKG_CONFIG_NAME="tesseract"' 'PKG_CONFIG_NAME="tesseract lept"' + ''; + }); + ijtiff = old.ijtiff.overrideAttrs (_: { preConfigure = '' patchShebangs configure diff --git a/pkgs/development/tools/sqlboiler/default.nix b/pkgs/development/tools/sqlboiler/default.nix index c3026d072498..432582dbc46e 100644 --- a/pkgs/development/tools/sqlboiler/default.nix +++ b/pkgs/development/tools/sqlboiler/default.nix @@ -5,16 +5,16 @@ buildGoModule rec { pname = "sqlboiler"; - version = "4.14.2"; + version = "4.15.0"; src = fetchFromGitHub { owner = "volatiletech"; repo = "sqlboiler"; rev = "refs/tags/v${version}"; - hash = "sha256-d3SML1cm+daYU5dEuwSXSsKwsJHxGuOEbwCvYfsMcFI="; + hash = "sha256-MT1tjVCDaFB9HfjlGGnf6jTiPdKcrDamgp2nTpIarqY="; }; - vendorHash = "sha256-/z5l+tgQuYBZ0A99A8CoTuqTSfnM52R43ppFrooRgOM="; + vendorHash = "sha256-tZ1RQGmeDv4rtdF1WTRQV1K4Xy1AgIatLPPexnHJnkA="; tags = [ "mysql" diff --git a/pkgs/games/path-of-building/default.nix b/pkgs/games/path-of-building/default.nix index baa10d462862..c8265d13b1a8 100644 --- a/pkgs/games/path-of-building/default.nix +++ b/pkgs/games/path-of-building/default.nix @@ -2,13 +2,13 @@ let data = stdenv.mkDerivation(finalAttrs: { pname = "path-of-building-data"; - version = "2.38.2"; + version = "2.38.3"; src = fetchFromGitHub { owner = "PathOfBuildingCommunity"; repo = "PathOfBuilding"; rev = "v${finalAttrs.version}"; - hash = "sha256-WgnYjG47E5p0R5MXlDXN8sbh0Y9E8cZN0gMSdkHpXfw="; + hash = "sha256-LzNHc6lx0d+Hg0qkOb9G50V5pYOxH7eavQdcAXE5EKI="; }; nativeBuildInputs = [ unzip ]; diff --git a/pkgs/servers/home-assistant/component-packages.nix b/pkgs/servers/home-assistant/component-packages.nix index 31a389b98200..e9d881978dbd 100644 --- a/pkgs/servers/home-assistant/component-packages.nix +++ b/pkgs/servers/home-assistant/component-packages.nix @@ -169,7 +169,8 @@ anel-pwrctrl-homeassistant ]; "anova" = ps: with ps; [ - ]; # missing inputs: anova-wifi + anova-wifi + ]; "anthemav" = ps: with ps; [ anthemav ]; diff --git a/pkgs/servers/home-assistant/custom-components/default.nix b/pkgs/servers/home-assistant/custom-components/default.nix index fe1c39487903..310b4592b20f 100644 --- a/pkgs/servers/home-assistant/custom-components/default.nix +++ b/pkgs/servers/home-assistant/custom-components/default.nix @@ -9,4 +9,6 @@ miele = callPackage ./miele {}; prometheus_sensor = callPackage ./prometheus_sensor {}; + + waste_collection_schedule = callPackage ./waste_collection_schedule {}; } diff --git a/pkgs/servers/home-assistant/custom-components/waste_collection_schedule/default.nix b/pkgs/servers/home-assistant/custom-components/waste_collection_schedule/default.nix new file mode 100644 index 000000000000..513d593ce51d --- /dev/null +++ b/pkgs/servers/home-assistant/custom-components/waste_collection_schedule/default.nix @@ -0,0 +1,47 @@ +{ lib +, buildHomeAssistantComponent +, fetchFromGitHub +, fetchpatch +, beautifulsoup4 +, icalendar +, icalevents +, lxml +, recurring-ical-events +}: + +buildHomeAssistantComponent rec { + owner = "mampfes"; + domain = "waste_collection_schedule"; + version = "1.44.0"; + + src = fetchFromGitHub { + inherit owner; + repo = "hacs_${domain}"; + rev = "refs/tags/${version}"; + hash = "sha256-G1x7HtgdtK+IaPAfxT+7xsDJi5FnXN4Pg3q7T5Xr8lA="; + }; + + patches = [ + # Corrects a dependency on beautifulsoup4 + (fetchpatch { + url = "https://github.com/mampfes/hacs_waste_collection_schedule/pull/1515.patch"; + hash = "sha256-dvmicKTjolEcCrKRtZfpN0M/9RQCEQkFk+M6E+qCqfQ="; + }) + ]; + + propagatedBuildInputs = [ + beautifulsoup4 + icalendar + icalevents + lxml + recurring-ical-events + ]; + + meta = with lib; { + changelog = "https://github.com/mampfes/hacs_waste_collection_schedule/releases/tag/${version}"; + description = "Home Assistant integration framework for (garbage collection) schedules"; + homepage = "https://github.com/mampfes/hacs_waste_collection_schedule"; + maintainers = with maintainers; [jamiemagee]; + license = licenses.mit; + }; +} diff --git a/pkgs/servers/monitoring/prometheus/collectd-exporter.nix b/pkgs/servers/monitoring/prometheus/collectd-exporter.nix index 8b842b7ce3da..1ff0ad38f47a 100644 --- a/pkgs/servers/monitoring/prometheus/collectd-exporter.nix +++ b/pkgs/servers/monitoring/prometheus/collectd-exporter.nix @@ -2,16 +2,16 @@ buildGoModule rec { pname = "collectd-exporter"; - version = "0.5.0"; + version = "0.6.0"; src = fetchFromGitHub { owner = "prometheus"; repo = "collectd_exporter"; rev = "v${version}"; - sha256 = "0vb6vnd2j87iqxdl86j30dk65vrv4scprv200xb83203aprngqgh"; + sha256 = "sha256-8oibunEHPtNdbhVgF3CL6D/xE7bR8hee6+D2IJMzaqY="; }; - vendorHash = null; + vendorHash = "sha256-fQO2fiotqv18xewXVyh6sA4zx5ZNUR6mCebYenryrKI="; ldflags = [ "-s" "-w" ]; diff --git a/pkgs/servers/monitoring/prometheus/mysqld-exporter.nix b/pkgs/servers/monitoring/prometheus/mysqld-exporter.nix index f0d2ac078274..2e2bead90b35 100644 --- a/pkgs/servers/monitoring/prometheus/mysqld-exporter.nix +++ b/pkgs/servers/monitoring/prometheus/mysqld-exporter.nix @@ -2,16 +2,16 @@ buildGoModule rec { pname = "mysqld_exporter"; - version = "0.15.0"; + version = "0.15.1"; src = fetchFromGitHub { owner = "prometheus"; repo = "mysqld_exporter"; rev = "v${version}"; - sha256 = "sha256-LW9vH//TjnKbZGMF3owDSUx/Mu0TUuWxMtmdeKM/q7k="; + sha256 = "sha256-P7EoWa0BWuAr3sjtrUxzofwlklhRLpzwpGVe31hFo7Q="; }; - vendorHash = "sha256-8zoiYSW8/z1Ch5W1WJHbWAPKFUOhUT8YcjrvyhwI+8w="; + vendorHash = "sha256-GEL9sMwwdGqpklm4yKNqzSOM6I/JzZjg3+ZB2ix2M8w="; ldflags = let t = "github.com/prometheus/common/version"; in [ "-s" "-w" diff --git a/pkgs/tools/networking/ooniprobe-cli/default.nix b/pkgs/tools/networking/ooniprobe-cli/default.nix index b677b1d1ca01..a3c4c64a1097 100644 --- a/pkgs/tools/networking/ooniprobe-cli/default.nix +++ b/pkgs/tools/networking/ooniprobe-cli/default.nix @@ -5,16 +5,16 @@ buildGoModule rec { pname = "ooniprobe-cli"; - version = "3.19.1"; + version = "3.20.0"; src = fetchFromGitHub { owner = "ooni"; repo = "probe-cli"; rev = "v${version}"; - hash = "sha256-sYIp5zl49waERfTYPfNjbyzep7p4sRlweDVcuTtWB28="; + hash = "sha256-kOARV3tnRyOAScc3Vn96TFQFgqvTgi6NFHWM7ZbpciU="; }; - vendorHash = "sha256-6RyK0oy9Lcuh2TXpQqAqmrA+bS9hug6+il7L1z+kYvs="; + vendorHash = "sha256-c922VpxtpNfua3Sx3vXKz4x1FsLMwbaSvRH4dyFrr9s="; subPackages = [ "cmd/ooniprobe" ]; diff --git a/pkgs/tools/security/trufflehog/default.nix b/pkgs/tools/security/trufflehog/default.nix index fcaf193e3261..75cfe23552f5 100644 --- a/pkgs/tools/security/trufflehog/default.nix +++ b/pkgs/tools/security/trufflehog/default.nix @@ -7,16 +7,16 @@ buildGoModule rec { pname = "trufflehog"; - version = "3.63.1"; + version = "3.63.4"; src = fetchFromGitHub { owner = "trufflesecurity"; repo = "trufflehog"; rev = "refs/tags/v${version}"; - hash = "sha256-YZH3f5m/7RFf8acmDCw4wQY6LgI98I+5kTIwEFkTwiI="; + hash = "sha256-z99p3VecDsxtEr6bdu1qFyADn/NvJZurZMVunqv4YD4="; }; - vendorHash = "sha256-+Boe/bzCsmihspGqmiJ3jOcRJ9KPjkzu6MBmgtAgwjE="; + vendorHash = "sha256-LDDb00Vc+zeq25ArrG9/KD4SKXKfXJGljyLMUmw8owc="; ldflags = [ "-s" diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 6ec2f1204846..29bad9f62b31 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -554,6 +554,8 @@ self: super: with self; { anonip = callPackage ../development/python-modules/anonip { }; + anova-wifi = callPackage ../development/python-modules/anova-wifi { }; + ansi2html = callPackage ../development/python-modules/ansi2html { }; ansi2image = callPackage ../development/python-modules/ansi2image { }; @@ -5347,6 +5349,8 @@ self: super: with self; { icalendar = callPackage ../development/python-modules/icalendar { }; + icalevents = callPackage ../development/python-modules/icalevents { }; + icecream = callPackage ../development/python-modules/icecream { }; iceportal = callPackage ../development/python-modules/iceportal { };