mod check_output;
mod config;
mod execution;
mod explain_output;
mod init;
mod languages;
mod machine;
mod ratchet;
mod reference;
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand, ValueEnum};
use sprawl_guard_lib::{LanguageId, TraversalErrorPolicy};
use crate::error::{CliError, Result};
#[derive(Debug, Parser)]
#[command(
name = crate::CLI_NAME,
version,
about = "Source-tree structure guard for local navigability"
)]
pub struct Cli {
#[arg(long, global = true)]
root: Option<PathBuf>,
#[arg(long, global = true)]
config: Option<PathBuf>,
#[arg(long, global = true)]
color: Option<ColorModeArg>,
#[arg(long, global = true)]
quiet: bool,
#[command(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
Init(InitArgs),
Languages(LanguagesArgs),
Check(CheckArgs),
Baseline(BaselineArgs),
Ratchet(RatchetArgs),
Config(ConfigCommand),
Explain(ExplainArgs),
Machine(machine::MachineArgs),
}
#[derive(Debug, Args)]
struct InitArgs {
#[arg(long, value_delimiter = ',', conflicts_with = "all_languages")]
languages: Vec<LanguageId>,
#[arg(long)]
all_languages: bool,
#[arg(long)]
dry_run: bool,
}
#[derive(Debug, Args)]
struct CheckArgs {
#[arg(long)]
format: Option<CheckFormat>,
#[arg(long, conflicts_with = "no_require_ratchet_current")]
require_ratchet_current: bool,
#[arg(long, conflicts_with = "require_ratchet_current")]
no_require_ratchet_current: bool,
#[arg(long)]
traversal_error_policy: Option<TraversalErrorPolicyArg>,
paths: Vec<PathBuf>,
}
#[derive(Debug, Args)]
struct LanguagesArgs {
#[arg(long)]
format: Option<HumanJsonFormat>,
#[arg(long)]
detected: bool,
}
#[derive(Debug, Args)]
struct BaselineArgs {
paths: Vec<PathBuf>,
#[arg(long)]
write: bool,
#[arg(long)]
all: bool,
#[arg(long)]
allow_raises: bool,
}
#[derive(Debug, Args)]
struct RatchetArgs {
paths: Vec<PathBuf>,
#[arg(long)]
write: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
enum HumanJsonFormat {
Human,
Json,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
enum ColorModeArg {
Auto,
Always,
Never,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
enum CheckFormat {
Human,
Json,
Sarif,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
enum TraversalErrorPolicyArg {
Fail,
Warn,
}
impl From<TraversalErrorPolicyArg> for TraversalErrorPolicy {
fn from(value: TraversalErrorPolicyArg) -> Self {
match value {
TraversalErrorPolicyArg::Fail => Self::Fail,
TraversalErrorPolicyArg::Warn => Self::Warn,
}
}
}
#[derive(Debug, Args)]
struct ConfigCommand {
#[command(subcommand)]
command: ConfigSubcommand,
}
#[derive(Debug, Subcommand)]
enum ConfigSubcommand {
Resolved,
Export,
}
#[derive(Debug, Args)]
struct ExplainArgs {
#[arg(long)]
format: Option<HumanJsonFormat>,
path: PathBuf,
}
pub fn run(cli: Cli) -> Result<i32> {
let Cli {
root,
config,
color,
quiet,
command,
} = cli;
match command {
Command::Machine(args) => machine::run_machine(machine::MachineCliArgs::new(
root, config, color, quiet, args,
)),
command => {
let default_root =
std::env::current_dir().map_err(|source| CliError::CurrentDirectory { source })?;
let outcome = execution::execute_cli_command(
Cli {
root,
config,
color,
quiet,
command,
},
default_root,
)?;
execution::print_command_outcome(&outcome);
Ok(outcome.exit_code)
}
}
}