#dot #dotfiles #hoard

bin+lib hoard

Hoard backups of files across your filesystem into one location

2 unstable releases

0.2.0 Jun 4, 2021
0.1.0 Aug 4, 2020

BSD-3-Clause

120KB
2.5K SLoC

Hoard

hoard is a program for backing up files from across a filesystem into a single directory and restoring them later.

Most people will know these programs as "dotfile managers," where dotfiles are configuration files on *nix (read: non-Windows) systems. Files on *nix systems are marked as hidden by starting the file name with a dot (.).

Terminology

  • "Environment": An identifiable system configuration consisting of zero or more each of: operating system, hostname, environment variable, executables in $PATH, and/or existing paths,
  • "Pile": A single file or directory with multiple possible paths where it can be found depending on the environment(s).
  • "Hoard": One of:
    • A single anonymous pile.
    • One or more named, related piles.

Usage

Subcommands

  • Backup: hoard [flags...] backup [name] [name] [...]
    • Back up the specified hoard(s). If no name is specified, all hoards are backed up.
  • Restore: hoard [flags...] restore [name] [name] [...]
    • Restore the specified hoard(s). If no name is specified, all hoards are restored.
  • Validate: hoard [flags...] validate
    • Attempt to parse the default configuration file (or the one provided via --config-file) Exits with code 0 if the config is valid.

Flags

  • --help: View the program's help message.
  • -V/--version: Print the version of hoard.
  • -c/--config-file: Path to (non-default) configuration file.
  • -h/--hoards-root: Path to (non-default) hoards root directory.
  • -l/--log-level: Logging level to use.

Verbosity

Output verbosity is controlled by the logging level. You can set the logging level with the -l/--log-level flag or the HOARD_LOG environment variable. In both cases, valid values (in decreasing verbosity) are:

  • trace
  • debug
  • info
  • warn
  • error

The default logging level is info for release builds and debug for debugging builds.

Default file locations

  • Configuration file
    • Linux: $XDG_CONFIG_HOME/hoard/config.toml or /home/$USER/.config/hoard/config.toml
    • macos: $HOME/Library/Application Support/com.shadow53.hoard/
    • Windows: C:\Users\$USER\AppData\Roaming\shadow53\hoard\config.toml
  • Hoards root
    • Linux: $XDG_DATA_HOME/hoard/hoards or /home/$USER/.local/share/hoard/hoards
    • macos: $HOME/Library/Application Support/com.shadow53.hoard/hoards
    • Windows: C:\Users\$USER\AppData\Roaming\shadow53\hoard\data\hoards

More specifically, hoard uses the directories library, placing the configuration file in the config_dir and the hoards root in the data_dir.

Configuration

See config.toml.sample for a documented example configuration file.

Environments

Environments can be matched on one or more of five possible factors:

  • os: Operating System
  • env: Environment variables
    • Can match on just existence or also a specific value.
  • hostname: The system hostname.
  • exe_exists: Whether an executable file exists in $PATH.
  • path_exists: Whether something exists (one of) the given path(s).

All the above factors can be written using two-dimensional array syntax. That is, ["foo", ["bar, "baz"]] is interpreted as (foo) OR (bar AND baz), in whatever way applies to that given factor.

It is an error to include an AND condition for os or hostname, as a system can only have one of each.

[envs]
[envs.example_env]
    # Matching something *nix-y
    os = ["linux", "freebsd"]
    # Either sed and sh, or bash, must exist
    exe_exists = ["bash", ["sh", "sed"]]
    # Require both $HOME to exist and $HOARD_EXAMPLE_ENV to equal YES.
    # Note the double square brackets that indicate AND instead of OR.
    env = [[
      { var = "HOME" },
      { var = "HOARD_EXAMPLE_ENV", expected = "YES" },
    ]]

Exclusivity

The exclusivity lists indicate names of environments that are considered mutually exclusive to each other -- that is, cannot appear in the same environment condition -- and the order indicates which one(s) have precedence when matching environments.

See the example config file for a more thorough example.

exclusivity = [
    # Assuming all else the same, an environment condition string with "neovim" will take
    # precedence over one with "vim", which takes precedence over one with "emacs".
    ["neovim", "vim", "emacs"]
]

Hoards

Hoards consist of one or more piles, where each pile is a mapping of environment condition strings to paths on the filesystem.

An environment condition string is one or more environment names separated by pipes. The system must match ALL environments in the string in order for the associated path to be considered.

The following rules determine which path to use for a pile:

  1. The condition string with the most environments wins.
  2. If multiple conditions have the most environments, the exclusivity list is used to determine if one takes precedence.
  3. If multiple conditions have the same precedence, an error is printed and hoard exits.
  4. If no conditions match, the pile is skipped and a warning is printed.

Note: it is possible that one condition may take precedence over another despite them not having mutually exclusive environments between them, if one condition contains an environment that shows up in the exclusivity list.

[hoards]
# This hoard consists of a single anonymous pile
[hoards.simple_hoard]
    # This is "foo" and "bar" separated by a pipe character (`|`).
    # It will use this path if the system matches both environments "foo" and "bar".
    "foo|bar" = "/path/to/a/thing"
    # This path is considered if the system matches the environment "baz".
    # It will use this path if one of "foo" or "bar" doesn't match. Otherwise, "foo|bar"
    # takes precedence because it is a longer condition (more environments to match).
    "baz" = "/some/different/path"

[hoards.complex_hoard]
# This hoard consists of two named piles: "first" and "second".
[hoards.complex_hoard.first]
    "foo|bar" = "/some/path/first"
    "baz" = "/some/different/path/first"
[hoards.complex_hoard.second]
    "foo|bar" = "/some/path/second"
    "baz" = "/some/different/path/second"

Dependencies

~4.5–6MB
~126K SLoC