diff --git a/flake.nix b/flake.nix index e0deb3d..a1ab023 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ # `lib.flake-utils-plus.mkApp`. # Usage: mkLib { inherit inputs; src = ./.; } # result: lib - mkLib = import ./lib core-inputs; + mkLib = import ./snowfall-lib core-inputs; # A convenience wrapper to create the library and then call `lib.mkFlake`. # Usage: mkFlake { inherit inputs; src = ./.; ... } @@ -50,5 +50,36 @@ homeModules = { user = ./modules/home/user/default.nix; }; + + _snowfall = rec { + + raw-config = config; + + config = { + root = ./.; + src = ./.; + namespace = "snowfall"; + lib-dir = "snowfall-lib"; + + meta = { + name = "snowfall-lib"; + title = "Snowfall Lib"; + }; + }; + + internal-lib = + let + lib = mkLib { + src = ./.; + + inputs = inputs // { + self = { }; + }; + }; + in + builtins.removeAttrs + lib.snowfall + [ "internal" ]; + }; }; } diff --git a/lib/attrs/default.nix b/lib/attrs/default.nix deleted file mode 100644 index c7a171f..0000000 --- a/lib/attrs/default.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (core-inputs.nixpkgs.lib) - assertMsg - mapAttrsToList - mapAttrs - flatten - foldl - recursiveUpdate - mergeAttrs - isDerivation; -in -{ - attrs = { - # Map and flatten an attribute set into a list. - # Type: (a -> b -> [c]) -> Attrs -> [c] - # Usage: map-concat-attrs-to-list (name: value: [name value]) { x = 1; y = 2; } - # result: [ "x" 1 "y" 2 ] - map-concat-attrs-to-list = f: attrs: - flatten (mapAttrsToList f attrs); - - # Recursively merge a list of attribute sets. - # Type: [Attrs] -> Attrs - # Usage: merge-deep [{ x = 1; } { x = 2; }] - # result: { x = 2; } - merge-deep = foldl recursiveUpdate { }; - - # Merge the root of a list of attribute sets. - # Type: [Attrs] -> Attrs - # Usage: merge-shallow [{ x = 1; } { x = 2; }] - # result: { x = 2; } - merge-shallow = foldl mergeAttrs { }; - - # Merge shallow for packages, but allow one deeper layer of attribute sets. - # Type: [Attrs] -> Attrs - # Usage: merge-shallow-packages [ { inherit (pkgs) vim; some.value = true; } { some.value = false; } ] - # result: { vim = ...; some.value = false; } - merge-shallow-packages = items: - foldl - (result: item: - result // (mapAttrs - (name: value: - if isDerivation value then - value - else if builtins.isAttrs value then - (result.${name} or { }) // value - else - value - ) - item) - ) - { } - items; - }; -} diff --git a/lib/fp/default.nix b/lib/fp/default.nix deleted file mode 100644 index 63e0826..0000000 --- a/lib/fp/default.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (builtins) baseNameOf dirOf; - inherit (core-inputs.nixpkgs.lib) id foldr flip; -in -{ - fp = rec { - # Compose two functions. - # Type: (b -> c) -> (a -> b) -> a -> c - # Usage: compose add-two add-one - # result: (x: add-two (add-one x)) - compose = f: g: x: f (g x); - - # Compose many functions. - # Type: [(x -> y)] -> a -> b - # Usage: compose-all [ add-two add-one ] - # result: (x: add-two (add-one x)) - compose-all = foldr compose id; - - # Call a function with an argument. - # Type: (a -> b) -> a -> b - # Usage: call (x: x + 1) 0 - # result: 1 - call = f: x: f x; - - # Apply an argument to a function. - # Type: a -> (a -> b) -> b - # Usage: call (x: x + 1) 0 - # result: 1 - apply = flip call; - }; -} diff --git a/lib/fs/default.nix b/lib/fs/default.nix deleted file mode 100644 index 54cbe64..0000000 --- a/lib/fs/default.nix +++ /dev/null @@ -1,161 +0,0 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (builtins) readDir pathExists; - inherit (core-inputs) flake-utils-plus; - inherit (core-inputs.nixpkgs.lib) assertMsg filterAttrs mapAttrsToList flatten; - - file-name-regex = "(.*)\\.(.*)$"; -in -{ - fs = rec { - # Matchers for file kinds. These are often used with `readDir`. - # Type: String -> Bool - # Usage: is-file-kind "directory" - # result: false - is-file-kind = kind: kind == "regular"; - is-symlink-kind = kind: kind == "symlink"; - is-directory-kind = kind: kind == "directory"; - is-unknown-kind = kind: kind == "unknown"; - - # Get a file path relative to the user's flake. - # Type: Path -> Path - # Usage: get-file "systems" - # result: "/user-source/systems" - get-file = path: "${user-inputs.src}/${path}"; - - # Get a file path relative to the user's snowfall directory. - # Type: Path -> Path - # Usage: get-snowfall-file "systems" - # result: "/user-source/snowfall-dir/systems" - get-snowfall-file = path: "${snowfall-config.root}/${path}"; - - # Get a file path relative to the this flake. - # Type: Path -> Path - # Usage: get-file "systems" - # result: "/user-source/systems" - internal-get-file = path: "${core-inputs.src}/${path}"; - - # Safely read from a directory if it exists. - # Type: Path -> Attrs - # Usage: safe-read-directory ./some/path - # result: { "my-file.txt" = "regular"; } - safe-read-directory = path: - if pathExists path then - readDir path - else - { }; - - # Get directories at a given path. - # Type: Path -> [Path] - # Usage: get-directories ./something - # result: [ "./something/a-directory" ] - get-directories = path: - let - entries = safe-read-directory path; - filtered-entries = filterAttrs (name: kind: is-directory-kind kind) entries; - in - mapAttrsToList (name: kind: "${path}/${name}") filtered-entries; - - # Get files at a given path. - # Type: Path -> [Path] - # Usage: get-files ./something - # result: [ "./something/a-file" ] - get-files = path: - let - entries = safe-read-directory path; - filtered-entries = filterAttrs (name: kind: is-file-kind kind) entries; - in - mapAttrsToList (name: kind: "${path}/${name}") filtered-entries; - - # Get files at a given path, traversing any directories within. - # Type: Path -> [Path] - # Usage: get-files-recursive ./something - # result: [ "./something/some-directory/a-file" ] - get-files-recursive = path: - let - entries = safe-read-directory path; - filtered-entries = - filterAttrs - (name: kind: (is-file-kind kind) || (is-directory-kind kind)) - entries; - map-file = name: kind: - let - path' = "${path}/${name}"; - in - if is-directory-kind kind then - get-files-recursive path' - else - path'; - files = snowfall-lib.attrs.map-concat-attrs-to-list - map-file - filtered-entries; - in - files; - - # Get nix files at a given path. - # Type: Path -> [Path] - # Usage: get-nix-files "./something" - # result: [ "./something/a.nix" ] - get-nix-files = path: - builtins.filter - (snowfall-lib.path.has-file-extension "nix") - (get-files path); - - # Get nix files at a given path, traversing any directories within. - # Type: Path -> [Path] - # Usage: get-nix-files "./something" - # result: [ "./something/a.nix" ] - get-nix-files-recursive = path: - builtins.filter - (snowfall-lib.path.has-file-extension "nix") - (get-files-recursive path); - - # Get nix files at a given path named "default.nix". - # Type: Path -> [Path] - # Usage: get-default-nix-files "./something" - # result: [ "./something/default.nix" ] - get-default-nix-files = path: - builtins.filter - (name: builtins.baseNameOf name == "default.nix") - (get-files path); - - # Get nix files at a given path named "default.nix", traversing any directories within. - # Type: Path -> [Path] - # Usage: get-default-nix-files-recursive "./something" - # result: [ "./something/some-directory/default.nix" ] - get-default-nix-files-recursive = path: - builtins.filter - (name: builtins.baseNameOf name == "default.nix") - (get-files-recursive path); - - # Get nix files at a given path not named "default.nix". - # Type: Path -> [Path] - # Usage: get-non-default-nix-files "./something" - # result: [ "./something/a.nix" ] - get-non-default-nix-files = path: - builtins.filter - (name: - (snowfall-lib.path.has-file-extension "nix" name) - && (builtins.baseNameOf name != "default.nix") - ) - (get-files path); - - # Get nix files at a given path not named "default.nix", - # traversing any directories within. - # Type: Path -> [Path] - # Usage: get-non-default-nix-files-recursive "./something" - # result: [ "./something/some-directory/a.nix" ] - get-non-default-nix-files-recursive = path: - builtins.filter - (name: - (snowfall-lib.path.has-file-extension "nix" name) - && (builtins.baseNameOf name != "default.nix") - ) - (get-files-recursive path); - }; -} diff --git a/lib/path/default.nix b/lib/path/default.nix deleted file mode 100644 index 602f42f..0000000 --- a/lib/path/default.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (builtins) toString baseNameOf dirOf concatStringsSep; - inherit (core-inputs.nixpkgs.lib) assertMsg last init; - - file-name-regex = "(.*)\\.(.*)$"; -in -{ - path = rec { - # Split a file name and its extension. - # Type: String -> [String] - # Usage: split-file-extension "my-file.md" - # result: [ "my-file" "md" ] - split-file-extension = file: - let - match = builtins.match file-name-regex file; - in - assert assertMsg (match != null) "lib.snowfall.split-file-extension: File must have an extension to split."; - match; - - # Check if a file name has a file extension. - # Type: String -> Bool - # Usage: has-any-file-extension "my-file.txt" - # result: true - has-any-file-extension = file: - let - match = builtins.match file-name-regex (toString file); - in - match != null; - - # Get the file extension of a file name. - # Type: String -> String - # Usage: get-file-extension "my-file.final.txt" - # result: "txt" - get-file-extension = file: - if has-any-file-extension file then - let - match = builtins.match file-name-regex (toString file); - in - last match - else - ""; - - # Check if a file name has a specific file extension. - # Type: String -> String -> Bool - # Usage: has-file-extension "txt" "my-file.txt" - # result: true - has-file-extension = extension: file: - if has-any-file-extension file then - extension == get-file-extension file - else - false; - - # Get the parent directory for a given path. - # Type: Path -> Path - # Usage: get-parent-directory "/a/b/c" - # result: "/a/b" - get-parent-directory = snowfall-lib.fp.compose baseNameOf dirOf; - - # Get the file name of a path without its extension. - # Type: Path -> String - # Usage: get-file-name-without-extension ./some-directory/my-file.pdf - # result: "my-file" - get-file-name-without-extension = path: - let - file-name = baseNameOf path; - in - if has-any-file-extension file-name then - concatStringsSep "" (init (split-file-extension file-name)) - else - file-name; - }; -} diff --git a/modules/nixos/user/default.nix b/modules/nixos/user/default.nix index 757997d..e8483f1 100644 --- a/modules/nixos/user/default.nix +++ b/modules/nixos/user/default.nix @@ -1,10 +1,12 @@ -{ pkgs, lib, options, config, inputs, ... }: +args@{ pkgs, lib, options, config, ... }: let inherit (lib) types mkOption mkDefault foldl optionalAttrs optional; cfg = config.snowfallorg; + inputs = args.inputs or { }; + user-names = builtins.attrNames cfg.user; create-system-users = system-users: name: @@ -58,29 +60,32 @@ in config = mkOption { # HM-compatible options taken from: # https://github.com/nix-community/home-manager/blob/0ee5ab611dc1fbb5180bd7d88d2aeb7841a4d179/nixos/common.nix#L14 + # @NOTE(jakehamilton): This has been adapted to support documentation generation without + # having home-manager options fully declared. type = types.submoduleWith { specialArgs = { osConfig = config; - modulesPath = "${inputs.home-manager}/modules"; - } // config.home-manager.extraSpecialArgs; + modulesPath = "${inputs.home-manager or "/"}/modules"; + } // (config.home-manager.extraSpecialArgs or { }); modules = [ - ({ lib, modulesPath, ... }: { - imports = import "${modulesPath}/modules.nix" { - inherit pkgs lib; - useNixpkgsModule = !config.home-manager.useGlobalPkgs; - }; + ({ lib, modulesPath, ... }: + if inputs ? home-manager then { + imports = import "${modulesPath}/modules.nix" { + inherit pkgs lib; + useNixpkgsModule = !(config.home-manager.useGlobalPkgs or false); + }; - config = { - submoduleSupport.enable = true; - submoduleSupport.externalPackageInstall = cfg.useUserPackages; + config = { + submoduleSupport.enable = true; + submoduleSupport.externalPackageInstall = cfg.useUserPackages; - home.username = config.users.users.${name}.name; - home.homeDirectory = config.users.users.${name}.home; + home.username = config.users.users.${name}.name; + home.homeDirectory = config.users.users.${name}.home; - nix.package = config.nix.package; - }; - }) - ] ++ config.home-manager.sharedModules; + nix.package = config.nix.package; + }; + } else { }) + ] ++ (config.home-manager.sharedModules or [ ]); }; }; }; diff --git a/snowfall-lib/attrs/default.nix b/snowfall-lib/attrs/default.nix new file mode 100644 index 0000000..ea5dbee --- /dev/null +++ b/snowfall-lib/attrs/default.nix @@ -0,0 +1,84 @@ +{ core-inputs +, user-inputs +, snowfall-lib +, snowfall-config +}: + +let + inherit (core-inputs.nixpkgs.lib) + assertMsg + mapAttrsToList + mapAttrs + flatten + foldl + recursiveUpdate + mergeAttrs + isDerivation; +in +{ + attrs = { + ## Map and flatten an attribute set into a list. + ## Example Usage: + ## ```nix + ## map-concat-attrs-to-list (name: value: [name value]) { x = 1; y = 2; } + ## ``` + ## Result: + ## ```nix + ## [ "x" 1 "y" 2 ] + ## ``` + #@ (a -> b -> [c]) -> Attrs -> [c] + map-concat-attrs-to-list = f: attrs: + flatten (mapAttrsToList f attrs); + + ## Recursively merge a list of attribute sets. + ## Example Usage: + ## ```nix + ## merge-deep [{ x = 1; } { x = 2; }] + ## ``` + ## Result: + ## ```nix + ## { x = 2; } + ## ``` + #@ [Attrs] -> Attrs + merge-deep = foldl recursiveUpdate { }; + + ## Merge the root of a list of attribute sets. + ## Example Usage: + ## ```nix + ## merge-shallow [{ x = 1; } { x = 2; }] + ## ``` + ## Result: + ## ```nix + ## { x = 2; } + ## ``` + #@ [Attrs] -> Attrs + merge-shallow = foldl mergeAttrs { }; + + ## Merge shallow for packages, but allow one deeper layer of attribute sets. + ## Example Usage: + ## ```nix + ## merge-shallow-packages [ { inherit (pkgs) vim; some.value = true; } { some.value = false; } ] + ## ``` + ## Result: + ## ```nix + ## { vim = ...; some.value = false; } + ## ``` + #@ [Attrs] -> Attrs + merge-shallow-packages = items: + foldl + (result: item: + result // (mapAttrs + (name: value: + if isDerivation value then + value + else if builtins.isAttrs value then + (result.${name} or { }) // value + else + value + ) + item) + ) + { } + items; + }; +} diff --git a/lib/default.nix b/snowfall-lib/default.nix similarity index 89% rename from lib/default.nix rename to snowfall-lib/default.nix index 05f0c3d..988142c 100644 --- a/lib/default.nix +++ b/snowfall-lib/default.nix @@ -8,7 +8,13 @@ user-options: let raw-snowfall-config = user-options.snowfall or { }; snowfall-config = raw-snowfall-config // { + src = user-options.src; root = raw-snowfall-config.root or user-options.src; + namespace = raw-snowfall-config.namespace or "internal"; + meta = { + name = raw-snowfall-config.meta.name or null; + title = raw-snowfall-config.meta.title or null; + }; }; user-inputs = user-options.inputs // { src = user-options.src; }; @@ -53,7 +59,9 @@ let core-inputs-libs = get-libs (without-self core-inputs); user-inputs-libs = get-libs (without-self user-inputs); - snowfall-lib-root = "${core-inputs.src}/lib"; + # @NOTE(jakehamilton): This root is different to accomodate the creation + # of a fake user-lib in order to run documentation on this flake. + snowfall-lib-root = "${core-inputs.src}/snowfall-lib"; snowfall-lib-dirs = let files = builtins.readDir snowfall-lib-root; diff --git a/lib/flake/default.nix b/snowfall-lib/flake/default.nix similarity index 74% rename from lib/flake/default.nix rename to snowfall-lib/flake/default.nix index 15de25a..223762e 100644 --- a/lib/flake/default.nix +++ b/snowfall-lib/flake/default.nix @@ -9,29 +9,52 @@ let in rec { flake = rec { - # Remove the `self` attribute from an attribute set. - # Type: Attrs -> Attrs - # Usage: without-self { self = {}; x = true; } - # result: { x = true; } + ## Remove the `self` attribute from an attribute set. + ## Example Usage: + ## ```nix + ## without-self { self = {}; x = true; } + ## ``` + ## Result: + ## ```nix + ## { x = true; } + ## ``` + #@ Attrs -> Attrs without-self = flake-inputs: builtins.removeAttrs flake-inputs [ "self" ]; - # Remove the `src` attribute from an attribute set. - # Type: Attrs -> Attrs - # Usage: without-src { src = ./.; x = true; } - # result: { x = true; } + ## Remove the `src` attribute from an attribute set. + ## Example Usage: + ## ```nix + ## without-src { src = ./.; x = true; } + ## ``` + ## Result: + ## ```nix + ## { x = true; } + ## ``` + #@ Attrs -> Attrs without-src = flake-inputs: builtins.removeAttrs flake-inputs [ "src" ]; - # Remove the `src` and `self` attributes from an attribute set. - # Type: Attrs -> Attrs - # Usage: without-snowfall-inputs { self = {}; src = ./.; x = true; } - # result: { x = true; } + ## Remove the `src` and `self` attributes from an attribute set. + ## Example Usage: + ## ```nix + ## without-snowfall-inputs { self = {}; src = ./.; x = true; } + ## ``` + ## Result: + ## ```nix + ## { x = true; } + ## ``` + #@ Attrs -> Attrs without-snowfall-inputs = snowfall-lib.fp.compose without-self without-src; - # Remove Snowfall-specific attributes so the rest can be safely - # passed to flake-utils-plus. - # Type: Attrs -> Attrs - # Usage: without-snowfall-options { src = ./.; x = true; } - # result: { x = true; } + ## Remove Snowfall-specific attributes so the rest can be safely passed to flake-utils-plus. + ## Example Usage: + ## ```nix + ## without-snowfall-options { src = ./.; x = true; } + ## ``` + ## Result: + ## ```nix + ## { x = true; } + ## ``` + #@ Attrs -> Attrs without-snowfall-options = flake-options: builtins.removeAttrs flake-options @@ -51,12 +74,16 @@ rec { "snowfall" ]; - # Transform an attribute set of inputs into an attribute set where - # the values are the inputs' `lib` attribute. Entries without a `lib` - # attribute are removed. - # Type: Attrs -> Attrs - # Usage: get-lib { x = nixpkgs; y = {}; } - # result: { x = nixpkgs.lib; } + ## Transform an attribute set of inputs into an attribute set where the values are the inputs' `lib` attribute. Entries without a `lib` attribute are removed. + ## Example Usage: + ## ```nix + ## get-lib { x = nixpkgs; y = {}; } + ## ``` + ## Result: + ## ```nix + ## { x = nixpkgs.lib; } + ## ``` + #@ Attrs -> Attrs get-libs = attrs: let # @PERF(jakehamilton): Replace filter+map with a fold. @@ -71,7 +98,7 @@ rec { mkFlake = full-flake-options: let - package-namespace = full-flake-options.package-namespace or "internal"; + package-namespace = full-flake-options.package-namespace or snowfall-config.namespace or "internal"; custom-flake-options = flake.without-snowfall-options full-flake-options; alias = full-flake-options.alias or { }; homes = snowfall-lib.home.create-homes (full-flake-options.homes or { }); @@ -149,6 +176,12 @@ rec { }; outputsBuilder = outputs-builder; + + _snowfall = { + config = snowfall-config; + raw-config = full-flake-options.snowfall or { }; + user-lib = snowfall-lib.internal.user-lib; + }; }; flake-utils-plus-outputs = diff --git a/snowfall-lib/fp/default.nix b/snowfall-lib/fp/default.nix new file mode 100644 index 0000000..04dd03c --- /dev/null +++ b/snowfall-lib/fp/default.nix @@ -0,0 +1,61 @@ +{ core-inputs +, user-inputs +, snowfall-lib +, snowfall-config +}: + +let + inherit (builtins) baseNameOf dirOf; + inherit (core-inputs.nixpkgs.lib) id foldr flip; +in +{ + fp = rec { + ## Compose two functions. + ## Example Usage: + ## ```nix + ## compose add-two add-one + ## ``` + ## Result: + ## ```nix + ## (x: add-two (add-one x)) + ## ``` + #@ (b -> c) -> (a -> b) -> a -> c + compose = f: g: x: f (g x); + + ## Compose many functions. + ## Example Usage: + ## ```nix + ## compose-all [ add-two add-one ] + ## ``` + ## Result: + ## ```nix + ## (x: add-two (add-one x)) + ## ``` + #@ [(x -> y)] -> a -> b + compose-all = foldr compose id; + + ## Call a function with an argument. + ## Example Usage: + ## ```nix + ## call (x: x + 1) 0 + ## ``` + ## Result: + ## ```nix + ## 1 + ## ``` + #@ (a -> b) -> a -> b + call = f: x: f x; + + ## Apply an argument to a function. + ## Example Usage: + ## ```nix + ## apply 0 (x: x + 1) + ## ``` + ## Result: + ## ```nix + ## 1 + ## ``` + #@ a -> (a -> b) -> b + apply = flip call; + }; +} diff --git a/snowfall-lib/fs/default.nix b/snowfall-lib/fs/default.nix new file mode 100644 index 0000000..3877408 --- /dev/null +++ b/snowfall-lib/fs/default.nix @@ -0,0 +1,244 @@ +{ core-inputs +, user-inputs +, snowfall-lib +, snowfall-config +}: + +let + inherit (builtins) readDir pathExists; + inherit (core-inputs) flake-utils-plus; + inherit (core-inputs.nixpkgs.lib) assertMsg filterAttrs mapAttrsToList flatten; + + file-name-regex = "(.*)\\.(.*)$"; +in +{ + fs = rec { + ## Matchers for file kinds. These are often used with `readDir`. + ## Example Usage: + ## ```nix + ## is-file-kind "directory" + ## ``` + ## Result: + ## ```nix + ## false + ## ``` + #@ String -> Bool + is-file-kind = kind: kind == "regular"; + is-symlink-kind = kind: kind == "symlink"; + is-directory-kind = kind: kind == "directory"; + is-unknown-kind = kind: kind == "unknown"; + + ## Get a file path relative to the user's flake. + ## Example Usage: + ## ```nix + ## get-file "systems" + ## ``` + ## Result: + ## ```nix + ## "/user-source/systems" + ## ``` + #@ Path -> Path + get-file = path: "${user-inputs.src}/${path}"; + + ## Get a file path relative to the user's snowfall directory. + ## Example Usage: + ## ```nix + ## get-snowfall-file "systems" + ## ``` + ## Result: + ## ```nix + ## "/user-source/snowfall-dir/systems" + ## ``` + #@ Path -> Path + get-snowfall-file = path: "${snowfall-config.root}/${path}"; + + ## Get a file path relative to the this flake. + ## Example Usage: + ## ```nix + ## get-file "systems" + ## ``` + ## Result: + ## ```nix + ## "/user-source/systems" + ## ``` + #@ Path -> Path + internal-get-file = path: "${core-inputs.src}/${path}"; + + ## Safely read from a directory if it exists. + ## Example Usage: + ## ```nix + ## safe-read-directory ./some/path + ## ``` + ## Result: + ## ```nix + ## { "my-file.txt" = "regular"; } + ## ``` + #@ Path -> Attrs + safe-read-directory = path: + if pathExists path then + readDir path + else + { }; + + ## Get directories at a given path. + ## Example Usage: + ## ```nix + ## get-directories ./something + ## ``` + ## Result: + ## ```nix + ## [ "./something/a-directory" ] + ## ``` + #@ Path -> [Path] + get-directories = path: + let + entries = safe-read-directory path; + filtered-entries = filterAttrs (name: kind: is-directory-kind kind) entries; + in + mapAttrsToList (name: kind: "${path}/${name}") filtered-entries; + + ## Get files at a given path. + ## Example Usage: + ## ```nix + ## get-files ./something + ## ``` + ## Result: + ## ```nix + ## [ "./something/a-file" ] + ## ``` + #@ Path -> [Path] + get-files = path: + let + entries = safe-read-directory path; + filtered-entries = filterAttrs (name: kind: is-file-kind kind) entries; + in + mapAttrsToList (name: kind: "${path}/${name}") filtered-entries; + + ## Get files at a given path, traversing any directories within. + ## Example Usage: + ## ```nix + ## get-files-recursive ./something + ## ``` + ## Result: + ## ```nix + ## [ "./something/some-directory/a-file" ] + ## ``` + #@ Path -> [Path] + get-files-recursive = path: + let + entries = safe-read-directory path; + filtered-entries = + filterAttrs + (name: kind: (is-file-kind kind) || (is-directory-kind kind)) + entries; + map-file = name: kind: + let + path' = "${path}/${name}"; + in + if is-directory-kind kind then + get-files-recursive path' + else + path'; + files = snowfall-lib.attrs.map-concat-attrs-to-list + map-file + filtered-entries; + in + files; + + ## Get nix files at a given path. + ## Example Usage: + ## ```nix + ## get-nix-files "./something" + ## ``` + ## Result: + ## ```nix + ## [ "./something/a.nix" ] + ## ``` + #@ Path -> [Path] + get-nix-files = path: + builtins.filter + (snowfall-lib.path.has-file-extension "nix") + (get-files path); + + ## Get nix files at a given path, traversing any directories within. + ## Example Usage: + ## ```nix + ## get-nix-files "./something" + ## ``` + ## Result: + ## ```nix + ## [ "./something/a.nix" ] + ## ``` + #@ Path -> [Path] + get-nix-files-recursive = path: + builtins.filter + (snowfall-lib.path.has-file-extension "nix") + (get-files-recursive path); + + ## Get nix files at a given path named "default.nix". + ## Example Usage: + ## ```nix + ## get-default-nix-files "./something" + ## ``` + ## Result: + ## ```nix + ## [ "./something/default.nix" ] + ## ``` + #@ Path -> [Path] + get-default-nix-files = path: + builtins.filter + (name: builtins.baseNameOf name == "default.nix") + (get-files path); + + ## Get nix files at a given path named "default.nix", traversing any directories within. + ## Example Usage: + ## ```nix + ## get-default-nix-files-recursive "./something" + ## ``` + ## Result: + ## ```nix + ## [ "./something/some-directory/default.nix" ] + ## ``` + #@ Path -> [Path] + get-default-nix-files-recursive = path: + builtins.filter + (name: builtins.baseNameOf name == "default.nix") + (get-files-recursive path); + + ## Get nix files at a given path not named "default.nix". + ## Example Usage: + ## ```nix + ## get-non-default-nix-files "./something" + ## ``` + ## Result: + ## ```nix + ## [ "./something/a.nix" ] + ## ``` + #@ Path -> [Path] + get-non-default-nix-files = path: + builtins.filter + (name: + (snowfall-lib.path.has-file-extension "nix" name) + && (builtins.baseNameOf name != "default.nix") + ) + (get-files path); + + ## Get nix files at a given path not named "default.nix", traversing any directories within. + ## Example Usage: + ## ```nix + ## get-non-default-nix-files-recursive "./something" + ## ``` + ## Result: + ## ```nix + ## [ "./something/some-directory/a.nix" ] + ## ``` + #@ Path -> [Path] + get-non-default-nix-files-recursive = path: + builtins.filter + (name: + (snowfall-lib.path.has-file-extension "nix" name) + && (builtins.baseNameOf name != "default.nix") + ) + (get-files-recursive path); + }; +} diff --git a/lib/home/default.nix b/snowfall-lib/home/default.nix similarity index 82% rename from lib/home/default.nix rename to snowfall-lib/home/default.nix index c2ea41b..e5cac40 100644 --- a/lib/home/default.nix +++ b/snowfall-lib/home/default.nix @@ -31,19 +31,32 @@ in { home = rec { # Modules in home-manager expect `hm` to be available directly on `lib` itself. - home-lib = snowfall-lib.internal.system-lib.extend (final: prev: - # @NOTE(jakehamilton): This order is important, this library's extend and other utilities must write - # _over_ the original `system-lib`. - snowfall-lib.internal.system-lib - // prev - // { - hm = snowfall-lib.internal.system-lib.home-manager.hm; - }); + home-lib = + # @NOTE(jakehamilton): This prevents an error during evaluation if the input does + # not exist. + if user-inputs ? home-manager then + snowfall-lib.internal.system-lib.extend + (final: prev: + # @NOTE(jakehamilton): This order is important, this library's extend and other utilities must write + # _over_ the original `system-lib`. + snowfall-lib.internal.system-lib + // prev + // { + hm = snowfall-lib.internal.system-lib.home-manager.hm; + }) + else + { }; - # Get the user and host from a combined string. - # Type: String -> Attrs - # Usage: split-user-and-host "myuser@myhost" - # result: { user = "myuser"; host = "myhost"; } + ## Get the user and host from a combined string. + ## Example Usage: + ## ```nix + ## split-user-and-host "myuser@myhost" + ## ``` + ## Result: + ## ```nix + ## { user = "myuser"; host = "myhost"; } + ## ``` + #@ String -> Attrs split-user-and-host = target: let raw-name-parts = builtins.split "@" target; @@ -61,10 +74,16 @@ in }; - # Create a home. - # Type: Attrs -> Attrs - # Usage: create-home { path = ./homes/my-home; } - # result: + ## Create a home. + ## Example Usage: + ## ```nix + ## create-home { path = ./homes/my-home; } + ## ``` + ## Result: + ## ```nix + ## + ## ``` + #@ Attrs -> Attrs create-home = { path , name ? builtins.unsafeDiscardStringContext (snowfall-lib.system.get-inferred-system-name path) @@ -122,10 +141,16 @@ in }); }; - # Get structured data about all homes for a given target. - # Type: String -> [Attrs] - # Usage: get-target-homes-metadata ./homes - # result: [ { system = "x86_64-linux"; name = "my-home"; path = "/homes/x86_64-linux/my-home";} ] + ## Get structured data about all homes for a given target. + ## Example Usage: + ## ```nix + ## get-target-homes-metadata ./homes + ## ``` + ## Result: + ## ```nix + ## [ { system = "x86_64-linux"; name = "my-home"; path = "/homes/x86_64-linux/my-home";} ] + ## ``` + #@ String -> [Attrs] get-target-homes-metadata = target: let homes = snowfall-lib.fs.get-directories target; @@ -145,10 +170,16 @@ in in home-configurations; - # Create all available homes. - # Type: Attrs -> Attrs - # Usage: create-homes { users."my-user@my-system".specialArgs.x = true; modules = [ my-shared-module ]; } - # result: { "my-user@my-system" = ; } + ## Create all available homes. + ## Example Usage: + ## ```nix + ## create-homes { users."my-user@my-system".specialArgs.x = true; modules = [ my-shared-module ]; } + ## ``` + ## Result: + ## ```nix + ## { "my-user@my-system" = ; } + ## ``` + #@ Attrs -> Attrs create-homes = homes: let targets = snowfall-lib.fs.get-directories user-homes-root; @@ -179,10 +210,16 @@ in in created-homes; - # Create system modules for home-manager integration. - # Type: Attrs -> [Module] - # Usage: create-home-system-modules { users."my-user@my-system".specialArgs.x = true; modules = [ my-shared-module ]; } - # result: [Module] + ## Create system modules for home-manager integration. + ## Example Usage: + ## ```nix + ## create-home-system-modules { users."my-user@my-system".specialArgs.x = true; modules = [ my-shared-module ]; } + ## ``` + ## Result: + ## ```nix + ## [Module] + ## ``` + #@ Attrs -> [Module] create-home-system-modules = users: let created-users = create-homes users; diff --git a/lib/home/nix-registry-module.nix b/snowfall-lib/home/nix-registry-module.nix similarity index 100% rename from lib/home/nix-registry-module.nix rename to snowfall-lib/home/nix-registry-module.nix diff --git a/lib/internal/default.nix b/snowfall-lib/internal/default.nix similarity index 96% rename from lib/internal/default.nix rename to snowfall-lib/internal/default.nix index 40aa8b3..e61eb73 100644 --- a/lib/internal/default.nix +++ b/snowfall-lib/internal/default.nix @@ -42,7 +42,7 @@ let system-lib = snowfall-lib.attrs.merge-shallow [ base-lib - { internal = user-lib; } + { "${snowfall-config.namespace}" = user-lib; } ]; in { diff --git a/lib/module/default.nix b/snowfall-lib/module/default.nix similarity index 89% rename from lib/module/default.nix rename to snowfall-lib/module/default.nix index 6ef087a..7b12e45 100644 --- a/lib/module/default.nix +++ b/snowfall-lib/module/default.nix @@ -12,10 +12,16 @@ let in { module = { - # Create flake output modules. - # Type: Attrs -> Attrs - # Usage: create-modules { src = ./my-modules; overrides = { inherit another-module; }; alias = { default = "another-module" }; } - # result: { another-module = ...; my-module = ...; default = ...; } + ## Create flake output modules. + ## Example Usage: + ## ```nix + ## create-modules { src = ./my-modules; overrides = { inherit another-module; }; alias = { default = "another-module" }; } + ## ``` + ## Result: + ## ```nix + ## { another-module = ...; my-module = ...; default = ...; } + ## ``` + #@ Attrs -> Attrs create-modules = { src ? "${user-modules-root}/nixos" , overrides ? { } diff --git a/lib/overlay/default.nix b/snowfall-lib/overlay/default.nix similarity index 86% rename from lib/overlay/default.nix rename to snowfall-lib/overlay/default.nix index be2ea5d..f1fd589 100644 --- a/lib/overlay/default.nix +++ b/snowfall-lib/overlay/default.nix @@ -12,10 +12,16 @@ let in { overlay = { - # Create a flake-utils-plus overlays builder. - # Type: Attrs -> Attrs -> [(a -> b -> c)] - # Usage: create-overlays { src = ./my-overlays; package-namespace = "my-packages"; } - # result: (channels: [ ... ]) + ## Create a flake-utils-plus overlays builder. + ## Example Usage: + ## ```nix + ## create-overlays { src = ./my-overlays; package-namespace = "my-packages"; } + ## ``` + ## Result: + ## ```nix + ## (channels: [ ... ]) + ## ``` + #@ Attrs -> Attrs -> [(a -> b -> c)] create-overlays-builder = { src ? user-overlays-root , package-namespace ? "internal" @@ -41,12 +47,17 @@ in in overlays; - # Create exported overlays from the user flake. - # Adapted from flake-utils-plus: - # https://github.com/gytis-ivaskevicius/flake-utils-plus/blob/2bf0f91643c2e5ae38c1b26893ac2927ac9bd82a/lib/exportOverlays.nix - # Type: Attrs -> Attrs - # Usage: create-overlays { src = ./my-overlays; packages-src = ./my-packages; package-namespace = "my-namespace"; extra-overlays = {}; } - # result: { default = final: prev: ...; some-overlay = final: prev: ...; } + ## Create exported overlays from the user flake. Adapted [from flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus/blob/2bf0f91643c2e5ae38c1b26893ac2927ac9bd82a/lib/exportOverlays.nix). + ## + ## Example Usage: + ## ```nix + ## create-overlays { src = ./my-overlays; packages-src = ./my-packages; package-namespace = "my-namespace"; extra-overlays = {}; } + ## ``` + ## Result: + ## ```nix + ## { default = final: prev: ...; some-overlay = final: prev: ...; } + ## ``` + #@ Attrs -> Attrs create-overlays = { src ? user-overlays-root , packages-src ? user-packages-root diff --git a/lib/package/default.nix b/snowfall-lib/package/default.nix similarity index 72% rename from lib/package/default.nix rename to snowfall-lib/package/default.nix index b77b51c..3fea3b5 100644 --- a/lib/package/default.nix +++ b/snowfall-lib/package/default.nix @@ -12,10 +12,16 @@ let in { package = rec { - # Create flake output packages. - # Type: Attrs -> Attrs - # Usage: create-packages { inherit channels; src = ./my-packages; overrides = { inherit another-package; }; alias.default = "another-package"; } - # result: { another-package = ...; my-package = ...; default = ...; } + ## Create flake output packages. + ## Example Usage: + ## ```nix + ## create-packages { inherit channels; src = ./my-packages; overrides = { inherit another-package; }; alias.default = "another-package"; } + ## ``` + ## Result: + ## ```nix + ## { another-package = ...; my-package = ...; default = ...; } + ## ``` + #@ Attrs -> Attrs create-packages = { channels , src ? user-packages-root @@ -40,7 +46,17 @@ in in { name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory package); - drv = callPackageWith extra-inputs package { }; + drv = + let + pkg = callPackageWith extra-inputs package { }; + in + pkg // { + meta = (pkg.meta or { }) // { + snowfall = { + path = package; + }; + }; + }; }; packages-metadata = builtins.map create-package-metadata user-packages; merge-packages = packages: metadata: diff --git a/snowfall-lib/path/default.nix b/snowfall-lib/path/default.nix new file mode 100644 index 0000000..d09173e --- /dev/null +++ b/snowfall-lib/path/default.nix @@ -0,0 +1,114 @@ +{ core-inputs +, user-inputs +, snowfall-lib +, snowfall-config +}: + +let + inherit (builtins) toString baseNameOf dirOf concatStringsSep; + inherit (core-inputs.nixpkgs.lib) assertMsg last init; + + file-name-regex = "(.*)\\.(.*)$"; +in +{ + path = rec { + ## Split a file name and its extension. + ## Example Usage: + ## ```nix + ## split-file-extension "my-file.md" + ## ``` + ## Result: + ## ```nix + ## [ "my-file" "md" ] + ## ``` + #@ String -> [String] + split-file-extension = file: + let + match = builtins.match file-name-regex file; + in + assert assertMsg (match != null) "lib.snowfall.split-file-extension: File must have an extension to split."; + match; + + ## Check if a file name has a file extension. + ## Example Usage: + ## ```nix + ## has-any-file-extension "my-file.txt" + ## ``` + ## Result: + ## ```nix + ## true + ## ``` + #@ String -> Bool + has-any-file-extension = file: + let + match = builtins.match file-name-regex (toString file); + in + match != null; + + ## Get the file extension of a file name. + ## Example Usage: + ## ```nix + ## get-file-extension "my-file.final.txt" + ## ``` + ## Result: + ## ```nix + ## "txt" + ## ``` + #@ String -> String + get-file-extension = file: + if has-any-file-extension file then + let + match = builtins.match file-name-regex (toString file); + in + last match + else + ""; + + ## Check if a file name has a specific file extension. + ## Example Usage: + ## ```nix + ## has-file-extension "txt" "my-file.txt" + ## ``` + ## Result: + ## ```nix + ## true + ## ``` + #@ String -> String -> Bool + has-file-extension = extension: file: + if has-any-file-extension file then + extension == get-file-extension file + else + false; + + ## Get the parent directory for a given path. + ## Example Usage: + ## ```nix + ## get-parent-directory "/a/b/c" + ## ``` + ## Result: + ## ```nix + ## "/a/b" + ## ``` + #@ Path -> Path + get-parent-directory = snowfall-lib.fp.compose baseNameOf dirOf; + + ## Get the file name of a path without its extension. + ## Example Usage: + ## ```nix + ## get-file-name-without-extension ./some-directory/my-file.pdf + ## ``` + ## Result: + ## ```nix + ## "my-file" + ## ``` + #@ Path -> String + get-file-name-without-extension = path: + let + file-name = baseNameOf path; + in + if has-any-file-extension file-name then + concatStringsSep "" (init (split-file-extension file-name)) + else + file-name; + }; +} diff --git a/lib/shell/default.nix b/snowfall-lib/shell/default.nix similarity index 80% rename from lib/shell/default.nix rename to snowfall-lib/shell/default.nix index 4eb5aec..c1cb6a7 100644 --- a/lib/shell/default.nix +++ b/snowfall-lib/shell/default.nix @@ -12,10 +12,16 @@ let in { shell = { - # Create flake output packages. - # Type: Attrs -> Attrs - # Usage: create-shells { inherit channels; src = ./my-shells; overrides = { inherit another-shell; }; alias = { default = "another-shell"; }; } - # result: { another-shell = ...; my-shell = ...; default = ...; } + ## Create flake output packages. + ## Example Usage: + ## ```nix + ## create-shells { inherit channels; src = ./my-shells; overrides = { inherit another-shell; }; alias = { default = "another-shell"; }; } + ## ``` + ## Result: + ## ```nix + ## { another-shell = ...; my-shell = ...; default = ...; } + ## ``` + #@ Attrs -> Attrs create-shells = { channels , src ? user-shells-root diff --git a/lib/system/default.nix b/snowfall-lib/system/default.nix similarity index 73% rename from lib/system/default.nix rename to snowfall-lib/system/default.nix index 6d9bfa5..5e3e345 100644 --- a/lib/system/default.nix +++ b/snowfall-lib/system/default.nix @@ -15,39 +15,69 @@ let in { system = rec { - # Get the name of a system based on its file path. - # Type: Path -> String - # Usage: get-inferred-system-name "/systems/my-system/default.nix" - # result: "my-system" + ## Get the name of a system based on its file path. + ## Example Usage: + ## ```nix + ## get-inferred-system-name "/systems/my-system/default.nix" + ## ``` + ## Result: + ## ```nix + ## "my-system" + ## ``` + #@ Path -> String get-inferred-system-name = path: if snowfall-lib.path.has-file-extension "nix" path then snowfall-lib.path.get-parent-directory path else baseNameOf path; - # Check whether a named system is macOS. - # Type: String -> Bool - # Usage: is-darwin "x86_64-linux" - # result: false + ## Check whether a named system is macOS. + ## Example Usage: + ## ```nix + ## is-darwin "x86_64-linux" + ## ``` + ## Result: + ## ```nix + ## false + ## ``` + #@ String -> Bool is-darwin = hasInfix "darwin"; - # Check whether a named system is Linux. - # Type: String -> Bool - # Usage: is-linux "x86_64-linux" - # result: false + ## Check whether a named system is Linux. + ## Example Usage: + ## ```nix + ## is-linux "x86_64-linux" + ## ``` + ## Result: + ## ```nix + ## false + ## ``` + #@ String -> Bool is-linux = hasInfix "linux"; - # Check whether a named system is virtual. - # Type: String -> Bool - # Usage: is-virtual "x86_64-iso" - # result: true + ## Check whether a named system is virtual. + ## Example Usage: + ## ```nix + ## is-virtual "x86_64-iso" + ## ``` + ## Result: + ## ```nix + ## true + ## ``` + #@ String -> Bool is-virtual = target: (get-virtual-system-type target) != ""; - # Get the virtual system type of a system target. - # Type: String -> String - # Usage: get-virtual-system-type "x86_64-iso" - # result: "iso" + ## Get the virtual system type of a system target. + ## Example Usage: + ## ```nix + ## get-virtual-system-type "x86_64-iso" + ## ``` + ## Result: + ## ```nix + ## "iso" + ## ``` + #@ String -> String get-virtual-system-type = target: foldl (result: virtual-system: @@ -59,10 +89,16 @@ in "" virtual-systems; - # Get structured data about all systems for a given target. - # Type: String -> [Attrs] - # Usage: get-target-systems-metadata "x86_64-linux" - # result: [ { target = "x86_64-linux"; name = "my-machine"; path = "/systems/x86_64-linux/my-machine"; } ] + ## Get structured data about all systems for a given target. + ## Example Usage: + ## ```nix + ## get-target-systems-metadata "x86_64-linux" + ## ``` + ## Result: + ## ```nix + ## [ { target = "x86_64-linux"; name = "my-machine"; path = "/systems/x86_64-linux/my-machine"; } ] + ## ``` + #@ String -> [Attrs] get-target-systems-metadata = target: let systems = snowfall-lib.fs.get-directories target; @@ -82,10 +118,16 @@ in in system-configurations; - # Get the system builder for a given target. - # Type: String -> Function - # Usage: get-system-builder "x86_64-iso" - # result: (args: ) + ## Get the system builder for a given target. + ## Example Usage: + ## ```nix + ## get-system-builder "x86_64-iso" + ## ``` + ## Result: + ## ```nix + ## (args: ) + ## ``` + #@ String -> Function get-system-builder = target: let virtual-system-type = get-virtual-system-type target; @@ -130,10 +172,16 @@ in else linux-system-builder; - # Get the flake output attribute for a system target. - # Type: String -> String - # Usage: get-system-output "aarch64-darwin" - # result: "darwinConfigurations" + ## Get the flake output attribute for a system target. + ## Example Usage: + ## ```nix + ## get-system-output "aarch64-darwin" + ## ``` + ## Result: + ## ```nix + ## "darwinConfigurations" + ## ``` + #@ String -> String get-system-output = target: let virtual-system-type = get-virtual-system-type target; @@ -145,10 +193,16 @@ in else "nixosConfigurations"; - # Get the resolved (non-virtual) system target. - # Type: String -> String - # Usage: get-resolved-system-target "x86_64-iso" - # result: "x86_64-linux" + ## Get the resolved (non-virtual) system target. + ## Example Usage: + ## ```nix + ## get-resolved-system-target "x86_64-iso" + ## ``` + ## Result: + ## ```nix + ## "x86_64-linux" + ## ``` + #@ String -> String get-resolved-system-target = target: let virtual-system-type = get-virtual-system-type target; @@ -158,10 +212,16 @@ in else target; - # Create a system. - # Type: Attrs -> Attrs - # Usage: create-system { path = ./systems/my-system; } - # result: + ## Create a system. + ## Example Usage: + ## ```nix + ## create-system { path = ./systems/my-system; } + ## ``` + ## Result: + ## ```nix + ## + ## ``` + #@ Attrs -> Attrs create-system = { target ? "x86_64-linux" , system ? get-resolved-system-target target @@ -199,10 +259,16 @@ in }; }; - # Create all available systems. - # Type: Attrs -> Attrs - # Usage: create-systems { hosts.my-host.specialArgs.x = true; modules.nixos = [ my-shared-module ]; } - # result: { my-host = ; } + ## Create all available systems. + ## Example Usage: + ## ```nix + ## create-systems { hosts.my-host.specialArgs.x = true; modules.nixos = [ my-shared-module ]; } + ## ``` + ## Result: + ## ```nix + ## { my-host = ; } + ## ``` + #@ Attrs -> Attrs create-systems = { systems ? { }, homes ? { } }: let targets = snowfall-lib.fs.get-directories user-systems-root; diff --git a/lib/system/virtual-systems.nix b/snowfall-lib/system/virtual-systems.nix similarity index 100% rename from lib/system/virtual-systems.nix rename to snowfall-lib/system/virtual-systems.nix diff --git a/lib/template/default.nix b/snowfall-lib/template/default.nix similarity index 76% rename from lib/template/default.nix rename to snowfall-lib/template/default.nix index 6527c3a..40099e7 100644 --- a/lib/template/default.nix +++ b/snowfall-lib/template/default.nix @@ -12,10 +12,18 @@ let in { template = { - # Create flake templates. - # Type: Attrs -> Attrs - # Usage: create-templates { src = ./my-templates; overrides = { inherit another-template; }; alias = { default = "another-template"; }; } - # result: { another-template = ...; my-template = ...; default = ...; } + ## Create flake templates. + ## + ## Example Usage: + ## ```nix + ## create-templates { src = ./my-templates; overrides = { inherit another-template; }; alias = { default = "another-template"; }; } + ## ``` + ## + ## Result: + ## ```nix + ## { another-template = ...; my-template = ...; default = ...; } + ## ``` + #@ Attrs -> Attrs create-templates = { src ? user-templates-root , overrides ? { }