diff --git a/crates/uv/src/bin/uv.rs b/crates/uv/src/bin/uv.rs new file mode 100644 index 000000000000..dd3a216e3394 --- /dev/null +++ b/crates/uv/src/bin/uv.rs @@ -0,0 +1,7 @@ +use std::process::ExitCode; + +use uv::main as uv_main; + +fn main() -> ExitCode { + uv_main(std::env::args_os()) +} diff --git a/crates/uv/src/main.rs b/crates/uv/src/lib.rs similarity index 97% rename from crates/uv/src/main.rs rename to crates/uv/src/lib.rs index 41035ac80f9a..cd00d67e4431 100644 --- a/crates/uv/src/main.rs +++ b/crates/uv/src/lib.rs @@ -1,4 +1,5 @@ use std::env; +use std::ffi::OsString; use std::fmt::Write; use std::io::stdout; use std::path::PathBuf; @@ -48,76 +49,15 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; #[global_allocator] static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -mod commands; -mod logging; -mod printer; -mod settings; -mod shell; -mod version; - -#[instrument] -async fn run() -> Result { - let cli = match Cli::try_parse() { - Ok(cli) => cli, - Err(mut err) => { - if let Some(ContextValue::String(subcommand)) = err.get(ContextKind::InvalidSubcommand) - { - match subcommand.as_str() { - "compile" | "lock" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip compile".to_string()), - ); - } - "sync" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip sync".to_string()), - ); - } - "install" | "add" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip install".to_string()), - ); - } - "uninstall" | "remove" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip uninstall".to_string()), - ); - } - "freeze" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip freeze".to_string()), - ); - } - "list" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip list".to_string()), - ); - } - "show" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip show".to_string()), - ); - } - "tree" => { - err.insert( - ContextKind::SuggestedSubcommand, - ContextValue::String("uv pip tree".to_string()), - ); - } - _ => {} - } - } - err.exit() - } - }; +pub(crate) mod commands; +pub(crate) mod logging; +pub(crate) mod printer; +pub(crate) mod settings; +pub(crate) mod shell; +pub(crate) mod version; +#[instrument(skip_all)] +async fn run(cli: Cli) -> Result { // enable flag to pick up warnings generated by workspace loading. if !cli.global_args.quiet { uv_warnings::enable(); @@ -1030,7 +970,81 @@ async fn run_project( } } -fn main() -> ExitCode { +/// The main entry point for a uv invocation. +/// +/// WARNING: This entry point is not recommended for external consumption, the +/// `uv` binary interface is the official public API. When using this entry +/// point, uv assumes it is running in a process it controls and that the +/// entire process lifetime is managed by uv. Unexpected behavior may be +/// encountered if this entry pointis called multiple times in a single process. +pub fn main(args: I) -> ExitCode +where + I: IntoIterator, + T: Into + Clone, +{ + // `std::env::args` is not `Send` so we parse before passing to our runtime + // https://github.com/rust-lang/rust/pull/48005 + let cli = match Cli::try_parse_from(args) { + Ok(cli) => cli, + Err(mut err) => { + if let Some(ContextValue::String(subcommand)) = err.get(ContextKind::InvalidSubcommand) + { + match subcommand.as_str() { + "compile" | "lock" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip compile".to_string()), + ); + } + "sync" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip sync".to_string()), + ); + } + "install" | "add" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip install".to_string()), + ); + } + "uninstall" | "remove" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip uninstall".to_string()), + ); + } + "freeze" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip freeze".to_string()), + ); + } + "list" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip list".to_string()), + ); + } + "show" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip show".to_string()), + ); + } + "tree" => { + err.insert( + ContextKind::SuggestedSubcommand, + ContextValue::String("uv pip tree".to_string()), + ); + } + _ => {} + } + } + err.exit() + } + }; + // Windows has a default stack size of 1MB, which is lower than the linux and mac default. // https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-170 // We support increasing the stack size to avoid stack overflows in debug mode on Windows. In @@ -1045,7 +1059,7 @@ fn main() -> ExitCode { .build() .expect("Failed building the Runtime"); // Box the large main future to avoid stack overflows. - let result = runtime.block_on(Box::pin(run())); + let result = runtime.block_on(Box::pin(run(cli))); // Avoid waiting for pending tasks to complete. // // The resolver may have kicked off HTTP requests during resolution that @@ -1066,7 +1080,7 @@ fn main() -> ExitCode { .build() .expect("Failed building the Runtime"); // Box the large main future to avoid stack overflows. - let result = runtime.block_on(Box::pin(run())); + let result = runtime.block_on(Box::pin(run(cli))); runtime.shutdown_background(); result };