Change:
Currently, using in a local project fails when that project is fetched with e.g. , since there's no directory in that case. With Detect whether the passed path is already in the Nix store, in which case just return the set of all its files. Only fail if that's not the case. A bit icky but might be fine? Needs a bit more thought. This issue is sponsored by :sparkles:
I opened a draft PR which will fix this:
How about (also) printing out a message when directory isn't found? That would be similar to the but at eval time. The down side might be repetition of this message whenever one of whenever the expression gets evaluated.
Yeah I think that would be too noisy. Warnings/traces should only be displayed if it's actually something potentially dangerous that the user should know. But in this case, with how the above PR is implemented, it should be reasonably safe to not need that.

Discussion:
_printFileset _intersection _difference <del> _mirrorStorePath </del> <ins> _fromFetchGit </ins> _fetchGitSubmodulesMinver _emptyWithoutBase ;

inherit (lib.trivial) isFunction pipe <del> inPureEvalMode </del> ; in {

This directory must contain a `.git` file or subdirectory. */ path: <del> # See the gitTrackedWith implementation for more explanatory comments let fetchResult = builtins.fetchGit path; in if inPureEvalMode then throw "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." else if ! isPath path then throw "lib.fileset.gitTracked: Expected the argument to be a path, but it's a ${typeOf path} instead." else if ! pathExists (path + "/.git") then throw "lib.fileset.gitTracked: 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; </del> <ins> _fromFetchGit "gitTracked" "argument" path {}; </ins> /* 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.

This directory must contain a `.git` file or subdirectory. */ path: <del> 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 = builtins.fetchGit { url = path; # This is the only `fetchGit` parameter that makes sense in this context. # We can't just pass `submodules = recurseSubmodules` here because # this would fail for Nix versions that don't support `submodules`. ${if recurseSubmodules then "submodules" else null} = true; }; in if inPureEvalMode then throw "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." else if ! isBool recurseSubmodules then </del> <ins> if ! isBool recurseSubmodules then </ins> throw "lib.fileset.gitTrackedWith: Expected the attribute `recurseSubmodules` of the first argument to be a boolean, but it's a ${typeOf recurseSubmodules} instead." else if recurseSubmodules && versionOlder nixVersion _fetchGitSubmodulesMinver then throw "lib.fileset.gitTrackedWith: Setting the attribute `recurseSubmodules` to `true` is only supported for Nix version ${_fetchGitSubmodulesMinver} and after, but Nix version ${nixVersion} is used." <del> else if ! isPath path then throw "lib.fileset.gitTrackedWith: Expected the second argument to be a path, but it's a ${typeOf path} 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.gitTrackedWith: Expected the second argument (${toString path}) to point to a local working tree of a Git repository, but it's not." </del> else <del> _mirrorStorePath path fetchResult.outPath; </del> <ins> _fromFetchGit "gitTrackedWith" "second argument" path # This is the only `fetchGit` parameter that makes sense in this context. # We can't just pass `submodules = recurseSubmodules` here because # this would fail for Nix versions that don't support `submodules`. (lib.optionalAttrs recurseSubmodules { submodules = true; }); </ins> }

split trace typeOf <ins> fetchGit </ins> ; inherit (lib.attrsets)

hasSuffix ; <ins> inherit (lib.trivial) inPureEvalMode ; </ins> in # Rare case of justified usage of rec: # - This file is internal, so the return value doesn't matter, no need to make things overridable

in _create localPath (recurse storePath); <ins> # Create a file set from the files included in the result of a fetchGit call # 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); 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 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 _mirrorStorePath path fetchResult.outPath; </ins> }

expectFailure 'gitTracked null' 'lib.fileset.gitTracked: Expected the argument to be a path, but it'''s a null instead.' expectFailure 'gitTrackedWith {} null' 'lib.fileset.gitTrackedWith: Expected the second argument to be a path, but it'''s a null instead.' <ins> # The path must be a directory touch a expectFailure 'gitTracked ./a' 'lib.fileset.gitTracked: Expected the argument ('"$work"'/a) to be a directory, but it'''s a file instead' expectFailure 'gitTrackedWith {} ./a' 'lib.fileset.gitTrackedWith: Expected the second argument ('"$work"'/a) to be a directory, but it'''s a file instead' rm -rf -- * </ins> # The path has to contain a .git directory expectFailure 'gitTracked ./.' 'lib.fileset.gitTracked: Expected the argument ('"$work"') to point to a local working tree of a Git repository, but it'''s not.' expectFailure 'gitTrackedWith {} ./.' 'lib.fileset.gitTrackedWith: Expected the second argument ('"$work"') to point to a local working tree of a Git repository, but it'''s not.'