Something went wrong. Try again.
inkfinite (an infinite canvas/whiteboard) monorepo ink.stormlightlabs.org
svelte rust tauri svg canvas perfect-freehand
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153use std::env;use std::fs::{self, File};use std::path::{Path, PathBuf};use std::process::Command as ProcessCommand;
use anyhow::{Context, Result, bail};use clap::{CommandFactory, Parser, Subcommand};use clap_complete::aot::{Bash, Fish, Generator, Zsh};use clap_mangen::Man;use inkfinite_cli::cli::{Cli, CompletionShell};
const BINARY_NAME: &str = "inkfinite";
#[derive(Debug, Parser)]#[command( name = "cargo xtask", bin_name = "cargo xtask", about = "Inkfinite source distribution tasks")]struct Xtask { #[command(subcommand)] command: Task,}
#[derive(Debug, Subcommand)]enum Task { /// Generate the Inkfinite man page. Man, /// Generate Bash, Fish, and Zsh completion scripts. Completions, /// Build a release binary with its man page and shell completions. Dist,}
fn main() { if let Err(error) = run() { eprintln!("cargo xtask: {error:#}"); std::process::exit(1); }}
fn run() -> Result<()> { match Xtask::parse().command { Task::Man => generate_man(&target_dir().join("man")), Task::Completions => generate_completions(&target_dir().join("completions")), Task::Dist => generate_distribution(), }}
fn generate_man(output_dir: &Path) -> Result<()> { fs::create_dir_all(output_dir).with_context(|| format!("could not create {}", output_dir.display()))?; let output = output_dir.join("inkfinite.1"); let mut file = File::create(&output).with_context(|| format!("could not create {}", output.display()))?; Man::new(Cli::command()) .render(&mut file) .with_context(|| format!("could not write {}", output.display()))?; println!("generated {}", output.display()); Ok(())}
fn generate_completions(output_dir: &Path) -> Result<()> { fs::create_dir_all(output_dir).with_context(|| format!("could not create {}", output_dir.display()))?; for (shell, filename) in [ (CompletionShell::Bash, "inkfinite.bash"), (CompletionShell::Fish, "inkfinite.fish"), (CompletionShell::Zsh, "_inkfinite"), ] { write_completion(shell, &output_dir.join(filename))?; } println!("generated completions in {}", output_dir.display()); Ok(())}
fn generate_distribution() -> Result<()> { let target = target_dir(); build_release_binary(&workspace_root())?;
let distribution = target.join("dist"); if distribution.exists() { fs::remove_dir_all(&distribution).with_context(|| format!("could not remove {}", distribution.display()))?; } fs::create_dir_all(distribution.join("bin")) .with_context(|| format!("could not create {}", distribution.display()))?;
let binary_name = if cfg!(windows) { "inkfinite.exe" } else { BINARY_NAME }; let binary = target.join("release").join(binary_name); let installed_binary = distribution.join("bin").join(binary_name); fs::copy(&binary, &installed_binary).with_context(|| format!("could not copy {}", binary.display()))?;
generate_man(&distribution.join("share/man/man1"))?; write_completion( CompletionShell::Bash, &distribution.join("share/bash-completion/completions/inkfinite"), )?; write_completion( CompletionShell::Fish, &distribution.join("share/fish/vendor_completions.d/inkfinite.fish"), )?; write_completion( CompletionShell::Zsh, &distribution.join("share/zsh/site-functions/_inkfinite"), )?;
println!("distribution written to {}", distribution.display()); Ok(())}
fn build_release_binary(root: &Path) -> Result<()> { let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); let status = ProcessCommand::new(cargo) .args(["build", "--release", "-p", "inkfinite-cli", "--bin", BINARY_NAME]) .current_dir(root) .status() .context("could not start the release build")?; if !status.success() { bail!("release build failed with {status}"); } Ok(())}
fn write_completion(shell: CompletionShell, output: &Path) -> Result<()> { if let Some(parent) = output.parent() { fs::create_dir_all(parent).with_context(|| format!("could not create {}", parent.display()))?; } let mut command = Cli::command(); command.set_bin_name(BINARY_NAME); command.build(); let mut file = File::create(output).with_context(|| format!("could not create {}", output.display()))?; let result = match shell { CompletionShell::Bash => Bash.try_generate(&command, &mut file), CompletionShell::Fish => Fish.try_generate(&command, &mut file), CompletionShell::Zsh => Zsh.try_generate(&command, &mut file), }; result.with_context(|| format!("could not write {}", output.display()))?; println!("generated {}", output.display()); Ok(())}
fn workspace_root() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .parent() .expect("xtask is inside the workspace") .to_path_buf()}
fn target_dir() -> PathBuf { let root = workspace_root(); let target = env::var_os("CARGO_TARGET_DIR") .map(PathBuf::from) .unwrap_or_else(|| PathBuf::from("target")); if target.is_absolute() { target } else { root.join(target) }}