121 lines
4.5 KiB
Markdown
121 lines
4.5 KiB
Markdown
# Cram
|
|
|
|
> To force (people or things) into a place or container that is or appears to be too small to contain them.
|
|
|
|
An alternative to GNU Stow, more some notion of packages with dependencies and install scripts.
|
|
|
|
Think an Ansible, Puppet or even NixOS but anyarch and lite enough to check in with your dotfiles.
|
|
|
|
## Overview
|
|
|
|
Cram operates on a directory of packages called `packages.d/`, and two directories of metapackages called `profiles.d` and `hosts.d`.
|
|
|
|
### Packages
|
|
|
|
A Cram package consists of a directory containing a `pkg.toml` file with the following format -
|
|
|
|
```toml
|
|
[cram]
|
|
version = 1
|
|
|
|
[package]
|
|
# The package.require list names depended artifacts.
|
|
[[package.require]]
|
|
name = "packages.d/some-other-package"
|
|
|
|
# (optional) The package.build list enumerates either
|
|
# inline scripts or script files. These are run as a
|
|
# package is 'built' before it is installed.
|
|
[[package.build]]
|
|
run = "some-build-command"
|
|
|
|
# (optional) Hook script(s) which occur before installation.
|
|
[[package.pre_install]]
|
|
run = "some-hook"
|
|
|
|
# (optional) Override installation scrpt(s).
|
|
# By default, everthing under the package directory
|
|
# (the `pkg.toml` excepted) treated is as a file to be
|
|
# installed and stow is emulated using symlinks.
|
|
[[package.install]]
|
|
run = "some-install-command"
|
|
|
|
# (optional) Hook script(s) which after installation.
|
|
[[package.post_install]]
|
|
run = "some-other-hook"
|
|
```
|
|
|
|
To take a somewhat real example from my own dotfiles -
|
|
|
|
```shell
|
|
$ tree -a packages.d/tmux
|
|
packages.d/tmux
|
|
├── pkg.toml
|
|
└── .tmux.conf
|
|
```
|
|
|
|
This TMUX package provides only my `.tmux.conf` file, and a stub `pkg.toml` that does nothing.
|
|
A fancier setup could use `pkg.toml` to install TMUX either as a `pre_install` task or by using a separate TMUX package and providing the config in a profile.
|
|
|
|
### Metapackages
|
|
|
|
Writing lots of packages gets cumbersome quickly, as does managing long lists of explicit dependencies.
|
|
To try and manage this, Cram provides metapackages - packages which contain no stowable files, but instad contain subpackages.
|
|
|
|
To take a somewhat real example from my own dotfiles -
|
|
|
|
```shell
|
|
$ tree -a -L 1 profiles.d/macos
|
|
profiles.d/macos
|
|
├── pkg.toml
|
|
├── emacs/
|
|
├── homebrew/
|
|
└── zsh/
|
|
```
|
|
|
|
The `profiles.d/macos` package depends AUTOMATICALLY on the contents of the `profiles.d/macos/emacs`, `profiles.d/macos/homebrew` and `profiles.d/macos/zsh` packages, which are normal packages.
|
|
These sub-packages can have normal dependencies on other packages both within and without the profile and install files or run scripts.
|
|
|
|
Profiles allow users to write groups of related packages, especially configs, which go together and allows for scoped reuse of meaningful names.
|
|
|
|
Likewise the `hosts.d/` tree allows users to store host-specific packages.
|
|
|
|
## Usage
|
|
|
|
```
|
|
$ cram apply [--dry-run|--execute] [--optimize] [--require <package>] <configdir> <destdir>
|
|
```
|
|
|
|
The `apply` task applies a configuration to a destination directory.
|
|
The most common uses of this would be `--dry-run` (the default), which functions as a `diff` or `--execute ~/conf ~/` for emulating Stow and installing dotfiles.
|
|
|
|
By default `cram` installs two packages - `profiles.d/default` and `hosts.d/$(hostname -s)`.
|
|
This default can be overriden by providing `--require <package>` one or more times to enumerate specific packages to install.
|
|
|
|
Cram always reads the `.cram.log` state file and diffs the current state against the configured state.
|
|
Files and directories no longer defined by the configured state are cleaned up automatically.
|
|
|
|
```
|
|
$ cram state <configdir>
|
|
```
|
|
|
|
The `state` task loads up and prints the `.cram.log` state file generated by any previous `cram apply --execute` so you can read a manifest of what cram thinks it did.
|
|
This is useful because `cram` attempts to optimize repeated executions and implement change detection using the state file.
|
|
|
|
This cache can be busted if needed by using `apply --execute --no-optimize`, which will cause cram to take all actions it deems presently required.
|
|
This can result in dangling symlinks in the filesystem.
|
|
|
|
```
|
|
$ cram list <configdir> [package]
|
|
```
|
|
|
|
The `list` task lists out all available packages (eg. packages, profiles, hosts, and subpackages) as a dependency graph.
|
|
When provided a specific package, the details of that package (its requirements and installation task log) will be printed.
|
|
|
|
## License
|
|
|
|
Copyright Reid 'arrdem' McKenzie, 15/02/2022.
|
|
|
|
Published under the terms of the Anticapitalist Software License (https://anticapitalist.software).
|
|
|
|
Unlimited commercial licensing is available at nominal pricing.
|