diff --git a/.gitignore b/.gitignore index ccbfadb..65dba65 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -site/ \ No newline at end of file +site/ +result diff --git a/lib/default.nix b/lib/default.nix index c1575fb..209a84f 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,13 +1,49 @@ { inputs, ... }: -# A bunch of helper utilities for the project +# A bunch of helper utilities for the Blueprint project let bpInputs = inputs; nixpkgs = bpInputs.nixpkgs; lib = nixpkgs.lib; -in rec { - # A generator for the top-level attributes of the flake. - # - # Designed to work with https://github.com/nix-systems +in +rec { + /** + Generate the top-level per-system attributes for a flake. + + Designed to work with https://github.com/nix-systems. + + This function memoises per-system arguments in `systemArgs` and exposes an + `eachSystem` helper that maps a callback over all supported systems. + + # Type + + ``` + mkEachSystem :: { + inputs :: AttrSet, + flake :: AttrSet, + systems :: [ String ], + nixpkgs :: { config :: AttrSet; overlays :: [ Overlay ]; }, + unfilteredPackages :: AttrSet, + } -> { systemArgs :: AttrSet; eachSystem :: (AttrSet -> AttrSet) -> AttrSet; } + ``` + + # Arguments + + inputs + : The flake inputs. + + flake + : The current flake (`inputs.self`). + + systems + : List of supported systems. + + nixpkgs + : nixpkgs configuration (`config` and/or `overlays`). + + unfilteredPackages + : Per-system package set, used to break the `perSystem` ↔ `packages` + infinite recursion. + */ mkEachSystem = { inputs, @@ -66,12 +102,63 @@ in rec { inherit systemArgs eachSystem; }; + /** + Apply `f` to `path` if it exists, returning an empty attribute set otherwise. + + # Type + + ``` + optionalPathAttrs :: Path -> (Path -> AttrSet) -> AttrSet + ``` + + # Arguments + + path + : The filesystem path to check. + + f + : Function called with `path` when it exists. + */ optionalPathAttrs = path: f: lib.optionalAttrs (builtins.pathExists path) (f path); - # Imports the path and pass the `args` to it if it exists, otherwise, return an empty attrset. + /** + Import `path` with `args` if it exists, returning an empty attribute set otherwise. + + # Type + + ``` + tryImport :: Path -> AttrSet -> AttrSet + ``` + + # Arguments + + path + : The Nix file to import. + + args + : The attribute set passed to the imported expression. + */ tryImport = path: args: optionalPathAttrs path (path: import path args); - # Maps all the toml files in a directory to name -> path. + /** + Map every `.toml` file in `path` to a name -> { path, type } attribute set. + + Names are derived from the basename without the `.toml` extension. + + # Type + + ``` + importTomlFilesAt :: Path -> (AttrSet -> AttrSet) -> AttrSet + ``` + + # Arguments + + path + : The directory to scan. + + fn + : Callback that receives the resulting attribute set. + */ importTomlFilesAt = path: fn: let @@ -94,7 +181,27 @@ in rec { in lib.optionalAttrs (builtins.pathExists path) (fn nixPaths); - # Maps all the nix files and folders in a directory to name -> path. + /** + Map Nix files and directories in `path` to a name -> { path, type } attribute set. + + Directories are included as-is. Regular `.nix` files are keyed by their + basename without the `.nix` extension and take precedence over a directory + with the same name. + + # Type + + ``` + importDir :: Path -> (AttrSet -> AttrSet) -> AttrSet + ``` + + # Arguments + + path + : The directory to scan. + + fn + : Callback that receives the resulting attribute set. + */ importDir = path: fn: let @@ -127,9 +234,33 @@ in rec { in lib.optionalAttrs (builtins.pathExists path) (fn combined); + /** + Extract just the `path` value from an attribute set of `{ path, type }` entries. + + Useful as the callback for `importDir` when only the path is needed. + + # Type + + ``` + entriesPath :: AttrSet -> AttrSet + ``` + */ entriesPath = lib.mapAttrs (_name: { path, type }: path); - # Prefixes all the keys of an attrset with the given prefix + /** + Prefix every key of an attribute set with `prefix`. + + # Type + + ``` + withPrefix :: String -> AttrSet -> AttrSet + ``` + + # Arguments + + prefix + : String prepended to each key. + */ withPrefix = prefix: lib.mapAttrs' ( @@ -139,12 +270,37 @@ in rec { } ); - # Resolve perSystem. for every flake input. For inputs.self, - # `selfPackages` is merged instead of `self.packages.${system}` so the - # caller can break the packages → filterPlatforms → perSystem.self - # → packages cycle (see the comment on `unfilteredPackages` in - # mkEachSystem) and, in the overlay case, point intra-set references - # at the set built against the caller's nixpkgs. + /** + Resolve `perSystem.` for every flake input. + + For `inputs.self`, `selfPackages` is merged instead of + `self.packages.${system}` so the caller can break the + `packages → filterPlatforms → perSystem.self → packages` cycle + (see the comment on `unfilteredPackages` in `mkEachSystem`) and, + in the overlay case, point intra-set references at the set built + against the caller's nixpkgs. + + # Type + + ``` + mkPerSystem :: { + inputs :: AttrSet, + system :: String, + selfPackages :: AttrSet, + } -> AttrSet + ``` + + # Arguments + + inputs + : The flake inputs. + + system + : The system to resolve for. + + selfPackages + : The package set used for `inputs.self`. + */ mkPerSystem = { inputs, @@ -157,6 +313,25 @@ in rec { // (if name == "self" then selfPackages else input.packages.${system} or { }) ) inputs; + /** + Filter an attribute set of derivations to those that support `system`. + + Derivations without `meta.platforms` are kept unconditionally. + + # Type + + ``` + filterPlatforms :: String -> AttrSet -> AttrSet + ``` + + # Arguments + + system + : The platform to keep packages for. + + attrs + : The attribute set of derivations to filter. + */ filterPlatforms = system: attrs: lib.filterAttrs ( @@ -167,6 +342,42 @@ in rec { lib.elem system x.meta.platforms ) attrs; + /** + Internal implementation of `mkBlueprint`. + + Builds the complete set of flake outputs from the project folder structure + under `src`. Use `mkBlueprint` instead unless you need to override internal + wiring. + + # Type + + ``` + mkBlueprint' :: { + inputs :: AttrSet, + nixpkgs :: AttrSet, + flake :: AttrSet, + src :: Path, + systems :: [ String ], + } -> AttrSet + ``` + + # Arguments + + inputs + : The flake inputs. + + nixpkgs + : nixpkgs configuration (`config` and/or `overlays`). + + flake + : The current flake (`inputs.self`). + + src + : The project source path. + + systems + : List of supported systems. + */ mkBlueprint' = { inputs, @@ -386,7 +597,8 @@ in rec { nixpkgsConfigModule perSystemModule path - ] ++ mkHomeUsersModule hostName home-manager.nixosModules.default; + ] + ++ mkHomeUsersModule hostName home-manager.nixosModules.default; specialArgs = specialArgs // { inherit hostName; }; @@ -430,7 +642,8 @@ in rec { nixpkgsConfigModule perSystemModule path - ] ++ mkHomeUsersModule hostName home-manager.darwinModules.default; + ] + ++ mkHomeUsersModule hostName home-manager.darwinModules.default; specialArgs = specialArgs // { inherit hostName; }; @@ -556,19 +769,33 @@ in rec { })); # See the comment in mkEachSystem - unfilteredPackages = - lib.traceIf (builtins.pathExists (src + "/pkgs")) "blueprint: the /pkgs folder is now /packages" - (eachSystem ({ pkgs, ... }: mkPackagesFor pkgs)); - - # Load the packages/ tree against a given nixpkgs instance. - # Packages get the same scope arguments as via systemArgs (pkgs, - # flake, inputs, system, perSystem, pname). perSystem.self resolves - # within this scope so intra-set references stay consistent with - # the supplied nixpkgs. - # - # Used internally for packages. (with blueprint's own - # pkgs) and exposed so consumers can build an overlay that uses - # their pkgs instead. + unfilteredPackages = lib.traceIf (builtins.pathExists ( + src + "/pkgs" + )) "blueprint: the /pkgs folder is now /packages" (eachSystem ({ pkgs, ... }: mkPackagesFor pkgs)); + + /** + Load the `packages/` tree against a given nixpkgs instance. + + Packages get the same scope arguments as via `systemArgs` (`pkgs`, + `flake`, `inputs`, `system`, `perSystem`, `pname`). `perSystem.self` + resolves within this scope so intra-set references stay consistent + with the supplied nixpkgs. + + Used internally for `packages.` (with Blueprint's own `pkgs`) + and exposed so consumers can build an overlay that uses their `pkgs` + instead. + + # Type + + ``` + mkPackagesFor :: AttrSet -> AttrSet + ``` + + # Arguments + + pkgs + : The nixpkgs instance to build the packages against. + */ mkPackagesFor = pkgs: let @@ -698,8 +925,12 @@ in rec { darwinConfigurations = lib.mapAttrs (_: x: x.value) (hostsByCategory.darwinConfigurations or { }); nixosConfigurations = lib.mapAttrs (_: x: x.value) (hostsByCategory.nixosConfigurations or { }); systemConfigs = lib.mapAttrs (_: x: x.value) (hostsByCategory.systemConfigs or { }); - robotnixConfigurations = lib.mapAttrs (_: x: x.value) (hostsByCategory.robotnixConfigurations or { }); - nixOnDroidConfigurations = lib.mapAttrs (_: x: x.value) (hostsByCategory.nixOnDroidConfigurations or { }); + robotnixConfigurations = lib.mapAttrs (_: x: x.value) ( + hostsByCategory.robotnixConfigurations or { } + ); + nixOnDroidConfigurations = lib.mapAttrs (_: x: x.value) ( + hostsByCategory.nixOnDroidConfigurations or { } + ); inherit modules; @@ -747,13 +978,17 @@ in rec { # add nixos system closures to checks (withPrefix "nixos-" ( lib.mapAttrs (_: x: x.config.system.build.toplevel) ( - lib.filterAttrs (_: x: x.pkgs.stdenv.hostPlatform.system == system) (inputs.self.nixosConfigurations or { }) + lib.filterAttrs (_: x: x.pkgs.stdenv.hostPlatform.system == system) ( + inputs.self.nixosConfigurations or { } + ) ) )) # add darwin system closures to checks (withPrefix "darwin-" ( lib.mapAttrs (_: x: x.system) ( - lib.filterAttrs (_: x: x.pkgs.stdenv.hostPlatform.system == system) (inputs.self.darwinConfigurations or { }) + lib.filterAttrs (_: x: x.pkgs.stdenv.hostPlatform.system == system) ( + inputs.self.darwinConfigurations or { } + ) ) )) # add system-manager closures to checks @@ -797,7 +1032,40 @@ in rec { ); }; - # Create a new flake blueprint + /** + Create a new Blueprint flake. + + This is the main entry point for consumers. It takes the project inputs, + an optional `prefix` under which the Blueprint folder structure lives, + nixpkgs configuration and a list of systems, and returns the generated + flake outputs. + + # Type + + ``` + mkBlueprint :: { + inputs :: AttrSet, + prefix :: Path | String | null, + nixpkgs :: { config :: AttrSet; overlays :: [ Overlay ]; }, + systems :: [ String ] | Path, + } -> AttrSet + ``` + + # Arguments + + inputs + : The flake inputs. `inputs.self` is the flake being built. + + prefix + : Optional sub-directory under `inputs.self` where the Blueprint + structure lives. Can be `null`, a `Path`, or a `String`. + + nixpkgs + : nixpkgs configuration (`config` and/or `overlays`). + + systems + : List of supported systems, or a path to a nix-systems file. + */ mkBlueprint = { # Pass the flake inputs to blueprint @@ -838,6 +1106,11 @@ in rec { }; }; - # Make this callable + /** + Make `lib.blueprint` callable as a function. + + Calling `inputs.blueprint { inherit inputs; }` is equivalent to + `inputs.blueprint.lib.mkBlueprint { inherit inputs; }`. + */ __functor = _: mkBlueprint; } diff --git a/mkdocs.yml b/mkdocs.yml index 608bb9a..1f91f62 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -105,6 +105,20 @@ markdown_extensions: - pymdownx.snippets - pymdownx.keys +nav: + - Home: index.md + - Getting Started: + - getting-started/install.md + - getting-started/folder_structure.md + - getting-started/built_in_templates.md + - getting-started/configuration.md + - Guides: + - guides/examples.md + - guides/configuring_direnv.md + - Contributing: + - contributing/code.md + - Library Reference: reference/lib_reference.md + plugins: - awesome-pages - mike diff --git a/packages/docs/default.nix b/packages/docs/default.nix index 84bf8d3..8225a1c 100644 --- a/packages/docs/default.nix +++ b/packages/docs/default.nix @@ -1,14 +1,29 @@ { pkgs, perSystem, + inputs, ... }: +let + libReference = pkgs.runCommandLocal "lib-reference" { nativeBuildInputs = [ pkgs.nixdoc ]; } '' + mkdir $out + nixdoc --category lib \ + --description "Blueprint public library functions" \ + --file ${../../lib/default.nix} \ + --prefix "" \ + --anchor-prefix "" \ + > $out/lib_reference.md + ''; +in pkgs.stdenvNoCC.mkDerivation { name = "docs"; unpackPhase = '' - cp ${../../mkdocs.yml} mkdocs.yaml cp -r ${../../docs} docs + chmod -R +w docs + cp ${../../mkdocs.yml} mkdocs.yaml + mkdir -p docs/content/reference + cp ${libReference}/lib_reference.md docs/content/reference/lib_reference.md ''; nativeBuildInputs = with pkgs.python3Packages; [