Как известно, большинство программ в мире Linux и частично в MacOS используют текстовые файлы для конфигурации.
Иногда случается необходимость в переносе своих настроек на новую систему. Также очень важно иметь одинаковое окружение дома и на работе.
Особенно важно это тем людям, которые как и я любят перенастраивать свое рабочее окружение.
Очень долгое время у меня был git
репозиторий, синхронизированный с Github, Gitlab и Bitbucket.
Для некоторых конфигов я вручную делал симлинки, для других использовал vimdiff
/meld
для визуального сравнения файлов и переноса общих настроек.
Например я добавил настройку в свой .vimrc
на домашнем компьютере. Запустил meld ~/.vimrc <git path>/.vimrc
, просмотрел изменения, синхронизировал их и запушил в репозиторий.
Потом на работе уже нужно было скачать изменения и запустить такую же команду, чтобы синхронизировать изменения на рабочем компе.
Сценарий далек от идеального и на это уходит много времени. А еще так не синхронизируешь какие-то секретные данные, типа ssh ключей.
Я знаю, что можно шифровать данные в репозитории, но так как они публичные, я предпочитаю использовать флешку, на которой так же хранится моя keepassxc база паролей.
Совсем недавно в ютубе я наткнулся на видео про использование GNU Stow
для синхронизации дотфайлов и понял, что не только меня беспокоит эта ситуация и кто-то уже инвестировал свое время в ее решение. Как только вопрос сформулировался, как сразу нашелся на него ответ в виде отличной статьи на Archwiki. Так как у меня много файлов, которые немного отличаются на разных машинах, то все программы, не умеющие в шаблоны сразу отпали. Мой выбор пал на chezmoi
, так как он написан на go
и можно напрямую скачать один бинарник с Github курлом, если нужно перенести свои настройки на новую машину. Так же решается проблема синхронизации секретных данных интеграцией с разными менеджерами паролей(1Password, Bitwarden, gopass, KeePassXC, LastPass, pass, Vault, Keychain, Keyring) или шифрованием данных с помощью GnuPG/age.
Я не буду прямо переводить документацию, кто захочет прочитает сам, она хорошо структурирована.
Просто приведу пару собственных примеров, чтобы оценить всю мощь данной программы.
Собственный конфиг
chezmoi
как и любая другая программа в мире Linux имеет собственный конфиг, который должен быть по пути $XDG_CONFIG_HOME/chezmoi/config.toml
.
Сам конфиг может быть 3 форматов — Toml, Yaml или Json. Для себя я выбрал Toml.
Можно хранить конфиг на каждой машине отдельно, но я предпочитаю синхронизировать его вместе с другими файлами. Поэтому я использую специальный файл .chezmoi.toml.tmpl
в корне репозитория. Все файлы с расширением *.tmpl
интерпретируются как шаблоны на языке go
(также доступны все дополнительные функции шаблонизатора sprig). Вот мой шаблон конфига
{{- $type := "personal" -}}
{{- $kps_key := "" -}}
{{- $personal_ip := "" -}}
{{- if ne .chezmoi.hostname "personal" -}}
{{- $type = "work" -}}
{{- end -}}
{{- if (hasKey . "kps_key") -}}
{{- $kps_key = .kps_key -}}
{{- else -}}
{{- $kps_key = promptString "kps_key" -}}
{{- end -}}
{{- if (hasKey . "personal_ip") -}}
{{- $personal_ip = .personal_ip -}}
{{- else -}}
{{- $personal_ip = promptString "personal_ip" -}}
{{- end -}}
[data]
type = {{ $type | quote }}
kps_key = {{ $kps_key | quote }}
personal_ip = {{ $personal_ip | quote }}
{{ if eq .chezmoi.hostname "personal" -}}
bluetooth_mac = "<mac>"
cpu_format = "{utilization} {frequency}"
eth_id = "<personal eth>"
wifi_id = "<personal wifi>"
{{- else }}
cpu_format = "{barchart} {utilization} {frequency}"
eth_id = "<work eth>"
wifi_id = "<work wifi>"
{{- end }}
color = "on"
format = "toml"
mode = "file"
pager = "bat"
[diff]
command = "meld"
[git]
autoAdd = true
[keepassxc]
database = "<path to db>.kdbx"
args = ["-k", "{{ .kps_key }}" ]
В конфиге есть общие настройки, типа color или format, а есть секция data
.
В данной секции объявляется список ключей=значений, которые потом можно использовать в шаблонах. Пример использования — {{ .kps_key }}
Для общих данных есть файл .chezmoidata.<format>
.
Создание конфига происходит командой chezmoi init
После этого можно добавлять файлы, которые будут синхронизироваться командой chezmoi add <path>
Чтобы посмотреть разницу между репозиторием и текущим состоянием системы есть команда chezmoi diff
Если вы вручную отредактировали файл, можно смержить командой chezmoi merge <path>
или chezmoi merge-all
.
Чтобы применить изменения — chezmoi apply
.
Отдельно стоит выделить создание шаблонов.
Можно просто руками переименовать файл, добавив в конце суффикс .tmpl
, но для этого лучше использовать специальные флаги при добавлении файлов.
При использовании флага --template
файл сразу добавится с нужным расширением.
А если файл уже содержит значение, которое есть в конфиге в секции data
— chezmoi add --autotemplate <path>
автоматически подставит нужный ключ, как переменную в созданный шаблон.
Кстати, все файлы, которые добавляются в репозиторий, вместо точки в начале имени файла используют префикс dot_
.
Например команда chezmoi add ~/.bashrc
создаст файл с именем dot_bashrc
.
Скрипты
Шаблоны — это хорошо, но они не могут заменить все возможные сценарии, поэтому данная программа может запускать любые скрипты, если их правильно оформить.
Например вам надо создать какую-то директорию, на которую потом будет ссылка в .bashrc
Надо создать скрипт с префиксом before_dot_basrc
, например before_dot_bashrc_run.sh
#!/usr/bin/env bash
mkdir -p $HOME/.local/share/bash/functions
Не забываем про шебанг и соответствующие исполнительные привилегии. Скрипт может быть любой, на баш, на питоне, бинарник на го/раст и тд.
Есть разные другие полезные префиксы и для скриптов и для файлов
Например, вот как я создаю ssh ключ для github на новой машине
Файл private_dot_ssh/private_dot_ssh/create_private_github.tmpl
с контентом
{{ keepassxcAttribute "/dotfiles/ssh/github" "private" }}
Префикс create_
создает файл, если его нету, private_
добавляет маску чтения файла владельцем.
Еще примеры
Я использую шаблоны чтобы создавать уникальные конфиги для каждой системы.
Например в моем .zshrc
раньше были такие проверки
if [ -f $ZDOTDIR/aliases.local.zsh ]; then
. $ZDOTDIR/aliases.local.zsh
fi
Сейчас я их заменил таким шаблоном
{{ if stat (expandenv "$ZDOTDIR/aliases.local.zsh") }}
. $ZDOTDIR/aliases.local.zsh
{{ end }}
Также можно проверять на наличие исполнительного файла в $PATH
{{- if (or (lookPath "cargo") (stat (expandenv "$HOME/.rustup"))) }}
alias crn='cargo run'
alias cup='cargo update'
alias cbd='cargo build'
alias cbr='cargo build --release'
setup_cargo () {
rustup completions zsh cargo > $LOCAL_ZSH_COMP_DIR/_cargo
rustup completions zsh rustup > $LOCAL_ZSH_COMP_DIR/_rustup
}
setup_cargo_tools() {
if ! command_exists cargo-expand; then
cargo install cargo-expand
fi
if ! command_exists cargo-audit; then
cargo install cargo-audit
fi
if ! command_exists cargo-outdated; then
cargo install cargo-outdated
fi
}
{{- end }}
Заключение
Мой сценарий синхронизации конфиг-файлов сильно упростился. Также надеюсь, что эта статья кому-то поможет упростить их сценарии.
P.S. Так же посматриваю на различные системы установки необходимых пакетов, при переустановке системы. Пока в планах затестить Comtrya, как ориентированную на локалхост альтернативу Ansible
.