mirror of https://github.com/astral-sh/uv
Merge workspace settings with CLI settings (#3045)
## Summary This PR adds the structs and logic necessary to respect settings from the workspace. It's a ton of code, but it's mostly mechanical. And, believe it or not, I pulled out a few refactors in advance to trim down the code and complexity. The highlights are: - All CLI arguments are now `Option`, so that we can detect whether they were provided (i.e., we can't let Clap fill in the defaults). - We now have a `*Settings` struct for each command, which merges the CLI and workspace options (e.g., `PipCompileSettings`). I've only implemented `PipCompileSettings` for now. If approved, I'll implement the others prior to merging, but it's very mechanical and I both didn't want to do the conversion prior to receiving feedback _and_ realized it would make the PR harder to review.
This commit is contained in:
parent
dcc2c6865c
commit
e5d4ea55ca
|
|
@ -16,7 +16,7 @@ pub struct CacheArgs {
|
|||
alias = "no-cache-dir",
|
||||
env = "UV_NO_CACHE"
|
||||
)]
|
||||
no_cache: bool,
|
||||
pub no_cache: Option<bool>,
|
||||
|
||||
/// Path to the cache directory.
|
||||
///
|
||||
|
|
@ -24,7 +24,31 @@ pub struct CacheArgs {
|
|||
/// Linux, and `$HOME/.cache/<project_path> {FOLDERID_LocalAppData}/<project_path>/cache/uv`
|
||||
/// on Windows.
|
||||
#[arg(global = true, long, env = "UV_CACHE_DIR")]
|
||||
pub cache_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
/// Prefer, in order:
|
||||
/// 1. A temporary cache directory, if the user requested `--no-cache`.
|
||||
/// 2. The specific cache directory specified by the user via `--cache-dir` or `UV_CACHE_DIR`.
|
||||
/// 3. The system-appropriate cache directory.
|
||||
/// 4. A `.uv_cache` directory in the current working directory.
|
||||
///
|
||||
/// Returns an absolute cache dir.
|
||||
pub fn from_settings(
|
||||
no_cache: Option<bool>,
|
||||
cache_dir: Option<PathBuf>,
|
||||
) -> Result<Self, io::Error> {
|
||||
if no_cache.unwrap_or(false) {
|
||||
Cache::temp()
|
||||
} else if let Some(cache_dir) = cache_dir {
|
||||
Cache::from_path(cache_dir)
|
||||
} else if let Some(project_dirs) = ProjectDirs::from("", "", "uv") {
|
||||
Cache::from_path(project_dirs.cache_dir())
|
||||
} else {
|
||||
Cache::from_path(".uv_cache")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<CacheArgs> for Cache {
|
||||
|
|
@ -38,14 +62,6 @@ impl TryFrom<CacheArgs> for Cache {
|
|||
///
|
||||
/// Returns an absolute cache dir.
|
||||
fn try_from(value: CacheArgs) -> Result<Self, Self::Error> {
|
||||
if value.no_cache {
|
||||
Self::temp()
|
||||
} else if let Some(cache_dir) = value.cache_dir {
|
||||
Self::from_path(cache_dir)
|
||||
} else if let Some(project_dirs) = ProjectDirs::from("", "", "uv") {
|
||||
Self::from_path(project_dirs.cache_dir())
|
||||
} else {
|
||||
Self::from_path(".uv_cache")
|
||||
}
|
||||
Cache::from_settings(value.no_cache, value.cache_dir)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use serde::Deserialize;
|
|||
use distribution_types::{FlatIndexLocation, IndexUrl};
|
||||
use install_wheel_rs::linker::LinkMode;
|
||||
use uv_configuration::{ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_toolchain::PythonVersion;
|
||||
|
||||
|
|
@ -28,10 +28,8 @@ pub(crate) struct Tools {
|
|||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
pub struct Options {
|
||||
pub quiet: Option<bool>,
|
||||
pub verbose: Option<bool>,
|
||||
pub native_tls: Option<bool>,
|
||||
pub no_cache: bool,
|
||||
pub no_cache: Option<bool>,
|
||||
pub cache_dir: Option<PathBuf>,
|
||||
pub pip: Option<PipOptions>,
|
||||
}
|
||||
|
|
@ -41,10 +39,12 @@ pub struct Options {
|
|||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
pub struct PipOptions {
|
||||
pub python: Option<String>,
|
||||
pub system: Option<bool>,
|
||||
pub break_system_packages: Option<bool>,
|
||||
pub offline: Option<bool>,
|
||||
pub index_url: Option<IndexUrl>,
|
||||
pub extra_index_url: Option<IndexUrl>,
|
||||
pub extra_index_url: Option<Vec<IndexUrl>>,
|
||||
pub no_index: Option<bool>,
|
||||
pub find_links: Option<Vec<FlatIndexLocation>>,
|
||||
pub index_strategy: Option<IndexStrategy>,
|
||||
|
|
@ -53,21 +53,29 @@ pub struct PipOptions {
|
|||
pub no_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
pub only_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
pub no_build_isolation: Option<bool>,
|
||||
pub strict: Option<bool>,
|
||||
pub extra: Option<Vec<ExtraName>>,
|
||||
pub all_extras: Option<bool>,
|
||||
pub no_deps: Option<bool>,
|
||||
pub resolution: Option<ResolutionMode>,
|
||||
pub prerelease: Option<PreReleaseMode>,
|
||||
pub output_file: Option<PathBuf>,
|
||||
pub no_strip_extras: Option<bool>,
|
||||
pub no_annotate: Option<bool>,
|
||||
pub no_header: Option<bool>,
|
||||
pub custom_compile_command: Option<String>,
|
||||
pub generate_hashes: Option<bool>,
|
||||
pub legacy_setup_py: Option<bool>,
|
||||
pub config_setting: Option<ConfigSettings>,
|
||||
pub config_settings: Option<ConfigSettings>,
|
||||
pub python_version: Option<PythonVersion>,
|
||||
pub exclude_newer: Option<ExcludeNewer>,
|
||||
pub no_emit_package: Option<Vec<PackageName>>,
|
||||
pub emit_index_url: Option<bool>,
|
||||
pub emit_find_links: Option<bool>,
|
||||
pub emit_marker_expression: Option<bool>,
|
||||
pub emit_index_annotation: Option<bool>,
|
||||
pub annotation_style: Option<AnnotationStyle>,
|
||||
pub require_hashes: Option<bool>,
|
||||
pub link_mode: Option<LinkMode>,
|
||||
pub compile_bytecode: Option<bool>,
|
||||
pub require_hashes: Option<bool>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use crate::{Options, PyProjectToml};
|
|||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Workspace {
|
||||
options: Options,
|
||||
root: PathBuf,
|
||||
pub options: Options,
|
||||
pub root: PathBuf,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ pub(crate) struct PipCompileArgs {
|
|||
|
||||
/// Include optional dependencies in the given extra group name; may be provided more than once.
|
||||
#[arg(long, conflicts_with = "all_extras", value_parser = extra_name_with_clap_error)]
|
||||
pub(crate) extra: Vec<ExtraName>,
|
||||
pub(crate) extra: Option<Vec<ExtraName>>,
|
||||
|
||||
/// Include all optional dependencies.
|
||||
#[arg(long, conflicts_with = "extra")]
|
||||
|
|
@ -259,11 +259,20 @@ pub(crate) struct PipCompileArgs {
|
|||
#[arg(long)]
|
||||
pub(crate) no_deps: bool,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = ResolutionMode::default(), env = "UV_RESOLUTION")]
|
||||
pub(crate) resolution: ResolutionMode,
|
||||
/// The strategy to use when selecting between the different compatible versions for a given
|
||||
/// package requirement.
|
||||
///
|
||||
/// By default, `uv` will use the latest compatible version of each package (`highest`).
|
||||
#[arg(long, value_enum, env = "UV_RESOLUTION")]
|
||||
pub(crate) resolution: Option<ResolutionMode>,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = PreReleaseMode::default(), env = "UV_PRERELEASE")]
|
||||
pub(crate) prerelease: PreReleaseMode,
|
||||
/// The strategy to use when considering pre-release versions.
|
||||
///
|
||||
/// By default, `uv` will accept pre-releases for packages that _only_ publish pre-releases,
|
||||
/// along with first-party requirements that contain an explicit pre-release marker in the
|
||||
/// declared specifiers (`if-necessary-or-explicit`).
|
||||
#[arg(long, value_enum, env = "UV_PRERELEASE")]
|
||||
pub(crate) prerelease: Option<PreReleaseMode>,
|
||||
|
||||
#[arg(long, hide = true)]
|
||||
pub(crate) pre: bool,
|
||||
|
|
@ -289,8 +298,10 @@ pub(crate) struct PipCompileArgs {
|
|||
pub(crate) no_header: bool,
|
||||
|
||||
/// Choose the style of the annotation comments, which indicate the source of each package.
|
||||
#[arg(long, default_value_t=AnnotationStyle::Split, value_enum)]
|
||||
pub(crate) annotation_style: AnnotationStyle,
|
||||
///
|
||||
/// Defaults to `split`.
|
||||
#[arg(long, value_enum)]
|
||||
pub(crate) annotation_style: Option<AnnotationStyle>,
|
||||
|
||||
/// Change header comment to reflect custom command wrapping `uv pip compile`.
|
||||
#[arg(long, env = "UV_CUSTOM_COMPILE_COMMAND")]
|
||||
|
|
@ -311,7 +322,7 @@ pub(crate) struct PipCompileArgs {
|
|||
|
||||
/// Refresh cached data for a specific package.
|
||||
#[arg(long)]
|
||||
pub(crate) refresh_package: Vec<PackageName>,
|
||||
pub(crate) refresh_package: Option<Vec<PackageName>>,
|
||||
|
||||
/// The method to use when installing packages from the global cache.
|
||||
///
|
||||
|
|
@ -319,8 +330,8 @@ pub(crate) struct PipCompileArgs {
|
|||
///
|
||||
/// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
|
||||
/// Windows.
|
||||
#[arg(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())]
|
||||
pub(crate) link_mode: install_wheel_rs::linker::LinkMode,
|
||||
#[arg(long, value_enum)]
|
||||
pub(crate) link_mode: Option<install_wheel_rs::linker::LinkMode>,
|
||||
|
||||
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
|
||||
///
|
||||
|
|
@ -343,7 +354,7 @@ pub(crate) struct PipCompileArgs {
|
|||
/// as it finds it in an index. That is, it isn't possible for `uv` to
|
||||
/// consider versions of the same package across multiple indexes.
|
||||
#[arg(long, env = "UV_EXTRA_INDEX_URL", value_delimiter = ' ', value_parser = parse_index_url)]
|
||||
pub(crate) extra_index_url: Vec<Maybe<IndexUrl>>,
|
||||
pub(crate) extra_index_url: Option<Vec<Maybe<IndexUrl>>>,
|
||||
|
||||
/// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those
|
||||
/// discovered via `--find-links`.
|
||||
|
|
@ -353,18 +364,20 @@ pub(crate) struct PipCompileArgs {
|
|||
/// The strategy to use when resolving against multiple index URLs.
|
||||
///
|
||||
/// By default, `uv` will stop at the first index on which a given package is available, and
|
||||
/// limit resolutions to those present on that first index. This prevents "dependency confusion"
|
||||
/// attacks, whereby an attack can upload a malicious package under the same name to a secondary
|
||||
/// index.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: IndexStrategy,
|
||||
/// limit resolutions to those present on that first index (`first-match`. This prevents
|
||||
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||
/// same name to a secondary
|
||||
#[arg(long, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: Option<IndexStrategy>,
|
||||
|
||||
/// Attempt to use `keyring` for authentication for index urls
|
||||
/// Attempt to use `keyring` for authentication for index URLs.
|
||||
///
|
||||
/// Due to not having Python imports, only `--keyring-provider subprocess` argument is currently
|
||||
/// implemented `uv` will try to use `keyring` via CLI when this flag is used.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: KeyringProviderType,
|
||||
///
|
||||
/// Defaults to `disabled`.
|
||||
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||
|
||||
/// Locations to search for candidate distributions, beyond those found in the indexes.
|
||||
///
|
||||
|
|
@ -373,7 +386,7 @@ pub(crate) struct PipCompileArgs {
|
|||
///
|
||||
/// If a URL, the page must contain a flat list of links to package files.
|
||||
#[arg(long, short)]
|
||||
pub(crate) find_links: Vec<FlatIndexLocation>,
|
||||
pub(crate) find_links: Option<Vec<FlatIndexLocation>>,
|
||||
|
||||
/// Allow package upgrades, ignoring pinned versions in the existing output file.
|
||||
#[arg(long, short = 'U')]
|
||||
|
|
@ -382,7 +395,7 @@ pub(crate) struct PipCompileArgs {
|
|||
/// Allow upgrades for a specific package, ignoring pinned versions in the existing output
|
||||
/// file.
|
||||
#[arg(long, short = 'P')]
|
||||
pub(crate) upgrade_package: Vec<PackageName>,
|
||||
pub(crate) upgrade_package: Option<Vec<PackageName>>,
|
||||
|
||||
/// Include distribution hashes in the output file.
|
||||
#[arg(long)]
|
||||
|
|
@ -418,11 +431,11 @@ pub(crate) struct PipCompileArgs {
|
|||
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||
/// Clear previously specified packages with `:none:`.
|
||||
#[arg(long, conflicts_with = "no_build")]
|
||||
pub(crate) only_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) only_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
|
||||
/// Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs.
|
||||
#[arg(long, short = 'C', alias = "config-settings")]
|
||||
pub(crate) config_setting: Vec<ConfigSettingEntry>,
|
||||
pub(crate) config_setting: Option<Vec<ConfigSettingEntry>>,
|
||||
|
||||
/// The minimum Python version that should be supported by the compiled requirements (e.g.,
|
||||
/// `3.7` or `3.7.9`).
|
||||
|
|
@ -442,7 +455,7 @@ pub(crate) struct PipCompileArgs {
|
|||
/// Specify a package to omit from the output resolution. Its dependencies will still be
|
||||
/// included in the resolution. Equivalent to pip-compile's `--unsafe-package` option.
|
||||
#[arg(long, alias = "unsafe-package")]
|
||||
pub(crate) no_emit_package: Vec<PackageName>,
|
||||
pub(crate) no_emit_package: Option<Vec<PackageName>>,
|
||||
|
||||
/// Include `--index-url` and `--extra-index-url` entries in the generated output file.
|
||||
#[arg(long)]
|
||||
|
|
@ -506,8 +519,8 @@ pub(crate) struct PipSyncArgs {
|
|||
///
|
||||
/// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
|
||||
/// Windows.
|
||||
#[arg(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())]
|
||||
pub(crate) link_mode: install_wheel_rs::linker::LinkMode,
|
||||
#[arg(long, value_enum)]
|
||||
pub(crate) link_mode: Option<install_wheel_rs::linker::LinkMode>,
|
||||
|
||||
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
|
||||
///
|
||||
|
|
@ -530,7 +543,7 @@ pub(crate) struct PipSyncArgs {
|
|||
/// as it finds it in an index. That is, it isn't possible for `uv` to
|
||||
/// consider versions of the same package across multiple indexes.
|
||||
#[arg(long, env = "UV_EXTRA_INDEX_URL", value_delimiter = ' ', value_parser = parse_index_url)]
|
||||
pub(crate) extra_index_url: Vec<Maybe<IndexUrl>>,
|
||||
pub(crate) extra_index_url: Option<Vec<Maybe<IndexUrl>>>,
|
||||
|
||||
/// Locations to search for candidate distributions, beyond those found in the indexes.
|
||||
///
|
||||
|
|
@ -539,7 +552,7 @@ pub(crate) struct PipSyncArgs {
|
|||
///
|
||||
/// If a URL, the page must contain a flat list of links to package files.
|
||||
#[arg(long, short)]
|
||||
pub(crate) find_links: Vec<FlatIndexLocation>,
|
||||
pub(crate) find_links: Option<Vec<FlatIndexLocation>>,
|
||||
|
||||
/// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those
|
||||
/// discovered via `--find-links`.
|
||||
|
|
@ -549,11 +562,11 @@ pub(crate) struct PipSyncArgs {
|
|||
/// The strategy to use when resolving against multiple index URLs.
|
||||
///
|
||||
/// By default, `uv` will stop at the first index on which a given package is available, and
|
||||
/// limit resolutions to those present on that first index. This prevents "dependency confusion"
|
||||
/// attacks, whereby an attack can upload a malicious package under the same name to a secondary
|
||||
/// index.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: IndexStrategy,
|
||||
/// limit resolutions to those present on that first index (`first-match`. This prevents
|
||||
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||
/// same name to a secondary
|
||||
#[arg(long, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: Option<IndexStrategy>,
|
||||
|
||||
/// Require a matching hash for each requirement.
|
||||
///
|
||||
|
|
@ -569,12 +582,14 @@ pub(crate) struct PipSyncArgs {
|
|||
#[arg(long)]
|
||||
pub(crate) require_hashes: bool,
|
||||
|
||||
/// Attempt to use `keyring` for authentication for index urls
|
||||
/// Attempt to use `keyring` for authentication for index URLs.
|
||||
///
|
||||
/// Function's similar to `pip`'s `--keyring-provider subprocess` argument,
|
||||
/// `uv` will try to use `keyring` via CLI when this flag is used.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: KeyringProviderType,
|
||||
///
|
||||
/// Defaults to `disabled`.
|
||||
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||
|
||||
/// The Python interpreter into which packages should be installed.
|
||||
///
|
||||
|
|
@ -640,7 +655,7 @@ pub(crate) struct PipSyncArgs {
|
|||
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||
/// Clear previously specified packages with `:none:`.
|
||||
#[arg(long, conflicts_with = "no_build")]
|
||||
pub(crate) no_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) no_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
|
||||
/// Only use pre-built wheels; don't build source distributions.
|
||||
///
|
||||
|
|
@ -651,7 +666,7 @@ pub(crate) struct PipSyncArgs {
|
|||
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||
/// Clear previously specified packages with `:none:`.
|
||||
#[arg(long, conflicts_with = "no_build")]
|
||||
pub(crate) only_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) only_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
|
||||
/// Compile Python files to bytecode.
|
||||
///
|
||||
|
|
@ -671,7 +686,7 @@ pub(crate) struct PipSyncArgs {
|
|||
|
||||
/// Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs.
|
||||
#[arg(long, short = 'C', alias = "config-settings")]
|
||||
pub(crate) config_setting: Vec<ConfigSettingEntry>,
|
||||
pub(crate) config_setting: Option<Vec<ConfigSettingEntry>>,
|
||||
|
||||
/// Validate the virtual environment after completing the installation, to detect packages with
|
||||
/// missing dependencies or other issues.
|
||||
|
|
@ -722,7 +737,7 @@ pub(crate) struct PipInstallArgs {
|
|||
|
||||
/// Include optional dependencies in the given extra group name; may be provided more than once.
|
||||
#[arg(long, conflicts_with = "all_extras", value_parser = extra_name_with_clap_error)]
|
||||
pub(crate) extra: Vec<ExtraName>,
|
||||
pub(crate) extra: Option<Vec<ExtraName>>,
|
||||
|
||||
/// Include all optional dependencies.
|
||||
#[arg(long, conflicts_with = "extra")]
|
||||
|
|
@ -734,7 +749,7 @@ pub(crate) struct PipInstallArgs {
|
|||
|
||||
/// Allow upgrade of a specific package.
|
||||
#[arg(long, short = 'P')]
|
||||
pub(crate) upgrade_package: Vec<PackageName>,
|
||||
pub(crate) upgrade_package: Option<Vec<PackageName>>,
|
||||
|
||||
/// Reinstall all packages, regardless of whether they're already installed.
|
||||
#[arg(long, alias = "force-reinstall")]
|
||||
|
|
@ -742,7 +757,7 @@ pub(crate) struct PipInstallArgs {
|
|||
|
||||
/// Reinstall a specific package, regardless of whether it's already installed.
|
||||
#[arg(long)]
|
||||
pub(crate) reinstall_package: Vec<PackageName>,
|
||||
pub(crate) reinstall_package: Option<Vec<PackageName>>,
|
||||
|
||||
/// Run offline, i.e., without accessing the network.
|
||||
#[arg(
|
||||
|
|
@ -759,7 +774,7 @@ pub(crate) struct PipInstallArgs {
|
|||
|
||||
/// Refresh cached data for a specific package.
|
||||
#[arg(long)]
|
||||
pub(crate) refresh_package: Vec<PackageName>,
|
||||
pub(crate) refresh_package: Option<Vec<PackageName>>,
|
||||
|
||||
/// Ignore package dependencies, instead only installing those packages explicitly listed
|
||||
/// on the command line or in the requirements files.
|
||||
|
|
@ -770,14 +785,23 @@ pub(crate) struct PipInstallArgs {
|
|||
///
|
||||
/// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
|
||||
/// Windows.
|
||||
#[arg(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())]
|
||||
pub(crate) link_mode: install_wheel_rs::linker::LinkMode,
|
||||
#[arg(long, value_enum)]
|
||||
pub(crate) link_mode: Option<install_wheel_rs::linker::LinkMode>,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = ResolutionMode::default(), env = "UV_RESOLUTION")]
|
||||
pub(crate) resolution: ResolutionMode,
|
||||
/// The strategy to use when selecting between the different compatible versions for a given
|
||||
/// package requirement.
|
||||
///
|
||||
/// By default, `uv` will use the latest compatible version of each package (`highest`).
|
||||
#[arg(long, value_enum, env = "UV_RESOLUTION")]
|
||||
pub(crate) resolution: Option<ResolutionMode>,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = PreReleaseMode::default(), env = "UV_PRERELEASE")]
|
||||
pub(crate) prerelease: PreReleaseMode,
|
||||
/// The strategy to use when considering pre-release versions.
|
||||
///
|
||||
/// By default, `uv` will accept pre-releases for packages that _only_ publish pre-releases,
|
||||
/// along with first-party requirements that contain an explicit pre-release marker in the
|
||||
/// declared specifiers (`if-necessary-or-explicit`).
|
||||
#[arg(long, value_enum, env = "UV_PRERELEASE")]
|
||||
pub(crate) prerelease: Option<PreReleaseMode>,
|
||||
|
||||
#[arg(long, hide = true)]
|
||||
pub(crate) pre: bool,
|
||||
|
|
@ -803,7 +827,7 @@ pub(crate) struct PipInstallArgs {
|
|||
/// as it finds it in an index. That is, it isn't possible for `uv` to
|
||||
/// consider versions of the same package across multiple indexes.
|
||||
#[arg(long, env = "UV_EXTRA_INDEX_URL", value_delimiter = ' ', value_parser = parse_index_url)]
|
||||
pub(crate) extra_index_url: Vec<Maybe<IndexUrl>>,
|
||||
pub(crate) extra_index_url: Option<Vec<Maybe<IndexUrl>>>,
|
||||
|
||||
/// Locations to search for candidate distributions, beyond those found in the indexes.
|
||||
///
|
||||
|
|
@ -812,7 +836,7 @@ pub(crate) struct PipInstallArgs {
|
|||
///
|
||||
/// If a URL, the page must contain a flat list of links to package files.
|
||||
#[arg(long, short)]
|
||||
pub(crate) find_links: Vec<FlatIndexLocation>,
|
||||
pub(crate) find_links: Option<Vec<FlatIndexLocation>>,
|
||||
|
||||
/// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those
|
||||
/// discovered via `--find-links`.
|
||||
|
|
@ -822,11 +846,11 @@ pub(crate) struct PipInstallArgs {
|
|||
/// The strategy to use when resolving against multiple index URLs.
|
||||
///
|
||||
/// By default, `uv` will stop at the first index on which a given package is available, and
|
||||
/// limit resolutions to those present on that first index. This prevents "dependency confusion"
|
||||
/// attacks, whereby an attack can upload a malicious package under the same name to a secondary
|
||||
/// index.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: IndexStrategy,
|
||||
/// limit resolutions to those present on that first index (`first-match`. This prevents
|
||||
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||
/// same name to a secondary
|
||||
#[arg(long, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: Option<IndexStrategy>,
|
||||
|
||||
/// Require a matching hash for each requirement.
|
||||
///
|
||||
|
|
@ -842,12 +866,14 @@ pub(crate) struct PipInstallArgs {
|
|||
#[arg(long)]
|
||||
pub(crate) require_hashes: bool,
|
||||
|
||||
/// Attempt to use `keyring` for authentication for index urls
|
||||
/// Attempt to use `keyring` for authentication for index URLs.
|
||||
///
|
||||
/// Due to not having Python imports, only `--keyring-provider subprocess` argument is currently
|
||||
/// implemented `uv` will try to use `keyring` via CLI when this flag is used.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: KeyringProviderType,
|
||||
///
|
||||
/// Defaults to `disabled`.
|
||||
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||
|
||||
/// The Python interpreter into which packages should be installed.
|
||||
///
|
||||
|
|
@ -913,7 +939,7 @@ pub(crate) struct PipInstallArgs {
|
|||
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||
/// Clear previously specified packages with `:none:`.
|
||||
#[arg(long, conflicts_with = "no_build")]
|
||||
pub(crate) no_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) no_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
|
||||
/// Only use pre-built wheels; don't build source distributions.
|
||||
///
|
||||
|
|
@ -924,7 +950,7 @@ pub(crate) struct PipInstallArgs {
|
|||
/// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
|
||||
/// Clear previously specified packages with `:none:`.
|
||||
#[arg(long, conflicts_with = "no_build")]
|
||||
pub(crate) only_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) only_binary: Option<Vec<PackageNameSpecifier>>,
|
||||
|
||||
/// Compile Python files to bytecode.
|
||||
///
|
||||
|
|
@ -944,7 +970,7 @@ pub(crate) struct PipInstallArgs {
|
|||
|
||||
/// Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs.
|
||||
#[arg(long, short = 'C', alias = "config-settings")]
|
||||
pub(crate) config_setting: Vec<ConfigSettingEntry>,
|
||||
pub(crate) config_setting: Option<Vec<ConfigSettingEntry>>,
|
||||
|
||||
/// Validate the virtual environment after completing the installation, to detect packages with
|
||||
/// missing dependencies or other issues.
|
||||
|
|
@ -995,8 +1021,10 @@ pub(crate) struct PipUninstallArgs {
|
|||
///
|
||||
/// Due to not having Python imports, only `--keyring-provider subprocess` argument is currently
|
||||
/// implemented `uv` will try to use `keyring` via CLI when this flag is used.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: KeyringProviderType,
|
||||
///
|
||||
/// Defaults to `disabled`.
|
||||
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||
|
||||
/// Use the system Python to uninstall packages.
|
||||
///
|
||||
|
|
@ -1209,7 +1237,7 @@ pub(crate) struct VenvArgs {
|
|||
/// WARNING: `--system` is intended for use in continuous integration (CI) environments and
|
||||
/// should be used with caution, as it can modify the system Python installation.
|
||||
#[arg(long, env = "UV_SYSTEM_PYTHON", group = "discovery")]
|
||||
system: bool,
|
||||
pub(crate) system: bool,
|
||||
|
||||
/// Install seed packages (`pip`, `setuptools`, and `wheel`) into the virtual environment.
|
||||
#[arg(long)]
|
||||
|
|
@ -1247,8 +1275,8 @@ pub(crate) struct VenvArgs {
|
|||
///
|
||||
/// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
|
||||
/// Windows.
|
||||
#[arg(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())]
|
||||
pub(crate) link_mode: install_wheel_rs::linker::LinkMode,
|
||||
#[arg(long, value_enum)]
|
||||
pub(crate) link_mode: Option<install_wheel_rs::linker::LinkMode>,
|
||||
|
||||
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
|
||||
///
|
||||
|
|
@ -1271,7 +1299,7 @@ pub(crate) struct VenvArgs {
|
|||
/// as it finds it in an index. That is, it isn't possible for `uv` to
|
||||
/// consider versions of the same package across multiple indexes.
|
||||
#[arg(long, env = "UV_EXTRA_INDEX_URL", value_delimiter = ' ', value_parser = parse_index_url)]
|
||||
pub(crate) extra_index_url: Vec<Maybe<IndexUrl>>,
|
||||
pub(crate) extra_index_url: Option<Vec<Maybe<IndexUrl>>>,
|
||||
|
||||
/// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those
|
||||
/// discovered via `--find-links`.
|
||||
|
|
@ -1281,18 +1309,20 @@ pub(crate) struct VenvArgs {
|
|||
/// The strategy to use when resolving against multiple index URLs.
|
||||
///
|
||||
/// By default, `uv` will stop at the first index on which a given package is available, and
|
||||
/// limit resolutions to those present on that first index. This prevents "dependency confusion"
|
||||
/// attacks, whereby an attack can upload a malicious package under the same name to a secondary
|
||||
/// index.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: IndexStrategy,
|
||||
/// limit resolutions to those present on that first index (`first-match`. This prevents
|
||||
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||
/// same name to a secondary
|
||||
#[arg(long, value_enum, env = "UV_INDEX_STRATEGY")]
|
||||
pub(crate) index_strategy: Option<IndexStrategy>,
|
||||
|
||||
/// Attempt to use `keyring` for authentication for index urls
|
||||
/// Attempt to use `keyring` for authentication for index URLs.
|
||||
///
|
||||
/// Due to not having Python imports, only `--keyring-provider subprocess` argument is currently
|
||||
/// implemented `uv` will try to use `keyring` via CLI when this flag is used.
|
||||
#[arg(long, default_value_t, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: KeyringProviderType,
|
||||
///
|
||||
/// Defaults to `disabled`.
|
||||
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
|
||||
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||
|
||||
/// Run offline, i.e., without accessing the network.
|
||||
#[arg(global = true, long)]
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ pub(crate) async fn pip_compile(
|
|||
python_version: Option<PythonVersion>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
annotation_style: AnnotationStyle,
|
||||
link_mode: LinkMode,
|
||||
native_tls: bool,
|
||||
quiet: bool,
|
||||
link_mode: LinkMode,
|
||||
cache: Cache,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
|
|
|
|||
|
|
@ -13,15 +13,19 @@ use tracing::instrument;
|
|||
use distribution_types::IndexLocations;
|
||||
use uv_cache::{Cache, Refresh};
|
||||
use uv_client::Connectivity;
|
||||
use uv_configuration::{ConfigSettings, NoBinary, NoBuild, Reinstall, SetupPyStrategy, Upgrade};
|
||||
use uv_configuration::{NoBinary, NoBuild, Reinstall, SetupPyStrategy, Upgrade};
|
||||
use uv_requirements::{ExtrasSpecification, RequirementsSource};
|
||||
use uv_resolver::{DependencyMode, PreReleaseMode};
|
||||
use uv_resolver::DependencyMode;
|
||||
|
||||
use crate::cli::{CacheCommand, CacheNamespace, Cli, Commands, Maybe, PipCommand, PipNamespace};
|
||||
use crate::cli::{CacheCommand, CacheNamespace, Cli, Commands, PipCommand, PipNamespace};
|
||||
#[cfg(feature = "self-update")]
|
||||
use crate::cli::{SelfCommand, SelfNamespace};
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::compat::CompatArgs;
|
||||
use crate::settings::{
|
||||
CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings,
|
||||
PipInstallSettings, PipListSettings, PipShowSettings, PipSyncSettings, PipUninstallSettings,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[global_allocator]
|
||||
|
|
@ -44,6 +48,7 @@ mod commands;
|
|||
mod compat;
|
||||
mod logging;
|
||||
mod printer;
|
||||
mod settings;
|
||||
mod shell;
|
||||
mod version;
|
||||
|
||||
|
|
@ -104,7 +109,11 @@ async fn run() -> Result<ExitStatus> {
|
|||
}
|
||||
};
|
||||
|
||||
let globals = cli.global_args;
|
||||
// Load the workspace settings.
|
||||
let workspace = uv_workspace::Workspace::find(env::current_dir()?)?;
|
||||
|
||||
// Resolve the global settings.
|
||||
let globals = GlobalSettings::resolve(cli.global_args, workspace.as_ref());
|
||||
|
||||
// Configure the `tracing` crate, which controls internal logging.
|
||||
#[cfg(feature = "tracing-durations-export")]
|
||||
|
|
@ -134,11 +143,7 @@ async fn run() -> Result<ExitStatus> {
|
|||
uv_warnings::enable();
|
||||
}
|
||||
|
||||
if globals.no_color {
|
||||
anstream::ColorChoice::write_global(anstream::ColorChoice::Never);
|
||||
} else {
|
||||
anstream::ColorChoice::write_global(globals.color.into());
|
||||
}
|
||||
|
||||
miette::set_hook(Box::new(|_| {
|
||||
Box::new(
|
||||
|
|
@ -151,7 +156,9 @@ async fn run() -> Result<ExitStatus> {
|
|||
)
|
||||
}))?;
|
||||
|
||||
let cache = Cache::try_from(cli.cache_args)?;
|
||||
// Resolve the cache settings.
|
||||
let cache = CacheSettings::resolve(cli.cache_args, workspace.as_ref());
|
||||
let cache = Cache::from_settings(cache.no_cache, cache.cache_dir)?;
|
||||
|
||||
match cli.command {
|
||||
Commands::Pip(PipNamespace {
|
||||
|
|
@ -159,6 +166,9 @@ async fn run() -> Result<ExitStatus> {
|
|||
}) => {
|
||||
args.compat_args.validate()?;
|
||||
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipCompileSettings::resolve(args, workspace);
|
||||
|
||||
let cache = cache.with_refresh(Refresh::from_args(args.refresh, args.refresh_package));
|
||||
let requirements = args
|
||||
.src_file
|
||||
|
|
@ -176,77 +186,70 @@ async fn run() -> Result<ExitStatus> {
|
|||
.map(RequirementsSource::from_overrides_txt)
|
||||
.collect::<Vec<_>>();
|
||||
let index_urls = IndexLocations::new(
|
||||
args.index_url.and_then(Maybe::into_option),
|
||||
args.extra_index_url
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect(),
|
||||
args.find_links,
|
||||
args.no_index,
|
||||
args.shared.index_url,
|
||||
args.shared.extra_index_url,
|
||||
args.shared.find_links,
|
||||
args.shared.no_index,
|
||||
);
|
||||
let extras = if args.all_extras {
|
||||
// TODO(charlie): Move into `PipCompileSettings::resolve`.
|
||||
let extras = if args.shared.all_extras {
|
||||
ExtrasSpecification::All
|
||||
} else if args.extra.is_empty() {
|
||||
} else if args.shared.extra.is_empty() {
|
||||
ExtrasSpecification::None
|
||||
} else {
|
||||
ExtrasSpecification::Some(&args.extra)
|
||||
ExtrasSpecification::Some(&args.shared.extra)
|
||||
};
|
||||
let upgrade = Upgrade::from_args(args.upgrade, args.upgrade_package);
|
||||
let no_build = NoBuild::from_args(args.only_binary, args.no_build);
|
||||
let dependency_mode = if args.no_deps {
|
||||
let no_build = NoBuild::from_args(args.shared.only_binary, args.shared.no_build);
|
||||
let dependency_mode = if args.shared.no_deps {
|
||||
DependencyMode::Direct
|
||||
} else {
|
||||
DependencyMode::Transitive
|
||||
};
|
||||
let prerelease = if args.pre {
|
||||
PreReleaseMode::Allow
|
||||
} else {
|
||||
args.prerelease
|
||||
};
|
||||
let setup_py = if args.legacy_setup_py {
|
||||
let setup_py = if args.shared.legacy_setup_py {
|
||||
SetupPyStrategy::Setuptools
|
||||
} else {
|
||||
SetupPyStrategy::Pep517
|
||||
};
|
||||
let config_settings = args.config_setting.into_iter().collect::<ConfigSettings>();
|
||||
|
||||
commands::pip_compile(
|
||||
&requirements,
|
||||
&constraints,
|
||||
&overrides,
|
||||
extras,
|
||||
args.output_file.as_deref(),
|
||||
args.resolution,
|
||||
prerelease,
|
||||
args.shared.output_file.as_deref(),
|
||||
args.shared.resolution,
|
||||
args.shared.prerelease,
|
||||
dependency_mode,
|
||||
upgrade,
|
||||
args.generate_hashes,
|
||||
args.no_emit_package,
|
||||
args.no_strip_extras,
|
||||
!args.no_annotate,
|
||||
!args.no_header,
|
||||
args.custom_compile_command,
|
||||
args.emit_index_url,
|
||||
args.emit_find_links,
|
||||
args.emit_marker_expression,
|
||||
args.emit_index_annotation,
|
||||
args.shared.generate_hashes,
|
||||
args.shared.no_emit_package,
|
||||
args.shared.no_strip_extras,
|
||||
!args.shared.no_annotate,
|
||||
!args.shared.no_header,
|
||||
args.shared.custom_compile_command,
|
||||
args.shared.emit_index_url,
|
||||
args.shared.emit_find_links,
|
||||
args.shared.emit_marker_expression,
|
||||
args.shared.emit_index_annotation,
|
||||
index_urls,
|
||||
args.index_strategy,
|
||||
args.keyring_provider,
|
||||
args.shared.index_strategy,
|
||||
args.shared.keyring_provider,
|
||||
setup_py,
|
||||
config_settings,
|
||||
if args.offline {
|
||||
args.shared.config_setting,
|
||||
if args.shared.offline {
|
||||
Connectivity::Offline
|
||||
} else {
|
||||
Connectivity::Online
|
||||
},
|
||||
args.no_build_isolation,
|
||||
args.shared.no_build_isolation,
|
||||
no_build,
|
||||
args.python_version,
|
||||
args.exclude_newer,
|
||||
args.annotation_style,
|
||||
args.shared.python_version,
|
||||
args.shared.exclude_newer,
|
||||
args.shared.annotation_style,
|
||||
args.shared.link_mode,
|
||||
globals.native_tls,
|
||||
globals.quiet,
|
||||
args.link_mode,
|
||||
cache,
|
||||
printer,
|
||||
)
|
||||
|
|
@ -257,15 +260,15 @@ async fn run() -> Result<ExitStatus> {
|
|||
}) => {
|
||||
args.compat_args.validate()?;
|
||||
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipSyncSettings::resolve(args, workspace);
|
||||
|
||||
let cache = cache.with_refresh(Refresh::from_args(args.refresh, args.refresh_package));
|
||||
let index_urls = IndexLocations::new(
|
||||
args.index_url.and_then(Maybe::into_option),
|
||||
args.extra_index_url
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect(),
|
||||
args.find_links,
|
||||
args.no_index,
|
||||
args.shared.index_url,
|
||||
args.shared.extra_index_url,
|
||||
args.shared.find_links,
|
||||
args.shared.no_index,
|
||||
);
|
||||
let sources = args
|
||||
.src_file
|
||||
|
|
@ -273,38 +276,37 @@ async fn run() -> Result<ExitStatus> {
|
|||
.map(RequirementsSource::from_requirements_file)
|
||||
.collect::<Vec<_>>();
|
||||
let reinstall = Reinstall::from_args(args.reinstall, args.reinstall_package);
|
||||
let no_binary = NoBinary::from_args(args.no_binary);
|
||||
let no_build = NoBuild::from_args(args.only_binary, args.no_build);
|
||||
let setup_py = if args.legacy_setup_py {
|
||||
let no_binary = NoBinary::from_args(args.shared.no_binary);
|
||||
let no_build = NoBuild::from_args(args.shared.only_binary, args.shared.no_build);
|
||||
let setup_py = if args.shared.legacy_setup_py {
|
||||
SetupPyStrategy::Setuptools
|
||||
} else {
|
||||
SetupPyStrategy::Pep517
|
||||
};
|
||||
let config_settings = args.config_setting.into_iter().collect::<ConfigSettings>();
|
||||
|
||||
commands::pip_sync(
|
||||
&sources,
|
||||
&reinstall,
|
||||
args.link_mode,
|
||||
args.compile,
|
||||
args.require_hashes,
|
||||
args.shared.link_mode,
|
||||
args.shared.compile_bytecode,
|
||||
args.shared.require_hashes,
|
||||
index_urls,
|
||||
args.index_strategy,
|
||||
args.keyring_provider,
|
||||
args.shared.index_strategy,
|
||||
args.shared.keyring_provider,
|
||||
setup_py,
|
||||
if args.offline {
|
||||
if args.shared.offline {
|
||||
Connectivity::Offline
|
||||
} else {
|
||||
Connectivity::Online
|
||||
},
|
||||
&config_settings,
|
||||
args.no_build_isolation,
|
||||
&args.shared.config_setting,
|
||||
args.shared.no_build_isolation,
|
||||
no_build,
|
||||
no_binary,
|
||||
args.strict,
|
||||
args.python,
|
||||
args.system,
|
||||
args.break_system_packages,
|
||||
args.shared.strict,
|
||||
args.shared.python,
|
||||
args.shared.system,
|
||||
args.shared.break_system_packages,
|
||||
globals.native_tls,
|
||||
cache,
|
||||
printer,
|
||||
|
|
@ -314,6 +316,9 @@ async fn run() -> Result<ExitStatus> {
|
|||
Commands::Pip(PipNamespace {
|
||||
command: PipCommand::Install(args),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipInstallSettings::resolve(args, workspace);
|
||||
|
||||
let cache = cache.with_refresh(Refresh::from_args(args.refresh, args.refresh_package));
|
||||
let requirements = args
|
||||
.package
|
||||
|
|
@ -337,73 +342,64 @@ async fn run() -> Result<ExitStatus> {
|
|||
.map(RequirementsSource::from_overrides_txt)
|
||||
.collect::<Vec<_>>();
|
||||
let index_urls = IndexLocations::new(
|
||||
args.index_url.and_then(Maybe::into_option),
|
||||
args.extra_index_url
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect(),
|
||||
args.find_links,
|
||||
args.no_index,
|
||||
args.shared.index_url,
|
||||
args.shared.extra_index_url,
|
||||
args.shared.find_links,
|
||||
args.shared.no_index,
|
||||
);
|
||||
let extras = if args.all_extras {
|
||||
let extras = if args.shared.all_extras {
|
||||
ExtrasSpecification::All
|
||||
} else if args.extra.is_empty() {
|
||||
} else if args.shared.extra.is_empty() {
|
||||
ExtrasSpecification::None
|
||||
} else {
|
||||
ExtrasSpecification::Some(&args.extra)
|
||||
ExtrasSpecification::Some(&args.shared.extra)
|
||||
};
|
||||
let reinstall = Reinstall::from_args(args.reinstall, args.reinstall_package);
|
||||
let upgrade = Upgrade::from_args(args.upgrade, args.upgrade_package);
|
||||
let no_binary = NoBinary::from_args(args.no_binary);
|
||||
let no_build = NoBuild::from_args(args.only_binary, args.no_build);
|
||||
let dependency_mode = if args.no_deps {
|
||||
let no_binary = NoBinary::from_args(args.shared.no_binary);
|
||||
let no_build = NoBuild::from_args(args.shared.only_binary, args.shared.no_build);
|
||||
let dependency_mode = if args.shared.no_deps {
|
||||
DependencyMode::Direct
|
||||
} else {
|
||||
DependencyMode::Transitive
|
||||
};
|
||||
let prerelease = if args.pre {
|
||||
PreReleaseMode::Allow
|
||||
} else {
|
||||
args.prerelease
|
||||
};
|
||||
let setup_py = if args.legacy_setup_py {
|
||||
let setup_py = if args.shared.legacy_setup_py {
|
||||
SetupPyStrategy::Setuptools
|
||||
} else {
|
||||
SetupPyStrategy::Pep517
|
||||
};
|
||||
let config_settings = args.config_setting.into_iter().collect::<ConfigSettings>();
|
||||
|
||||
commands::pip_install(
|
||||
&requirements,
|
||||
&constraints,
|
||||
&overrides,
|
||||
&extras,
|
||||
args.resolution,
|
||||
prerelease,
|
||||
args.shared.resolution,
|
||||
args.shared.prerelease,
|
||||
dependency_mode,
|
||||
upgrade,
|
||||
index_urls,
|
||||
args.index_strategy,
|
||||
args.keyring_provider,
|
||||
args.shared.index_strategy,
|
||||
args.shared.keyring_provider,
|
||||
reinstall,
|
||||
args.link_mode,
|
||||
args.compile,
|
||||
args.require_hashes,
|
||||
args.shared.link_mode,
|
||||
args.shared.compile_bytecode,
|
||||
args.shared.require_hashes,
|
||||
setup_py,
|
||||
if args.offline {
|
||||
if args.shared.offline {
|
||||
Connectivity::Offline
|
||||
} else {
|
||||
Connectivity::Online
|
||||
},
|
||||
&config_settings,
|
||||
args.no_build_isolation,
|
||||
&args.shared.config_setting,
|
||||
args.shared.no_build_isolation,
|
||||
no_build,
|
||||
no_binary,
|
||||
args.strict,
|
||||
args.exclude_newer,
|
||||
args.python,
|
||||
args.system,
|
||||
args.break_system_packages,
|
||||
args.shared.strict,
|
||||
args.shared.exclude_newer,
|
||||
args.shared.python,
|
||||
args.shared.system,
|
||||
args.shared.break_system_packages,
|
||||
globals.native_tls,
|
||||
cache,
|
||||
args.dry_run,
|
||||
|
|
@ -414,6 +410,9 @@ async fn run() -> Result<ExitStatus> {
|
|||
Commands::Pip(PipNamespace {
|
||||
command: PipCommand::Uninstall(args),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipUninstallSettings::resolve(args, workspace);
|
||||
|
||||
let sources = args
|
||||
.package
|
||||
.into_iter()
|
||||
|
|
@ -426,61 +425,84 @@ async fn run() -> Result<ExitStatus> {
|
|||
.collect::<Vec<_>>();
|
||||
commands::pip_uninstall(
|
||||
&sources,
|
||||
args.python,
|
||||
args.system,
|
||||
args.break_system_packages,
|
||||
args.shared.python,
|
||||
args.shared.system,
|
||||
args.shared.break_system_packages,
|
||||
cache,
|
||||
if args.offline {
|
||||
if args.shared.offline {
|
||||
Connectivity::Offline
|
||||
} else {
|
||||
Connectivity::Online
|
||||
},
|
||||
globals.native_tls,
|
||||
args.keyring_provider,
|
||||
args.shared.keyring_provider,
|
||||
printer,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Commands::Pip(PipNamespace {
|
||||
command: PipCommand::Freeze(args),
|
||||
}) => commands::pip_freeze(
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipFreezeSettings::resolve(args, workspace);
|
||||
|
||||
commands::pip_freeze(
|
||||
args.exclude_editable,
|
||||
args.strict,
|
||||
args.python.as_deref(),
|
||||
args.system,
|
||||
args.shared.strict,
|
||||
args.shared.python.as_deref(),
|
||||
args.shared.system,
|
||||
&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, workspace);
|
||||
|
||||
commands::pip_list(
|
||||
args.editable,
|
||||
args.exclude_editable,
|
||||
&args.exclude,
|
||||
&args.format,
|
||||
args.strict,
|
||||
args.python.as_deref(),
|
||||
args.system,
|
||||
args.shared.strict,
|
||||
args.shared.python.as_deref(),
|
||||
args.shared.system,
|
||||
&cache,
|
||||
printer,
|
||||
)
|
||||
}
|
||||
Commands::Pip(PipNamespace {
|
||||
command: PipCommand::Show(args),
|
||||
}) => commands::pip_show(
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipShowSettings::resolve(args, workspace);
|
||||
|
||||
commands::pip_show(
|
||||
args.package,
|
||||
args.strict,
|
||||
args.python.as_deref(),
|
||||
args.system,
|
||||
args.shared.strict,
|
||||
args.shared.python.as_deref(),
|
||||
args.shared.system,
|
||||
&cache,
|
||||
printer,
|
||||
),
|
||||
)
|
||||
}
|
||||
Commands::Pip(PipNamespace {
|
||||
command: PipCommand::Check(args),
|
||||
}) => commands::pip_check(args.python.as_deref(), args.system, &cache, printer),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipCheckSettings::resolve(args, workspace);
|
||||
|
||||
commands::pip_check(
|
||||
args.shared.python.as_deref(),
|
||||
args.shared.system,
|
||||
&cache,
|
||||
printer,
|
||||
)
|
||||
}
|
||||
Commands::Cache(CacheNamespace {
|
||||
command: CacheCommand::Clean(args),
|
||||
})
|
||||
|
|
@ -497,15 +519,14 @@ async fn run() -> Result<ExitStatus> {
|
|||
Commands::Venv(args) => {
|
||||
args.compat_args.validate()?;
|
||||
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = settings::VenvSettings::resolve(args, workspace);
|
||||
|
||||
let index_locations = IndexLocations::new(
|
||||
args.index_url.and_then(Maybe::into_option),
|
||||
args.extra_index_url
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect(),
|
||||
// No find links for the venv subcommand, to keep things simple
|
||||
Vec::new(),
|
||||
args.no_index,
|
||||
args.shared.index_url,
|
||||
args.shared.extra_index_url,
|
||||
args.shared.find_links,
|
||||
args.shared.no_index,
|
||||
);
|
||||
|
||||
// Since we use ".venv" as the default name, we use "." as the default prompt.
|
||||
|
|
@ -519,20 +540,20 @@ async fn run() -> Result<ExitStatus> {
|
|||
|
||||
commands::venv(
|
||||
&args.name,
|
||||
args.python.as_deref(),
|
||||
args.link_mode,
|
||||
args.shared.python.as_deref(),
|
||||
args.shared.link_mode,
|
||||
&index_locations,
|
||||
args.index_strategy,
|
||||
args.keyring_provider,
|
||||
args.shared.index_strategy,
|
||||
args.shared.keyring_provider,
|
||||
uv_virtualenv::Prompt::from_args(prompt),
|
||||
args.system_site_packages,
|
||||
if args.offline {
|
||||
if args.shared.offline {
|
||||
Connectivity::Offline
|
||||
} else {
|
||||
Connectivity::Online
|
||||
},
|
||||
args.seed,
|
||||
args.exclude_newer,
|
||||
args.shared.exclude_newer,
|
||||
globals.native_tls,
|
||||
&cache,
|
||||
printer,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,840 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use distribution_types::{FlatIndexLocation, IndexUrl};
|
||||
use install_wheel_rs::linker::LinkMode;
|
||||
use uv_cache::CacheArgs;
|
||||
use uv_configuration::{ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier};
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_toolchain::PythonVersion;
|
||||
use uv_workspace::{PipOptions, Workspace};
|
||||
|
||||
use crate::cli::{
|
||||
ColorChoice, GlobalArgs, Maybe, PipCheckArgs, PipCompileArgs, PipFreezeArgs, PipInstallArgs,
|
||||
PipListArgs, PipShowArgs, PipSyncArgs, PipUninstallArgs, VenvArgs,
|
||||
};
|
||||
use crate::commands::ListFormat;
|
||||
|
||||
/// The resolved global settings to use for any invocation of the CLI.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct GlobalSettings {
|
||||
pub(crate) quiet: bool,
|
||||
pub(crate) verbose: u8,
|
||||
pub(crate) color: ColorChoice,
|
||||
pub(crate) native_tls: bool,
|
||||
}
|
||||
|
||||
impl GlobalSettings {
|
||||
/// Resolve the [`GlobalSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: GlobalArgs, workspace: Option<&Workspace>) -> Self {
|
||||
Self {
|
||||
quiet: args.quiet,
|
||||
verbose: args.verbose,
|
||||
color: if args.no_color {
|
||||
ColorChoice::Never
|
||||
} else {
|
||||
args.color
|
||||
},
|
||||
native_tls: args.native_tls
|
||||
|| workspace
|
||||
.and_then(|workspace| workspace.options.native_tls)
|
||||
.unwrap_or(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved cache settings to use for any invocation of the CLI.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct CacheSettings {
|
||||
pub(crate) no_cache: Option<bool>,
|
||||
pub(crate) cache_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl CacheSettings {
|
||||
/// Resolve the [`CacheSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: CacheArgs, workspace: Option<&Workspace>) -> Self {
|
||||
Self {
|
||||
no_cache: args
|
||||
.no_cache
|
||||
.or(workspace.and_then(|workspace| workspace.options.no_cache)),
|
||||
cache_dir: args
|
||||
.cache_dir
|
||||
.or_else(|| workspace.and_then(|workspace| workspace.options.cache_dir.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip compile` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipCompileSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) src_file: Vec<PathBuf>,
|
||||
pub(crate) constraint: Vec<PathBuf>,
|
||||
pub(crate) r#override: Vec<PathBuf>,
|
||||
pub(crate) refresh: bool,
|
||||
pub(crate) refresh_package: Vec<PackageName>,
|
||||
pub(crate) upgrade: bool,
|
||||
pub(crate) upgrade_package: Vec<PackageName>,
|
||||
|
||||
// Shared settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipCompileSettings {
|
||||
/// Resolve the [`PipCompileSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipCompileArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipCompileArgs {
|
||||
src_file,
|
||||
constraint,
|
||||
r#override,
|
||||
extra,
|
||||
all_extras,
|
||||
no_deps,
|
||||
resolution,
|
||||
prerelease,
|
||||
pre,
|
||||
output_file,
|
||||
no_strip_extras,
|
||||
no_annotate,
|
||||
no_header,
|
||||
annotation_style,
|
||||
custom_compile_command,
|
||||
offline,
|
||||
refresh,
|
||||
refresh_package,
|
||||
link_mode,
|
||||
index_url,
|
||||
extra_index_url,
|
||||
no_index,
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
find_links,
|
||||
upgrade,
|
||||
upgrade_package,
|
||||
generate_hashes,
|
||||
legacy_setup_py,
|
||||
no_build_isolation,
|
||||
no_build,
|
||||
only_binary,
|
||||
config_setting,
|
||||
python_version,
|
||||
exclude_newer,
|
||||
no_emit_package,
|
||||
emit_index_url,
|
||||
emit_find_links,
|
||||
emit_marker_expression,
|
||||
emit_index_annotation,
|
||||
compat_args: _,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
src_file,
|
||||
constraint,
|
||||
r#override,
|
||||
refresh,
|
||||
refresh_package: refresh_package.unwrap_or_default(),
|
||||
upgrade,
|
||||
upgrade_package: upgrade_package.unwrap_or_default(),
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
offline: Some(offline),
|
||||
index_url: index_url.and_then(Maybe::into_option),
|
||||
extra_index_url: extra_index_url.map(|extra_index_urls| {
|
||||
extra_index_urls
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect()
|
||||
}),
|
||||
no_index: Some(no_index),
|
||||
find_links,
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
no_build: Some(no_build),
|
||||
only_binary,
|
||||
no_build_isolation: Some(no_build_isolation),
|
||||
extra,
|
||||
all_extras: Some(all_extras),
|
||||
no_deps: Some(no_deps),
|
||||
resolution,
|
||||
prerelease: if pre {
|
||||
Some(PreReleaseMode::Allow)
|
||||
} else {
|
||||
prerelease
|
||||
},
|
||||
output_file,
|
||||
no_strip_extras: Some(no_strip_extras),
|
||||
no_annotate: Some(no_annotate),
|
||||
no_header: Some(no_header),
|
||||
custom_compile_command,
|
||||
generate_hashes: Some(generate_hashes),
|
||||
legacy_setup_py: Some(legacy_setup_py),
|
||||
config_settings: config_setting.map(|config_settings| {
|
||||
config_settings.into_iter().collect::<ConfigSettings>()
|
||||
}),
|
||||
python_version,
|
||||
exclude_newer,
|
||||
no_emit_package,
|
||||
emit_index_url: Some(emit_index_url),
|
||||
emit_find_links: Some(emit_find_links),
|
||||
emit_marker_expression: Some(emit_marker_expression),
|
||||
emit_index_annotation: Some(emit_index_annotation),
|
||||
annotation_style,
|
||||
link_mode,
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip sync` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipSyncSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) src_file: Vec<PathBuf>,
|
||||
pub(crate) reinstall: bool,
|
||||
pub(crate) reinstall_package: Vec<PackageName>,
|
||||
pub(crate) refresh: bool,
|
||||
pub(crate) refresh_package: Vec<PackageName>,
|
||||
|
||||
// Shared settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipSyncSettings {
|
||||
/// Resolve the [`PipSyncSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipSyncArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipSyncArgs {
|
||||
src_file,
|
||||
reinstall,
|
||||
reinstall_package,
|
||||
offline,
|
||||
refresh,
|
||||
refresh_package,
|
||||
link_mode,
|
||||
index_url,
|
||||
extra_index_url,
|
||||
find_links,
|
||||
no_index,
|
||||
index_strategy,
|
||||
require_hashes,
|
||||
keyring_provider,
|
||||
python,
|
||||
system,
|
||||
break_system_packages,
|
||||
legacy_setup_py,
|
||||
no_build_isolation,
|
||||
no_build,
|
||||
no_binary,
|
||||
only_binary,
|
||||
compile,
|
||||
no_compile: _,
|
||||
config_setting,
|
||||
strict,
|
||||
compat_args: _,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
src_file,
|
||||
reinstall,
|
||||
reinstall_package,
|
||||
refresh,
|
||||
refresh_package,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
break_system_packages: Some(break_system_packages),
|
||||
offline: Some(offline),
|
||||
index_url: index_url.and_then(Maybe::into_option),
|
||||
extra_index_url: extra_index_url.map(|extra_index_urls| {
|
||||
extra_index_urls
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect()
|
||||
}),
|
||||
no_index: Some(no_index),
|
||||
find_links,
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
no_build: Some(no_build),
|
||||
no_binary,
|
||||
only_binary,
|
||||
no_build_isolation: Some(no_build_isolation),
|
||||
strict: Some(strict),
|
||||
legacy_setup_py: Some(legacy_setup_py),
|
||||
config_settings: config_setting.map(|config_settings| {
|
||||
config_settings.into_iter().collect::<ConfigSettings>()
|
||||
}),
|
||||
link_mode,
|
||||
compile_bytecode: Some(compile),
|
||||
require_hashes: Some(require_hashes),
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip install` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipInstallSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) package: Vec<String>,
|
||||
pub(crate) requirement: Vec<PathBuf>,
|
||||
pub(crate) editable: Vec<String>,
|
||||
pub(crate) constraint: Vec<PathBuf>,
|
||||
pub(crate) r#override: Vec<PathBuf>,
|
||||
pub(crate) upgrade: bool,
|
||||
pub(crate) upgrade_package: Vec<PackageName>,
|
||||
pub(crate) reinstall: bool,
|
||||
pub(crate) reinstall_package: Vec<PackageName>,
|
||||
pub(crate) refresh: bool,
|
||||
pub(crate) refresh_package: Vec<PackageName>,
|
||||
pub(crate) dry_run: bool,
|
||||
// Shared settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipInstallSettings {
|
||||
/// Resolve the [`PipInstallSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipInstallArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipInstallArgs {
|
||||
package,
|
||||
requirement,
|
||||
editable,
|
||||
constraint,
|
||||
r#override,
|
||||
extra,
|
||||
all_extras,
|
||||
upgrade,
|
||||
upgrade_package,
|
||||
reinstall,
|
||||
reinstall_package,
|
||||
offline,
|
||||
refresh,
|
||||
refresh_package,
|
||||
no_deps,
|
||||
link_mode,
|
||||
resolution,
|
||||
prerelease,
|
||||
pre,
|
||||
index_url,
|
||||
extra_index_url,
|
||||
find_links,
|
||||
no_index,
|
||||
index_strategy,
|
||||
require_hashes,
|
||||
keyring_provider,
|
||||
python,
|
||||
system,
|
||||
break_system_packages,
|
||||
legacy_setup_py,
|
||||
no_build_isolation,
|
||||
no_build,
|
||||
no_binary,
|
||||
only_binary,
|
||||
compile,
|
||||
no_compile: _,
|
||||
config_setting,
|
||||
strict,
|
||||
exclude_newer,
|
||||
dry_run,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
package,
|
||||
requirement,
|
||||
editable,
|
||||
constraint,
|
||||
r#override,
|
||||
upgrade,
|
||||
upgrade_package: upgrade_package.unwrap_or_default(),
|
||||
reinstall,
|
||||
reinstall_package: reinstall_package.unwrap_or_default(),
|
||||
refresh,
|
||||
refresh_package: refresh_package.unwrap_or_default(),
|
||||
dry_run,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
break_system_packages: Some(break_system_packages),
|
||||
offline: Some(offline),
|
||||
index_url: index_url.and_then(Maybe::into_option),
|
||||
extra_index_url: extra_index_url.map(|extra_index_urls| {
|
||||
extra_index_urls
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect()
|
||||
}),
|
||||
no_index: Some(no_index),
|
||||
find_links,
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
no_build: Some(no_build),
|
||||
no_binary,
|
||||
only_binary,
|
||||
no_build_isolation: Some(no_build_isolation),
|
||||
strict: Some(strict),
|
||||
extra,
|
||||
all_extras: Some(all_extras),
|
||||
no_deps: Some(no_deps),
|
||||
resolution,
|
||||
prerelease: if pre {
|
||||
Some(PreReleaseMode::Allow)
|
||||
} else {
|
||||
prerelease
|
||||
},
|
||||
legacy_setup_py: Some(legacy_setup_py),
|
||||
config_settings: config_setting.map(|config_settings| {
|
||||
config_settings.into_iter().collect::<ConfigSettings>()
|
||||
}),
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
compile_bytecode: Some(compile),
|
||||
require_hashes: Some(require_hashes),
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip uninstall` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipUninstallSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) package: Vec<String>,
|
||||
pub(crate) requirement: Vec<PathBuf>,
|
||||
// Shared settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipUninstallSettings {
|
||||
/// Resolve the [`PipUninstallSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipUninstallArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipUninstallArgs {
|
||||
package,
|
||||
requirement,
|
||||
python,
|
||||
keyring_provider,
|
||||
system,
|
||||
break_system_packages,
|
||||
offline,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
package,
|
||||
requirement,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
break_system_packages: Some(break_system_packages),
|
||||
offline: Some(offline),
|
||||
keyring_provider,
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip freeze` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipFreezeSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) exclude_editable: bool,
|
||||
// Shared settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipFreezeSettings {
|
||||
/// Resolve the [`PipFreezeSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipFreezeArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipFreezeArgs {
|
||||
exclude_editable,
|
||||
strict,
|
||||
python,
|
||||
system,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
exclude_editable,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
strict: Some(strict),
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip list` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipListSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) editable: bool,
|
||||
pub(crate) exclude_editable: bool,
|
||||
pub(crate) exclude: Vec<PackageName>,
|
||||
pub(crate) format: ListFormat,
|
||||
|
||||
// CLI-only settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipListSettings {
|
||||
/// Resolve the [`PipListSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipListArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipListArgs {
|
||||
editable,
|
||||
exclude_editable,
|
||||
exclude,
|
||||
format,
|
||||
strict,
|
||||
python,
|
||||
system,
|
||||
compat_args: _,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
editable,
|
||||
exclude_editable,
|
||||
exclude,
|
||||
format,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
strict: Some(strict),
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip show` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipShowSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) package: Vec<PackageName>,
|
||||
|
||||
// CLI-only settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipShowSettings {
|
||||
/// Resolve the [`PipShowSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipShowArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipShowArgs {
|
||||
package,
|
||||
strict,
|
||||
python,
|
||||
system,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
package,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
strict: Some(strict),
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip check` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipCheckSettings {
|
||||
// CLI-only settings.
|
||||
|
||||
// Shared settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl PipCheckSettings {
|
||||
/// Resolve the [`PipCheckSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: PipCheckArgs, workspace: Option<Workspace>) -> Self {
|
||||
let PipCheckArgs { python, system } = args;
|
||||
|
||||
Self {
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `pip check` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct VenvSettings {
|
||||
// CLI-only settings.
|
||||
pub(crate) seed: bool,
|
||||
pub(crate) name: PathBuf,
|
||||
pub(crate) prompt: Option<String>,
|
||||
pub(crate) system_site_packages: bool,
|
||||
|
||||
// CLI-only settings.
|
||||
pub(crate) shared: PipSharedSettings,
|
||||
}
|
||||
|
||||
impl VenvSettings {
|
||||
/// Resolve the [`VenvSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn resolve(args: VenvArgs, workspace: Option<Workspace>) -> Self {
|
||||
let VenvArgs {
|
||||
python,
|
||||
system,
|
||||
seed,
|
||||
name,
|
||||
prompt,
|
||||
system_site_packages,
|
||||
link_mode,
|
||||
index_url,
|
||||
extra_index_url,
|
||||
no_index,
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
offline,
|
||||
exclude_newer,
|
||||
compat_args: _,
|
||||
} = args;
|
||||
|
||||
Self {
|
||||
// CLI-only settings.
|
||||
seed,
|
||||
name,
|
||||
prompt,
|
||||
system_site_packages,
|
||||
|
||||
// Shared settings.
|
||||
shared: PipSharedSettings::combine(
|
||||
PipOptions {
|
||||
python,
|
||||
system: Some(system),
|
||||
offline: Some(offline),
|
||||
index_url: index_url.and_then(Maybe::into_option),
|
||||
extra_index_url: extra_index_url.map(|extra_index_urls| {
|
||||
extra_index_urls
|
||||
.into_iter()
|
||||
.filter_map(Maybe::into_option)
|
||||
.collect()
|
||||
}),
|
||||
no_index: Some(no_index),
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
..PipOptions::default()
|
||||
},
|
||||
workspace,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for an invocation of the `pip` CLI.
|
||||
///
|
||||
/// Represents the shared settings that are used across all `pip` commands.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct PipSharedSettings {
|
||||
pub(crate) python: Option<String>,
|
||||
pub(crate) system: bool,
|
||||
pub(crate) break_system_packages: bool,
|
||||
pub(crate) offline: bool,
|
||||
pub(crate) index_url: Option<IndexUrl>,
|
||||
pub(crate) extra_index_url: Vec<IndexUrl>,
|
||||
pub(crate) no_index: bool,
|
||||
pub(crate) find_links: Vec<FlatIndexLocation>,
|
||||
pub(crate) index_strategy: IndexStrategy,
|
||||
pub(crate) keyring_provider: KeyringProviderType,
|
||||
pub(crate) no_build: bool,
|
||||
pub(crate) no_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) only_binary: Vec<PackageNameSpecifier>,
|
||||
pub(crate) no_build_isolation: bool,
|
||||
pub(crate) strict: bool,
|
||||
pub(crate) extra: Vec<ExtraName>,
|
||||
pub(crate) all_extras: bool,
|
||||
pub(crate) no_deps: bool,
|
||||
pub(crate) resolution: ResolutionMode,
|
||||
pub(crate) prerelease: PreReleaseMode,
|
||||
pub(crate) output_file: Option<PathBuf>,
|
||||
pub(crate) no_strip_extras: bool,
|
||||
pub(crate) no_annotate: bool,
|
||||
pub(crate) no_header: bool,
|
||||
pub(crate) custom_compile_command: Option<String>,
|
||||
pub(crate) generate_hashes: bool,
|
||||
pub(crate) legacy_setup_py: bool,
|
||||
pub(crate) config_setting: ConfigSettings,
|
||||
pub(crate) python_version: Option<PythonVersion>,
|
||||
pub(crate) exclude_newer: Option<ExcludeNewer>,
|
||||
pub(crate) no_emit_package: Vec<PackageName>,
|
||||
pub(crate) emit_index_url: bool,
|
||||
pub(crate) emit_find_links: bool,
|
||||
pub(crate) emit_marker_expression: bool,
|
||||
pub(crate) emit_index_annotation: bool,
|
||||
pub(crate) annotation_style: AnnotationStyle,
|
||||
pub(crate) link_mode: LinkMode,
|
||||
pub(crate) compile_bytecode: bool,
|
||||
pub(crate) require_hashes: bool,
|
||||
}
|
||||
|
||||
impl PipSharedSettings {
|
||||
/// Resolve the [`PipSharedSettings`] from the CLI and workspace configuration.
|
||||
pub(crate) fn combine(args: PipOptions, workspace: Option<Workspace>) -> Self {
|
||||
let PipOptions {
|
||||
python,
|
||||
system,
|
||||
break_system_packages,
|
||||
offline,
|
||||
index_url,
|
||||
extra_index_url,
|
||||
no_index,
|
||||
find_links,
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
no_build,
|
||||
no_binary,
|
||||
only_binary,
|
||||
no_build_isolation,
|
||||
strict,
|
||||
extra,
|
||||
all_extras,
|
||||
no_deps,
|
||||
resolution,
|
||||
prerelease,
|
||||
output_file,
|
||||
no_strip_extras,
|
||||
no_annotate,
|
||||
no_header,
|
||||
custom_compile_command,
|
||||
generate_hashes,
|
||||
legacy_setup_py,
|
||||
config_settings,
|
||||
python_version,
|
||||
exclude_newer,
|
||||
no_emit_package,
|
||||
emit_index_url,
|
||||
emit_find_links,
|
||||
emit_marker_expression,
|
||||
emit_index_annotation,
|
||||
annotation_style,
|
||||
link_mode,
|
||||
compile_bytecode,
|
||||
require_hashes,
|
||||
} = workspace
|
||||
.and_then(|workspace| workspace.options.pip)
|
||||
.unwrap_or_default();
|
||||
|
||||
Self {
|
||||
extra: args.extra.or(extra).unwrap_or_default(),
|
||||
all_extras: args.all_extras.unwrap_or(false) || all_extras.unwrap_or(false),
|
||||
no_deps: args.no_deps.unwrap_or(false) || no_deps.unwrap_or(false),
|
||||
resolution: args.resolution.or(resolution).unwrap_or_default(),
|
||||
prerelease: args.prerelease.or(prerelease).unwrap_or_default(),
|
||||
output_file: args.output_file.or(output_file),
|
||||
no_strip_extras: args.no_strip_extras.unwrap_or(false)
|
||||
|| no_strip_extras.unwrap_or(false),
|
||||
no_annotate: args.no_annotate.unwrap_or(false) || no_annotate.unwrap_or(false),
|
||||
no_header: args.no_header.unwrap_or(false) || no_header.unwrap_or(false),
|
||||
custom_compile_command: args.custom_compile_command.or(custom_compile_command),
|
||||
annotation_style: args
|
||||
.annotation_style
|
||||
.or(annotation_style)
|
||||
.unwrap_or_default(),
|
||||
offline: args.offline.unwrap_or(false) || offline.unwrap_or(false),
|
||||
index_url: args.index_url.or(index_url),
|
||||
extra_index_url: args.extra_index_url.or(extra_index_url).unwrap_or_default(),
|
||||
no_index: args.no_index.unwrap_or(false) || no_index.unwrap_or(false),
|
||||
index_strategy: args.index_strategy.or(index_strategy).unwrap_or_default(),
|
||||
keyring_provider: args
|
||||
.keyring_provider
|
||||
.or(keyring_provider)
|
||||
.unwrap_or_default(),
|
||||
find_links: args.find_links.or(find_links).unwrap_or_default(),
|
||||
generate_hashes: args.generate_hashes.unwrap_or(false)
|
||||
|| generate_hashes.unwrap_or(false),
|
||||
legacy_setup_py: args.legacy_setup_py.unwrap_or(false)
|
||||
|| legacy_setup_py.unwrap_or(false),
|
||||
no_build_isolation: args.no_build_isolation.unwrap_or(false)
|
||||
|| no_build_isolation.unwrap_or(false),
|
||||
no_build: args.no_build.unwrap_or(false) || no_build.unwrap_or(false),
|
||||
only_binary: args.only_binary.or(only_binary).unwrap_or_default(),
|
||||
config_setting: args.config_settings.or(config_settings).unwrap_or_default(),
|
||||
python_version: args.python_version.or(python_version),
|
||||
exclude_newer: args.exclude_newer.or(exclude_newer),
|
||||
no_emit_package: args.no_emit_package.or(no_emit_package).unwrap_or_default(),
|
||||
emit_index_url: args.emit_index_url.unwrap_or(false) || emit_index_url.unwrap_or(false),
|
||||
emit_find_links: args.emit_find_links.unwrap_or(false)
|
||||
|| emit_find_links.unwrap_or(false),
|
||||
emit_marker_expression: args.emit_marker_expression.unwrap_or(false)
|
||||
|| emit_marker_expression.unwrap_or(false),
|
||||
emit_index_annotation: args.emit_index_annotation.unwrap_or(false)
|
||||
|| emit_index_annotation.unwrap_or(false),
|
||||
link_mode: args.link_mode.or(link_mode).unwrap_or_default(),
|
||||
require_hashes: args.require_hashes.unwrap_or(false) || require_hashes.unwrap_or(false),
|
||||
python: args.python.or(python),
|
||||
system: args.system.unwrap_or(false) || system.unwrap_or(false),
|
||||
break_system_packages: args.break_system_packages.unwrap_or(false)
|
||||
|| break_system_packages.unwrap_or(false),
|
||||
no_binary: args.no_binary.or(no_binary).unwrap_or_default(),
|
||||
compile_bytecode: args.compile_bytecode.unwrap_or(false)
|
||||
|| compile_bytecode.unwrap_or(false),
|
||||
strict: args.strict.unwrap_or(false) || strict.unwrap_or(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue