about summary refs log tree commit diff
diff options
context:
space:
mode:
authorShea Levy <shea@shealevy.com>2017-03-04 13:15:23 -0500
committerShea Levy <shea@shealevy.com>2017-03-04 13:15:23 -0500
commit56e71f62dc49e64fcd37768cc7d1ec219d4990e6 (patch)
tree7e91a13dface2b09b4574447eaa8e5c5ec3b916c
parent7b914b29864132ae73e4a0eb9656eec8bb05102f (diff)
Add locateDominatingFile lib function
-rw-r--r--lib/default.nix5
-rw-r--r--lib/filesystem.nix26
2 files changed, 30 insertions, 1 deletions
diff --git a/lib/default.nix b/lib/default.nix
index c0d7899b882af..09a64f754d8f3 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -34,6 +34,9 @@ let
   sandbox = import ./sandbox.nix;
   fetchers = import ./fetchers.nix;
 
+  # Eval-time filesystem handling
+  filesystem = import ./filesystem.nix;
+
 in
   { inherit trivial
             attrsets lists strings stringsWithDeps
@@ -41,7 +44,7 @@ in
             modules options types
             licenses platforms systems
             debug generators misc
-            sandbox fetchers;
+            sandbox fetchers filesystem;
   }
   # !!! don't include everything at top-level; perhaps only the most
   # commonly used functions.
diff --git a/lib/filesystem.nix b/lib/filesystem.nix
new file mode 100644
index 0000000000000..91b04d81c13be
--- /dev/null
+++ b/lib/filesystem.nix
@@ -0,0 +1,26 @@
+{ # locateDominatingFile :  RegExp
+  #                      -> Path
+  #                      -> Nullable { path : Path;
+  #                                    matches : [ MatchResults ];
+  #                                  }
+  # Find the first directory containing a file matching 'pattern'
+  # upward from a given 'file'.
+  # Returns 'null' if no directories contain a file matching 'pattern'.
+  locateDominatingFile = pattern: file:
+    let go = path:
+          let files = builtins.attrNames (builtins.readDir path);
+              matches = builtins.filter (match: match != null)
+                          (map (builtins.match pattern) files);
+          in
+            if builtins.length matches != 0
+              then { inherit path matches; }
+              else if path == /.
+                then null
+                else go (dirOf path);
+        parent = dirOf file;
+        isDir =
+          let base = baseNameOf file;
+              type = (builtins.readDir parent).${base} or null;
+          in file == /. || type == "directory";
+    in go (if isDir then file else parent);
+}