Another day, another import from derivation avoided by builtins.unsafeDiscardStringContext! Change-Id: I67274b1ba13ba980bb3346b22f2955c702aa3151 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3372 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi> Reviewed-by: tazjin <mail@tazj.in>
		
			
				
	
	
		
			131 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ depot, lib, ... }:
 | 
						|
 | 
						|
let
 | 
						|
 | 
						|
  /* Takes an attribute set and adds a meta.targets
 | 
						|
     attribute to it which contains all direct children
 | 
						|
     of the attribute set which are derivations.
 | 
						|
 | 
						|
     Type: attrs -> attrs
 | 
						|
  */
 | 
						|
  drvTargets = attrs:
 | 
						|
    attrs // {
 | 
						|
      meta = {
 | 
						|
        targets = builtins.filter
 | 
						|
          (x: lib.isDerivation attrs."${x}")
 | 
						|
          (builtins.attrNames attrs);
 | 
						|
      } // (attrs.meta or {});
 | 
						|
    };
 | 
						|
 | 
						|
  /* Get the basename of a store path without
 | 
						|
     the leading hash.
 | 
						|
 | 
						|
     Type: (path | drv | string) -> string
 | 
						|
 | 
						|
     Example:
 | 
						|
       storePathName ./foo.c
 | 
						|
       => "foo.c"
 | 
						|
 | 
						|
       storePathName (writeText "foo.c" "int main() { return 0; }")
 | 
						|
       => "foo.c"
 | 
						|
 | 
						|
       storePathName "${hello}/bin/hello"
 | 
						|
       => "hello"
 | 
						|
  */
 | 
						|
  storePathName = p:
 | 
						|
    if lib.isDerivation p
 | 
						|
    then p.name
 | 
						|
    else if builtins.isPath p
 | 
						|
    then builtins.baseNameOf p
 | 
						|
    else if builtins.isString p
 | 
						|
    then
 | 
						|
      let
 | 
						|
        # strip leading storeDir and trailing slashes
 | 
						|
        noStoreDir = lib.removeSuffix "/"
 | 
						|
          (lib.removePrefix "${builtins.storeDir}/" p);
 | 
						|
        # a basename of a child of a store path isn't really
 | 
						|
        # referring to a store path, so removing the string
 | 
						|
        # context is safe (e. g. "hello" for "${hello}/bin/hello").
 | 
						|
        basename = builtins.unsafeDiscardStringContext
 | 
						|
          (builtins.baseNameOf p);
 | 
						|
      in
 | 
						|
        # If p is a direct child of storeDir, we need to remove
 | 
						|
        # the leading hash as well to make sure that:
 | 
						|
        # `storePathName drv == storePathName (toString drv)`.
 | 
						|
        if noStoreDir == basename
 | 
						|
        then builtins.substring 33 (-1) basename
 | 
						|
        else basename
 | 
						|
    else builtins.throw "Don't know how to get (base)name of "
 | 
						|
      + lib.generators.toPretty {} p;
 | 
						|
 | 
						|
  /* Get the type of a path itself as it would be returned for a
 | 
						|
     directory child by builtins.readDir.
 | 
						|
 | 
						|
     Type: path(-like) -> option<string>
 | 
						|
 | 
						|
     Example:
 | 
						|
       pathType ./foo.c
 | 
						|
       => "regular"
 | 
						|
 | 
						|
       pathType /home/lukas
 | 
						|
       => "directory"
 | 
						|
 | 
						|
       pathType ./result
 | 
						|
       => "symlink"
 | 
						|
 | 
						|
       pathType /does/not/exist
 | 
						|
       => null
 | 
						|
  */
 | 
						|
  pathType = path:
 | 
						|
    let
 | 
						|
      # baseNameOf is very annoyed if we proceed with string context.
 | 
						|
      # We need to call toString to prevent unsafeDiscardStringContext
 | 
						|
      # from importing a path into store which messes with base- and
 | 
						|
      # dirname of course.
 | 
						|
      path'= builtins.unsafeDiscardStringContext (toString path);
 | 
						|
      # To read the containing directory we absolutely need
 | 
						|
      # to keep the string context, otherwise a derivation
 | 
						|
      # would not be realized before our check (at eval time)
 | 
						|
      containingDir = builtins.readDir (builtins.dirOf path);
 | 
						|
    in
 | 
						|
      containingDir.${builtins.baseNameOf path'} or null;
 | 
						|
 | 
						|
  pathType' = path:
 | 
						|
    let
 | 
						|
      p = pathType path;
 | 
						|
    in
 | 
						|
      if p == null
 | 
						|
      then builtins.throw "${lib.generators.toPretty {} path} does not exist"
 | 
						|
      else p;
 | 
						|
 | 
						|
  /* Check whether the given path is a directory.
 | 
						|
     Throws if the path in question doesn't exist.
 | 
						|
 | 
						|
     Type: path(-like) -> bool
 | 
						|
  */
 | 
						|
  isDirectory = path: pathType' path == "directory";
 | 
						|
 | 
						|
  /* Check whether the given path is a regular file.
 | 
						|
     Throws if the path in question doesn't exist.
 | 
						|
 | 
						|
     Type: path(-like) -> bool
 | 
						|
  */
 | 
						|
  isRegularFile = path: pathType' path == "regular";
 | 
						|
 | 
						|
  /* Check whether the given path is a symbolic link.
 | 
						|
     Throws if the path in question doesn't exist.
 | 
						|
 | 
						|
     Type: path(-like) -> bool
 | 
						|
  */
 | 
						|
  isSymlink = path: pathType' path == "symlink";
 | 
						|
 | 
						|
in {
 | 
						|
  inherit
 | 
						|
    drvTargets
 | 
						|
    storePathName
 | 
						|
    pathType
 | 
						|
    isDirectory
 | 
						|
    isRegularFile
 | 
						|
    isSymlink
 | 
						|
    ;
 | 
						|
}
 |