Change-Id: I6a087279b5d819db475f2179cb77c0f55cbd0ac6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/1860 Tested-by: BuildkiteCI Reviewed-by: glittershark <grfn@gws.fyi> Reviewed-by: lukegb <lukegb@tvl.fyi>
		
			
				
	
	
		
			80 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| { ... }:
 | |
| 
 | |
| args: initPath:
 | |
| 
 | |
| let
 | |
|   inherit (builtins)
 | |
|     attrNames
 | |
|     baseNameOf
 | |
|     concatStringsSep
 | |
|     filter
 | |
|     hasAttr
 | |
|     head
 | |
|     isAttrs
 | |
|     length
 | |
|     listToAttrs
 | |
|     map
 | |
|     match
 | |
|     readDir
 | |
|     substring;
 | |
| 
 | |
|   argsWithPath = parts:
 | |
|     let meta.locatedAt = parts;
 | |
|     in meta // (if isAttrs args then args else args meta);
 | |
| 
 | |
|   readDirVisible = path:
 | |
|     let
 | |
|       children = readDir path;
 | |
|       isVisible = f: f == ".skip-subtree" || (substring 0 1 f) != ".";
 | |
|       names = filter isVisible (attrNames children);
 | |
|     in listToAttrs (map (name: {
 | |
|       inherit name;
 | |
|       value = children.${name};
 | |
|     }) names);
 | |
| 
 | |
|   # Create a mark containing the location of this attribute.
 | |
|   marker = parts: {
 | |
|     __readTree = parts;
 | |
|   };
 | |
| 
 | |
|   # The marker is added to every set that was imported directly by
 | |
|   # readTree.
 | |
|   importWithMark = path: parts:
 | |
|     let imported = import path (argsWithPath parts);
 | |
|     in if (isAttrs imported)
 | |
|       then imported // (marker parts)
 | |
|       else imported;
 | |
| 
 | |
|   nixFileName = file:
 | |
|     let res = match "(.*)\.nix" file;
 | |
|     in if res == null then null else head res;
 | |
| 
 | |
|   readTree = path: parts:
 | |
|     let
 | |
|       dir = readDirVisible path;
 | |
|       self = importWithMark path parts;
 | |
|       joinChild = c: path + ("/" + c);
 | |
| 
 | |
|       # Import subdirectories of the current one, unless the special
 | |
|       # `.skip-subtree` file exists which makes readTree ignore the
 | |
|       # children.
 | |
|       #
 | |
|       # This file can optionally contain information on why the tree
 | |
|       # should be ignored, but its content is not inspected by
 | |
|       # readTree
 | |
|       filterDir = f: dir."${f}" == "directory";
 | |
|       children = if hasAttr ".skip-subtree" dir then [] else map (c: {
 | |
|         name = c;
 | |
|         value = readTree (joinChild c) (parts ++ [ c ]);
 | |
|       }) (filter filterDir (attrNames dir));
 | |
| 
 | |
|       # Import Nix files
 | |
|       nixFiles = filter (f: f != null) (map nixFileName (attrNames dir));
 | |
|       nixChildren = map (c: let p = joinChild (c + ".nix"); in {
 | |
|         name = c;
 | |
|         value = importWithMark p (parts ++ [ c ]);
 | |
|       }) nixFiles;
 | |
|     in if dir ? "default.nix"
 | |
|       then (if isAttrs self then self // (listToAttrs children) else self)
 | |
|       else (listToAttrs (nixChildren ++ children) // (marker parts));
 | |
| in readTree initPath [ (baseNameOf initPath) ]
 |