diff --git a/modules/fs/default.nix b/modules/fs/default.nix index 97596c4b..79d0352c 100644 --- a/modules/fs/default.nix +++ b/modules/fs/default.nix @@ -302,12 +302,7 @@ let # return all ancestors of this path. # e.g. ancestorsOf "/foo/bar/baz" => [ "/" "/foo" "/foo/bar" ] - # TODO: move this to path-lib? - ancestorsOf = path: if path-lib.hasParent path then - ancestorsOf (path-lib.parent path) ++ [ (path-lib.parent path) ] - else - [ ] - ; + ancestorsOf = path: lib.init (path-lib.walk "/" path); # attrsOf fsEntry type which for every entry ensures that all ancestor entries are created. # we do this with a custom type to ensure that users can access `config.sane.fs."/parent/path"` diff --git a/modules/impermanence/default.nix b/modules/impermanence/default.nix index 8d895032..9aea8e55 100644 --- a/modules/impermanence/default.nix +++ b/modules/impermanence/default.nix @@ -162,30 +162,37 @@ in cfgFor = opt: let store = opt.store; - store-rel-path = path.from store.prefix opt.directory; - backing-path = path.concat [ store.origin store-rel-path ]; + fsPathToStoreRelPath = fspath: path.from store.prefix fspath; + fsPathToBackingPath = fspath: path.concat [ store.origin (fsPathToStoreRelPath fspath) ]; # pass through the perm/mode overrides dir-acl = sane-lib.filterNonNull { inherit (opt) user group mode; }; - in { - # create destination and backing directory, with correct perms - sane.fs."${opt.directory}" = { - # inherit perms & make sure we don't mount until after the mount point is setup correctly. - dir.acl = dir-acl; - mount.bind = backing-path; - inherit (store.defaultOrdering) wantedBy wantedBeforeBy; - }; - sane.fs."${backing-path}" = { - # ensure the backing path has same perms as the mount point. - # TODO: maybe we want to do this, crawling all the way up to the store base? - # that would simplify (remove) the code in stores/default.nix - dir.acl = config.sane.fs."${opt.directory}".generated.acl; - }; - }; + in [ + { + # create destination dir, with correct perms + sane.fs."${opt.directory}" = { + # inherit perms & make sure we don't mount until after the mount point is setup correctly. + dir.acl = dir-acl; + mount.bind = fsPathToBackingPath opt.directory; + inherit (store.defaultOrdering) wantedBy wantedBeforeBy; + }; + + # create the backing path as a dir + sane.fs."${fsPathToBackingPath opt.directory}".dir = {}; + # sane.fs."${fsPathToBackingPath opt.directory}".dir.acl = config.sane.fs."${opt.directory}".generated.acl; + } + { + # default each item along the backing path to have the same acl as the location it would be mounted. + sane.fs = sane-lib.mapToAttrs (fspath: { + name = fsPathToBackingPath fspath; + value.generated.acl = config.sane.fs."${fspath}".generated.acl; + }) (path.walk store.prefix opt.directory); + } + ]; in mkIf cfg.enable { - sane.fs = lib.mkMerge (map (d: (cfgFor d).sane.fs) cfg.dirs.all); + sane.fs = lib.mkMerge (map (c: c.sane.fs) (concatMap cfgFor cfg.dirs.all)); }; } diff --git a/modules/lib/default.nix b/modules/lib/default.nix index 58af0bf5..d4033868 100644 --- a/modules/lib/default.nix +++ b/modules/lib/default.nix @@ -5,4 +5,7 @@ types = import ./types.nix moduleArgs; filterNonNull = attrs: lib.filterAttrsRecursive (n: v: v != null) attrs; + # transform a list into an attrset via a function which maps an element to a name + value + # Type: mapToAttrs :: (a -> { name, value }) -> [a] -> AttrSet + mapToAttrs = f: list: builtins.listToAttrs (builtins.map f list); } diff --git a/modules/lib/path.nix b/modules/lib/path.nix index c4cb7c59..d6430601 100644 --- a/modules/lib/path.nix +++ b/modules/lib/path.nix @@ -26,5 +26,14 @@ let path = rec { assert lib.hasPrefix s e; "/" + (lib.removePrefix s e) ); + + # yield every node between start and end, including each the endpoints + # e.g. walk "/foo" "/foo/bar/baz" => [ "/foo" "/foo/bar" "/foo/bar/baz" ] + # XXX: assumes input paths are normalized + walk = start: end: if start == end then + [ start ] + else + (walk start (parent end)) ++ [ end ] + ; }; in path