diff --git a/doc/mkFlakeOptions.md b/doc/mkFlakeOptions.md new file mode 100644 index 000000000..529d0027e --- /dev/null +++ b/doc/mkFlakeOptions.md @@ -0,0 +1,160 @@ +## extern +Function with argument 'inputs' that contains all devos and ${self}'s inputs. +The function should return an attribute set with modules, overlays, and +specialArgs to be included across nixos and home manager configurations. +Only attributes that are used should be returned. + + +*_Type_*: +function that evaluates to a(n) attrs + +*_Default_* +``` +"{ modules = []; overlays = []; specialArgs = []; userModules = []; userSpecialArgs = []; }\n" +``` + + +## hosts +Path to directory containing host configurations that will be exported +to the 'nixosConfigurations' output. + + +*_Type_*: +path + +*_Default_* +``` +"${self}/hosts" +``` + + +## modules +list of modules to include in confgurations and export in 'nixosModules' output + + +*_Type_*: +list of valid modules + +*_Default_* +``` +[] +``` + + +## overlays +path to folder containing overlays which will be applied to pkgs and exported in +the 'overlays' output + + +*_Type_*: +path + +*_Default_* +``` +"${self}/overlays" +``` + + +## overrides +attrset of packages and modules that will be pulled from nixpkgs master + +*_Type_*: +attribute set + +*_Default_* +``` +"{ modules = []; disabledModules = []; packages = {}; }" +``` + + +## packages +Overlay for custom packages that will be included in treewide 'pkgs'. +This should follow the standard nixpkgs overlay format - two argument function +that returns an attrset. +These packages will be exported to the 'packages' and 'legacyPackages' outputs. + + +*_Type_*: +Nixpkgs overlay + +*_Default_* +``` +"(final: prev: {})" +``` + + +## profiles +path to profiles folder that can be collected into suites + +*_Type_*: +path + +*_Default_* +``` +"${self}/profiles" +``` + + +## self +The flake to create the devos outputs for + +*_Type_*: +attribute set + + + +## suites +Function with inputs 'users' and 'profiles' that returns attribute set +with user and system suites. The former for Home Manager and the latter +for nixos configurations. +These can be accessed through the 'suites' specialArg in each config system. + + +*_Type_*: +function that evaluates to a(n) attrs + +*_Default_* +``` +"{ user = {}; system = {}; }" +``` + + +## userModules +list of modules to include in home-manager configurations and export in +'homeModules' output + + +*_Type_*: +list of valid modules + +*_Default_* +``` +[] +``` + + +## userProfiles +path to user profiles folder that can be collected into userSuites + +*_Type_*: +path + +*_Default_* +``` +"${self}/users/profiles" +``` + + +## users +path to folder containing profiles that define system users + + +*_Type_*: +path + +*_Default_* +``` +"${self}/users" +``` + + diff --git a/doc/start/index.md b/doc/start/index.md index 48d2b16f7..9fa0061cf 100644 --- a/doc/start/index.md +++ b/doc/start/index.md @@ -33,6 +33,7 @@ In addition, the [binary cache](../../cachix) is added for faster deployment. > upstream changes. ## Next Steps: +- [Use Devos as a library!](./mkflake.md) - [Make installable ISO](./iso.md) - [Bootstrap Host](./bootstrapping.md) - [Already on NixOS](./from-nixos.md) diff --git a/doc/start/mkflake.md b/doc/start/mkflake.md new file mode 100644 index 000000000..6b2236271 --- /dev/null +++ b/doc/start/mkflake.md @@ -0,0 +1,42 @@ +# Use Devos as a library! +You can also add devos as a flake input and use its library function, `mkFlake` to +create your flake. This gives you the advantage of using nix flakes to sync with +upstream changes in devos. + +You can either use the default template or use the 'mkflake' template which only +includes the necessary folders for `mkFlake` usage. It can be pulled with: +```sh +nix flake init -t github:divnix/devos#mkflake +``` + +Once you have a template, you need to add devos as a flake input, which would look +like this: +```nix +inputs = { + ... + devos.url = "github:divnix/devos"; +}; +``` +> ##### Note: +> - All devos inputs must still be included in your flake, due to a nix +> [issue](https://github.com/NixOS/nix/pull/4641) with the `follows` attribute. +> - You can append `/community` to access community modules [extern](../../extern). + +You can then call `mkFlake` to create your outputs. Here is a simple example: +```nix +outputs = { self, devos, ... }: devos.lib.mkFlake { + inherit self; + hosts = ./hosts; +}; +``` +`mkFlake` has various arguments to include more devos concepts like suites and profiles. +These options are documented in [mkFlakeOptions](../mkFlakeOptions.md). + +The devos template itself uses mkFlake to export its own outputs, so you can take +a look at this repository's [flake.nix](../../flake.nix) for a more realistic use +of `mkFlake`. + +You can now sync with upstream devos changes just like any other flake input. But +you will no longer be able to edit devos's internals, since you are directly following +upstream devos changes. + diff --git a/flake.lock b/flake.lock index 399626897..dad9766c6 100644 --- a/flake.lock +++ b/flake.lock @@ -216,7 +216,7 @@ ] }, "locked": { - "narHash": "sha256-XG4TOZObj2Wd8KiqnHgtlWjjMbJOIJB7+DxUFzMCXw8=", + "narHash": "sha256-8Xx9gpptVG5H114Tpv+Xfn1gUtXcDUaUnjH3x3KFiso=", "path": "./pkgs", "type": "path" }, diff --git a/flake.nix b/flake.nix index 2af75209e..4f5d3564b 100644 --- a/flake.nix +++ b/flake.nix @@ -28,79 +28,33 @@ pkgs.inputs.nixpkgs.follows = "nixos"; }; - outputs = inputs@{ deploy, nixos, nur, self, utils, ... }: - let - inherit (self) lib; - inherit (lib) os; - - extern = import ./extern { inherit inputs; }; - overrides = import ./overrides; - - multiPkgs = os.mkPkgs { - inherit extern overrides; - }; - - suites = os.mkSuites { + outputs = inputs@{ deploy, nixos, nur, self, utils, ... }: + let + lib = import ./lib { inherit self nixos inputs; }; + in lib.mkFlake { + inherit self; + hosts = ./hosts; + packages = import ./pkgs; suites = import ./suites; - users = os.mkProfileAttrs "${self}/users"; - profiles = os.mkProfileAttrs "${self}/profiles"; - userProfiles = os.mkProfileAttrs "${self}/users/profiles"; - }; - - outputs = { - nixosConfigurations = os.mkHosts { - dir = "${self}/hosts"; - overrides = import ./overrides; - inherit multiPkgs suites extern; - }; - - homeConfigurations = os.mkHomeConfigurations; - - nixosModules = - let moduleList = import ./modules/module-list.nix; - in lib.pathsToImportedAttrs moduleList; - - homeModules = - let moduleList = import ./users/modules/module-list.nix; - in lib.pathsToImportedAttrs moduleList; - - overlay = import ./pkgs; - overlays = lib.pathsToImportedAttrs (lib.pathsIn ./overlays); - - lib = import ./lib { inherit nixos self inputs; }; - + extern = import ./extern; + overrides = import ./overrides; + overlays = ./overlays; + profiles = ./profiles; + userProfiles = ./users/profiles; + modules = import ./modules/module-list.nix; + userModules = import ./users/modules/module-list.nix; + } // { + inherit lib; + defaultTemplate = self.templates.flk; templates.flk.path = ./.; templates.flk.description = "flk template"; - defaultTemplate = self.templates.flk; - - deploy.nodes = os.mkNodes deploy self.nixosConfigurations; + templates.mkflake.path = + let + excludes = [ "lib" "tests" "cachix" "nix" "theme" ".github" "bors.toml" "cachix.nix" ]; + filter = path: type: ! builtins.elem (baseNameOf path) excludes; + in + builtins.filterSource filter ./.; + templates.mkflake.description = "template with necessary folders for mkFlake usage"; }; - systemOutputs = utils.lib.eachDefaultSystem (system: - let - pkgs = multiPkgs.${system}; - # all packages that are defined in ./pkgs - legacyPackages = os.mkPackages { inherit pkgs; }; - in - { - checks = - let - tests = nixos.lib.optionalAttrs (system == "x86_64-linux") - (import ./tests { inherit self pkgs; }); - deployHosts = nixos.lib.filterAttrs - (n: _: self.nixosConfigurations.${n}.config.nixpkgs.system == system) self.deploy.nodes; - deployChecks = deploy.lib.${system}.deployChecks { nodes = deployHosts; }; - in - nixos.lib.recursiveUpdate tests deployChecks; - - inherit legacyPackages; - packages = lib.filterPackages system legacyPackages; - - devShell = import ./shell { - inherit self system extern overrides; - }; - } - ); - in - nixos.lib.recursiveUpdate outputs systemOutputs; } diff --git a/lib/default.nix b/lib/default.nix index 8ed28a43d..a44613b79 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,14 +1,10 @@ -args@{ nixos, self, ... }: -let inherit (nixos) lib; in -lib.makeExtensible (final: - let callLibs = file: import file - ({ - inherit lib; - - dev = final; - } // args); +args@{ nixos, self, ... }: # TODO: craft well-defined api for devos-lib +let + inherit (nixos) lib; +in lib.makeExtensible (final: + let + callLibs = file: import file ({ lib = final; } // args); in - with final; { inherit callLibs; @@ -17,6 +13,9 @@ lib.makeExtensible (final: lists = callLibs ./lists.nix; strings = callLibs ./strings.nix; + mkFlake = callLibs ./mkFlake; + } // + with final; { inherit (attrs) mapFilterAttrs genAttrs' safeReadDir pathsToImportedAttrs concatAttrs filterPackages; inherit (lists) pathsIn; diff --git a/lib/devos/default.nix b/lib/devos/default.nix index e580ef005..fb9e990f1 100644 --- a/lib/devos/default.nix +++ b/lib/devos/default.nix @@ -1,4 +1,4 @@ -{ lib, nixos, dev, ... }: +{ lib, ... }: { # pkgImport :: Nixpkgs -> Overlays -> System -> Pkgs pkgImport = nixpkgs: overlays: system: @@ -9,22 +9,22 @@ profileMap = map (profile: profile.default); - mkNodes = dev.callLibs ./mkNodes.nix; + mkNodes = lib.callLibs ./mkNodes.nix; - mkHosts = dev.callLibs ./mkHosts.nix; + mkHosts = lib.callLibs ./mkHosts.nix; - mkSuites = dev.callLibs ./mkSuites.nix; + mkSuites = lib.callLibs ./mkSuites.nix; - mkProfileAttrs = dev.callLibs ./mkProfileAttrs.nix; + mkProfileAttrs = lib.callLibs ./mkProfileAttrs.nix; - mkPkgs = dev.callLibs ./mkPkgs.nix; + mkPkgs = lib.callLibs ./mkPkgs.nix; - recImport = dev.callLibs ./recImport.nix; + recImport = lib.callLibs ./recImport.nix; - devosSystem = dev.callLibs ./devosSystem.nix; + devosSystem = lib.callLibs ./devosSystem.nix; - mkHomeConfigurations = dev.callLibs ./mkHomeConfigurations.nix; + mkHomeConfigurations = lib.callLibs ./mkHomeConfigurations.nix; - mkPackages = dev.callLibs ./mkPackages.nix; + mkPackages = lib.callLibs ./mkPackages.nix; } diff --git a/lib/devos/mkHosts.nix b/lib/devos/mkHosts.nix index 1d1bfce0e..032d262b0 100644 --- a/lib/devos/mkHosts.nix +++ b/lib/devos/mkHosts.nix @@ -1,6 +1,6 @@ -{ lib, dev, nixos, inputs, self, ... }: +{ lib, nixos, inputs, ... }: -{ dir, extern, suites, overrides, multiPkgs, ... }: +{ self, dir, extern, suites, overrides, multiPkgs, ... }: let defaultSystem = "x86_64-linux"; @@ -12,7 +12,7 @@ let ]; modules = { - core = "${self}/profiles/core"; + core = toString ../../profiles/core; modOverrides = { config, overrideModulesPath, ... }: let inherit (overrides) modules disabledModules; @@ -44,7 +44,7 @@ let nixpkgs.pkgs = lib.mkDefault multiPkgs.${config.nixpkgs.system}; nix.registry = { - devos.flake = self; + self.flake = self; nixos.flake = nixos; override.flake = inputs.override; }; @@ -61,7 +61,7 @@ let # Everything in `./modules/list.nix`. flakeModules = { imports = builtins.attrValues self.nixosModules ++ extern.modules; }; - cachix = ../../cachix.nix; + cachix = "${self}/cachix.nix"; }; specialArgs = extern.specialArgs // { suites = suites.system; }; @@ -88,13 +88,13 @@ let }; }; in - dev.os.devosSystem { + lib.os.devosSystem { inherit specialArgs; system = defaultSystem; modules = modules // { inherit local lib; }; }; - hosts = dev.os.recImport + hosts = lib.os.recImport { inherit dir; _import = mkHostConfig; diff --git a/lib/devos/mkPackages.nix b/lib/devos/mkPackages.nix index a876ea0b7..0aebb7ebf 100644 --- a/lib/devos/mkPackages.nix +++ b/lib/devos/mkPackages.nix @@ -1,10 +1,10 @@ -{ lib, dev, self, ... }: +{ lib, self, ... }: { pkgs }: let inherit (self) overlay overlays; packagesNames = lib.attrNames (overlay null null) - ++ lib.attrNames (dev.concatAttrs + ++ lib.attrNames (lib.concatAttrs (lib.attrValues (lib.mapAttrs (_: v: v null null) overlays) ) diff --git a/lib/devos/mkPkgs.nix b/lib/devos/mkPkgs.nix index f3126eaff..4eb709b6a 100644 --- a/lib/devos/mkPkgs.nix +++ b/lib/devos/mkPkgs.nix @@ -1,27 +1,19 @@ -{ lib, dev, nixos, self, inputs, ... }: +{ lib, nixos, self, inputs, ... }: { extern, overrides }: (inputs.utils.lib.eachDefaultSystem (system: let - overridePkgs = dev.os.pkgImport inputs.override [ ] system; + overridePkgs = lib.os.pkgImport inputs.override [ ] system; overridesOverlay = overrides.packages; overlays = [ - (final: prev: { - lib = prev.lib.extend (lfinal: lprev: { - inherit dev; - inherit (lib) nixosSystem; - - utils = inputs.utils.lib; - }); - }) (overridesOverlay overridePkgs) self.overlay ] ++ extern.overlays ++ (lib.attrValues self.overlays); in - { pkgs = dev.os.pkgImport nixos overlays system; } + { pkgs = lib.os.pkgImport nixos overlays system; } ) ).pkgs diff --git a/lib/devos/mkProfileAttrs.nix b/lib/devos/mkProfileAttrs.nix index d89c6ba22..7168b2910 100644 --- a/lib/devos/mkProfileAttrs.nix +++ b/lib/devos/mkProfileAttrs.nix @@ -1,4 +1,4 @@ -{ lib, dev, ... }: +{ lib, ... }: let mkProfileAttrs = /** @@ -16,7 +16,7 @@ let mkProfileAttrs = let imports = let - files = dev.safeReadDir dir; + files = lib.safeReadDir dir; p = n: v: v == "directory" diff --git a/lib/devos/mkSuites.nix b/lib/devos/mkSuites.nix index a3a329440..7adb7c889 100644 --- a/lib/devos/mkSuites.nix +++ b/lib/devos/mkSuites.nix @@ -1,8 +1,7 @@ -{ lib, dev, ... }: +{ lib, ... }: { users, profiles, userProfiles, suites } @ args: let - inherit (dev) os; definedSuites = suites { inherit (args) users profiles userProfiles; @@ -16,7 +15,7 @@ let let defaults = lib.collect (x: x ? default) users; in map (x: x.default) defaults; - createSuites = _: suites: lib.mapAttrs (_: v: os.profileMap v) suites // { + createSuites = _: suites: lib.mapAttrs (_: v: lib.os.profileMap v) suites // { inherit allProfiles allUsers; }; diff --git a/lib/devos/recImport.nix b/lib/devos/recImport.nix index d7f2aa82b..66a818c4a 100644 --- a/lib/devos/recImport.nix +++ b/lib/devos/recImport.nix @@ -1,7 +1,7 @@ -{ lib, dev, ... }: +{ lib, ... }: { dir, _import ? base: import "${dir}/${base}.nix" }: -dev.mapFilterAttrs +lib.mapFilterAttrs (_: v: v != null) (n: v: if n != "default.nix" && lib.hasSuffix ".nix" n && v == "regular" @@ -9,4 +9,4 @@ dev.mapFilterAttrs let name = lib.removeSuffix ".nix" n; in lib.nameValuePair (name) (_import name) else lib.nameValuePair ("") (null)) - (dev.safeReadDir dir) + (lib.safeReadDir dir) diff --git a/lib/lists.nix b/lib/lists.nix index b6530f133..74cf9bd4b 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -1,8 +1,8 @@ -{ lib, dev, ... }: +{ lib, ... }: { pathsIn = dir: let fullPath = name: "${toString dir}/${name}"; in - map fullPath (lib.attrNames (dev.safeReadDir dir)); + map fullPath (lib.attrNames (lib.safeReadDir dir)); } diff --git a/lib/mkFlake/default.nix b/lib/mkFlake/default.nix new file mode 100644 index 000000000..300445e55 --- /dev/null +++ b/lib/mkFlake/default.nix @@ -0,0 +1,60 @@ +{ lib, inputs, ... }: +let + inherit (lib) os; # TODO: find a more approriate naming scheme + inherit (inputs) utils deploy; # TODO: make this direct inputs of future devos-lib flake + evalFlakeArgs = lib.callLibs ./evalArgs.nix; +in + +{ self, ... } @ args: +let + + cfg = (evalFlakeArgs { inherit args; }).config; + + multiPkgs = os.mkPkgs { inherit (cfg) extern overrides; }; + + outputs = { + nixosConfigurations = os.mkHosts { + inherit self multiPkgs; + inherit (cfg) extern suites overrides; + dir = cfg.hosts; + }; + + homeConfigurations = os.mkHomeConfigurations; + + nixosModules = cfg.modules; + + homeModules = cfg.userModules; + + overlay = cfg.packages; + inherit (cfg) overlays; + + deploy.nodes = os.mkNodes deploy self.nixosConfigurations; + }; + + systemOutputs = utils.lib.eachDefaultSystem (system: + let + pkgs = multiPkgs.${system}; + # all packages that are defined in ./pkgs + legacyPackages = os.mkPackages { inherit pkgs; }; + in + { + checks = + let + tests = nixos.lib.optionalAttrs (system == "x86_64-linux") + (import "${self}/tests" { inherit self pkgs; }); + deployHosts = nixos.lib.filterAttrs + (n: _: self.nixosConfigurations.${n}.config.nixpkgs.system == system) self.deploy.nodes; + deployChecks = deploy.lib.${system}.deployChecks { nodes = deployHosts; }; + in + nixos.lib.recursiveUpdate tests deployChecks; + + inherit legacyPackages; + packages = lib.filterPackages system legacyPackages; + + devShell = import "${self}/shell" { + inherit self system; + }; + }); +in + outputs // systemOutputs + diff --git a/lib/mkFlake/evalArgs.nix b/lib/mkFlake/evalArgs.nix new file mode 100644 index 000000000..de8a8692b --- /dev/null +++ b/lib/mkFlake/evalArgs.nix @@ -0,0 +1,149 @@ +{ self, lib, inputs, ... }: + +{ args }: +let + argOpts = with lib; { config, options, ... }: + let + inherit (config) self; + + inputAttrs = with types; functionTo attrs; + moduleType = with types; anything // { + inherit (submodule {}) check; + description = "valid module"; + }; + in + { + options = with types; { + self = mkOption { + type = addCheck attrs isStorePath; + description = "The flake to create the devos outputs for"; + }; + hosts = mkOption { + type = path; + default = "${self}/hosts"; + defaultText = "\${self}/hosts"; + apply = toString; + description = '' + Path to directory containing host configurations that will be exported + to the 'nixosConfigurations' output. + ''; + }; + packages = mkOption { + # functionTo changes arg names which breaks flake check + type = types.anything // { + check = builtins.isFunction; + description = "Nixpkgs overlay"; + }; + default = (final: prev: {}); + defaultText = "(final: prev: {})"; + description = '' + Overlay for custom packages that will be included in treewide 'pkgs'. + This should follow the standard nixpkgs overlay format - two argument function + that returns an attrset. + These packages will be exported to the 'packages' and 'legacyPackages' outputs. + ''; + }; + modules = mkOption { + type = listOf moduleType; + default = []; + apply = pathsToImportedAttrs; + description = '' + list of modules to include in confgurations and export in 'nixosModules' output + ''; + }; + userModules = mkOption { + type = listOf moduleType; + default = []; + apply = pathsToImportedAttrs; + description = '' + list of modules to include in home-manager configurations and export in + 'homeModules' output + ''; + }; + profiles = mkOption { + type = path; + default = "${self}/profiles"; + defaultText = "\${self}/profiles"; + apply = x: os.mkProfileAttrs (toString x); + description = "path to profiles folder that can be collected into suites"; + }; + userProfiles = mkOption { + type = path; + default = "${self}/users/profiles"; + defaultText = "\${self}/users/profiles"; + apply = x: os.mkProfileAttrs (toString x); + description = "path to user profiles folder that can be collected into userSuites"; + }; + suites = + let + defaults = { user = {}; system = {}; }; + in + mkOption { + type = inputAttrs; + default = { ... }: defaults; + defaultText = "{ user = {}; system = {}; }"; + apply = suites: defaults // os.mkSuites { + inherit suites; + inherit (config) profiles users userProfiles; + }; + description = '' + Function with inputs 'users' and 'profiles' that returns attribute set + with user and system suites. The former for Home Manager and the latter + for nixos configurations. + These can be accessed through the 'suites' specialArg in each config system. + ''; + }; + users = mkOption { + type = path; + default = "${self}/users"; + defaultText = "\${self}/users"; + apply = x: os.mkProfileAttrs (toString x); + description = '' + path to folder containing profiles that define system users + ''; + }; + extern = + let + defaults = { + modules = []; overlays = []; specialArgs = {}; + userModules = []; userSpecialArgs = []; + }; + in + mkOption { + type = inputAttrs; + default = { ... }: defaults; + defaultText = '' + { modules = []; overlays = []; specialArgs = []; userModules = []; userSpecialArgs = []; } + ''; + # So unneeded extern attributes can safely be deleted + apply = x: defaults // (x { inputs = inputs // self.inputs; }); + description = '' + Function with argument 'inputs' that contains all devos and ''${self}'s inputs. + The function should return an attribute set with modules, overlays, and + specialArgs to be included across nixos and home manager configurations. + Only attributes that are used should be returned. + ''; + }; + overlays = mkOption { + type = path; + default = "${self}/overlays"; + defaultText = "\${self}/overlays"; + apply = x: pathsToImportedAttrs (pathsIn (toString x)); + description = '' + path to folder containing overlays which will be applied to pkgs and exported in + the 'overlays' output + ''; + }; + overrides = mkOption rec { + type = attrs; + default = { modules = []; disabledModules = []; packages = _: _: _: {}; }; + defaultText = "{ modules = []; disabledModules = []; packages = {}; }"; + apply = x: default // x; + description = "attrset of packages and modules that will be pulled from nixpkgs master"; + }; + }; + }; +in + lib.evalModules { + modules = [ argOpts args ]; + } diff --git a/pkgs/default.nix b/pkgs/default.nix index ce1687071..45a4a07c5 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1 +1,2 @@ -final: prev: { } +final: prev: { +}