Crate hm

source ·
Expand description

hm is a commandline program to help with dotfile (and more) management.

It can handle putting configuration files where they should go, but its real strength lies in the solutions it’ll execute - shell scripts, usually - to pull a git repository, compile something from source, etc.

hm exists because I bring along a few utilities to all Linux boxes I regularly use, and those are often built from source. So rather than manually install all dependency libraries, then build each dependent piece, then finally the top-level dependent program, I built hm. It also provides functionality to thread off heavier operations into task threads, which regularly report back their status with Worker objects over a std::sync::mpsc.

hm can also perform dependency resolution, thanks to the solvent crate. You can provide a big ol’ list of tasks to complete, each with their own dependencies, and as long as you have a solveable dependency graph, you can get workable batches from get_task_batches(). They will be in some order that will resolve your dependencies, but that order is non-deterministic - if there’s multiple ways to solve a graph, you’ll probably get all those different ways back if you run it multiple times.

The crate provides this library, which is in turn used by the bin hm (in src/bin/main.rs). hm is a commandline program to help with dotfile (and more) management.

gfycat of it in action

  1. create a config.toml file either anywhere or in ~/.config/homemaker/.
  2. enter things to do things to in the file. example:
# config.toml

[[obj]]
file = 'tmux.conf'
source = '~/dotfiles/.tmux.conf'
destination = '~/.tmux.conf'
method = 'symlink'

[[obj]]
task = 'zt'
solution = 'cd ~/dotfiles/zt && git pull'
dependencies = 'maim, slop'

[[obj]]
task = 'slop'
source = '~/dotfiles/zt/slop'
solution = 'cd ~/dotfiles/zt/slop; make clean; cmake -DCMAKE_INSTALL_PREFIX="/usr" ./ && make && sudo make install'
method = 'execute'
platform = "linux::debian"
  1. hm ~/path/to/your/config.toml

built with spacemacs and neovim

thanks to actual good code: serde toml symlink solvent indicatif console

Modules

Define our Config and Worker. Implement how to take the config.toml and turn it into a Config { files: Vec<ManagedObject> }. Describes the Worker object, which is how we communicate back to our main() thread about how our task is going.
Custom Error implementation to allow for our own kind, along with run-of-the-mill std::io::Errors.

Macros

equivalent of func for stacktrace/debugging see https://stackoverflow.com/questions/38088067/equivalent-of-func-or-function-in-rust

Functions

Copy our {file|directory} to the destination. Generally we’ll be doing this in a tilde’d home subdirectory, so we need to be careful to get our Path right.
Take our list of ManagedObjects to do stuff to, and determine if they’re simple or complex (simple is symlink or copy, complex maybe compilation or pulling a git repo). We just do the simple ones, as they won’t be computationally expensive.
Create a non-cyclical dependency graph and give it back as a Vec<Vec<ManagedObject>>. Will return a CyclicalDependencyError if the graph is unsolveable. Intended to be used with either mgmt::execute_solution or mgmt::send_tasks_off_to_college.
Pretty simple. Hand off to the actual function that does the work.
Take a ManagedObject task, an mpsc tx, and a Progressbar. Execute task and regularly inform the rx (all the way over back in main())about our status using config::Worker.
Either create a symlink to a file or directory. Generally we’ll be doing this in a tilde’d home subdirectory, so we need to be careful to get our Path right.