migalmoreno / ordenada

A reproducible development environment for Nix
GNU General Public License v3.0
9 stars 1 forks source link
nix nixos nixos-configuration

-- mode: org; org-html-head-include-default-style: nil; org-html-postamble: nil; org-export-with-author: nil; org-export-with-date: nil; --

+OPTIONS: toc:nil num:nil

+title: ordenada

Ordenada is a configuration framework based on the [[https://nixos.org/][Nix]] package manager that aims to make it easy to build reproducible development environments. It draws inspiration from the [[https://git.sr.ht/~abcdw/rde][RDE]] project for [[https://guix.gnu.org/][GNU Guix]].

Ordenada's configuration is centered around users and features. Features are blocks of configuration that provide certain functionality for a user, such as setting up your email, adding your GnuPG keys, or configuring your window manager. Normally, you only need to enable them and all the required settings will automatically be configured for you, although there are many available options you can tweak to fit your needs. See the [[https://migalmoreno.com/projects/ordenada.html#configuration-options][full list of features and options]].

+begin_quote

NOTE: Ordenada is in current development and its API is subject to change

+end_quote

+begin_src nix

{ inputs = {

...other inputs

ordenada.url = "github:migalmoreno/ordenada";

}; }

+end_src

Import its list of modules into your configuration.

+begin_src nix

{ outputs = { nixpkgs, ordenada, ... }: { nixosConfigurations."" = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [

...other modules

      ordenada.nixosModules.ordenada
    ];
  };
};

}

+end_src

Optionally, if you want to make use of Ordenada's utility library, to e.g. create your own features, add the following to your configuration.

+begin_src nix

nixpkgs.overlays = [ ordenada.overlays.default ];

+end_src

+begin_src nix

{ config, pkgs, ... }:

{ ordenada = { users = { bob = { }; }; features = { userInfo = { username = "bob"; }; home.enable = true; gnupg.enable = true; gtk = { enable = true; theme = { name = "adw-gtk3"; package = pkgs.adw-gtk3; }; }; emacs = { enable = true; all-the-icons.enable = true; appearance.enable = true; eglot.enable = true; modus-themes = { enable = true; dark = true; }; }; irc = { enable = true; accounts = { libera = { network = "irc.libera.chat"; nick = "bob"; }; oftc = { network = "irc.oftc.net"; nick = "bob"; }; }; }; mail = { enable = true; accounts = { personal = { primary = true; fqda = "bob@example.com"; extraConfig = { imap = { host = "mail.example.com"; port = 993; }; smtp = { host = "mail.example.com"; port = 465; }; }; }; }; }; sway.enable = true; waybar = { enable = true; modules = with config.ordenada.features.waybar.defaultModules; [ swayWorkspaces swayWindow pulseaudio battery swayLanguage clock swaync ]; }; }; }; }

+end_src

In more complex multi-user installations, you can modify the set of user features to match each user's needs. As shown in the example below, you could make user =bob= augment the global features with ones specific to him. Alternatively, you could also create a set of user features from scratch and augment certain features as you go, like in the case of the =alice= user below.

+begin_src nix

{ config, ... }:

{ ordenada = { users = { bob = { features = config.ordenada.features // { emacs.spelling.enable = true; firefox.enable = false; }; }; alice = { features = with config.ordenada.features; { userInfo = { username = "alice"; }; inherit gnupg; home.enable = true; bash.enable = true; emacs = with emacs; { enable = true; dired.enable = true; org-roam.enable = true; inherit modus-themes eglot; }; }; }; }; features = { userInfo = { username = "bob"; };

...rest of global features

};

}; }

+end_src

With the above setup, two users =bob= and =alice= will be configured in the system. =bob= will end up with an augmented global features setup while =alice= will only have the features =home=, =bash=, the inherited global =gnupg= feature, and =emacs= along with its features.

By default, all users inherit the global features. Thus, if you want to write a user features set from scratch (e.g. =alice='s example above) you don't need to include the whole global features set again for a new user feature (e.g. the =home=, =bash=, and =emacs= features above). However, if you want to apply the feature default settings to the user feature (i.e. those that are not explicitly set in the global feature) you'll need to explicitly inherit from the global feature, such as the case with the =gnupg= feature above.

+begin_src nix

{ config, lib, pkgs, ... }:

with pkgs.lib.ordenada;

let cfg = config.ordenada.features.example; in { options = { ordenada.features.example = { enable = lib.mkEnableOption "the example feature"; message = lib.mkOption { type = lib.types.str; description = "The message to show."; default = ""; }; }; }; config = ( lib.mkMerge [ (lib.mkIf cfg.enable { environment.sessionVariables = { EXAMPLE_ENV = 1; }; }) { home-manager = mkHomeConfig config "example" (user: { home.sessionVariables = lib.mkIf (hasFeature "acme" user) { EXAMPLE_HOME_ENV = "EXAMPLE_HOME_ENV_VALUE"; }; programs.emacs = mkElispConfig { name = "ordenada-example"; config = '' ;; < your Elisp configuration > (setq my-elisp-value ${user.features.example.message}) ''; elispPackages = [ ]; summary = "My example Emacs feature"; }; }); } ] ); }

+end_src

The =example= feature above showcases a common feature definition workflow. First, we define a list of options for this feature that we'll be able to access from anywhere in our configuration. Then, we add a system configuration if the feature is enabled. Next, we add a home configuration via the special utility =mkHomeConfig=, which allows us to configure home settings for all our Ordenada users. In this example, we set a home environment variable as long as the =acme= feature is enabled (checked with the =hasFeature= utility). Finally, we add Emacs Lisp configuration through the =mkElispConfig= utility which will add a new Emacs configuration package for this feature with interpolated feature options (=user.features.example.message=).