342 lines
12 KiB
Markdown
342 lines
12 KiB
Markdown
+++
|
|
title = "Dotfiles with Chezmoi"
|
|
author = ["Elia el Lazkani"]
|
|
date = 2020-10-05T21:00:00+02:00
|
|
lastmod = 2021-06-28T00:00:29+02:00
|
|
tags = ["dotfiles", "chezmoi", "encryption", "templates"]
|
|
categories = ["backup"]
|
|
draft = false
|
|
+++
|
|
|
|
A few months ago, I went on a search for a solution for my _dotfiles_.
|
|
|
|
I tried projects likes [GNU Stow](https://www.gnu.org/software/stow/), [dotbot](https://github.com/anishathalye/dotbot) and a [bare _git_ repository](https://www.atlassian.com/git/tutorials/dotfiles).
|
|
Each one of these solutions has its advantages and its advantages, but I found mine in [_Chezmoi_](https://www.chezmoi.io/).
|
|
|
|
_Chezmoi_ ? That's **French** right ? How is learning **French** going to help me ?
|
|
|
|
<!--more-->
|
|
|
|
|
|
## Introduction {#introduction}
|
|
|
|
On a _\*nix_ system, whether _Linux_, _BSD_ or even _Mac OS_ now, the applications one uses have their configuration saved in the user's home directory. These files are called _configuration_ files. Usually, these configuration files start with a `.` which on these systems designate hidden files (they do not show up with a simple `ls`). Due their names, these _configuration_ files are also referred to as _dotfiles_.
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
|
|
I will be using _dotfiles_ and _configuration files_ interchangeably in this article, and they can be thought as such.
|
|
|
|
</div>
|
|
|
|
One example of such files is the `.bashrc` file found in the user's _home directory_. It allows the user to configure _bash_ and change some behaviours.
|
|
|
|
Now that we understand what _dotfiles_ are, let's talk a little bit about the _previously mentioned_ solutions.
|
|
They deserve mentioning, especially if you're looking for such solution.
|
|
|
|
|
|
### GNU Stow {#gnu-stow}
|
|
|
|
_GNU Stow_ leverages the power of _symlinks_ to keep your _configuration_ in a **centralized** location.
|
|
Wherever your repository lives, _GNU Stow_ will mimic the internal structure of said repository in your **home directory** by _smartly symlinking_ everything.
|
|
|
|
I said _smartly_ because it tries to **minimize** the amount of _symlinks_ created by _symlinking_ to common root directories if possible.
|
|
|
|
By having all your configuration files under one directory structure, it is easier to push it to any public repository and share it with others.
|
|
|
|
The downsize is, you end-up with a lot of _symlinks_. It is also worth mentioning that not all applications behave well when their _configuration directories_ are _symlinked_. Otherwise, _GNU Stow_ is a great project.
|
|
|
|
|
|
### Dotbot {#dotbot}
|
|
|
|
_Dotbot_ is a _Python_ project that **aims** at automating your _dotfiles_. It gives you great control over what and how to manage your _dotfiles_.
|
|
|
|
Having it written in _Python_ means it is very easy to install; `pip`. It also means that it _should_ be easy to migrate it to different systems.
|
|
|
|
_Dotbot_ has a lot going for it. If the idea of having control over every aspect of your _dotfiles_, including the _possibility_ of the setup of the environment along with it, then _dotbot_ is for you.
|
|
|
|
Well, it's not for **me**.
|
|
|
|
|
|
### Bare _Git_ Repository {#bare-git-repository}
|
|
|
|
This is arguably the _most elegant_ solution of them all.
|
|
|
|
The nice thing about this solution is its _simplicity_ and _cleanliness_. It is _essentially_ creating a _bare git_ repository _somewhere_ in your _home directory_ specifying the _home directory_ itself to be the _working directory_.
|
|
|
|
If you are wondering where one would use a _bare git_ repository in real life other than this use case.
|
|
Well, you have no other place to turn than any _git server_. On the server, _Gitea_ for example, your repository is only a _bare_ repository. One has to clone it to get the _working directory_ along with it.
|
|
|
|
Anyway, back to our topic. This is a great solution if you don't have to worry about things you would like to hide.
|
|
|
|
By hide, I mean things like _credentials_, _keys_ or _passwords_ which **never** belong in a _repository_.
|
|
You will need to find solutions for these types of files. I was looking for something _less involving_ and _more involved_.
|
|
|
|
|
|
## _Chezmoi_ to the rescue ? {#chezmoi-to-the-rescue}
|
|
|
|
Isn't that what they **all** say ?
|
|
|
|
I like how the creator(s) defines [_Chezmoi_](https://www.chezmoi.io/)
|
|
|
|
> Manage your dotfiles across multiple machines, securely.
|
|
|
|
Pretty basic, straight to the point. Unfortunately, it's a little bit harder to grasp the concept of how it works.
|
|
|
|
_Chezmoi_ basically _generates_ the _dotfiles_ from the _local repository_. These _dotfiles_ are saved in different forms in the _repository_ but they **always** generate the same output; the _dotfiles_. Think of _Chezmoi_ as a _dotfiles_ templating engine, at its basic form it saves your _dotfiles_ as is and _deploys_ them in **any** machine.
|
|
|
|
|
|
## Working with _Chezmoi_ {#working-with-chezmoi}
|
|
|
|
I think we should take a _quick_ look at _Chezmoi_ to see how it works.
|
|
|
|
_Chezmoi_ is written _Golang_ making it _fairly_ easy to [install](https://www.chezmoi.io/docs/install/) so I will forgo that boring part.
|
|
|
|
|
|
### First run {#first-run}
|
|
|
|
To start using _Chezmoi_, one has to **initialize** a new _Chezmoi repository_.
|
|
|
|
```bash
|
|
chezmoi init
|
|
```
|
|
|
|
This will create a **new** _git repository_ in `~/.local/share/chezmoi`. This is now the **source state**, where _Chezmoi_ will get your _dotfiles_.
|
|
|
|
|
|
### Plain _dotfiles_ management with _Chezmoi_ {#plain-dotfiles-management-with-chezmoi}
|
|
|
|
Now that we have a _Chezmoi_ repository. We can start to _populate_ it with _dotfiles_.
|
|
|
|
Let's assume that we would like to start managing one of our _dotfiles_ with _Chezmoi_.
|
|
I'm going with an _imaginary application_'s configuration directory.
|
|
This directory will hold different files with _versatile_ content types.
|
|
This is going to showcase some of _Chezmoi_'s capabilities.
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
|
|
This is how I use _Chezmoi_. If you have a better way to do things, I'd like to hear about it!
|
|
|
|
</div>
|
|
|
|
|
|
#### Adding a _dotfile_ {#adding-a-dotfile}
|
|
|
|
This **DS9** application has its directory configuration in `~/.ds9/` where we find the `config`.
|
|
|
|
The configuration looks like any _generic_ _ini_ configuration.
|
|
|
|
```ini
|
|
[character/sisko]
|
|
Name = Benjamin
|
|
Rank = Captain
|
|
Credentials = sisko-creds.cred
|
|
Mastodon = sisko-api.mastodon
|
|
```
|
|
|
|
_Nothing_ special about this file, let's add it to _Chezmoi_
|
|
|
|
```bash
|
|
chezmoi add ~/.ds9/config
|
|
```
|
|
|
|
|
|
#### Listing _dotfiles_ {#listing-dotfiles}
|
|
|
|
And _nothing_ happened... Hmm...
|
|
|
|
```bash
|
|
chezmoi managed
|
|
```
|
|
|
|
```text
|
|
/home/user/.ds9
|
|
/home/user/.ds9/config
|
|
```
|
|
|
|
Okay, it seems that it is being managed.
|
|
|
|
|
|
#### Diffing _dotfiles_ {#diffing-dotfiles}
|
|
|
|
We can _test_ it out by doing something like this.
|
|
|
|
```bash
|
|
mv ~/.ds9/config ~/.ds9/config.old
|
|
chezmoi diff
|
|
```
|
|
|
|
```text
|
|
install -m 644 /dev/null /home/user/.ds9/config
|
|
--- a/home/user/.ds9/config
|
|
+++ b/home/user/.ds9/config
|
|
@@ -0,0 +1,5 @@
|
|
+[character/sisko]
|
|
+Name = Benjamin
|
|
+Rank = Captain
|
|
+Credentials = sisko-creds.cred
|
|
+Mastodon = sisko-api.mastodon
|
|
```
|
|
|
|
Alright, everything looks as it should be.
|
|
|
|
|
|
#### Apply _dotfiles_ {#apply-dotfiles}
|
|
|
|
But that's only a _diff_, how do I make _Chezmoi_ apply the changes because my _dotfile_ is still `config.old`.
|
|
|
|
Okay, we can actually get rid of the `config.old` file and make _Chezmoi_ regenerate the configuration.
|
|
|
|
```bash
|
|
rm ~/.ds9/config ~/.ds9/config.old
|
|
chezmoi -v apply
|
|
```
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
|
|
I like to use the `-v` flag to check what is **actually** being applied.
|
|
|
|
</div>
|
|
|
|
```text
|
|
install -m 644 /dev/null /home/user/.ds9/config
|
|
--- a/home/user/.ds9/config
|
|
+++ b/home/user/.ds9/config
|
|
@@ -0,0 +1,5 @@
|
|
+[character/sisko]
|
|
+Name = Benjamin
|
|
+Rank = Captain
|
|
+Credentials = sisko-creds.cred
|
|
+Mastodon = sisko-api.mastodon
|
|
```
|
|
|
|
And we get the same output as the `diff`. Nice!
|
|
The configuration file was also recreated, that's awesome.
|
|
|
|
|
|
#### Editing _dotfiles_ {#editing-dotfiles}
|
|
|
|
If you've followed so far, you might have wondered... If I edit `~/.ds9/config`, then _Chezmoi_ is going to **override** it!
|
|
|
|
**YES**, **yes** it will.
|
|
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">warning</p>
|
|
|
|
Always use _Chezmoi_ to edit your managed _dotfiles_. Do **NOT** edit them directly.
|
|
|
|
**ALWAYS** use `chezmoi diff` before every _applying_.
|
|
|
|
</div>
|
|
|
|
To _edit_ your managed _dotfile_, simply tell _Chezmoi_ about it.
|
|
|
|
```bash
|
|
chezmoi edit ~/.ds9/config
|
|
```
|
|
|
|
_Chezmoi_ will use your `$EDITOR` to open the file for you to edit. Once saved, it's saved in the _repository database_.
|
|
|
|
Be aware, at this point the changes are not reflected in your _home_ directory, **only** in the _Chezmoi source state_. Make sure you **diff** and then **apply** to make the changes in your _home_.
|
|
|
|
|
|
### _Chezmoi_ repository management {#chezmoi-repository-management}
|
|
|
|
As mentioned previously, the repository is found in `~/.local/share/chezmoi`.
|
|
I **always** forget where it is, luckily _Chezmoi_ has a solution for that.
|
|
|
|
```bash
|
|
chezmoi cd
|
|
```
|
|
|
|
Now, we are in the repository. We can work with it as a _regultar_ _git_ repository.
|
|
When you're done, don't forget to `exit`.
|
|
|
|
|
|
### Other features {#other-features}
|
|
|
|
It is worth mentioning at this point that _Chezmoi_ offers a few more integrations.
|
|
|
|
|
|
#### Templating {#templating}
|
|
|
|
Due to the fact that _Chezmoi_ is written in _Golang_, it can leverage the power of the _Golang [templating](https://www.chezmoi.io/docs/how-to/#use-templates-to-manage-files-that-vary-from-machine-to-machine)_ system.
|
|
One can replace _repeatable_ values like **email** or **name** with a template like `{{ .email }}` or `{{ .name }}`.
|
|
|
|
This will result in a replacement of these _templated variables_ with their real values in the resulting _dotfile_.
|
|
This is another reason why you should **always** edit your managed _dotfiles_ through _Chezmoi_.
|
|
|
|
Our _previous_ example would look a bit different.
|
|
|
|
```ini
|
|
[character/sisko]
|
|
Name = {{ .sisko.name }}
|
|
Rank = {{ .sisko.rank }}
|
|
Credentials = sisko-creds.cred
|
|
Mastodon = sisko-api.mastodon
|
|
```
|
|
|
|
And we would add it a bit differently now.
|
|
|
|
```bash
|
|
chezmoi add --template ~/.ds9/config
|
|
```
|
|
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">warning</p>
|
|
|
|
Follow the [documentation](https://www.chezmoi.io/docs/how-to/#use-templates-to-manage-files-that-vary-from-machine-to-machine) to _configure_ the **values**.
|
|
|
|
</div>
|
|
|
|
|
|
#### Password manager integration {#password-manager-integration}
|
|
|
|
Once you have the power of _templating_ on your side, you can always take it one step further.
|
|
_Chezmoi_ has integration with a big list of [password managers](https://www.chezmoi.io/docs/how-to/#keep-data-private). These can be used directly into the _configuration files_.
|
|
|
|
In our _hypothetical_ example, we can think of the _credentials_ file (`~/.ds9/sisko-creds.cred`).
|
|
|
|
```init
|
|
Name = {{ (keepassxc "sisko.ds9").Name }}
|
|
Rank = {{ (keepassxc "sisko.ds9").Rank }}
|
|
Access_Code = {{ (keepassxc "sisko.ds9").AccessCode }}
|
|
```
|
|
|
|
Do not _forget_ that this is also using the _templating_ engine. So you need to add as a _template_.
|
|
|
|
```bash
|
|
chezmoi add --template ~/.ds9/sisko-creds.cred
|
|
```
|
|
|
|
|
|
#### File encryption {#file-encryption}
|
|
|
|
Wait, what ! You almost slipped away right there old fellow.
|
|
|
|
We have our _Mastodon_ **API** key in the `sisko-api.mastodon` file. The whole file cannot be pushed to a repository.
|
|
It turns out that _Chezmoi_ can use _gpg_ to [encrypt your files](https://www.chezmoi.io/docs/how-to/#use-gpg-to-keep-your-secrets) making it possible for you to push them.
|
|
|
|
To add a file encrypted to the _Chezmoi_ repository, use the following command.
|
|
|
|
```bash
|
|
chezmoi add --encrypt ~/.ds9/sisko-api.mastodon
|
|
```
|
|
|
|
|
|
#### Misc {#misc}
|
|
|
|
There is a list of other features that _Chezmoi_ supports that I did not mention.
|
|
I did not use all the _features_ offered yet. You should check the [website](https://www.chezmoi.io/) for the full documentation.
|
|
|
|
|
|
## Conclusion {#conclusion}
|
|
|
|
I am fully migrated into _Chezmoi_ so far. I have used all the features above, and it has worked flawlessly so far.
|
|
|
|
I like the idea that it offers **all** the features I need while at the same time staying out of the way.
|
|
I find myself, often, editing the _dotfiles_ in my _home_ directory as a _dev_ version. Once I get to a configuration I like, I add it to _Chezmoi_. If I ever mess up badly, I ask _Chezmoi_ to override my changes.
|
|
|
|
I understand it adds a little bit of _overhead_ with the use of `chezmoi` commands, which I aliased to `cm`. But the end result is a _home_ directory which seems untouched by any tools (no symlinks, no copies, etc...) making it easier to migrate _out_ of _Chezmoi_ as a solution and into another one if I ever choose in the future.
|