diff --git a/modules/chezmoi/README.md b/modules/chezmoi/README.md new file mode 100644 index 0000000..88833ec --- /dev/null +++ b/modules/chezmoi/README.md @@ -0,0 +1,67 @@ +# `chezmoi` + +The `chezmoi` module takes care of installing, initializing and updating you dotfiles. +Each feature can be enabled or disabled individually. + +Installation of the `chezmoi` binary happens at build time and is done by downloading the `amd64` binary from the latest release to `/usr/bin/chezmoi`. +This can be disabled by setting `install` to false. (defaults: true) + +A systemd user service is installed that will initialize a `chezmoi` repository on chezmoi's default path (`~/.local/share/chezmoi`) for any user when it logs in, or at boot if it has lingering enabled. +The service will only run if `~/.local/share/chezmoi` does not exist. +Set `repository` to the URL of your dotfiles repository. (eg. `repository: https://example.org/user/dotfiles`) +:::note +The value of `repository` will be passed directly to `chezmoi init --apply ${repository}`. +See the [`chezmoi init` documenation](https://www.chezmoi.io/reference/commands/init/) for detailed syntax. +::: +Set `disable_init` to `true` if you do not want to install the init service. + +:::caution +If `repository` is not set, and `disable_init` is false the module will fail, due to not being able to initialize the repository. +::: + +Set `enable_all_users` to `false` if you want to install the update and initialization services, but do not want them enabled for all users. +You can enable them manually instead when the system has been installed: + +To enable the services for a single user, run the following command as that user: + +```bash +systemctl enable --user chezmoi-init.service chezmoi-update.timer` +``` + +To manually enable the services for all users, run the following command with sudo: + +```bash +sudo systemctl enable --user chesmoi-init.service chezmoi-update.timer +``` + +To turn on lingering for a given user, run the following commmand with sudo: + +:::note +By default, any systemd units in a user's namespace will run after the user logs in, and will close after the user closes their last session. +When you enable lingering for a user, that user's units will run at boot and will continue running even if the user has no active sessions. + +If your dotfiles only contain things used by humans, such as cosmetic settings and aliases, you shouldn't need this. +If you understand the above implications, and decide you need this feature, you can enable it with the following command, after installation: +::: + +```bash +sudo loginctl enable-linger ` +``` + +You can configure the interval between updates of your dotfiles by setting the value of `run_every`. +The string is passed directly to OnUnitInactiveSec. (default: '1d') +See [`systemd.time` documenation](https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html) for detailed syntax. +Examples: '1d' (1 day - default), '6h' (6 hours), '10m' (10 minutes) + +Likewise, `wait_after_boot` configures the delay between the system booting and the update service starting. +This follows the same syntax as `run_every`. (default: '5m') + +The installation of the initialization service and the update service can be disabled separately by setting `disable_init` and/or `disable_update` to `true`. (Both default: false) + +:::caution +Note that this will skip the installation of the services completely. If you want them installed but disabled, see `enable_all_users` instead. +::: + +## Development + +Setting `DEBUG=true` inside `chezmoi.sh` will enable additional output in bash useful for debugging. diff --git a/modules/chezmoi/chezmoi.sh b/modules/chezmoi/chezmoi.sh new file mode 100644 index 0000000..33c8d20 --- /dev/null +++ b/modules/chezmoi/chezmoi.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash + +# Tell build process to exit if there are any errors. +set -euo pipefail + +# '-I=0' makes sure the output isn't indented + +# Activates debugging output. This should only be true if you changed it yourself. +# -v = Verbose output. Outputs every line before executing. +# -u = Treat unset variables as errors. Useful for spotting typos. +# -x = Show expanded input for conditional statements. +DEBUG=false +if [[ $DEBUG ]]; then + echo "Running in debug mode. If you didn't enable this yourself, this is a bug." + set -vux +fi + +# If true, downloads the chezmoi binary from the latest Github release and moves it to /usr/bin/. (default: true) +INSTALL_CHEZMOI=$(echo "$1" | yq -I=0 ".install-chezmoi") # (boolean) +if [[ -z $INSTALL_CHEZMOI || $INSTALL_CHEZMOI == "null" ]]; then + INSTALL_CHEZMOI=true +fi + +# The repository with your chezmoi dotfiles. (default: null) +DOTFILE_REPOSITORY=$(echo "$1" | yq -I=0 ".repository") # (string) + +# If true, chezmoi services will be enabled for all logged in users, and users with lingering enabled. (default: true) +# If false, chezmoi services will not be enabled for any users, but can be enabled manually, after installation. +# +# To enable the services for a single user, run the following command as that user: +# 'systemctl enable --user chezmoi-init.service chezmoi-update.timer' +# +# To manually enable the services for all users, run the following command with sudo: +# 'sudo systemctl enable --user chesmoi-init.service chezmoi-update.timer' +# +# To turn on lingering for a given user, run the following commmand with sudo: +# 'sudo loginctl enable-linger ' +ENABLE_ALL_USERS=$(echo "$1" | yq -I=0 ".enable-all-users") # (boolean) +if [[ -z $ENABLE_ALL_USERS || $ENABLE_ALL_USERS == "null" ]]; then + ENABLE_ALL_USERS=true +fi + +# chezmoi-update.service will run with this interval +# This string is passed on directly to systemd's OnUnitInactiveSec. Complete syntax is described here: +# https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html# +# Examples: '1d' (1 day - default), '6h' (6 hours), '10m' (10 minutes) +RUN_EVERY=$(echo "$1" | yq -I=0 ".run-every") # (string) +if [[ -z $RUN_EVERY || $RUN_EVERY == "null" ]]; then + RUN_EVERY="1d" +fi +# chezmoi-update.service will also run this much time after the system has booted. +# Same syntax as RUN_EVERY (default: '5m') +WAIT_AFTER_BOOT=$(echo "$1" | yq -I=0 ".wait-after-boot") # (string) +if [[ -z $WAIT_AFTER_BOOT || $WAIT_AFTER_BOOT == "null" ]]; then + WAIT_AFTER_BOOT="5m" +fi + +# If true, disables automatic initialization of chezmoi if no dotfile directory is found. (default: false) +DISABLE_INIT=$(echo "$1" | yq -I=0 ".disable-init") # (boolean) +if [[ -z $DISABLE_INIT || $DISABLE_INIT == "null" ]]; then + DISABLE_INIT=false +fi +# If true, disables automatic activation of 'chezmoi-update.timer'. (default: false) +DISABLE_UPDATE=$(echo "$1" | yq -I=0 ".disable-update") # (boolean) +if [[ -z $DISABLE_UPDATE || $DISABLE_UPDATE == "null" ]]; then + DISABLE_UPDATE=false +fi + +echo "Checking for conflicting arguments" +if [[ (-z $DOTFILE_REPOSITORY || $DOTFILE_REPOSITORY == "null") && $DISABLE_INIT == false ]]; then + echo "ERROR: Invalid Config: 'repository' is not set, but initialization is not disabled." + echo "Set a value for 'repository' or set 'disable_update' to true, if you do not wish to initialize a chezmoi directory using this module" + exit 1 +fi + +if [[ $INSTALL_CHEZMOI == true ]]; then + echo "Checking if curl is installed and executable at /usr/bin/curl" + if [ -x /usr/bin/curl ]; then + echo "Downloading chezmoi binary from the latest Github release" + /usr/bin/curl -Ls https://github.com/twpayne/chezmoi/releases/latest/download/chezmoi-linux-amd64 -o /usr/bin/chezmoi + echo "Ensuring chezmoi is executable" + /usr/bin/chmod 755 /usr/bin/chezmoi + else + echo "ERROR: curl could not be found in /usr/bin/." + echo "Please make sure curl is installed on the system you are building your image." + exit 1 + fi +else + echo "Skipping install of chezmoi binary" +fi + +if [[ $DISABLE_INIT == false ]]; then + # Write the service to initialize Chezmoi, and insert the repo url in the file + echo "Writing init service to user unit directory" + cat >>/usr/lib/systemd/user/chezmoi-init.service <>/usr/lib/systemd/user/chezmoi-update.service <>/usr/lib/systemd/user/chezmoi-update.timer <