From 6760a78f446b8edbe516e1f0737bd49c54812c6c Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Thu, 27 Aug 2026 22:53:59 +0800 Subject: [PATCH 1/3] feat(pm): expose embeddable command library --- crates/pm/Cargo.toml | 4 + crates/pm/src/cli_entry.rs | 613 +++++++++++++++++++++++++++++++ crates/pm/src/lib.rs | 289 +++++++++++++++ crates/pm/src/main.rs | 635 +-------------------------------- crates/pm/tests/library_api.rs | 40 +++ 5 files changed, 947 insertions(+), 634 deletions(-) create mode 100644 crates/pm/src/cli_entry.rs create mode 100644 crates/pm/src/lib.rs create mode 100644 crates/pm/tests/library_api.rs diff --git a/crates/pm/Cargo.toml b/crates/pm/Cargo.toml index f5f2ea6b8..5df3dbee3 100644 --- a/crates/pm/Cargo.toml +++ b/crates/pm/Cargo.toml @@ -12,6 +12,10 @@ categories = ["command-line-utilities", "development-tools"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "utoo_pm" +path = "src/lib.rs" + [[bin]] name = "utoo" path = "src/main.rs" diff --git a/crates/pm/src/cli_entry.rs b/crates/pm/src/cli_entry.rs new file mode 100644 index 000000000..47766e036 --- /dev/null +++ b/crates/pm/src/cli_entry.rs @@ -0,0 +1,613 @@ +use std::{io, process}; + +use anyhow::{Context, Result}; +use clap::error::ErrorKind as ClapErrorKind; +use clap::{CommandFactory, FromArgMatches}; + +use crate::cli::{Cli, Commands, detect_shell_from_env}; +use crate::constants::APP_VERSION; +use crate::error::{CliError, ErrorKind, classify}; +use crate::helper::auto_update::init_auto_update; +use crate::helper::self_pin::handoff_if_needed; +use crate::model::cli_output::{ + CompletionsResult, ErrorDetails, HelpResult, HelpTarget, InitResult, RequestedPackage, + RequiredBy, VersionResult, +}; +use crate::service::config::ConfigService; +use crate::service::script::{MissingScript, ScriptExit, script_failure_details}; +use crate::service::workspace::WorkspaceFilter; +use crate::types::InitOutput; +use crate::util::cli_enum::{ + ColorPolicy, ConfigScope, ConfirmationPolicy, ConsoleVerbosity, InitMode, OutputFormat, + ProvenancePolicy, ScriptPolicy, +}; +use crate::util::config_file::Config; +use crate::util::format_print::{format_resolve_chain, resolve_chain}; +use crate::util::invocation::{self, Invocation}; +use crate::util::logger::{get_log_file_path, init_tracing, log_time, log_time_end}; +use crate::util::presenter; +use crate::{InitializeOptions, commands}; + +/// Run the complete `utoo` command-line application. +/// +/// Embedders normally call the functions under [`crate::commands`] instead. +/// This entry point exists so the native binary stays a thin wrapper around +/// the same library crate. +pub fn run() { + invocation::start(); + crate::util::sysconf::init(); + + let worker_threads = std::thread::available_parallelism() + .map(|n| n.get()) + .unwrap_or(4); + + let result = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(worker_threads) + .build() + .expect("failed to build tokio runtime") + .block_on(async_main()); + + if let Err(e) = result { + let category = classify(&e); + // A failed package script propagates its own exit status so + // `utoo run