feat: Add Chezmoi module (#215)
* build: Added cosign.pub * Feat: Add chezmoi module * Excaped characters making build fail * Switch ` for ' * Fixed syntax issues * Fixed bash syntax and systemctl parameters * Update modules/chezmoi/module.yml to correct README url Co-authored-by: Gerald Pinder <gmpinder@gmail.com> * Used -z instead of `! -n` * Fixed default settings * Made script more verbose to ease debugging * Fixed wrong default values * Changed output to be more meaningful for the end user, instead of the developer. * Added debugging function * Rename `install` > `install_chezmoi`, imrpove docs Gave `install` a clearer name. Added information to docs and improved readability. * Fixed conditional check for set variable * Removed unneeded commands and updated output. * Change to official public key * Fixed invalid systemd targets * Fix chezmoi dir being created but not populated ~/.local/share/chezmoi is created before this service runs, failing `ConditionPathExists=!%h/.local/share/chezmoi`. `.git` only exists if a repository has been cloned there. * Made variable naming conform to project style * fix: Redo suggested commits I accidently overwrote some commits. * docs: Explain what lingering does * docs: fix typo in shortdesc (oops my fault) --------- Co-authored-by: Gerald Pinder <gmpinder@gmail.com> Co-authored-by: xyny <60004820+xynydev@users.noreply.github.com>
This commit is contained in:
parent
3a33f7706b
commit
824fa565e5
3 changed files with 241 additions and 0 deletions
67
modules/chezmoi/README.md
Normal file
67
modules/chezmoi/README.md
Normal file
|
|
@ -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 <username>`
|
||||||
|
```
|
||||||
|
|
||||||
|
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.
|
||||||
155
modules/chezmoi/chezmoi.sh
Normal file
155
modules/chezmoi/chezmoi.sh
Normal file
|
|
@ -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 <username>'
|
||||||
|
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 <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Initializes Chezmoi if directory is missing
|
||||||
|
|
||||||
|
# This service will not execute for a user with an existing chezmoi directory
|
||||||
|
ConditionPathExists=!%h/.local/share/chezmoi/.git/
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/chezmoi init --apply ${DOTFILE_REPOSITORY}
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
echo "Skipping install of chezmoi-init.service"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $DISABLE_UPDATE == false ]]; then
|
||||||
|
# Write the service and timer to update chezmoi for all logged in users and users with lingering enabled
|
||||||
|
echo "Writing update service to user unit directory"
|
||||||
|
cat >>/usr/lib/systemd/user/chezmoi-update.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Chezmoi Update
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/chezmoi update
|
||||||
|
Type=oneshot
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Writing update timer to user unit directory"
|
||||||
|
cat >>/usr/lib/systemd/user/chezmoi-update.timer <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Timer for Chezmoi Update
|
||||||
|
# This service will only execute for a user with an existing chezmoi directory
|
||||||
|
ConditionPathExists=%h/.local/share/chezmoi
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=${WAIT_AFTER_BOOT}
|
||||||
|
OnUnitInactiveSec=${RUN_EVERY}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
echo "Skipping install of chezmoi-update.service"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable services
|
||||||
|
echo "Checking which services to enable"
|
||||||
|
if [[ $ENABLE_ALL_USERS == true && $DISABLE_INIT == false && $DISABLE_UPDATE == false ]]; then
|
||||||
|
echo "Enabling init timer and update service"
|
||||||
|
systemctl --global enable chezmoi-init.service chezmoi-update.timer
|
||||||
|
elif [[ $ENABLE_ALL_USERS == true && $DISABLE_INIT == true && $DISABLE_UPDATE == false ]]; then
|
||||||
|
echo "Enabling update timer"
|
||||||
|
systemctl --global enable chezmoi-update.timer
|
||||||
|
elif [[ $ENABLE_ALL_USERS == true && $DISABLE_INIT == false && $DISABLE_UPDATE == true ]]; then
|
||||||
|
echo "Enabling init service"
|
||||||
|
systemctl --global enable chezmoi-init.service
|
||||||
|
else
|
||||||
|
echo "No services were enabled"
|
||||||
|
fi
|
||||||
19
modules/chezmoi/module.yml
Normal file
19
modules/chezmoi/module.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
name: chezmoi
|
||||||
|
shortdesc: The chezmoi module installs the latest chezmoi release at build time, along with services to clone a dotfile repository and keep it up-to-date.
|
||||||
|
readme: https://raw.githubusercontent.com/blue-build/modules/main/modules/chezmoi/README.md
|
||||||
|
example: |
|
||||||
|
type: chezmoi
|
||||||
|
# Installs chezmoi to /usr/bin/chezmoi from latest Github release
|
||||||
|
install_chezmoi: true # Optional - Default: true - Expects type: boolean
|
||||||
|
# () Git repository to initialize
|
||||||
|
repository: "https://example.org/user/dotfiles" # Required - Default: n/a - Expects type: string
|
||||||
|
# Enable the modules services globally for all users
|
||||||
|
enable_all_users: true # Optional - Default: true - Expects type: boolean
|
||||||
|
# Dotfiles will be updated with this interval
|
||||||
|
run_every: '1d' # Optional - Default: '1d' - Expects type: string
|
||||||
|
# Dotfile updates will wait this long after a boot before running
|
||||||
|
wait_after_boot: '5m' # Optional - Default: '5m' - Expects type: string
|
||||||
|
# Disable the service that initializes `repository` on users that are logged in or has linger enabled
|
||||||
|
disable_init: false # Optional - Default: false - Expects type: boolean
|
||||||
|
# Disable the timer that updates chezmoi with the interval set above
|
||||||
|
disable_update: false # Optional - Default: false - Expects type: boolean
|
||||||
Loading…
Add table
Add a link
Reference in a new issue