use std::borrow::Cow;
use std::collections::BTreeMap;
use std::ffi::OsString;
use std::fmt::Write;
use std::io::stdout;
use std::path::Path;
use std::process::ExitCode;
use std::str::FromStr;
use std::sync::atomic::Ordering;

use anstream::eprintln;
use anyhow::{bail, Context, Result};
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};
use uv_cache::{Cache, Refresh};
use uv_cache_info::Timestamp;
use uv_cli::{
    compat::CompatArgs, BuildBackendCommand, CacheCommand, CacheNamespace, Cli, Commands,
    PipCommand, PipNamespace, ProjectCommand,
};
use uv_cli::{PythonCommand, PythonNamespace, ToolCommand, ToolNamespace, TopLevelArgs};
#[cfg(feature = "self-update")]
use uv_cli::{SelfCommand, SelfNamespace, SelfUpdateArgs};
use uv_fs::{Simplified, CWD};
use uv_pep508::VersionOrUrl;
use uv_pypi_types::{ParsedDirectoryUrl, ParsedUrl};
use uv_requirements::RequirementsSource;
use uv_requirements_txt::RequirementsTxtRequirement;
use uv_scripts::{Pep723Error, Pep723Item, Pep723ItemRef, Pep723Metadata, Pep723Script};
use uv_settings::{Combine, 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 commands;
pub(crate) mod logging;
pub(crate) mod printer;
pub(crate) mod settings;

#[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);

    // 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) {
            return Err(anyhow::anyhow!(
                "Required uv version `{required_version}` does not match the running version `{package_version}`",
            ));
        }
    }

    // Configure the `tracing` crate, which controls internal logging.
    #[cfg(feature = "tracing-durations-export")]
    let (duration_layer, _duration_guard) = logging::setup_duration()?;
    #[cfg(not(feature = "tracing-durations-export"))]
    let duration_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,
        },
        duration_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::SeqCst);

    debug!("uv {}", uv_cli::version::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)?;

    let result = 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::<Vec<_>>();
            let constraints = args
                .constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();
            let overrides = args
                .overrides
                .into_iter()
                .map(RequirementsSource::from_overrides_txt)
                .collect::<Vec<_>>();
            let build_constraints = args
                .build_constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();

            let mut groups = BTreeMap::new();
            for group in args.settings.groups {
                // If there's no path provided, expect a pyproject.toml in the project-dir
                // (Which is typically the current working directory, matching pip's behaviour)
                let pyproject_path = group
                    .path
                    .clone()
                    .unwrap_or_else(|| project_dir.join("pyproject.toml"));
                groups
                    .entry(pyproject_path)
                    .or_insert_with(Vec::new)
                    .push(group.name.clone());
            }

            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.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.no_build_isolation,
                args.settings.no_build_isolation_package,
                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::<Vec<_>>();
            let constraints = args
                .constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();
            let build_constraints = args
                .build_constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();

            commands::pip_sync(
                &requirements,
                &constraints,
                &build_constraints,
                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.no_build_isolation,
                args.settings.no_build_isolation_package,
                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),
            );
            let constraints = args
                .constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();
            let overrides = args
                .overrides
                .into_iter()
                .map(RequirementsSource::from_overrides_txt)
                .collect::<Vec<_>>();
            let build_constraints = args
                .build_constraints
                .into_iter()
                .map(RequirementsSource::from_overrides_txt)
                .collect::<Vec<_>>();

            let mut groups = BTreeMap::new();
            for group in args.settings.groups {
                // If there's no path provided, expect a pyproject.toml in the project-dir
                // (Which is typically the current working directory, matching pip's behaviour)
                let pyproject_path = group
                    .path
                    .clone()
                    .unwrap_or_else(|| project_dir.join("pyproject.toml"));
                groups
                    .entry(pyproject_path)
                    .or_insert_with(Vec::new)
                    .push(group.name.clone());
            }

            // 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.no_build_isolation,
                args.settings.no_build_isolation_package,
                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),
            );
            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,
            )
            .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,
            )
        }
        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,
            )
            .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,
            )
        }
        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,
            )
            .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,
            )
        }
        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::<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
                }
            });

            commands::venv(
                &project_dir,
                args.path,
                args.settings.python.as_deref(),
                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,
                args.allow_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,
                filesystem,
                cache,
                printer,
            ))
            .await
        }
        #[cfg(feature = "self-update")]
        Commands::Self_(SelfNamespace {
            command:
                SelfCommand::Update(SelfUpdateArgs {
                    target_version,
                    token,
                }),
        }) => commands::self_update(target_version, token, printer).await,
        #[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::Version { output_format } => {
            commands::version(output_format, &mut stdout())?;
            Ok(ExitStatus::Success)
        }
        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, 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)
                    .version(env!("CARGO_PKG_VERSION"));

                // Copy the top-level arguments into the `uvx` command. (Like `Args::augment_args`, but
                // expanded to skip collisions.)
                for arg in TopLevelArgs::command().get_arguments() {
                    if arg.get_id() != "isolated" {
                        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),
                );
                requirements
            };
            let constraints = args
                .constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();
            let overrides = args
                .overrides
                .into_iter()
                .map(RequirementsSource::from_overrides_txt)
                .collect::<Vec<_>>();

            Box::pin(commands::tool_run(
                args.command,
                args.from,
                &requirements,
                &constraints,
                &overrides,
                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 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),
            );

            let constraints = args
                .constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();
            let overrides = args
                .overrides
                .into_iter()
                .map(RequirementsSource::from_overrides_txt)
                .collect::<Vec<_>>();

            Box::pin(commands::tool_install(
                args.package,
                args.editable,
                args.from,
                &requirements,
                &constraints,
                &overrides,
                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,
                &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,
                globals.python_preference,
                globals.python_downloads,
                &cache,
                printer,
            )
            .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);
            show_settings!(args);

            commands::python_install(
                &project_dir,
                args.install_dir,
                args.targets,
                args.reinstall,
                args.force,
                args.python_install_mirror,
                args.pypy_install_mirror,
                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(
                    Pep723ItemRef::Script(&script),
                    &globals.network_settings,
                    globals.python_preference,
                    globals.python_downloads,
                    cli.top_level.no_config,
                    &cache,
                    printer,
                )
                .await
            } else {
                commands::python_find(
                    &project_dir,
                    args.request,
                    args.no_project,
                    cli.top_level.no_config,
                    args.system,
                    globals.python_preference,
                    &cache,
                )
                .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,
                args.no_project,
                args.global,
                &cache,
                printer,
            )
            .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::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"),
    };
    result
}

/// 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,
    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),
            );

            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.dev,
                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.dev,
                args.editable,
                args.install_options,
                args.modifications,
                args.python,
                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,
            ))
            .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 args = settings::AddSettings::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())),
            );

            // 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)
                        .map(Ok),
                )
                .collect::<Result<Vec<_>>>()?;
            let constraints = args
                .constraints
                .into_iter()
                .map(RequirementsSource::from_constraints_txt)
                .collect::<Vec<_>>();

            Box::pin(commands::add(
                project_dir,
                args.locked,
                args.frozen,
                args.active,
                args.no_sync,
                requirements,
                constraints,
                args.marker,
                args.editable,
                args.dependency_type,
                args.raw_sources,
                args.indexes,
                args.rev,
                args.tag,
                args.branch,
                args.extras,
                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::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::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.dev,
                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.dev,
                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,
{
    // 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()
        }
    };

    // Running out of stack has been an issue for us. We box types and futures in various places
    // to mitigate this, with this being an especially important case.
    //
    // Non-main threads should all have 2MB, as Rust forces platform consistency there,
    // but that can be overridden with the RUST_MIN_STACK environment variable if you need more.
    //
    // Main thread stack-size is the real issue. There's BIG variety here across platforms
    // and it's harder to control (which is why Rust doesn't by default). Notably
    // on macOS and Linux you will typically get 8MB main thread, while on Windows you will
    // typically get 1MB, which is *tiny*:
    // https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-170
    //
    // To normalize this we just spawn a new thread called main2 with a size we can set
    // ourselves. 2MB is typically too small (especially for our debug builds), while 4MB
    // seems fine. Also we still try to respect RUST_MIN_STACK if it's set, in case useful,
    // but don't let it ask for a smaller stack to avoid messy misconfiguration since we
    // know we use quite a bit of main stack space.
    let main_stack_size = std::env::var(EnvVars::RUST_MIN_STACK)
        .ok()
        .and_then(|var| var.parse::<usize>().ok())
        .unwrap_or(0)
        .max(4 * 1024 * 1024);

    let main2 = move || {
        let runtime = tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .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(main_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) => {
            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()
        }
    }
}
