These are my personal dotfiles.
This setup is designed to support ad-hoc management of modular packages, where a package may consist of multiple dependencies, configurations, and shell extensions.
This design has a couple of benefits over a traditional dotfile setup:
-
Portability: A single package can be used by others without needing to install all of the dotfiles. For example, try out my neovim setup with
./install nvim
. -
Composability: Different sets of packages can be configured for various environments. For example, you may want to have just your neovim setup on a remote server without installing all of your language packages used in your development environment.
Packages are identified by their directory name within packages.
To install one or more packages manually, include the name(s) as arguments to the install script:
./install <package1> <package2> ...
To configure which packages are automatically installed, update the install
script to detect your environment and specify a list of packages:
packages=()
if [ ! $# -eq 0 ]; then
# Manually selected packages
packages=$*
elif [[ -n "${GITPOD_WORKSPACE_ID}" ]]; then
# Gitpod packages
packages=(
homebrew
zsh
)
elif [[ $(uname) == "Darwin" ]]; then
# MacOS packages
packages=(
elixir
git
macos
mutagen
nvim
ruby
tmux
wezterm
)
fi
Though there are a number of packages already included in this setup, you may want to add your own package(s) or start fresh and just use the package management portion of these dotfiles. To that end, I'll walk through what a package consists of and how to set up a new one. You can also just review the package.sh library if you want to skip the exposition.
For our example, we'll be creating a new package called acme
:
mkdir packages/acme
System dependencies are currently handled by homebrew since it's semi cross-platform.
To specify homebrew dependencies, create a Brewfile in the package root:
touch packages/acme/Brewfile
The Brewfile.lock.json
will automatically be ignored by the included .gitignore
.
Note
If a Brewfile
is detected during package installation, the homebrew package will be automatically installed before continuing. For this reason, it's not required to include homebrew
in your list of environment packages unless none of the other packages require homebrew and you would still like it installed.
Many dependencies have added support for XDG Base Directory Specification. In short, this means that they will look for their configuration in the $XDG_CONFIG_HOME
which defaults to ~/.config
.
To add XDG-compliant configuration, create a config
folder in the package root. This directory will be symlinked into the $XDG_CONFIG_HOME
with the package name as the target.
mkdir packages/acme/config # symlinked to ~/.config/acme
For files and directories that need to go into directly into your home directory, you can just add a dot-
prefix to their name. These will be symlinked to your home directory with the dot-
prefix replaced by a .
:
touch packages/acme/dot-file # symlinked to ~/.file
mkdir packages/acme/dot-directory # symlinked to ~/.directory
Important
These dotfiles are very dependent on zsh at the moment. I plan to loosen this dependency in the future, but this section won't really apply unless you're also using my zsh package.
If your package needs to add autoloaded zsh extensions (aliases, autocompletes, etc.), you can add a zsh
directory in the package root. This directory will be symlinked into the plugins
directory that my zsh package is configured to autoload:
mkdir packages/acme/zsh # symlinked to ~/.config/zsh/plugins/_acme
And finally, if you need to run some installation logic, you can create an install
executable in the package root. This will be executed at the very end, after dependencies and symlinks have been created:
touch packages/acme/install
chmod +x packages/acme/install
There are several bash variables that are available to your script:
$name
: the name of the package (e.g.acme
)$package
: the full path of the package directory (e.g.packages/acme
)$tmp
: the full path of a temporary directory that can be used for package artifacts (e.g..tmp/acme
)
Any artifacts from package installation will remain in the .tmp
directory and ignored by git.
Some ideas for future improvements:
- Better cross-platform dependency management instead of homebrew.
- Less dependency on zsh as the specific shell for extensions.
- Smarter shell reloading (it currently reloads zsh even if the plugin symlink already exists)
- A top-level
dot
command to be used in place of executing./install
directly - A set of subcommands to be used with
dot
(e.g.install
,uninstall
,package new
, etc.) - A complete separation of the
dot
package manager with a way to install external packages
Code is under the BSD 2-clause "Simplified" License. Documentation is under the Creative Commons Attribution license.