-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
source combinators: extend, trace, cutAt, focusAt and more #112083
Closed
Closed
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
2981160
lib/tests/property-test.nix: init
roberth d0d5abf
lib.filesystem.pathHasPrefix: init
roberth 66bc292
lib.filesystem.{commonPath,absolutePathComponentsBetween}: init
roberth b5cbaa5
lib.sources.setName: init
roberth 452eaf3
lib.sources.union: init
roberth e1a863c
lib.sources.filter: init
roberth 802f842
lib.sources.extend: init
roberth 984a9df
lib.sources.union: Make private
roberth bfeae60
lib.sources: Subpaths and extend with parent files
roberth d8e53d0
lib.sources.cutAt: init
roberth 6c923fa
WIP stdenv.mkDerivation: Support sources with subpath
roberth 2ecbff2
lib.sources: Generate docs and sanitize source name
roberth 11ff33e
lib.sources: Rewrite extend to be more efficient
roberth 231ae3b
lib.sources: Always validate paths
roberth 7589cf5
lib.sources: Use naming convention to avoid bug
roberth 940babe
lib.sources.{cutAt,pointAt}: assert type of path argument
roberth 35c240e
lib.sources: Support paths with metadata
roberth 5ccf760
lib.sources.extend: Use name from first argument
roberth 7eedeed
lib.sources.{pointAt -> focusAt}
roberth eff1344
lib.sources.getOriginalFocusPath: init
roberth 28e8371
lib.sources.getSubpath: init
roberth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,4 +1,22 @@ | ||||||||||||||||||||||||||||||
{ lib }: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let | ||||||||||||||||||||||||||||||
inherit (lib.attrsets) | ||||||||||||||||||||||||||||||
mapAttrs | ||||||||||||||||||||||||||||||
; | ||||||||||||||||||||||||||||||
inherit (lib.lists) | ||||||||||||||||||||||||||||||
head | ||||||||||||||||||||||||||||||
tail | ||||||||||||||||||||||||||||||
; | ||||||||||||||||||||||||||||||
inherit (lib.strings) | ||||||||||||||||||||||||||||||
hasPrefix | ||||||||||||||||||||||||||||||
; | ||||||||||||||||||||||||||||||
inherit (lib.filesystem) | ||||||||||||||||||||||||||||||
pathHasPrefix | ||||||||||||||||||||||||||||||
absolutePathComponentsBetween | ||||||||||||||||||||||||||||||
; | ||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
{ # haskellPathsInDir : Path -> Map String Path | ||||||||||||||||||||||||||||||
# A map of all haskell packages defined in the given path, | ||||||||||||||||||||||||||||||
# identified by having a cabal file with the same name as the | ||||||||||||||||||||||||||||||
|
@@ -54,4 +72,108 @@ | |||||||||||||||||||||||||||||
dir + "/${name}" | ||||||||||||||||||||||||||||||
) (builtins.readDir dir)); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# pathHasPrefix : Path -> Path -> Bool | ||||||||||||||||||||||||||||||
# pathHasPrefix ancestor somePath | ||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||
# Return true iff, disregarding trailing slashes, | ||||||||||||||||||||||||||||||
# - somePath is below ancestor | ||||||||||||||||||||||||||||||
# - or equal to ancestor | ||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||
# Equivalently, return true iff you can reach ancestor by starting at somePath | ||||||||||||||||||||||||||||||
# and traversing the `..` node zero or more times. | ||||||||||||||||||||||||||||||
pathHasPrefix = prefixPath: otherPath: | ||||||||||||||||||||||||||||||
let | ||||||||||||||||||||||||||||||
normalizedPathString = pathLike: toString (/. + pathLike); | ||||||||||||||||||||||||||||||
pre = normalizedPathString prefixPath; | ||||||||||||||||||||||||||||||
other = normalizedPathString otherPath; | ||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||
if pre == "/" # root is the only path that already ends in "/" | ||||||||||||||||||||||||||||||
then true | ||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||
hasPrefix (pre + "/") (other + "/"); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# commonPath : PathLike -> PathLike -> Path | ||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||
# Find the common ancestory; the longest prefix path that is common between | ||||||||||||||||||||||||||||||
# the input paths. | ||||||||||||||||||||||||||||||
commonPath = a: b: | ||||||||||||||||||||||||||||||
let | ||||||||||||||||||||||||||||||
b' = /. + b; | ||||||||||||||||||||||||||||||
go = c: | ||||||||||||||||||||||||||||||
if pathHasPrefix c b' | ||||||||||||||||||||||||||||||
then c | ||||||||||||||||||||||||||||||
else go (dirOf c); | ||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||
go (/. + a); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# absolutePathComponentsBetween : PathOrString -> PathOrString -> [String] | ||||||||||||||||||||||||||||||
# absolutePathComponentsBetween ancestor descendant | ||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||
# Returns the path components that form the path from ancestor to descendant. | ||||||||||||||||||||||||||||||
# Will not return ".." components, which is a feature. Throws when ancestor | ||||||||||||||||||||||||||||||
# and descendant arguments aren't in said relation to each other. | ||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||
# Example: | ||||||||||||||||||||||||||||||
# | ||||||||||||||||||||||||||||||
# absolutePathComponentsBetween /a /a/b/c == ["b" "c"] | ||||||||||||||||||||||||||||||
# absolutePathComponentsBetween /a/b/c /a/b/c == [] | ||||||||||||||||||||||||||||||
absolutePathComponentsBetween = | ||||||||||||||||||||||||||||||
ancestor: descendant: | ||||||||||||||||||||||||||||||
let | ||||||||||||||||||||||||||||||
a' = /. + ancestor; | ||||||||||||||||||||||||||||||
go = d: | ||||||||||||||||||||||||||||||
if a' == d | ||||||||||||||||||||||||||||||
then [] | ||||||||||||||||||||||||||||||
else if d == /. | ||||||||||||||||||||||||||||||
then throw "absolutePathComponentsBetween: path ${toString ancestor} is not an ancestor of ${toString descendant}" | ||||||||||||||||||||||||||||||
else go (dirOf d) ++ [(baseNameOf d)]; | ||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||
go (/. + descendant); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||
Memoize a function that takes a path argument. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Example: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
analyzeTree = dir: | ||||||||||||||||||||||||||||||
let g = memoizePathFunction (p: t: expensiveFunction p) (p: {}) dir; | ||||||||||||||||||||||||||||||
in presentExpensiveData g; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Type: | ||||||||||||||||||||||||||||||
memoizePathFunction :: (Path -> Type -> a) -> (Path -> a) -> Path -> (Path -> a) | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
memoizePathFunction = | ||||||||||||||||||||||||||||||
# Function to memoize | ||||||||||||||||||||||||||||||
f: | ||||||||||||||||||||||||||||||
# What to return when a path does not exist, as a function of the path | ||||||||||||||||||||||||||||||
missing: | ||||||||||||||||||||||||||||||
# Filesystem location below which the returned function is defined. `/.` may be acceptable, but a path closer to the data of interest is better. | ||||||||||||||||||||||||||||||
root: | ||||||||||||||||||||||||||||||
Comment on lines
+147
to
+152
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is a rather special function, 3 arguments and no clear order to them, I'd say this benefits from making it an attribute set argument
Suggested change
|
||||||||||||||||||||||||||||||
let | ||||||||||||||||||||||||||||||
makeTree = dir: type: { | ||||||||||||||||||||||||||||||
value = f dir type; | ||||||||||||||||||||||||||||||
children = | ||||||||||||||||||||||||||||||
if type == "directory" | ||||||||||||||||||||||||||||||
then mapAttrs | ||||||||||||||||||||||||||||||
(key: type: makeTree (dir + "/${key}") type) | ||||||||||||||||||||||||||||||
(builtins.readDir dir) | ||||||||||||||||||||||||||||||
else {}; | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# This is where the memoization happens | ||||||||||||||||||||||||||||||
tree = makeTree root (lib.pathType root); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
lookup = notFound: list: subtree: | ||||||||||||||||||||||||||||||
if list == [] | ||||||||||||||||||||||||||||||
then subtree.value | ||||||||||||||||||||||||||||||
else if subtree.children ? ${head list} | ||||||||||||||||||||||||||||||
then lookup notFound (tail list) subtree.children.${head list} | ||||||||||||||||||||||||||||||
else notFound; | ||||||||||||||||||||||||||||||
in | ||||||||||||||||||||||||||||||
path: lookup | ||||||||||||||||||||||||||||||
(missing path) | ||||||||||||||||||||||||||||||
(absolutePathComponentsBetween root path) | ||||||||||||||||||||||||||||||
tree; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit obscure why
+ "/"
is needed. From what I can tell, it's so that/some/path
doesn't match as a prefix of/some/pathpath
. WhilehasPrefix (pre + "/") other
would fix that, this would then break for whenpre == other
. So adding the"/"
toother
as well makes it work when the same path is a prefix of itself.