68f33e8fef
## Summary Closes https://github.com/astral-sh/uv/issues/15369.
2321 lines
87 KiB
Rust
2321 lines
87 KiB
Rust
use std::borrow::Cow;
|
|
use std::ffi::OsString;
|
|
use std::fmt::Write;
|
|
use std::io::stdout;
|
|
#[cfg(feature = "self-update")]
|
|
use std::ops::Bound;
|
|
use std::path::Path;
|
|
use std::process::ExitCode;
|
|
use std::str::FromStr;
|
|
use std::sync::atomic::Ordering;
|
|
|
|
use anstream::eprintln;
|
|
use anyhow::{Context, Result, bail};
|
|
use clap::error::{ContextKind, ContextValue};
|
|
use clap::{CommandFactory, Parser};
|
|
use futures::FutureExt;
|
|
use owo_colors::OwoColorize;
|
|
use settings::PipTreeSettings;
|
|
use tokio::task::spawn_blocking;
|
|
use tracing::{debug, instrument, trace};
|
|
|
|
use uv_cache::{Cache, Refresh};
|
|
use uv_cache_info::Timestamp;
|
|
#[cfg(feature = "self-update")]
|
|
use uv_cli::SelfUpdateArgs;
|
|
use uv_cli::{
|
|
BuildBackendCommand, CacheCommand, CacheNamespace, Cli, Commands, PipCommand, PipNamespace,
|
|
ProjectCommand, PythonCommand, PythonNamespace, SelfCommand, SelfNamespace, ToolCommand,
|
|
ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
|
};
|
|
use uv_configuration::min_stack_size;
|
|
use uv_fs::{CWD, Simplified};
|
|
#[cfg(feature = "self-update")]
|
|
use uv_pep440::release_specifiers_to_ranges;
|
|
use uv_pep508::VersionOrUrl;
|
|
use uv_pypi_types::{ParsedDirectoryUrl, ParsedUrl};
|
|
use uv_python::PythonRequest;
|
|
use uv_requirements::{GroupsSpecification, RequirementsSource};
|
|
use uv_requirements_txt::RequirementsTxtRequirement;
|
|
use uv_scripts::{Pep723Error, Pep723Item, Pep723Metadata, Pep723Script};
|
|
use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
|
|
use uv_static::EnvVars;
|
|
use uv_warnings::{warn_user, warn_user_once};
|
|
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
|
|
|
|
use crate::commands::{ExitStatus, RunCommand, ScriptPath, ToolRunCommand};
|
|
use crate::printer::Printer;
|
|
use crate::settings::{
|
|
CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings,
|
|
PipInstallSettings, PipListSettings, PipShowSettings, PipSyncSettings, PipUninstallSettings,
|
|
PublishSettings,
|
|
};
|
|
|
|
pub(crate) mod child;
|
|
pub(crate) mod commands;
|
|
pub(crate) mod logging;
|
|
pub(crate) mod printer;
|
|
pub(crate) mod settings;
|
|
#[cfg(windows)]
|
|
mod windows_exception;
|
|
|
|
#[instrument(skip_all)]
|
|
async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|
// Enable flag to pick up warnings generated by workspace loading.
|
|
if cli.top_level.global_args.quiet == 0 {
|
|
uv_warnings::enable();
|
|
}
|
|
|
|
// Switch directories as early as possible.
|
|
if let Some(directory) = cli.top_level.global_args.directory.as_ref() {
|
|
std::env::set_current_dir(directory)?;
|
|
}
|
|
|
|
// Determine the project directory.
|
|
let project_dir = cli
|
|
.top_level
|
|
.global_args
|
|
.project
|
|
.as_deref()
|
|
.map(std::path::absolute)
|
|
.transpose()?
|
|
.map(uv_fs::normalize_path_buf)
|
|
.map(Cow::Owned)
|
|
.unwrap_or_else(|| Cow::Borrowed(&*CWD));
|
|
|
|
// The `--isolated` argument is deprecated on preview APIs, and warns on non-preview APIs.
|
|
let deprecated_isolated = if cli.top_level.global_args.isolated {
|
|
match &*cli.command {
|
|
// Supports `--isolated` as its own argument, so we can't warn either way.
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::Uvx(_) | ToolCommand::Run(_),
|
|
}) => false,
|
|
|
|
// Supports `--isolated` as its own argument, so we can't warn either way.
|
|
Commands::Project(command) if matches!(**command, ProjectCommand::Run(_)) => false,
|
|
|
|
// `--isolated` moved to `--no-workspace`.
|
|
Commands::Project(command) if matches!(**command, ProjectCommand::Init(_)) => {
|
|
warn_user!(
|
|
"The `--isolated` flag is deprecated and has no effect. Instead, use `--no-config` to prevent uv from discovering configuration files or `--no-workspace` to prevent uv from adding the initialized project to the containing workspace."
|
|
);
|
|
false
|
|
}
|
|
|
|
// Preview APIs. Ignore `--isolated` and warn.
|
|
Commands::Project(_) | Commands::Tool(_) | Commands::Python(_) => {
|
|
warn_user!(
|
|
"The `--isolated` flag is deprecated and has no effect. Instead, use `--no-config` to prevent uv from discovering configuration files."
|
|
);
|
|
false
|
|
}
|
|
|
|
// Non-preview APIs. Continue to support `--isolated`, but warn.
|
|
_ => {
|
|
warn_user!(
|
|
"The `--isolated` flag is deprecated. Instead, use `--no-config` to prevent uv from discovering configuration files."
|
|
);
|
|
true
|
|
}
|
|
}
|
|
} else {
|
|
false
|
|
};
|
|
|
|
// Load configuration from the filesystem, prioritizing (in order):
|
|
// 1. The configuration file specified on the command-line.
|
|
// 2. The nearest configuration file (`uv.toml` or `pyproject.toml`) above the workspace root.
|
|
// If found, this file is combined with the user configuration file.
|
|
// 3. The nearest configuration file (`uv.toml` or `pyproject.toml`) in the directory tree,
|
|
// starting from the current directory.
|
|
let workspace_cache = WorkspaceCache::default();
|
|
let filesystem = if let Some(config_file) = cli.top_level.config_file.as_ref() {
|
|
if config_file
|
|
.file_name()
|
|
.is_some_and(|file_name| file_name == "pyproject.toml")
|
|
{
|
|
warn_user!(
|
|
"The `--config-file` argument expects to receive a `uv.toml` file, not a `pyproject.toml`. If you're trying to run a command from another project, use the `--project` argument instead."
|
|
);
|
|
}
|
|
Some(FilesystemOptions::from_file(config_file)?)
|
|
} else if deprecated_isolated || cli.top_level.no_config {
|
|
None
|
|
} else if matches!(&*cli.command, Commands::Tool(_) | Commands::Self_(_)) {
|
|
// For commands that operate at the user-level, ignore local configuration.
|
|
FilesystemOptions::user()?.combine(FilesystemOptions::system()?)
|
|
} else if let Ok(workspace) =
|
|
Workspace::discover(&project_dir, &DiscoveryOptions::default(), &workspace_cache).await
|
|
{
|
|
let project = FilesystemOptions::find(workspace.install_path())?;
|
|
let system = FilesystemOptions::system()?;
|
|
let user = FilesystemOptions::user()?;
|
|
project.combine(user).combine(system)
|
|
} else {
|
|
let project = FilesystemOptions::find(&project_dir)?;
|
|
let system = FilesystemOptions::system()?;
|
|
let user = FilesystemOptions::user()?;
|
|
project.combine(user).combine(system)
|
|
};
|
|
|
|
// Parse the external command, if necessary.
|
|
let run_command = if let Commands::Project(command) = &mut *cli.command {
|
|
if let ProjectCommand::Run(uv_cli::RunArgs {
|
|
command: Some(command),
|
|
module,
|
|
script,
|
|
gui_script,
|
|
..
|
|
}) = &mut **command
|
|
{
|
|
let settings = GlobalSettings::resolve(&cli.top_level.global_args, filesystem.as_ref());
|
|
Some(
|
|
RunCommand::from_args(
|
|
command,
|
|
settings.network_settings,
|
|
*module,
|
|
*script,
|
|
*gui_script,
|
|
)
|
|
.await?,
|
|
)
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// If the target is a PEP 723 script, parse it.
|
|
let script = if let Commands::Project(command) = &*cli.command {
|
|
match &**command {
|
|
ProjectCommand::Run(uv_cli::RunArgs { .. }) => match run_command.as_ref() {
|
|
Some(
|
|
RunCommand::PythonScript(script, _) | RunCommand::PythonGuiScript(script, _),
|
|
) => match Pep723Script::read(&script).await {
|
|
Ok(Some(script)) => Some(Pep723Item::Script(script)),
|
|
Ok(None) => None,
|
|
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => None,
|
|
Err(err) => return Err(err.into()),
|
|
},
|
|
Some(RunCommand::PythonRemote(url, script, _)) => {
|
|
match Pep723Metadata::read(&script).await {
|
|
Ok(Some(metadata)) => Some(Pep723Item::Remote(metadata, url.clone())),
|
|
Ok(None) => None,
|
|
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
|
None
|
|
}
|
|
Err(err) => return Err(err.into()),
|
|
}
|
|
}
|
|
Some(
|
|
RunCommand::PythonStdin(contents, _) | RunCommand::PythonGuiStdin(contents, _),
|
|
) => Pep723Metadata::parse(contents)?.map(Pep723Item::Stdin),
|
|
_ => None,
|
|
},
|
|
// For `uv add --script` and `uv lock --script`, we'll create a PEP 723 tag if it
|
|
// doesn't already exist.
|
|
ProjectCommand::Add(uv_cli::AddArgs {
|
|
script: Some(script),
|
|
..
|
|
})
|
|
| ProjectCommand::Lock(uv_cli::LockArgs {
|
|
script: Some(script),
|
|
..
|
|
}) => match Pep723Script::read(&script).await {
|
|
Ok(Some(script)) => Some(Pep723Item::Script(script)),
|
|
Ok(None) => None,
|
|
Err(err) => return Err(err.into()),
|
|
},
|
|
// For the remaining commands, the PEP 723 tag must exist already.
|
|
ProjectCommand::Remove(uv_cli::RemoveArgs {
|
|
script: Some(script),
|
|
..
|
|
})
|
|
| ProjectCommand::Sync(uv_cli::SyncArgs {
|
|
script: Some(script),
|
|
..
|
|
})
|
|
| ProjectCommand::Tree(uv_cli::TreeArgs {
|
|
script: Some(script),
|
|
..
|
|
})
|
|
| ProjectCommand::Export(uv_cli::ExportArgs {
|
|
script: Some(script),
|
|
..
|
|
}) => match Pep723Script::read(&script).await {
|
|
Ok(Some(script)) => Some(Pep723Item::Script(script)),
|
|
Ok(None) => {
|
|
bail!(
|
|
"`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
|
|
script.user_display().cyan(),
|
|
format!("uv init --script {}", script.user_display()).green()
|
|
)
|
|
}
|
|
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
|
bail!(
|
|
"Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
|
|
script.user_display().cyan(),
|
|
format!("uv init --script {}", script.user_display()).green()
|
|
)
|
|
}
|
|
Err(err) => return Err(err.into()),
|
|
},
|
|
_ => None,
|
|
}
|
|
} else if let Commands::Python(uv_cli::PythonNamespace {
|
|
command:
|
|
PythonCommand::Find(uv_cli::PythonFindArgs {
|
|
script: Some(script),
|
|
..
|
|
}),
|
|
}) = &*cli.command
|
|
{
|
|
match Pep723Script::read(&script).await {
|
|
Ok(Some(script)) => Some(Pep723Item::Script(script)),
|
|
Ok(None) => {
|
|
bail!(
|
|
"`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
|
|
script.user_display().cyan(),
|
|
format!("uv init --script {}", script.user_display()).green()
|
|
)
|
|
}
|
|
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
|
bail!(
|
|
"Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
|
|
script.user_display().cyan(),
|
|
format!("uv init --script {}", script.user_display()).green()
|
|
)
|
|
}
|
|
Err(err) => return Err(err.into()),
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// If the target is a PEP 723 script, merge the metadata into the filesystem metadata.
|
|
let filesystem = script
|
|
.as_ref()
|
|
.map(Pep723Item::metadata)
|
|
.and_then(|metadata| metadata.tool.as_ref())
|
|
.and_then(|tool| tool.uv.as_ref())
|
|
.map(|uv| Options::simple(uv.globals.clone(), uv.top_level.clone()))
|
|
.map(FilesystemOptions::from)
|
|
.combine(filesystem);
|
|
|
|
// Load environment variables not handled by Clap
|
|
let environment = EnvironmentOptions::new()?;
|
|
|
|
// Resolve the global settings.
|
|
let globals = GlobalSettings::resolve(&cli.top_level.global_args, filesystem.as_ref());
|
|
|
|
// Resolve the cache settings.
|
|
let cache_settings = CacheSettings::resolve(*cli.top_level.cache_args, filesystem.as_ref());
|
|
|
|
// Enforce the required version.
|
|
if let Some(required_version) = globals.required_version.as_ref() {
|
|
let package_version = uv_pep440::Version::from_str(uv_version::version())?;
|
|
if !required_version.contains(&package_version) {
|
|
#[cfg(feature = "self-update")]
|
|
let hint = {
|
|
// If the required version range includes a lower bound that's higher than
|
|
// the current version, suggest `uv self update`.
|
|
let ranges = release_specifiers_to_ranges(required_version.specifiers().clone());
|
|
|
|
if let Some(singleton) = ranges.as_singleton() {
|
|
// E.g., `==1.0.0`
|
|
format!(
|
|
". Update `uv` by running `{}`.",
|
|
format!("uv self update {singleton}").green()
|
|
)
|
|
} else if ranges
|
|
.bounding_range()
|
|
.iter()
|
|
.any(|(lowest, _highest)| match lowest {
|
|
Bound::Included(version) => **version > package_version,
|
|
Bound::Excluded(version) => **version > package_version,
|
|
Bound::Unbounded => false,
|
|
})
|
|
{
|
|
// E.g., `>=1.0.0`
|
|
format!(". Update `uv` by running `{}`.", "uv self update".cyan())
|
|
} else {
|
|
String::new()
|
|
}
|
|
};
|
|
#[cfg(not(feature = "self-update"))]
|
|
let hint = "";
|
|
return Err(anyhow::anyhow!(
|
|
"Required uv version `{required_version}` does not match the running version `{package_version}`{hint}",
|
|
));
|
|
}
|
|
}
|
|
|
|
// Configure the `tracing` crate, which controls internal logging.
|
|
#[cfg(feature = "tracing-durations-export")]
|
|
let (durations_layer, _duration_guard) = logging::setup_durations()?;
|
|
#[cfg(not(feature = "tracing-durations-export"))]
|
|
let durations_layer = None::<tracing_subscriber::layer::Identity>;
|
|
logging::setup_logging(
|
|
match globals.verbose {
|
|
0 => logging::Level::Off,
|
|
1 => logging::Level::DebugUv,
|
|
2 => logging::Level::TraceUv,
|
|
3.. => logging::Level::TraceAll,
|
|
},
|
|
durations_layer,
|
|
globals.color,
|
|
)?;
|
|
|
|
// Configure the `Printer`, which controls user-facing output in the CLI.
|
|
let printer = if globals.quiet == 1 {
|
|
Printer::Quiet
|
|
} else if globals.quiet > 1 {
|
|
Printer::Silent
|
|
} else if globals.verbose > 0 {
|
|
Printer::Verbose
|
|
} else if globals.no_progress {
|
|
Printer::NoProgress
|
|
} else {
|
|
Printer::Default
|
|
};
|
|
|
|
// Configure the `warn!` macros, which control user-facing warnings in the CLI.
|
|
if globals.quiet > 0 {
|
|
uv_warnings::disable();
|
|
} else {
|
|
uv_warnings::enable();
|
|
}
|
|
|
|
anstream::ColorChoice::write_global(globals.color.into());
|
|
|
|
miette::set_hook(Box::new(|_| {
|
|
Box::new(
|
|
miette::MietteHandlerOpts::new()
|
|
.break_words(false)
|
|
.word_separator(textwrap::WordSeparator::AsciiSpace)
|
|
.word_splitter(textwrap::WordSplitter::NoHyphenation)
|
|
.wrap_lines(
|
|
std::env::var(EnvVars::UV_NO_WRAP)
|
|
.map(|_| false)
|
|
.unwrap_or(true),
|
|
)
|
|
.build(),
|
|
)
|
|
}))?;
|
|
|
|
// Don't initialize the rayon threadpool yet, this is too costly when we're doing a noop sync.
|
|
uv_configuration::RAYON_PARALLELISM.store(globals.concurrency.installs, Ordering::Relaxed);
|
|
|
|
debug!("uv {}", uv_cli::version::uv_self_version());
|
|
|
|
// Write out any resolved settings.
|
|
macro_rules! show_settings {
|
|
($arg:expr) => {
|
|
if globals.show_settings {
|
|
writeln!(printer.stdout(), "{:#?}", $arg)?;
|
|
return Ok(ExitStatus::Success);
|
|
}
|
|
};
|
|
($arg:expr, false) => {
|
|
if globals.show_settings {
|
|
writeln!(printer.stdout(), "{:#?}", $arg)?;
|
|
}
|
|
};
|
|
}
|
|
show_settings!(globals, false);
|
|
show_settings!(cache_settings, false);
|
|
|
|
// Configure the cache.
|
|
let cache = Cache::from_settings(cache_settings.no_cache, cache_settings.cache_dir)?;
|
|
|
|
match *cli.command {
|
|
Commands::Help(args) => commands::help(
|
|
args.command.unwrap_or_default().as_slice(),
|
|
printer,
|
|
args.no_pager,
|
|
),
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Compile(args),
|
|
}) => {
|
|
args.compat_args.validate()?;
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipCompileSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.upgrade.clone())),
|
|
);
|
|
|
|
let requirements = args
|
|
.src_file
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let constraints = args
|
|
.constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let overrides = args
|
|
.overrides
|
|
.into_iter()
|
|
.map(RequirementsSource::from_overrides_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let build_constraints = args
|
|
.build_constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let groups = GroupsSpecification {
|
|
root: project_dir.to_path_buf(),
|
|
groups: args.settings.groups,
|
|
};
|
|
|
|
commands::pip_compile(
|
|
&requirements,
|
|
&constraints,
|
|
&overrides,
|
|
&build_constraints,
|
|
args.constraints_from_workspace,
|
|
args.overrides_from_workspace,
|
|
args.build_constraints_from_workspace,
|
|
args.environments,
|
|
args.settings.extras,
|
|
groups,
|
|
args.settings.output_file.as_deref(),
|
|
args.format,
|
|
args.settings.resolution,
|
|
args.settings.prerelease,
|
|
args.settings.fork_strategy,
|
|
args.settings.dependency_mode,
|
|
args.settings.upgrade,
|
|
args.settings.generate_hashes,
|
|
args.settings.no_emit_package,
|
|
args.settings.no_strip_extras,
|
|
args.settings.no_strip_markers,
|
|
!args.settings.no_annotate,
|
|
!args.settings.no_header,
|
|
args.settings.custom_compile_command,
|
|
args.settings.emit_index_url,
|
|
args.settings.emit_find_links,
|
|
args.settings.emit_build_options,
|
|
args.settings.emit_marker_expression,
|
|
args.settings.emit_index_annotation,
|
|
args.settings.index_locations,
|
|
args.settings.index_strategy,
|
|
args.settings.torch_backend,
|
|
args.settings.dependency_metadata,
|
|
args.settings.keyring_provider,
|
|
&globals.network_settings,
|
|
args.settings.config_setting,
|
|
args.settings.config_settings_package,
|
|
args.settings.no_build_isolation,
|
|
args.settings.no_build_isolation_package,
|
|
&args.settings.extra_build_dependencies,
|
|
&args.settings.extra_build_variables,
|
|
args.settings.build_options,
|
|
args.settings.python_version,
|
|
args.settings.python_platform,
|
|
args.settings.universal,
|
|
args.settings.exclude_newer,
|
|
args.settings.sources,
|
|
args.settings.annotation_style,
|
|
args.settings.link_mode,
|
|
args.settings.python,
|
|
args.settings.system,
|
|
globals.python_preference,
|
|
globals.concurrency,
|
|
globals.quiet > 0,
|
|
cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Sync(args),
|
|
}) => {
|
|
args.compat_args.validate()?;
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipSyncSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.upgrade.clone())),
|
|
);
|
|
|
|
let requirements = args
|
|
.src_file
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let constraints = args
|
|
.constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let build_constraints = args
|
|
.build_constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let groups = GroupsSpecification {
|
|
root: project_dir.to_path_buf(),
|
|
groups: args.settings.groups,
|
|
};
|
|
|
|
commands::pip_sync(
|
|
&requirements,
|
|
&constraints,
|
|
&build_constraints,
|
|
&args.settings.extras,
|
|
&groups,
|
|
args.settings.reinstall,
|
|
args.settings.link_mode,
|
|
args.settings.compile_bytecode,
|
|
args.settings.hash_checking,
|
|
args.settings.index_locations,
|
|
args.settings.index_strategy,
|
|
args.settings.torch_backend,
|
|
args.settings.dependency_metadata,
|
|
args.settings.keyring_provider,
|
|
&globals.network_settings,
|
|
args.settings.allow_empty_requirements,
|
|
globals.installer_metadata,
|
|
&args.settings.config_setting,
|
|
&args.settings.config_settings_package,
|
|
args.settings.no_build_isolation,
|
|
args.settings.no_build_isolation_package,
|
|
&args.settings.extra_build_dependencies,
|
|
&args.settings.extra_build_variables,
|
|
args.settings.build_options,
|
|
args.settings.python_version,
|
|
args.settings.python_platform,
|
|
args.settings.strict,
|
|
args.settings.exclude_newer,
|
|
args.settings.python,
|
|
args.settings.system,
|
|
args.settings.break_system_packages,
|
|
args.settings.target,
|
|
args.settings.prefix,
|
|
args.settings.sources,
|
|
globals.python_preference,
|
|
globals.concurrency,
|
|
cache,
|
|
args.dry_run,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Install(args),
|
|
}) => {
|
|
args.compat_args.validate()?;
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let mut args = PipInstallSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
let mut requirements = Vec::with_capacity(
|
|
args.package.len() + args.editables.len() + args.requirements.len(),
|
|
);
|
|
for package in args.package {
|
|
requirements.push(RequirementsSource::from_package_argument(&package)?);
|
|
}
|
|
for package in args.editables {
|
|
requirements.push(RequirementsSource::from_editable(&package)?);
|
|
}
|
|
requirements.extend(
|
|
args.requirements
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
);
|
|
let constraints = args
|
|
.constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let overrides = args
|
|
.overrides
|
|
.into_iter()
|
|
.map(RequirementsSource::from_overrides_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let build_constraints = args
|
|
.build_constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_overrides_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let groups = GroupsSpecification {
|
|
root: project_dir.to_path_buf(),
|
|
groups: args.settings.groups,
|
|
};
|
|
|
|
// Special-case: any source trees specified on the command-line are automatically
|
|
// reinstalled. This matches user expectations: `uv pip install .` should always
|
|
// re-build and re-install the package in the current working directory.
|
|
for requirement in &requirements {
|
|
let requirement = match requirement {
|
|
RequirementsSource::Package(requirement) => requirement,
|
|
RequirementsSource::Editable(requirement) => requirement,
|
|
_ => continue,
|
|
};
|
|
match requirement {
|
|
RequirementsTxtRequirement::Named(requirement) => {
|
|
if let Some(VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref() {
|
|
if let ParsedUrl::Directory(ParsedDirectoryUrl {
|
|
install_path, ..
|
|
}) = &url.parsed_url
|
|
{
|
|
debug!(
|
|
"Marking explicit source tree for reinstall: `{}`",
|
|
install_path.display()
|
|
);
|
|
args.settings.reinstall = args
|
|
.settings
|
|
.reinstall
|
|
.with_package(requirement.name.clone());
|
|
}
|
|
}
|
|
}
|
|
RequirementsTxtRequirement::Unnamed(requirement) => {
|
|
if let ParsedUrl::Directory(ParsedDirectoryUrl { install_path, .. }) =
|
|
&requirement.url.parsed_url
|
|
{
|
|
debug!(
|
|
"Marking explicit source tree for reinstall: `{}`",
|
|
install_path.display()
|
|
);
|
|
args.settings.reinstall =
|
|
args.settings.reinstall.with_path(install_path.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.upgrade.clone())),
|
|
);
|
|
|
|
commands::pip_install(
|
|
&requirements,
|
|
&constraints,
|
|
&overrides,
|
|
&build_constraints,
|
|
args.constraints_from_workspace,
|
|
args.overrides_from_workspace,
|
|
args.build_constraints_from_workspace,
|
|
&args.settings.extras,
|
|
&groups,
|
|
args.settings.resolution,
|
|
args.settings.prerelease,
|
|
args.settings.dependency_mode,
|
|
args.settings.upgrade,
|
|
args.settings.index_locations,
|
|
args.settings.index_strategy,
|
|
args.settings.torch_backend,
|
|
args.settings.dependency_metadata,
|
|
args.settings.keyring_provider,
|
|
&globals.network_settings,
|
|
args.settings.reinstall,
|
|
args.settings.link_mode,
|
|
args.settings.compile_bytecode,
|
|
args.settings.hash_checking,
|
|
globals.installer_metadata,
|
|
&args.settings.config_setting,
|
|
&args.settings.config_settings_package,
|
|
args.settings.no_build_isolation,
|
|
args.settings.no_build_isolation_package,
|
|
&args.settings.extra_build_dependencies,
|
|
&args.settings.extra_build_variables,
|
|
args.settings.build_options,
|
|
args.modifications,
|
|
args.settings.python_version,
|
|
args.settings.python_platform,
|
|
args.settings.strict,
|
|
args.settings.exclude_newer,
|
|
args.settings.sources,
|
|
args.settings.python,
|
|
args.settings.system,
|
|
args.settings.break_system_packages,
|
|
args.settings.target,
|
|
args.settings.prefix,
|
|
globals.python_preference,
|
|
globals.concurrency,
|
|
cache,
|
|
args.dry_run,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Uninstall(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipUninstallSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
let mut sources = Vec::with_capacity(args.package.len() + args.requirements.len());
|
|
for package in args.package {
|
|
sources.push(RequirementsSource::from_package_argument(&package)?);
|
|
}
|
|
sources.extend(
|
|
args.requirements
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
);
|
|
commands::pip_uninstall(
|
|
&sources,
|
|
args.settings.python,
|
|
args.settings.system,
|
|
args.settings.break_system_packages,
|
|
args.settings.target,
|
|
args.settings.prefix,
|
|
cache,
|
|
args.settings.keyring_provider,
|
|
&globals.network_settings,
|
|
args.dry_run,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Freeze(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipFreezeSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::pip_freeze(
|
|
args.exclude_editable,
|
|
args.settings.strict,
|
|
args.settings.python.as_deref(),
|
|
args.settings.system,
|
|
args.paths,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::List(args),
|
|
}) => {
|
|
args.compat_args.validate()?;
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipListSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::pip_list(
|
|
args.editable,
|
|
&args.exclude,
|
|
&args.format,
|
|
args.outdated,
|
|
args.settings.prerelease,
|
|
args.settings.index_locations,
|
|
args.settings.index_strategy,
|
|
args.settings.keyring_provider,
|
|
&globals.network_settings,
|
|
globals.concurrency,
|
|
args.settings.strict,
|
|
args.settings.exclude_newer,
|
|
args.settings.python.as_deref(),
|
|
args.settings.system,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Show(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipShowSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::pip_show(
|
|
args.package,
|
|
args.settings.strict,
|
|
args.settings.python.as_deref(),
|
|
args.settings.system,
|
|
args.files,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Tree(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipTreeSettings::resolve(args, filesystem);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::pip_tree(
|
|
args.show_version_specifiers,
|
|
args.depth,
|
|
&args.prune,
|
|
&args.package,
|
|
args.no_dedupe,
|
|
args.invert,
|
|
args.outdated,
|
|
args.settings.prerelease,
|
|
args.settings.index_locations,
|
|
args.settings.index_strategy,
|
|
args.settings.keyring_provider,
|
|
globals.network_settings,
|
|
globals.concurrency,
|
|
args.settings.strict,
|
|
args.settings.exclude_newer,
|
|
args.settings.python.as_deref(),
|
|
args.settings.system,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Pip(PipNamespace {
|
|
command: PipCommand::Check(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = PipCheckSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::pip_check(
|
|
args.settings.python.as_deref(),
|
|
args.settings.system,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
}
|
|
Commands::Cache(CacheNamespace {
|
|
command: CacheCommand::Clean(args),
|
|
})
|
|
| Commands::Clean(args) => {
|
|
show_settings!(args);
|
|
commands::cache_clean(&args.package, &cache, printer)
|
|
}
|
|
Commands::Cache(CacheNamespace {
|
|
command: CacheCommand::Prune(args),
|
|
}) => {
|
|
show_settings!(args);
|
|
commands::cache_prune(args.ci, &cache, printer)
|
|
}
|
|
Commands::Cache(CacheNamespace {
|
|
command: CacheCommand::Dir,
|
|
}) => {
|
|
commands::cache_dir(&cache);
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
Commands::Build(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::BuildSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.upgrade.clone())),
|
|
);
|
|
|
|
// Resolve the build constraints.
|
|
let build_constraints = args
|
|
.build_constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
commands::build_frontend(
|
|
&project_dir,
|
|
args.src,
|
|
args.package,
|
|
args.all_packages,
|
|
args.out_dir,
|
|
args.sdist,
|
|
args.wheel,
|
|
args.list,
|
|
args.build_logs,
|
|
args.force_pep517,
|
|
build_constraints,
|
|
args.hash_checking,
|
|
args.python,
|
|
args.install_mirrors,
|
|
&args.settings,
|
|
&globals.network_settings,
|
|
cli.top_level.no_config,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.concurrency,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Venv(args) => {
|
|
args.compat_args.validate()?;
|
|
|
|
if args.no_system {
|
|
warn_user_once!(
|
|
"The `--no-system` flag has no effect, a system Python interpreter is always used in `uv venv`"
|
|
);
|
|
}
|
|
|
|
if args.system {
|
|
warn_user_once!(
|
|
"The `--system` flag has no effect, a system Python interpreter is always used in `uv venv`"
|
|
);
|
|
}
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::VenvSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.upgrade.clone())),
|
|
);
|
|
|
|
// Since we use ".venv" as the default name, we use "." as the default prompt.
|
|
let prompt = args.prompt.or_else(|| {
|
|
if args.path.is_none() {
|
|
Some(".".to_string())
|
|
} else {
|
|
None
|
|
}
|
|
});
|
|
|
|
let python_request: Option<PythonRequest> =
|
|
args.settings.python.as_deref().map(PythonRequest::parse);
|
|
|
|
let on_existing = uv_virtualenv::OnExisting::from_args(args.allow_existing, args.clear);
|
|
|
|
commands::venv(
|
|
&project_dir,
|
|
args.path,
|
|
python_request,
|
|
args.settings.install_mirrors,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
args.settings.link_mode,
|
|
&args.settings.index_locations,
|
|
args.settings.index_strategy,
|
|
args.settings.dependency_metadata,
|
|
args.settings.keyring_provider,
|
|
&globals.network_settings,
|
|
uv_virtualenv::Prompt::from_args(prompt),
|
|
args.system_site_packages,
|
|
args.seed,
|
|
on_existing,
|
|
args.settings.exclude_newer,
|
|
globals.concurrency,
|
|
cli.top_level.no_config,
|
|
args.no_project,
|
|
&cache,
|
|
printer,
|
|
args.relocatable,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Project(project) => {
|
|
Box::pin(run_project(
|
|
project,
|
|
&project_dir,
|
|
run_command,
|
|
script,
|
|
globals,
|
|
cli.top_level.no_config,
|
|
cli.top_level.global_args.project.is_some(),
|
|
filesystem,
|
|
cache,
|
|
printer,
|
|
))
|
|
.await
|
|
}
|
|
#[cfg(feature = "self-update")]
|
|
Commands::Self_(SelfNamespace {
|
|
command:
|
|
SelfCommand::Update(SelfUpdateArgs {
|
|
target_version,
|
|
token,
|
|
dry_run,
|
|
}),
|
|
}) => {
|
|
commands::self_update(
|
|
target_version,
|
|
token,
|
|
dry_run,
|
|
printer,
|
|
globals.network_settings,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Self_(SelfNamespace {
|
|
command:
|
|
SelfCommand::Version {
|
|
short,
|
|
output_format,
|
|
},
|
|
}) => {
|
|
commands::self_version(short, output_format, printer)?;
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
#[cfg(not(feature = "self-update"))]
|
|
Commands::Self_(_) => {
|
|
anyhow::bail!(
|
|
"uv was installed through an external package manager, and self-update \
|
|
is not available. Please use your package manager to update uv."
|
|
);
|
|
}
|
|
Commands::GenerateShellCompletion(args) => {
|
|
args.shell.generate(&mut Cli::command(), &mut stdout());
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: run_variant @ (ToolCommand::Uvx(_) | ToolCommand::Run(_)),
|
|
}) => {
|
|
let (args, invocation_source) = match run_variant {
|
|
ToolCommand::Uvx(args) => (args.tool_run, ToolRunCommand::Uvx),
|
|
ToolCommand::Run(args) => (args, ToolRunCommand::ToolRun),
|
|
// OK guarded by the outer match statement
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
if let Some(shell) = args.generate_shell_completion {
|
|
// uvx: combine `uv tool uvx` with the top-level arguments
|
|
let mut uvx = Cli::command()
|
|
.find_subcommand("tool")
|
|
.unwrap()
|
|
.find_subcommand("uvx")
|
|
.unwrap()
|
|
.clone()
|
|
// Avoid duplicating the `--help` and `--version` flags from the top-level
|
|
// arguments.
|
|
.disable_help_flag(true)
|
|
.disable_version_flag(true);
|
|
|
|
// Copy the top-level arguments into the `uvx` command, as in `Args::augment_args`,
|
|
// but expanded to skip collisions.
|
|
for arg in TopLevelArgs::command().get_arguments() {
|
|
if arg.get_id() != "isolated" && arg.get_id() != "version" {
|
|
uvx = uvx.arg(arg);
|
|
}
|
|
}
|
|
shell.generate(&mut uvx, &mut stdout());
|
|
return Ok(ExitStatus::Success);
|
|
}
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ToolRunSettings::resolve(args, filesystem, invocation_source);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
let requirements = {
|
|
let mut requirements = Vec::with_capacity(
|
|
args.with.len() + args.with_editable.len() + args.with_requirements.len(),
|
|
);
|
|
for package in args.with {
|
|
requirements.push(RequirementsSource::from_with_package_argument(&package)?);
|
|
}
|
|
for package in args.with_editable {
|
|
requirements.push(RequirementsSource::from_editable(&package)?);
|
|
}
|
|
requirements.extend(
|
|
args.with_requirements
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
);
|
|
requirements
|
|
};
|
|
let constraints = args
|
|
.constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let overrides = args
|
|
.overrides
|
|
.into_iter()
|
|
.map(RequirementsSource::from_overrides_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
let build_constraints = args
|
|
.build_constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
Box::pin(commands::tool_run(
|
|
args.command,
|
|
args.from,
|
|
&requirements,
|
|
&constraints,
|
|
&overrides,
|
|
&build_constraints,
|
|
args.show_resolution || globals.verbose > 0,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.options,
|
|
args.settings,
|
|
globals.network_settings,
|
|
invocation_source,
|
|
args.isolated,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
cache,
|
|
printer,
|
|
args.env_file,
|
|
args.no_env_file,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::Install(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ToolInstallSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
let mut entrypoints = Vec::with_capacity(args.with_executables_from.len());
|
|
let mut requirements = Vec::with_capacity(
|
|
args.with.len()
|
|
+ args.with_editable.len()
|
|
+ args.with_requirements.len()
|
|
+ args.with_executables_from.len(),
|
|
);
|
|
for pkg in args.with {
|
|
requirements.push(RequirementsSource::from_with_package_argument(&pkg)?);
|
|
}
|
|
for pkg in args.with_editable {
|
|
requirements.push(RequirementsSource::from_editable(&pkg)?);
|
|
}
|
|
for path in args.with_requirements {
|
|
requirements.push(RequirementsSource::from_requirements_file(path)?);
|
|
}
|
|
for pkg in &args.with_executables_from {
|
|
let source = RequirementsSource::from_with_package_argument(pkg)?;
|
|
let RequirementsSource::Package(RequirementsTxtRequirement::Named(requirement)) =
|
|
&source
|
|
else {
|
|
bail!(
|
|
"Expected a named package for `--with-executables-from`, but got: {}",
|
|
source.to_string().cyan()
|
|
)
|
|
};
|
|
entrypoints.push(requirement.name.clone());
|
|
requirements.push(source);
|
|
}
|
|
|
|
let constraints = args
|
|
.constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let overrides = args
|
|
.overrides
|
|
.into_iter()
|
|
.map(RequirementsSource::from_overrides_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let build_constraints = args
|
|
.build_constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
Box::pin(commands::tool_install(
|
|
args.package,
|
|
args.editable,
|
|
args.from,
|
|
&requirements,
|
|
&constraints,
|
|
&overrides,
|
|
&build_constraints,
|
|
&entrypoints,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.force,
|
|
args.options,
|
|
args.settings,
|
|
globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::List(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ToolListSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::tool_list(
|
|
args.show_paths,
|
|
args.show_version_specifiers,
|
|
args.show_with,
|
|
args.show_extras,
|
|
&cache,
|
|
printer,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::Upgrade(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ToolUpgradeSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(Refresh::All(Timestamp::now()));
|
|
|
|
Box::pin(commands::tool_upgrade(
|
|
args.names,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.args,
|
|
args.filesystem,
|
|
globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::Uninstall(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ToolUninstallSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
commands::tool_uninstall(args.name, printer).await
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::UpdateShell,
|
|
}) => {
|
|
commands::tool_update_shell(printer).await?;
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
Commands::Tool(ToolNamespace {
|
|
command: ToolCommand::Dir(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ToolDirSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
commands::tool_dir(args.bin, globals.preview)?;
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::List(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonListSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::python_list(
|
|
args.request,
|
|
args.kinds,
|
|
args.all_versions,
|
|
args.all_platforms,
|
|
args.all_arches,
|
|
args.show_urls,
|
|
args.output_format,
|
|
args.python_downloads_json_url,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::Install(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonInstallSettings::resolve(args, filesystem, environment);
|
|
show_settings!(args);
|
|
// TODO(john): If we later want to support `--upgrade`, we need to replace this.
|
|
let upgrade = false;
|
|
|
|
commands::python_install(
|
|
&project_dir,
|
|
args.install_dir,
|
|
args.targets,
|
|
args.reinstall,
|
|
upgrade,
|
|
args.bin,
|
|
args.registry,
|
|
args.force,
|
|
args.python_install_mirror,
|
|
args.pypy_install_mirror,
|
|
args.python_downloads_json_url,
|
|
globals.network_settings,
|
|
args.default,
|
|
globals.python_downloads,
|
|
cli.top_level.no_config,
|
|
globals.preview,
|
|
printer,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::Upgrade(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonUpgradeSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
let upgrade = true;
|
|
|
|
commands::python_install(
|
|
&project_dir,
|
|
args.install_dir,
|
|
args.targets,
|
|
args.reinstall,
|
|
upgrade,
|
|
args.bin,
|
|
args.registry,
|
|
args.force,
|
|
args.python_install_mirror,
|
|
args.pypy_install_mirror,
|
|
args.python_downloads_json_url,
|
|
globals.network_settings,
|
|
args.default,
|
|
globals.python_downloads,
|
|
cli.top_level.no_config,
|
|
globals.preview,
|
|
printer,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::Uninstall(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonUninstallSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
commands::python_uninstall(
|
|
args.install_dir,
|
|
args.targets,
|
|
args.all,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::Find(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonFindSettings::resolve(args, filesystem);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
if let Some(Pep723Item::Script(script)) = script {
|
|
commands::python_find_script(
|
|
(&script).into(),
|
|
args.show_version,
|
|
&globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
cli.top_level.no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
} else {
|
|
commands::python_find(
|
|
&project_dir,
|
|
args.request,
|
|
args.show_version,
|
|
args.no_project,
|
|
cli.top_level.no_config,
|
|
args.system,
|
|
globals.python_preference,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::Pin(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonPinSettings::resolve(args, filesystem);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::python_pin(
|
|
&project_dir,
|
|
args.request,
|
|
args.resolved,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
args.no_project,
|
|
args.global,
|
|
args.rm,
|
|
args.install_mirrors,
|
|
globals.network_settings,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::Dir(args),
|
|
}) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::PythonDirSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
commands::python_dir(args.bin)?;
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
Commands::Python(PythonNamespace {
|
|
command: PythonCommand::UpdateShell,
|
|
}) => {
|
|
commands::python_update_shell(printer).await?;
|
|
Ok(ExitStatus::Success)
|
|
}
|
|
Commands::Publish(args) => {
|
|
show_settings!(args);
|
|
|
|
if args.skip_existing {
|
|
bail!(
|
|
"`uv publish` does not support `--skip-existing` because there is not a \
|
|
reliable way to identify when an upload fails due to an existing \
|
|
distribution. Instead, use `--check-url` to provide the URL to the simple \
|
|
API for your index. uv will check the index for existing distributions before \
|
|
attempting uploads."
|
|
);
|
|
}
|
|
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let PublishSettings {
|
|
files,
|
|
username,
|
|
password,
|
|
publish_url,
|
|
trusted_publishing,
|
|
keyring_provider,
|
|
check_url,
|
|
index,
|
|
index_locations,
|
|
} = PublishSettings::resolve(args, filesystem);
|
|
|
|
let (publish_url, check_url) = if let Some(index_name) = index {
|
|
debug!("Publishing with index {index_name}");
|
|
let index = index_locations
|
|
.simple_indexes()
|
|
.find(|index| {
|
|
index
|
|
.name
|
|
.as_ref()
|
|
.is_some_and(|name| name.as_ref() == index_name)
|
|
})
|
|
.with_context(|| {
|
|
let mut index_names: Vec<String> = index_locations
|
|
.simple_indexes()
|
|
.filter_map(|index| index.name.as_ref())
|
|
.map(ToString::to_string)
|
|
.collect();
|
|
index_names.sort();
|
|
if index_names.is_empty() {
|
|
format!("No indexes were found, can't use index: `{index_name}`")
|
|
} else {
|
|
let index_names = index_names.join("`, `");
|
|
format!(
|
|
"Index not found: `{index_name}`. Found indexes: `{index_names}`"
|
|
)
|
|
}
|
|
})?;
|
|
let publish_url = index
|
|
.publish_url
|
|
.clone()
|
|
.with_context(|| format!("Index is missing a publish URL: `{index_name}`"))?;
|
|
let check_url = index.url.clone();
|
|
(publish_url, Some(check_url))
|
|
} else {
|
|
(publish_url, check_url)
|
|
};
|
|
|
|
commands::publish(
|
|
files,
|
|
publish_url,
|
|
trusted_publishing,
|
|
keyring_provider,
|
|
&globals.network_settings,
|
|
username,
|
|
password,
|
|
check_url,
|
|
&cache,
|
|
printer,
|
|
)
|
|
.await
|
|
}
|
|
Commands::BuildBackend { command } => spawn_blocking(move || match command {
|
|
BuildBackendCommand::BuildSdist { sdist_directory } => {
|
|
commands::build_backend::build_sdist(&sdist_directory)
|
|
}
|
|
BuildBackendCommand::BuildWheel {
|
|
wheel_directory,
|
|
metadata_directory,
|
|
} => commands::build_backend::build_wheel(
|
|
&wheel_directory,
|
|
metadata_directory.as_deref(),
|
|
),
|
|
BuildBackendCommand::BuildEditable {
|
|
wheel_directory,
|
|
metadata_directory,
|
|
} => commands::build_backend::build_editable(
|
|
&wheel_directory,
|
|
metadata_directory.as_deref(),
|
|
),
|
|
BuildBackendCommand::GetRequiresForBuildSdist => {
|
|
commands::build_backend::get_requires_for_build_sdist()
|
|
}
|
|
BuildBackendCommand::GetRequiresForBuildWheel => {
|
|
commands::build_backend::get_requires_for_build_wheel()
|
|
}
|
|
BuildBackendCommand::PrepareMetadataForBuildWheel { wheel_directory } => {
|
|
commands::build_backend::prepare_metadata_for_build_wheel(&wheel_directory)
|
|
}
|
|
BuildBackendCommand::GetRequiresForBuildEditable => {
|
|
commands::build_backend::get_requires_for_build_editable()
|
|
}
|
|
BuildBackendCommand::PrepareMetadataForBuildEditable { wheel_directory } => {
|
|
commands::build_backend::prepare_metadata_for_build_editable(&wheel_directory)
|
|
}
|
|
})
|
|
.await
|
|
.expect("tokio threadpool exited unexpectedly"),
|
|
}
|
|
}
|
|
|
|
/// Run a [`ProjectCommand`].
|
|
async fn run_project(
|
|
project_command: Box<ProjectCommand>,
|
|
project_dir: &Path,
|
|
command: Option<RunCommand>,
|
|
script: Option<Pep723Item>,
|
|
globals: GlobalSettings,
|
|
// TODO(zanieb): Determine a better story for passing `no_config` in here
|
|
no_config: bool,
|
|
explicit_project: bool,
|
|
filesystem: Option<FilesystemOptions>,
|
|
cache: Cache,
|
|
printer: Printer,
|
|
) -> Result<ExitStatus> {
|
|
// Write out any resolved settings.
|
|
macro_rules! show_settings {
|
|
($arg:expr) => {
|
|
if globals.show_settings {
|
|
writeln!(printer.stdout(), "{:#?}", $arg)?;
|
|
return Ok(ExitStatus::Success);
|
|
}
|
|
};
|
|
}
|
|
|
|
match *project_command {
|
|
ProjectCommand::Init(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::InitSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
commands::init(
|
|
project_dir,
|
|
args.path,
|
|
args.name,
|
|
args.package,
|
|
args.kind,
|
|
args.bare,
|
|
args.description,
|
|
args.no_description,
|
|
args.vcs,
|
|
args.build_backend,
|
|
args.no_readme,
|
|
args.author_from,
|
|
args.pin_python,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.no_workspace,
|
|
&globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.await
|
|
}
|
|
ProjectCommand::Run(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::RunSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
let mut requirements = Vec::with_capacity(
|
|
args.with.len() + args.with_editable.len() + args.with_requirements.len(),
|
|
);
|
|
for package in args.with {
|
|
requirements.push(RequirementsSource::from_with_package_argument(&package)?);
|
|
}
|
|
for package in args.with_editable {
|
|
requirements.push(RequirementsSource::from_editable(&package)?);
|
|
}
|
|
requirements.extend(
|
|
args.with_requirements
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
);
|
|
|
|
Box::pin(commands::run(
|
|
project_dir,
|
|
script,
|
|
command,
|
|
requirements,
|
|
args.show_resolution || globals.verbose > 0,
|
|
args.locked,
|
|
args.frozen,
|
|
args.active,
|
|
args.no_sync,
|
|
args.isolated,
|
|
args.all_packages,
|
|
args.package,
|
|
args.no_project,
|
|
no_config,
|
|
args.extras,
|
|
args.groups,
|
|
args.editable,
|
|
args.modifications,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.settings,
|
|
globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
&cache,
|
|
printer,
|
|
args.env_file,
|
|
args.no_env_file,
|
|
globals.preview,
|
|
args.max_recursion_depth,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Sync(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::SyncSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
// Unwrap the script.
|
|
let script = script.map(|script| match script {
|
|
Pep723Item::Script(script) => script,
|
|
Pep723Item::Stdin(..) => unreachable!("`uv lock` does not support stdin"),
|
|
Pep723Item::Remote(..) => unreachable!("`uv lock` does not support remote files"),
|
|
});
|
|
|
|
Box::pin(commands::sync(
|
|
project_dir,
|
|
args.locked,
|
|
args.frozen,
|
|
args.dry_run,
|
|
args.active,
|
|
args.all_packages,
|
|
args.package,
|
|
args.extras,
|
|
args.groups,
|
|
args.editable,
|
|
args.install_options,
|
|
args.modifications,
|
|
args.python,
|
|
args.python_platform,
|
|
args.install_mirrors,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
args.settings,
|
|
globals.network_settings,
|
|
script,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
args.output_format,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Lock(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::LockSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.upgrade.clone())),
|
|
);
|
|
|
|
// If the script already exists, use it; otherwise, propagate the file path and we'll
|
|
// initialize it later on.
|
|
let script = script
|
|
.map(|script| match script {
|
|
Pep723Item::Script(script) => script,
|
|
Pep723Item::Stdin(..) => unreachable!("`uv add` does not support stdin"),
|
|
Pep723Item::Remote(..) => {
|
|
unreachable!("`uv add` does not support remote files")
|
|
}
|
|
})
|
|
.map(ScriptPath::Script)
|
|
.or(args.script.map(ScriptPath::Path));
|
|
|
|
Box::pin(commands::lock(
|
|
project_dir,
|
|
args.locked,
|
|
args.frozen,
|
|
args.dry_run,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.settings,
|
|
globals.network_settings,
|
|
script,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.concurrency,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Add(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let mut args = settings::AddSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// If the script already exists, use it; otherwise, propagate the file path and we'll
|
|
// initialize it later on.
|
|
let script = script
|
|
.map(|script| match script {
|
|
Pep723Item::Script(script) => script,
|
|
Pep723Item::Stdin(..) => unreachable!("`uv add` does not support stdin"),
|
|
Pep723Item::Remote(..) => {
|
|
unreachable!("`uv add` does not support remote files")
|
|
}
|
|
})
|
|
.map(ScriptPath::Script)
|
|
.or(args.script.map(ScriptPath::Path));
|
|
|
|
let requirements = args
|
|
.packages
|
|
.iter()
|
|
.map(String::as_str)
|
|
.map(RequirementsSource::from_package_argument)
|
|
.chain(
|
|
args.requirements
|
|
.into_iter()
|
|
.map(RequirementsSource::from_requirements_file),
|
|
)
|
|
.collect::<Result<Vec<_>>>()?;
|
|
|
|
// Special-case: any local source trees specified on the command-line are automatically
|
|
// reinstalled.
|
|
for requirement in &requirements {
|
|
let requirement = match requirement {
|
|
RequirementsSource::Package(requirement) => requirement,
|
|
RequirementsSource::Editable(requirement) => requirement,
|
|
_ => continue,
|
|
};
|
|
match requirement {
|
|
RequirementsTxtRequirement::Named(requirement) => {
|
|
if let Some(VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref() {
|
|
if let ParsedUrl::Directory(ParsedDirectoryUrl {
|
|
install_path, ..
|
|
}) = &url.parsed_url
|
|
{
|
|
debug!(
|
|
"Marking explicit source tree for reinstall: `{}`",
|
|
install_path.display()
|
|
);
|
|
args.settings.reinstall = args
|
|
.settings
|
|
.reinstall
|
|
.with_package(requirement.name.clone());
|
|
}
|
|
}
|
|
}
|
|
RequirementsTxtRequirement::Unnamed(requirement) => {
|
|
if let ParsedUrl::Directory(ParsedDirectoryUrl { install_path, .. }) =
|
|
&requirement.url.parsed_url
|
|
{
|
|
debug!(
|
|
"Marking explicit source tree for reinstall: `{}`",
|
|
install_path.display()
|
|
);
|
|
args.settings.reinstall =
|
|
args.settings.reinstall.with_path(install_path.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
let constraints = args
|
|
.constraints
|
|
.into_iter()
|
|
.map(RequirementsSource::from_constraints_txt)
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
Box::pin(commands::add(
|
|
project_dir,
|
|
args.locked,
|
|
args.frozen,
|
|
args.active,
|
|
args.no_sync,
|
|
args.no_install_project,
|
|
args.no_install_workspace,
|
|
requirements,
|
|
constraints,
|
|
args.marker,
|
|
args.editable,
|
|
args.dependency_type,
|
|
args.raw,
|
|
args.bounds,
|
|
args.indexes,
|
|
args.rev,
|
|
args.tag,
|
|
args.branch,
|
|
args.extras,
|
|
args.package,
|
|
args.python,
|
|
args.workspace,
|
|
args.install_mirrors,
|
|
args.settings,
|
|
globals.network_settings,
|
|
script,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Remove(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::RemoveSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
// Unwrap the script.
|
|
let script = script.map(|script| match script {
|
|
Pep723Item::Script(script) => script,
|
|
Pep723Item::Stdin(..) => unreachable!("`uv remove` does not support stdin"),
|
|
Pep723Item::Remote(..) => unreachable!("`uv remove` does not support remote files"),
|
|
});
|
|
|
|
Box::pin(commands::remove(
|
|
project_dir,
|
|
args.locked,
|
|
args.frozen,
|
|
args.active,
|
|
args.no_sync,
|
|
args.packages,
|
|
args.dependency_type,
|
|
args.package,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.settings,
|
|
globals.network_settings,
|
|
script,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Version(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::VersionSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?.with_refresh(
|
|
args.refresh
|
|
.combine(Refresh::from(args.settings.reinstall.clone()))
|
|
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
|
|
);
|
|
|
|
Box::pin(commands::project_version(
|
|
args.value,
|
|
args.bump,
|
|
args.short,
|
|
args.output_format,
|
|
project_dir,
|
|
args.package,
|
|
explicit_project,
|
|
args.dry_run,
|
|
args.locked,
|
|
args.frozen,
|
|
args.active,
|
|
args.no_sync,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.settings,
|
|
globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.installer_metadata,
|
|
globals.concurrency,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Tree(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::TreeSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
// Unwrap the script.
|
|
let script = script.map(|script| match script {
|
|
Pep723Item::Script(script) => script,
|
|
Pep723Item::Stdin(..) => unreachable!("`uv tree` does not support stdin"),
|
|
Pep723Item::Remote(..) => unreachable!("`uv tree` does not support remote files"),
|
|
});
|
|
|
|
Box::pin(commands::tree(
|
|
project_dir,
|
|
args.groups,
|
|
args.locked,
|
|
args.frozen,
|
|
args.universal,
|
|
args.depth,
|
|
args.prune,
|
|
args.package,
|
|
args.no_dedupe,
|
|
args.invert,
|
|
args.outdated,
|
|
args.python_version,
|
|
args.python_platform,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.resolver,
|
|
&globals.network_settings,
|
|
script,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.concurrency,
|
|
no_config,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
))
|
|
.await
|
|
}
|
|
ProjectCommand::Export(args) => {
|
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
|
let args = settings::ExportSettings::resolve(args, filesystem);
|
|
show_settings!(args);
|
|
|
|
// Initialize the cache.
|
|
let cache = cache.init()?;
|
|
|
|
// Unwrap the script.
|
|
let script = script.map(|script| match script {
|
|
Pep723Item::Script(script) => script,
|
|
Pep723Item::Stdin(..) => unreachable!("`uv export` does not support stdin"),
|
|
Pep723Item::Remote(..) => unreachable!("`uv export` does not support remote files"),
|
|
});
|
|
|
|
commands::export(
|
|
project_dir,
|
|
args.format,
|
|
args.all_packages,
|
|
args.package,
|
|
args.prune,
|
|
args.hashes,
|
|
args.install_options,
|
|
args.output_file,
|
|
args.extras,
|
|
args.groups,
|
|
args.editable,
|
|
args.locked,
|
|
args.frozen,
|
|
args.include_annotations,
|
|
args.include_header,
|
|
script,
|
|
args.python,
|
|
args.install_mirrors,
|
|
args.settings,
|
|
globals.network_settings,
|
|
globals.python_preference,
|
|
globals.python_downloads,
|
|
globals.concurrency,
|
|
no_config,
|
|
globals.quiet > 0,
|
|
&cache,
|
|
printer,
|
|
globals.preview,
|
|
)
|
|
.boxed_local()
|
|
.await
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The main entry point for a uv invocation.
|
|
///
|
|
/// # Usage
|
|
///
|
|
/// 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
|
|
/// point is called multiple times in a single process.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// It is only safe to call this routine when it is known that multiple threads are not running.
|
|
#[allow(unsafe_code)]
|
|
pub unsafe fn main<I, T>(args: I) -> ExitCode
|
|
where
|
|
I: IntoIterator<Item = T>,
|
|
T: Into<OsString> + Clone,
|
|
{
|
|
#[cfg(windows)]
|
|
windows_exception::setup();
|
|
|
|
// Set the `UV` variable to the current executable so it is implicitly propagated to all child
|
|
// processes, e.g., in `uv run`.
|
|
if let Ok(current_exe) = std::env::current_exe() {
|
|
// SAFETY: The proof obligation must be satisfied by the caller.
|
|
unsafe {
|
|
// This will become unsafe in Rust 2024
|
|
// See https://doc.rust-lang.org/std/env/fn.set_var.html#safety
|
|
std::env::set_var(EnvVars::UV, current_exe);
|
|
}
|
|
}
|
|
|
|
// `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" => {
|
|
err.insert(
|
|
ContextKind::SuggestedSubcommand,
|
|
ContextValue::String("uv pip compile".to_string()),
|
|
);
|
|
}
|
|
"install" => {
|
|
err.insert(
|
|
ContextKind::SuggestedSubcommand,
|
|
ContextValue::String("uv pip install".to_string()),
|
|
);
|
|
}
|
|
"uninstall" => {
|
|
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()),
|
|
);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
err.exit()
|
|
}
|
|
};
|
|
|
|
// See `min_stack_size` doc comment about `main2`
|
|
let min_stack_size = min_stack_size();
|
|
let main2 = move || {
|
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.thread_stack_size(min_stack_size)
|
|
.build()
|
|
.expect("Failed building the Runtime");
|
|
// Box the large main future to avoid stack overflows.
|
|
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
|
|
// turned out to be unnecessary. Waiting for those to complete can cause
|
|
// the CLI to hang before exiting.
|
|
runtime.shutdown_background();
|
|
result
|
|
};
|
|
let result = std::thread::Builder::new()
|
|
.name("main2".to_owned())
|
|
.stack_size(min_stack_size)
|
|
.spawn(main2)
|
|
.expect("Tokio executor failed, was there a panic?")
|
|
.join()
|
|
.expect("Tokio executor failed, was there a panic?");
|
|
|
|
match result {
|
|
Ok(code) => code.into(),
|
|
Err(err) => {
|
|
trace!("Error trace: {err:?}");
|
|
let mut causes = err.chain();
|
|
eprintln!(
|
|
"{}: {}",
|
|
"error".red().bold(),
|
|
causes.next().unwrap().to_string().trim()
|
|
);
|
|
for err in causes {
|
|
eprintln!(" {}: {}", "Caused by".red().bold(), err.to_string().trim());
|
|
}
|
|
ExitStatus::Error.into()
|
|
}
|
|
}
|
|
}
|