diff --git a/README.md b/README.md index e390ea24..b2dcc1e8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,12 @@ _Core of a distributed framework for writing Nix Flakes._ -`flake-parts` provides the options that represent standard flake attributes and establishes a way of working with `system`. Opinionated features are provided by an ecosystem of modules that you can import. +`flake-parts` provides the options that represent standard flake attributes +and establishes a way of working with `system`. +Opinionated features are provided by an ecosystem of modules that you can import. + +`flake-parts` _itself_ has the goal to be a minimal mirror of the Nix flake schema. +Used by itself, it is very lightweight. # Why Modules? @@ -16,8 +21,20 @@ module system has done for NixOS configurations. Unlike NixOS, but following Flakes' spirit, `flake-parts` is not a monorepo with the implied goal of absorbing all of open source, but rather a single module that other repositories can build upon, while ensuring a -baseline level of compatibility: which core attribute make up a flake and -how these are represented as module options. +baseline level of compatibility: the core attributes that constitute a flake. + +# Features + + - Split your `flake.nix` into focused units, each in their own file. + + - Take care of [system](./system.md). + + - Allow users of your library flake to easily integrate your generated flake outputs + into their flake. + + - Reuse project logic written by others + + # Getting Started diff --git a/dev/flake-module.nix b/dev/flake-module.nix index a621da92..95fdb639 100644 --- a/dev/flake-module.nix +++ b/dev/flake-module.nix @@ -16,6 +16,7 @@ pkgs.hci pkgs.netlify-cli pkgs.pandoc + pkgs.mdbook ]; shellHook = '' ${config.pre-commit.installationScript} diff --git a/dev/flake.lock b/dev/flake.lock index 60bc8b02..edcf2df9 100644 --- a/dev/flake.lock +++ b/dev/flake.lock @@ -69,6 +69,21 @@ "type": "github" } }, + "haskell-flake": { + "locked": { + "lastModified": 1668167720, + "narHash": "sha256-5wDTR6xt9BB3BjgKR+YOjOkZgMyDXKaX79g42sStzDU=", + "owner": "srid", + "repo": "haskell-flake", + "rev": "4fc511d93a55fedf815c1647ad146c26d7a2054e", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "haskell-flake", + "type": "github" + } + }, "hercules-ci-agent": { "inputs": { "flake-parts": "flake-parts_2", @@ -244,6 +259,7 @@ }, "root": { "inputs": { + "haskell-flake": "haskell-flake", "hercules-ci-effects": "hercules-ci-effects", "nixpkgs": "nixpkgs_3", "pre-commit-hooks-nix": "pre-commit-hooks-nix_2" diff --git a/dev/flake.nix b/dev/flake.nix index 3344f423..05c29906 100644 --- a/dev/flake.nix +++ b/dev/flake.nix @@ -12,6 +12,8 @@ pre-commit-hooks-nix.inputs.nixpkgs.follows = "nixpkgs"; hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects"; + + haskell-flake.url = "github:srid/haskell-flake"; }; outputs = { self, ... }: diff --git a/site/.gitignore b/site/.gitignore new file mode 100644 index 00000000..7585238e --- /dev/null +++ b/site/.gitignore @@ -0,0 +1 @@ +book diff --git a/site/book.toml b/site/book.toml new file mode 100644 index 00000000..fbede22f --- /dev/null +++ b/site/book.toml @@ -0,0 +1,6 @@ +[book] +authors = ["Robert Hensing", "Various module authors"] +language = "en" +multilingual = false +src = "src" +title = "flake-parts" diff --git a/site/flake-module.nix b/site/flake-module.nix index 617ccd89..6e99b562 100644 --- a/site/flake-module.nix +++ b/site/flake-module.nix @@ -8,6 +8,7 @@ imports = [ inputs.pre-commit-hooks-nix.flakeModule inputs.hercules-ci-effects.flakeModule + inputs.haskell-flake.flakeModule ]; }; opts = eval.options; @@ -31,9 +32,9 @@ then opt // { visible = false; } else opt // { inherit declarations; }; - optionsDoc = { sourceName, baseUrl, sourcePath, title }: pkgs.runCommand "${sourceName}-doc" + optionsDoc = { sourceName, baseUrl, sourcePath, title }: pkgs.runCommand "option-doc-${sourceName}" { - nativeBuildInputs = [ pkgs.libxslt.bin ]; + nativeBuildInputs = [ pkgs.libxslt.bin pkgs.pandoc ]; inputDoc = (pkgs.nixosOptionsDoc { options = opts; documentType = "none"; @@ -46,75 +47,84 @@ inherit title; } '' xsltproc --stringparam title "$title" \ - -o $out ${./options.xsl} \ + -o options.db.xml ${./options.xsl} \ "$inputDoc" + mkdir $out + pandoc --verbose --from docbook --to html options.db.xml >$out/options.md; ''; + + repos = { + flake-parts = { + title = "Core Options"; + sourceName = "flake-parts"; + baseUrl = "https://github.com/hercules-ci/flake-parts/blob/main"; + sourcePath = ../.; + }; + pre-commit-hooks-nix = { + title = "pre-commit-hooks.nix"; + sourceName = "pre-commit-hooks.nix"; + baseUrl = "https://github.com/hercules-ci/pre-commit-hooks.nix/blob/flakeModule"; + sourcePath = inputs.pre-commit-hooks-nix; + }; + hercules-ci-effects = { + title = "hercules-ci-effects"; + sourceName = "hercules-ci-effects"; + baseUrl = "https://github.com/hercules-ci/hercules-ci-effects/blob/master"; + sourcePath = inputs.hercules-ci-effects; + }; + haskell-flake = { + title = "haskell-flake"; + sourceName = "haskell-flake"; + baseUrl = "https://github.com/srid/haskell-flake/blob/master"; + sourcePath = inputs.haskell-flake; + }; + }; + + generatedDocs = lib.mapAttrs (k: optionsDoc) repos; + generatedDocs' = lib.mapAttrs' (name: value: { name = "generated-docs-${name}"; inherit value; }) generatedDocs; + in { - packages = { - siteContent = pkgs.stdenvNoCC.mkDerivation { name = "site"; - nativeBuildInputs = [ pkgs.pandoc pkgs.libxslt.bin ]; - src = lib.cleanSourceWith { - filter = path: type: - path == ./. - || baseNameOf path == "index.html"; - src = ./.; - }; - coreOptions = optionsDoc { - title = "Core Options"; - sourceName = "flake-parts"; - baseUrl = "https://github.com/hercules-ci/flake-parts/blob/main"; - sourcePath = ../.; - }; - # TODO make this a dynamic input - pre_commit_hooks_nixOptions = optionsDoc { - title = "pre-commit-hooks.nix"; - sourceName = "pre-commit-hooks.nix"; - baseUrl = "https://github.com/hercules-ci/pre-commit-hooks.nix/blob/flakeModule"; - sourcePath = inputs.pre-commit-hooks-nix; - }; - # TODO make this a dynamic input - hercules_ci_effectsOptions = optionsDoc { - title = "hercules-ci-effects"; - sourceName = "hercules-ci-effects"; - baseUrl = "https://github.com/hercules-ci/hercules-ci-effects/blob/master"; - sourcePath = inputs.hercules-ci-effects; - }; - # pandoc - htmlBefore = '' - - - Options - - - - ''; - htmlAfter = '' - - - ''; + nativeBuildInputs = [ pkgs.mdbook ]; + src = ./.; buildPhase = '' - ( echo "$htmlBefore"; - pandoc --verbose --from docbook --to html5 $coreOptions; - pandoc --verbose --from docbook --to html5 $hercules_ci_effectsOptions; - pandoc --verbose --from docbook --to html5 $pre_commit_hooks_nixOptions; - echo "$htmlAfter"; ) >options.html - ''; - installPhase = '' - mkdir -p $out - cp *.html $out/ + runHook preBuild + + { + while read ln; do + case "$ln" in + *end_of_intro*) + break + ;; + *) + echo "$ln" + ;; + esac + done + cat src/intro-continued.md + } <${../README.md} >src/README.md + + mkdir -p src/options + ${lib.concatStringsSep "\n" + (lib.mapAttrsToList + (name: generated: '' + cp '${generated}/options.md' 'src/options/${name}.md' + '') + generatedDocs) + } + + mdbook build --dest-dir $out + + echo 'to the options' \ + >$out/options.html + + runHook postBuild ''; + dontInstall = true; }; - }; + } // generatedDocs'; }; } diff --git a/site/index.html b/site/index.html deleted file mode 100644 index 271133f8..00000000 --- a/site/index.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - flake-parts - - - -

flake-parts

- -

- Compose flakes with the (NixOS) module system. -

- -

- Testimonials: -

- -
- yeah.. powerful stuff -
- -
- I cannot tell you how freeing the flake-modules concept is
- fucking hell
- I feel like a hipster using it too -
- -

- Learn more: -

- -

- GitHub -

- -

- Options Reference -

- -

- ChangeLog -

- -

- Integrations: -

- - -

Write your own integration

- -

- For a general introduction to modules, you can read Writing Modules in the NixOS manual, though it goes into NixOS specifics quite quickly. Instead of services.<name>.*, etc, we have our own options. -

- -

- Writing modules in a distributed ecosystem can be a bit different. If you're inclined to write to some other module's options, consider whether those will be loaded and whether your integration idea is always desirable. If it's not always desirable, consider splitting it off into an extra module, e.g. flakeModules.someOther. Otherwise check if it's loaded: lib.optionalAttrs (options?some.other.option). You can ask @roberth on GitHub. -

- - - - \ No newline at end of file diff --git a/site/options.xsl b/site/options.xsl index c1920d6f..830825d6 100644 --- a/site/options.xsl +++ b/site/options.xsl @@ -14,6 +14,10 @@ <xsl:value-of select="$title"/> + Overview: + + + diff --git a/site/src/SUMMARY.md b/site/src/SUMMARY.md new file mode 100644 index 00000000..6c24d4f3 --- /dev/null +++ b/site/src/SUMMARY.md @@ -0,0 +1,12 @@ +# Summary + +- [Introduction](./README.md) +- [Getting Started](./getting-started.md) +- [Working with `system`](./system.md) +- [Reference Documentation](./module-arguments.md) + - [Module Arguments](./module-arguments.md) + - [Options](./options/flake-parts.md) + - [Core `flake-parts`](./options/flake-parts.md) + - [`haskell-flake`](./options/haskell-flake.md) + - [`hercules-ci-effects`](./options/hercules-ci-effects.md) + - [`pre-commit-hooks.nix`](./options/pre-commit-hooks-nix.md) diff --git a/site/src/getting-started.md b/site/src/getting-started.md new file mode 100644 index 00000000..1cd713d5 --- /dev/null +++ b/site/src/getting-started.md @@ -0,0 +1,38 @@ + +# Getting Started + +## New flake + +If your project does not have a flake yet: + +```console +nix flake init -t github:hercules-ci/flake-parts +``` + +## Existing flake + +Otherwise, add the input, + +``` + flake-parts.url = "github:hercules-ci/flake-parts"; +``` + +then slide `mkFlake` between your outputs function head and body, + +``` + outputs = { self, flake-parts, ... }: + flake-parts.lib.mkFlake { inherit self; } { + flake = { + # Put your original flake attributes here. + }; + systems = [ + # systems for which you want to build the `perSystem` attributes + "x86_64-linux" + # ... + ]; + perSystem = { config, ... }: { + }; + }; +``` + +Now you can start using the flake-parts options. diff --git a/site/src/intro-continued.md b/site/src/intro-continued.md new file mode 100644 index 00000000..e398c97d --- /dev/null +++ b/site/src/intro-continued.md @@ -0,0 +1,7 @@ + + +# This documentation + +You can find guides and the options reference in the menu (top left). + +A site wide search is available by typing `s`. diff --git a/site/src/module-arguments.md b/site/src/module-arguments.md new file mode 100644 index 00000000..438305aa --- /dev/null +++ b/site/src/module-arguments.md @@ -0,0 +1,58 @@ + +# Module Arguments + +The module system allows modules and submodules to be defined using plain +attribute sets, or functions that return attribute sets. When a module is a +function, various attributes may be passed to it. + +# Top-level Module Arguments + +Top-level refers to the module passed to `mkFlake`, or any of the modules +imported into it using `imports`. + +The standard module system arguments are available in all modules and submodules. These are chiefly `config`, `options`, `lib`. + +## `getSystem` + +A function from [system](./system.md) string to the `config` of the appropriate `perSystem`. + +## `moduleWithSystem` + +A function that brings the `perSystem` module arguments. +This allows a module to reference the defining flake without introducing +global variables. + +```nix +{ moduleWithSystem, ... }: +{ + nixosModules.default = moduleWithSystem ( + perSystem@{ config }: # NOTE: only explicit params will be in perSystem + nixos@{ ... }: + { + services.foo.package = perSystem.config.packages.foo; + imports = [ ./nixos-foo.nix ]; + } + ); +} +``` + +## `withSystem` + +Enter the scope of a system. Worked example: + +```nix +{ withSystem, ... }: +{ + # perSystem = ...; + + nixosConfigurations.foo = withSystem "x86_64-linux" (ctx@{ pkgs, ... }: + pkgs.nixos ({ config, lib, packages, pkgs, ... }: { + _module.args.packages = ctx.config.packages; + imports = [ ./nixos-configuration.nix ]; + services.nginx.enable = true; + environment.systemPackages = [ + packages.hello + ]; + })); +} +``` diff --git a/site/src/system.md b/site/src/system.md new file mode 100644 index 00000000..64ed6358 --- /dev/null +++ b/site/src/system.md @@ -0,0 +1,20 @@ + +# `system` + +In Nix, "system" generally refers to the cpu-os string, such as `"x86_64-linux"`. + +In Flakes specifically, these strings are used as attribute names, so that the +Nix CLI can find a derivation for the right platform. + +Many things, such as packages, can exist on multiple systems. For these, use +the [`perSystem`](options/flake-parts.html#opt-perSystem) submodule. + +Other things do not exist on multiple systems. Examples are the configuration +of a specific machine, or a the execution of a deployment. These are not +written in `perSystem`, but in other top-level options, or directly into the +flake outputs' top level (e.g. [`flake.nixosConfigurations`](options/flake-parts.html#opt-flake.nixosConfigurations)). + +Such top-level entities typically do need to read packages, etc that are defined +in `perSystem`. Instead of reading them from `config.flake.packages..`, +it may be more convenient to bring all `perSystem` definitions for a system into +scope, using [`withSystem`](module-arguments.html#withsystem).