Skip to content

Commit

Permalink
feat(whiskers): add check mode (#52)
Browse files Browse the repository at this point in the history
* feat(whiskers): add check mode with diff view

* feat(whiskers): add version flag
  • Loading branch information
backwardspy authored Oct 28, 2023
1 parent a924c9b commit 6bb415e
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 17 deletions.
66 changes: 65 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions whiskers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ regex = "1.10.2"
serde = { version = "1.0.189", features = ["derive"] }
serde_json = "1.0.107"
serde_yaml = "0.9.25"
tempfile = "3.8.1"
thiserror = "1.0.50"
titlecase = "2.2.1"
48 changes: 35 additions & 13 deletions whiskers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,20 @@ A templating tool to simplify the creation of Catppuccin ports.
## Installation

[Compiled binaries are available for Windows, macOS, and Linux.](https://github.com/catppuccin/toolbox/releases)
Download the correct file for your system and place it somewhere in your executable path.

### Build from source
Download the correct file for your system and place it somewhere in your executable path.

If you have a rust toolchain installed, you can build and install Whiskers with cargo:
Alternatively, you can install with Cargo, Nix, or from source:

```console
# latest crates.io release:
$ cargo install catppuccin-whiskers
$ whiskers <template> <flavor>

# to install from source:
$ cargo install --git https://github.com/catppuccin/toolbox whiskers
# there's also a Nix flake:
$ nix run github:catppuccin/toolbox#whiskers -- <images> <flags>
```

### Nix flake

If you use Nix, you can use Whiskers' flake:

```console
# there's also a Nix flake:
$ nix run github:catppuccin/toolbox#whiskers -- <template> <flavor>
```

Expand All @@ -47,15 +41,21 @@ Make a template per file type that your port requires, then use the Whiskers CLI

```console
$ whiskers --help
Soothing port creation tool for the high-spirited!

Usage: whiskers [OPTIONS] [TEMPLATE] [FLAVOR]

Arguments:
[TEMPLATE] Path to the template file to render, or `-` for stdin
[FLAVOR] Flavor to get colors from [possible values: latte, frappe, macchiato, mocha]

Options:
-l, --list-helpers List all template helpers in markdown format
-h, --help Print help
--override <OVERRIDES> The overrides to apply to the template in key=value format
-o, --output-path <OUTPUT_PATH> Path to write to instead of stdout
--check <CHECK> Instead of printing a result just check if anything would change
-l, --list-helpers List all template helpers in markdown format
-h, --help Print help
-V, --version Print version
```

## Template Syntax
Expand Down Expand Up @@ -213,6 +213,28 @@ bg = "#000000"
fg = "#f9e2af"
```

## Check Mode

You can use Whiskers as a linter with *check mode*. To do so, set the `--check` option to a file containing the expected output. Whiskers will render your template as per usual, but then instead of printing the result it will check it against the expected output and fail with exit code 1 if they differ.

This is especially useful in CI pipelines to ensure that the generated files are not changed without a corresponding change to the templates.

Whiskers will diff the output against the check file using the program set in the `DIFFTOOL` environment variable, falling back to `diff` if it's not set. The command will be invoked as `$DIFFTOOL <actual> <expected>`.

```console
$ whiskers theme.hbs latte --check themes/latte.cfg
(no output, exit code 0)

$ whiskers theme.hbs latte --check themes/latte.cfg
Templating would result in changes.
4c4
< accent is #ea76cb
---
> accent is #40a02b

(exit code 1)
```

## Further Reading

- [The example template](examples/example.hbs) demonstrates the template syntax and usage of some of the helpers.
Expand Down
50 changes: 47 additions & 3 deletions whiskers/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::unwrap_used)]
// we like truncating u32s into u8s around here
#![allow(clippy::cast_possible_truncation)]
use std::clone::Clone;
use std::{
clone::Clone,
env, fs,
io::Write,
path::{Path, PathBuf},
process,
};

// we like truncating u32s into u8s around here
use clap::Parser;
use clap_stdin::FileOrStdin;
use color_eyre::{
Expand Down Expand Up @@ -53,6 +59,7 @@ fn parse_override(s: &str) -> Result<Override> {
}

#[derive(clap::Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path to the template file to render, or `-` for stdin
#[arg(required_unless_present = "list_helpers")]
Expand All @@ -66,6 +73,14 @@ struct Args {
#[arg(long("override"), value_parser(parse_override))]
overrides: Vec<Override>,

/// Path to write to instead of stdout
#[arg(short, long)]
output_path: Option<PathBuf>,

/// Instead of printing a result just check if anything would change
#[arg(long)]
check: Option<PathBuf>,

/// List all template helpers in markdown format
#[arg(short, long)]
list_helpers: bool,
Expand Down Expand Up @@ -143,7 +158,36 @@ fn main() -> Result<()> {
.render_template(content, &ctx)
.wrap_err("Failed to render template")?;
let result = postprocess(&result);
println!("{result}");

if let Some(expected_path) = args.check {
let expected = fs::read_to_string(&expected_path)?;
if result != expected {
eprintln!("Templating would result in changes.");
invoke_difftool(&result, &expected_path)?;
process::exit(1);
}
} else if let Some(output_path) = args.output_path {
fs::write(output_path, result)?;
} else {
print!("{result}");
}

Ok(())
}

fn invoke_difftool(actual: &str, expected_path: &Path) -> Result<(), color_eyre::eyre::Error> {
let tool = env::var("DIFFTOOL").unwrap_or_else(|_| "diff".to_string());

let mut actual_file = tempfile::NamedTempFile::new()?;
write!(&mut actual_file, "{actual}")?;
if let Ok(mut child) = std::process::Command::new(tool)
.args([actual_file.path(), &expected_path])
.spawn()
{
child.wait()?;
} else {
eprintln!("warning: Can't display diff, try setting $DIFFTOOL.");
}

Ok(())
}
Expand Down

0 comments on commit 6bb415e

Please sign in to comment.