pint_cli/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use anyhow::Context;
use clap::{CommandFactory, Parser, Subcommand};

pub mod build;
pub mod new;
mod plugin;

#[derive(Parser, Debug)]
#[command(
    name = "pint",
    about = "Pint's package manager and CLI plugin host",
    version
)]
pub struct Pint {
    #[command(subcommand)]
    cmd: Cmd,
}

#[derive(Debug, Subcommand)]
enum Cmd {
    #[command(alias = "b")]
    Build(build::Args),
    New(new::Args),
    /// Print all pint plugins found in `PATH`.
    Plugins,
    /// A catch-all for unknown pint plugins and their arguments.
    ///
    /// Checks for a plugin exe named `pint-<unknown-subcommand>` and tries to
    /// execute it with the remaining args.
    #[clap(external_subcommand)]
    Plugin(Vec<String>),
}

// Manually print the help output for missing/unknown commands or plugins.
fn print_help_output() -> anyhow::Result<()> {
    let mut cli = Pint::command();
    cli.print_help()?;
    Ok(())
}

/// Run the `pint` CLI given the set of parsed commands/args.
pub fn run(pint: Pint) -> anyhow::Result<()> {
    match pint.cmd {
        Cmd::New(arg) => new::cmd(arg),
        Cmd::Build(arg) => {
            let (_plan, _built_pkgs) = build::cmd(arg)?;
            Ok(())
        }
        Cmd::Plugins => {
            plugin::print_all();
            Ok(())
        }
        Cmd::Plugin(args) if !args.is_empty() => {
            let Some(plugin_exe_path) = plugin::find_exe(&args[0]) else {
                // There's no plugin with the given name, so print help output.
                print_help_output()?;
                anyhow::bail!("no known command or plugin {:?}", &args[0]);
            };
            let output = plugin::exec(&plugin_exe_path, &args[1..])?;
            std::process::exit(output.status.code().context("unknown exit status")?);
        }
        _ => print_help_output(),
    }
}