-
Notifications
You must be signed in to change notification settings - Fork 49
Setup and Configuration
- If you don't have a dotfile repository yet:
- Figure out all the applications that use dotfiles that you want to keep track of, and write down where all those files are located.
- Create a new git repo (I suggest placing it in
~/.dotfiles
) - Move those dotfiles to the repo. You can also change the names to make sense to you - for example a file that was at
~/.i3/config
can be renamed to simplyi3
. - Commit and push, you now have a dotfiles repo!
- In your dotfiles repo, create a folder
.dotter
and two files:global.toml
andlocal.toml
. - Add
.dotter/local.toml
to your.gitignore
- that file contains the machine-specific configuration, so there's no point uploading it. - Add
.dotter/cache.toml
and.dotter/cache
to your.gitignore
as well - When installing, I recommend downloading the binaries (windows and linux) into the root of your repository.
That way, wherever your dotfiles are, Dotter also is. - On Linux, make sure
dotter
has execute permissions withchmod +x dotter
, then you can run it with./dotter
- To get a starter configuration after your files are in the repository, use
dotter init
Dotter operates under a concept of "packages". This comes from the idea that you don't always want all your dotfiles to be deployed - sometimes only part of the programs are installed.
In global.toml
, packages are defined. Which packages are deployed is configured in local.toml
.
Here's an example global.toml
, that showcases several features:
# Helpers are user-defined functions that can be executed inside templates.
# This section is optional.
[helpers]
color_hex2rgb = "dotter_settings/helpers/color_hex2rgb.rhai"
# A package contains two sections - "files" and "variables".
# Both of those sections are optional - you can have only one if you want.
# The 'files' section is a mapping between the path of the file relative to
# the repository root and its location in the filesystem (where the program
# expects it)
# In this case, say your repository is at `~/.dotfiles`, it will map
# `~/.dotfiles/zsh/zprofile` to `~/.zprofile`,
# and `~/.dotfiles/zshrc` to `~/.zshrc`
# To clarify, folders in the repository don't have to correspond to packages.
# On Windows, '~' is expanded to 'C:\Users\<USERNAME>\'
[zsh.files]
"zsh/zprofile" = "~/.zprofile"
zshrc = "~/.zshrc"
# The 'variables' section contains constants that the templated files
# can access. This section can contain all the types that toml supports,
# and is used by the Handlebars templating engine as the rendering context.
[zsh.variables]
prompt_color = "#00FF00"
# A package for all files relating to the i3 window manager
# I would only select it if I had i3 installed,
# so for example, I wouldn't select it on my VPS since it has no screen.
# The `depends` field means that when this package is enabled, all of the
# depended packages will be recursively enabled as well.
# As you can see, I also left a comment that I need to configure certain
# machine-specific variables if I want to use this package.
# Note that variables from a selected package are available to all others.
[i3]
depends = ["graphics"]
[i3.files]
Xinitrc = "~/.xinitrc"
i3 = "~/.i3/config"
polybar = "~/.config/polybar/config"
# Local variables: network_interface, screen_size, terminal
# A variables-only package, maybe it contains variables that are also
# used by my terminal so I want them to exist when I select either of
# the packages, without having to repeat them.
[graphics.variables]
font_size = 14
primary_color = "#CCCCCC"
background_color = "#333333"
As you can see, a global.toml
contains a description of all the dotfiles that are possible to install.
But you don't always want all of them. Which packages are installed as well as machine-specific tweaks are configured in local.toml
:
# local.toml can "include" another file - more on this in the next section.
includes = [".dotter/linux.toml"]
# An array of the names of all packages that are selected.
# Only the files and variables that belong to packages in this list are kept.
# Note that in this example, the `graphics` package is automatically added as well.
packages = ["i3"]
# File target locations can be overridden in local.toml
# This can be useful for example for applications which read from a different
# location depending on the platform.
# Disabling files is possible by setting them to the special value "".
[files]
Xinitrc = "~/.my_Xinitrc"
polybar = ""
# I need to define some machine-specific variables.
[variables]
network_interface = "wlan0"
screen_size = "1920x1080"
terminal = "xfce4-terminal"
# Actually, I want the font size on this screen to be a bit bigger.
# Any variables defined in local.toml override variables in global.toml.
# Unlike files, it's impossible to delete variables.
font_size = 18
For the initial configuration, you might want to have a single default
package that contains just a files
section, then select it in local.toml
.
You can always break it up into smaller packages later!
If local.toml
file is not found, Dotter will look for a file named <hostname>.toml
using the machine's hostname. If you're not sure what file this is looking for, then:
- Make sure there is no
local.toml
- Run
dotter -v
- Look for the message saying
local.toml not found, using SOMETHING.toml instead (based on hostname)
In local.toml
, you can specify a list of files to include. included.toml
looks similar to a global.toml
, but with only packages:
[zsh.files]
zshrc = "~/.another_location"
[zsh.variables]
prompt_color = "#0000FF"
The files are loaded and merged in the following order:
- First, all the packages from
global.toml
are loaded - Then, each package is merged with the included files in order
- The last time each key is set is the one that will win. So
included.toml
will override a file or variable set inglobal.toml
- The last time each key is set is the one that will win. So
- Then, only the packages that are in
local.toml
'spackages
variable and their dependencies are kept - Then, all the packages are merged into one - at this point, there mustn't be any file/variable clashes between the packages
- Then, the merged "package" is once again merged with
local.toml
's contents -local.toml
wins any clashes.
Why is this useful? Say, for example, you want an OS-specific configuration - maybe a program reads a file from a different location depending on the OS. (I'll use neovim as an example)
In that case, you could define global.toml
like this:
[vim.files]
# This is the location for Linux
vimrc = "~/.config/nvim/init.vim"
windows.toml
like this:
[vim.files]
# This is the location for Windows
vimrc = "~/AppData/Local/nvim/init.vim"
And then, on Windows you could include windows.toml
like this:
includes = [".dotter/windows.toml"]
packages = ["vim"]
This will load the default linux location, then override it with the windows location, and then only deploy the file if you've selected the package.
windows.toml
could contain the windows-specific tweaks of all of your packages.
If you wanted some of the settings from windows.toml
but then override the rest you could do that as well - the possibilities are limitless.
When using the -p
/--patch
flag, standard input will be taken as an additional step on top of local.toml
's [files]
and [variables]
- use this for one-time playing with the configuration, for example
dotter -p <<<"variables.font_size = 20"
This is using bash's here-string. Other shells have similar features allowing this as well (see also heredoc)
Dotter allows you to configure some global settings.
There is currently only one setting, but if you have an idea, please open an issue.
default_target_type
options: symbolic
, template
, or automatic
defaults to automatic
Sets the default target type for any package files that don't explicity set a target type.
In global.toml
:
[settings]
default_target_type = "symbolic"
[nvim]
depends = []
[nvim.files]
nvim = "~/.config/nvim" # Does not detect anymore, will always be symbolic
Dotter automatically defines the built-in variable dotter
, that is a mapping including the following:
-
dotter.packages
- a mapping between the package name and the valuetrue
of the selected packages, intended to be used like{{#if dotter.packages.my_package}}
(this will evaluate to false for packages that aren't in the mapping) -
dotter.files
- a mapping between the source and target of each deployed file -
dotter.os
- eitherwindows
orunix
, use something like{{#if (eq dotter.os "unix")}}
-
dotter.current_dir
- contains the absolute path to the directory Dotter was ran from (usually the root of the repository) - More will be added eventually - if you have an idea, please open an issue.
Dotter also supports configuring targets of files using this syntax:
[zsh.files]
zshrc = { target = "~/.zshrc", type = "symbolic" }
zprofile = { target = "~/.zshrc", type = "template" }
Use this to override Dotter's default detection behavior, where it checks whether the file contains {{
to see if it's a template or a symlink.
There is also an owner
field - it can either be an integer for a UID or a string for a username.
To set the owner, Dotter will use sudo
to request elevation.
When type = "template"
, Dotter also supports additional arguments:
[zsh.files]
zprofile = { target = "~/.zshrc", type = "template", append = "text to append", prepend = "text to prepend" }
This can be useful in certain cases in local.toml
.
An alternative syntax for this is:
[zsh.files.zprofile]
target = "~/.zshrc"
type = "template"
append = """
I can use
multiline text
here!
"""
TOML actually sees those two as equivalent, the difference is purely cosmetic.
If you want to control whether a file is included based on the result of a helper or a variable, use the if
field, like so:
[zsh.files.zprofile]
target = "~/.zshrc"
type = "symbolic"
if = "bash"
# This expression is evaluated just like the argument of an {{#if}}
if = "(eq shell 'bash')"
For an example of a repository that uses Dotter, check out my dotfiles. The folder of interest is .dotter
.
If you want your repository to be mentioned here, feel free to open an issue :)