Improve CLI

+ Add repository URL as valid input for dotfiles
+ Add regex, chrono crates
+ Add custom error types for Kot
+ Add uninstallation of dotfiles to revert changes when error is
  encountered
+ Update README, help text
This commit is contained in:
2022-05-29 19:19:42 -04:00
parent eabc227c09
commit a01ab6b532
15 changed files with 869 additions and 376 deletions

203
README.md
View File

@@ -6,50 +6,61 @@ This helps to protect against installing broken dotfiles by providing a way to r
and return the system back to the previous state.
The installation process creates symbolic links, much like what you would expect when using [stow](https://linux.die.net/man/8/stow).
`kot` can install dotfiles from any directory, using any target directory. To test how `kot` might behave,
you could point `--install-dir` to any directory that you've created for testing.
This directory could be empty, or it could contain another set of dotfiles. `kot` will attempt
to install the configurations. If conflicts are detected, output shows the conflicts and
`kot` can install dotfiles from any source directory, to any target directory.
To test how `kot` might behave, you could point `--install` to any directory that you've created for testing.
This directory could be empty, or it could contain another set of dotfiles.
Alternatively, you could set the `--dry-run` flag that will automatically install to a predefined path (`$HOME/.local/share/kot/dry-runs/$USER`)
Note that this directory will never be cleared automatically, each subsequent `--dry-run`
will stack configurations into this default directory until it is manually cleared.
If conflicts are detected, `kot` shows the conflicts found and
prompts to abort or continue. An example of this is seen below.
This prompt will be skipped if the `--force` flag is set.
```bash
kot dotfiles/dot/
args: Cli { dotfiles_dir: "/home/kapper/Code/kot/dotfiles/dot", install_dir: "/home/kapper/Code/kot/dry-runs/kapper", backup_dir: "/home/kapper/Code/kot/backups/kapper", force: false }
kot --dry-run dotfiles/dot/
args: Cli { dotfiles: "/home/kapper/Code/kot/dotfiles/dot", install_dir: "/home/kapper/.local/share/kot/dry-runs/kapper", backup_dir: Some("/home/kapper/.local/share/kot/backups/dot:2022-05-29T19:03:27"), clone_dir: None, force: false, dry_run: true, is_repo: false, conflicts: [] }
The following configurations already exist:
"/home/kapper/Code/kot/dry-runs/kapper/.bashrc"
"/home/kapper/Code/kot/dry-runs/kapper/.config"
"/home/kapper/Code/kot/dry-runs/kapper/README.md"
"/home/kapper/Code/kot/dry-runs/kapper/VimScreenshot.png"
"/home/kapper/Code/kot/dry-runs/kapper/fix-vbox.sh"
"/home/kapper/Code/kot/dry-runs/kapper/.git"
"/home/kapper/Code/kot/dry-runs/kapper/.bash_aliases"
"/home/kapper/Code/kot/dry-runs/kapper/.gitignore"
"/home/kapper/Code/kot/dry-runs/kapper/.gitmodules"
"/home/kapper/Code/kot/dry-runs/kapper/.vimrc"
"/home/kapper/Code/kot/dry-runs/kapper/.vim"
If you continue, backups will be made in "/home/kapper/Code/kot/backups/kapper". Any configurations there will be overwritten.
Abort? Enter y/n or Y/N:
"/home/kapper/.local/share/kot/dry-runs/kapper/.git"
"/home/kapper/.local/share/kot/dry-runs/kapper/.vimrc"
"/home/kapper/.local/share/kot/dry-runs/kapper/.bash_aliases"
"/home/kapper/.local/share/kot/dry-runs/kapper/.vim"
"/home/kapper/.local/share/kot/dry-runs/kapper/VimScreenshot.png"
"/home/kapper/.local/share/kot/dry-runs/kapper/.gitignore"
"/home/kapper/.local/share/kot/dry-runs/kapper/.config"
"/home/kapper/.local/share/kot/dry-runs/kapper/fix-vbox.sh"
"/home/kapper/.local/share/kot/dry-runs/kapper/.gitmodules"
"/home/kapper/.local/share/kot/dry-runs/kapper/.bashrc"
"/home/kapper/.local/share/kot/dry-runs/kapper/README.md"
If you continue, backups will be made in "/home/kapper/.local/share/kot/backups/dot:2022-05-29T19:03:27".
Any configurations there will be overwritten.
Continue? Enter Y/y or N/n:
```
If there are already files within the backup directory, `kot` will exit and show an error message.
This is to protect existing backups from being merged with configs from subsequent runs.
If you want to erase these backups and create a new backup, rerun the command with the `--force` flag set.
Otherwise, specify a different backup directory with the `--backup-dir` option.
If the backup directory does not exist, it will be created.
#### User Data
`kot` stores user data within `$HOME/.local/share/kot/`
```bash
kot dotfiles/dot/
When we provide a repository URL as our `dotfiles` to install, the repo will be *recursively* cloned into
`$HOME/.local/share/kot/dotfiles/<REPO_NAME>`.
This is to ensure each user of `kot` maintains their own dotfiles in a location that is accessible but not easy to accidentally modify or erase.
If needed, the user can provide a preferred clone directory to the CLI by setting the `--clone-dir` option
thread 'main' panicked at '
Error: Backups already exist at "/home/kapper/Code/kot/backups/kapper"
Set the --force flag to overwrite configurations stored here', src/kot/kcli.rs:94:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
When we encounter conflicts during installation of these dotfiles, backups will be created in
`$HOME/.local/share/kot/backups/<DOTFILES_NAME>:<DATE(%Y-%m-%dT%H:%M:%S)>`
If there are no conflicts found during installation, no backup is created.
Configurations are said to be conflicting if the `--install` path contains configuration files that are
also within the dotfiles we are currently installing.
#### Installation
Backups are intended to reverse changes applied during installation of dotfiles.
These backups are not exhaustive of all configurations tied to the system or user.
The backups only include files that were direct conflicts with configurations being installed.
When we reach an error during installation, `kot` will restore the configurations within the last backup, and then removes unused configurations.
#### Installing kot
Follow [Rustup instructions](https://rustup.rs/) to setup the Rust toolchain
@@ -60,65 +71,97 @@ git clone https://gitlab.com/shaunrd0/kot && cd kot
cargo install --path .
kot --help
kot 0.1.0
kot 0.1.5
CLI for managing Linux user configurations
USAGE:
kot [FLAGS] [OPTIONS] <dotfiles-dir>
kot [FLAGS] [OPTIONS] <dotfiles> --install <install>
FLAGS:
-d, --dry-run
Installs configurations to $HOME/.local/shared/kot/dry-runs
Useful flag to set when testing what an install would do to your home directory. This is synonymous with
setting --install $HOME/.local/shared/kot/dry-runs/$USER. Subsequent runs with this flag set will not delete
the contents of this directory.
-f, --force
Overwrites existing backups
This flag will replace existing backups if during installation we encounter conflicts and the backup-dir
provided already contains previous backups.
-h, --help
Prints help information
-V, --version
Prints version information
OPTIONS:
-b, --backup-dir <backup-dir>
The location to store backups for this user
If no backup-dir is provided, we create one within the default kot data directory:
$HOME/.local/share/kot/backups/
-c, --clone-dir <clone-dir>
An alternate path to clone a dotfiles repository to
If the clone-dir option is provided to the CLI, kot will clone the dotfiles repository into this directory.
If clone-dir is not provided, the repository is cloned into $HOME/.local/share/kot/dotfiles Custom clone-dir
will be used literally, and no subdirectory is created to store the cloned repository For example, clone-dir
of $HOME/clonedir for repo named Dotfiles We will clone into $HOME/clonedir, and NOT $HOME/clonedir/Dotfiles
The default path for cloned repos is $HOME/.local/share/kot/dotfiles/
-i, --install <install>
The location to attempt installation of user configurations
The desired installation directory for user configurations. By default this is your $HOME directory This
could optionally point to some other directory to perform a dry run, or the --dry-run flag could be set
[env: HOME=/home/kapper]
ARGS:
<dotfiles>
Local or full path to user configurations to install. Can also be a git repository.
System path or repository URL for dotfiles we want to install. If a path is used, it can either be local to
CWD or absolute. If a URL is used for a dotfiles repository, the repo is cloned into
$HOME/.local/shared/kot/dotfiles/
```
If you don't want to install `kot`, you can also use the following `cargo` command
where all arguments after the `--` are passed as arguments to `kot` and not `cargo`.
Below is an example of the short-help output text provided with the `-h` flag
```bash
cd path/to/kot
cargo build
cargo run -- --help
kot 0.1.5
CLI for managing Linux user configurations
USAGE:
kot [FLAGS] [OPTIONS] <dotfiles> --install <install>
FLAGS:
-d, --dry-run Installs configurations to $HOME/.local/shared/kot/dry-runs
-f, --force Overwrites existing backups
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-b, --backup-dir <backup-dir> The location to store backups for this user [default: backups/kapper]
-i, --install-dir <install-dir> The location to attempt installation of user configurations [default: dry-
runs/kapper]
-b, --backup-dir <backup-dir> The location to store backups for this user
-c, --clone-dir <clone-dir> An alternate path to clone a dotfiles repository to
-i, --install <install> The location to attempt installation of user configurations [env:
HOME=/home/kapper]
ARGS:
<dotfiles-dir> Local or full path to user configurations to install
<dotfiles> Local or full path to user configurations to install. Can also be a git repository
```
#### Dotfiles Management
#### TODO
To store dotfiles, this repository uses submodules. To update surface-level submodules, we can run the following commands
```bash
git submodule update --init
Submodule path 'dot': checked out '7877117d5bd413ecf35c86efb4514742d8136843'
```
But in the case of my dotfiles repository, [shaunrd0/dot](https://gitlab.com/shaunrd0/dot), I use submodules to clone repositories for vim plugins. To update all submodules *and their nested submodules*, we can run the following commands
```bash
git submodule update --init --recursive
Submodule 'dotfiles/dot' (https://gitlab.com/shaunrd0/dot) registered for path 'dotfiles/dot'
Cloning into '/home/kapper/Code/kotd/dotfiles/dot'...
warning: redirecting to https://gitlab.com/shaunrd0/dot.git/
Submodule path 'dotfiles/dot': checked out '7877117d5bd413ecf35c86efb4514742d8136843'
Submodule '.vim/bundle/Colorizer' (https://github.com/chrisbra/Colorizer) registered for path 'dotfiles/dot/.vim/bundle/Colorizer'
Submodule '.vim/bundle/ale' (https://github.com/dense-analysis/ale) registered for path 'dotfiles/dot/.vim/bundle/ale'
Submodule '.vim/bundle/clang_complete' (https://github.com/xavierd/clang_complete) registered for path 'dotfiles/dot/.vim/bundle/clang_complete'
Submodule '.vim/bundle/supertab' (https://github.com/ervandew/supertab) registered for path 'dotfiles/dot/.vim/bundle/supertab'
Submodule '.vim/bundle/unicode.vim' (https://github.com/chrisbra/unicode.vim) registered for path 'dotfiles/dot/.vim/bundle/unicode.vim'
Submodule '.vim/bundle/vim-airline' (https://github.com/vim-airline/vim-airline) registered for path 'dotfiles/dot/.vim/bundle/vim-airline'
Submodule '.vim/bundle/vim-airline-themes' (https://github.com/vim-airline/vim-airline-themes) registered for path 'dotfiles/dot/.vim/bundle/vim-airline-themes'
Submodule '.vim/bundle/vim-signify' (https://github.com/mhinz/vim-signify) registered for path 'dotfiles/dot/.vim/bundle/vim-signify'
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/Colorizer'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/ale'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/clang_complete'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/supertab'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/unicode.vim'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/vim-airline'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/vim-airline-themes'...
Cloning into '/home/kapper/Code/kotd/dotfiles/dot/.vim/bundle/vim-signify'...
Submodule path 'dotfiles/dot/.vim/bundle/Colorizer': checked out '826d5691ac7d36589591314621047b1b9d89ed34'
Submodule path 'dotfiles/dot/.vim/bundle/ale': checked out '3ea887d2f4d43dd55d81213517344226f6399ed6'
Submodule path 'dotfiles/dot/.vim/bundle/clang_complete': checked out '293a1062274a06be61797612034bd8d87851406e'
Submodule path 'dotfiles/dot/.vim/bundle/supertab': checked out 'd80e8e2c1fa08607fa34c0ca5f1b66d8a906c5ef'
Submodule path 'dotfiles/dot/.vim/bundle/unicode.vim': checked out 'afb8db4f81580771c39967e89bc5772e72b9018e'
Submodule path 'dotfiles/dot/.vim/bundle/vim-airline': checked out 'cb1bc19064d3762e4e08103afb37a246b797d902'
Submodule path 'dotfiles/dot/.vim/bundle/vim-airline-themes': checked out 'd148d42d9caf331ff08b6cae683d5b210003cde7'
Submodule path 'dotfiles/dot/.vim/bundle/vim-signify': checked out 'b2a0450e23c63b75bbeabf4f0c28f9b4b2480689'
```
* Ensure empty backups are not created
* Provide interface for managing agreed-upon /etc/skel/ configurations
* Provide more CLI options for git functionality; Branches, update submodules, etc
* Clean up warnings during build / installation
* Automate testing
*