1#![forbid(unsafe_code)]
23#![warn(missing_docs)]
24
25pub mod builtins;
26pub mod cache;
27pub mod capabilities;
28pub mod cli;
29pub mod discovery;
30pub mod env;
31pub mod exec;
32pub mod lifecycle;
33pub mod metadata;
34pub mod project;
35
36use std::ffi::OsString;
37use std::path::PathBuf;
38
39use ready_set_sdk::context::{ColorMode, LogLevel};
40use ready_set_sdk::{ExitCode, OutputMode};
41
42pub fn run(argv: impl IntoIterator<Item = OsString>) -> ExitCode {
44 let parsed = cli::parse(argv.into_iter());
45 let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
46 match parsed {
47 cli::ParsedArgs::Help => {
48 let contract = build_contract(&cli::GlobalFlags::default(), &cwd);
49 builtins::help::run(&[], &contract)
50 },
51 cli::ParsedArgs::Version => {
52 let contract = build_contract(&cli::GlobalFlags::default(), &cwd);
53 builtins::version::run(&[], &contract)
54 },
55 cli::ParsedArgs::List { all, globals } => {
56 let contract = build_contract(&globals, &cwd);
57 let forwarded: Vec<OsString> = if all {
58 vec![OsString::from("--all")]
59 } else {
60 Vec::new()
61 };
62 builtins::list::run(&forwarded, &contract)
63 },
64 cli::ParsedArgs::Empty { globals } => {
65 let contract = build_contract(&globals, &cwd);
66 builtins::ready::run(&[], &contract)
67 },
68 cli::ParsedArgs::Subcommand {
69 name,
70 args,
71 globals,
72 } => {
73 let contract = build_contract(&globals, &cwd);
74 if let Some(handler) = builtins::route(&name) {
75 return handler(&args, &contract);
76 }
77 let Some(entry) = discovery::find_plugin(&name) else {
79 eprintln!(
80 "ready-set: unknown subcommand `{name}`\n\
81 hint: search crates.io for `ready-set-{name}` to install one"
82 );
83 return ExitCode::UnknownSubcommand;
84 };
85 exec::dispatch_to_plugin(&entry, &args, &contract)
86 },
87 }
88}
89
90fn build_contract(globals: &cli::GlobalFlags, cwd: &std::path::Path) -> env::EnvContract {
91 let project_root = project::detect_project_root(cwd);
92 let config_path = project_root
93 .as_deref()
94 .map(|root| root.join(".ready-set.toml"))
95 .filter(|p| p.is_file());
96
97 env::EnvContract {
98 dispatcher_version: env!("CARGO_PKG_VERSION")
99 .parse()
100 .unwrap_or_else(|_| semver::Version::new(0, 0, 0)),
101 project_root,
102 config_path,
103 output: globals.output.unwrap_or(OutputMode::Human),
104 log: globals.log.unwrap_or(LogLevel::Normal),
105 color: globals.color.unwrap_or(ColorMode::Auto),
106 }
107}