+{ upgradeConfig, lib ? (import <nixpkgs> { }).lib, }:
+with lib;
+evalModules {
+ modules = upgradeConfig ++ [{
+ options = {
+
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to periodically upgrade NixOS to the latest version.
+ Presumes that /etc/nixos is a git repo with a remote and
+ contains a pinch file called "channels".
+ '';
+ };
+
+ dates = mkOption {
+ default = "04:40";
+ type = types.str;
+ description = ''
+ Specification (in the format described by
+ <citerefentry><refentrytitle>systemd.time</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry>) of the time at
+ which the update will occur.
+ '';
+ };
+
+ repos = mkOption {
+ description = ''
+ Git repositories to pull before running pinch. These are maintained
+ as git checkouts at specified places in the filesystem with specified
+ ownership rather than kept read-only in the nix store so that humans
+ can use them both as points of intervention in the automation and to
+ author and push changes back up.
+ '';
+ type = types.attrsOf (types.submodule {
+ options = {
+ url = mkOption {
+ description = "Remote git repo.";
+ type = types.str;
+ };
+ remoteName = mkOption {
+ description = ''Name of the git remote. Customarily "origin".'';
+ type = types.str;
+ default = "origin";
+ };
+ onRemoteURLMismatch = mkOption {
+ description = ''
+ What to do if the remote URL in the git repo doesn't match the
+ URL configured here.
+ '';
+ type = types.enum [ "update" "abort" ];
+ default = "update";
+ };
+ onBranchMismatch = mkOption {
+ description = ''
+ What to do if a different branch is currently checked out.
+
+ (Changes from <literal>remoteBranch</literal> are only ever
+ merged into <literal>localBranch</literal>, so if a different
+ branch is checked out, no remote changes will be merged.)
+ '';
+ type = types.enum [ "continue" "abort" ];
+ default = "continue";
+ };
+ user = mkOption {
+ description = "User as which to run 'git fetch'";
+ type = types.str;
+ };
+ localBranch = mkOption {
+ description = "";
+ type = types.str;
+ default = "master";
+ };
+ remoteBranch = mkOption {
+ type = types.str;
+ default = "master";
+ };
+ requireSignature = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Only pull when the tip of the remote ref is signed by a key
+ specifed in <literal>signingKeys</literal>.
+ '';
+ };
+ signingKeys = mkOption {
+ type = types.listOf types.path;
+ description = ''
+ Files containing GPG keys that are authorized to sign updates.
+ Updates are only merged if the commit at the tip of the remote
+ ref is signed with one of these keys.
+ '';
+ };
+ };
+ });
+ example = {
+ "/etc/nixos" = {
+ url = "https://github.com/chkno/auto-upgrade-demo-nixos";
+ user = "root";
+ signingKeys = [ ./admins.asc ];
+ };
+ "/home/alice/.config/nixpkgs" = {
+ url = "https://github.com/chkno/auto-upgrade-demo-user-nixpkgs";
+ user = "alice";
+ signingKeys = [ ./admins.asc ./alice.asc ];
+ };
+ };
+ };
+
+ pinchFiles = mkOption {
+ description = ''
+ Pinch files to use for channel updates. Typically these are inside
+ <literal>repos</literal>' paths.
+ '';
+ type = types.listOf types.path;
+ example = [ "/etc/nixos/channels" ];
+ };
+
+ userEnvironments = mkOption {
+ description = ''
+ User environments to update as part of an upgrade run.
+ '';
+ type = types.attrsOf (types.submodule {
+ options = {
+ package = mkOption {
+ type = types.str;
+ default = "userPackages";
+ description = ''
+ The name of the single package that will be updated. You'll
+ want to create an 'entire user environment' package as shown in
+ https://nixos.wiki/wiki/FAQ#How_can_I_manage_software_with_nix-env_like_with_configuration.nix.3F
+ '';
+ };
+ otherPackagesAction = mkOption {
+ type = types.enum [ "remove" "keep" "abort" ];
+ default = "remove";
+ description = ''
+ What to do with packages other than <literal>package</literal>.
+
+ THIS DEFAULTS TO "remove", WHICH IS POTENTIALLY SOMEWHAT
+ DESTRUCTIVE! This is the default because it is the recommended
+ setting -- This module recommends managing your environment
+ through your one entire-environment <literal>package</literal>.
+ This keeps your environment declarative and ensures that all
+ packages receive regular updates.
+ '';
+ # It seems like "upgrade" ought to be another choice here, powered
+ # by "nix-env --upgrade". But when I tried this, it didn't work.
+ };
+ };
+ });
+ example = { alice = { }; };
+ };
+ };
+ }];
+}