From af4ed30d66b91cc459e242d306c749c6501aaa70 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 6 Sep 2024 16:58:57 -0400 Subject: [PATCH] Move crate --- Cargo.lock | 24 +++++-- Cargo.toml | 1 + crates/distribution-types/Cargo.toml | 4 +- crates/distribution-types/src/cached.rs | 5 +- crates/distribution-types/src/installed.rs | 14 ++-- crates/distribution-types/src/lib.rs | 5 -- crates/install-wheel-rs/Cargo.toml | 2 +- crates/install-wheel-rs/Readme.md | 16 +---- crates/install-wheel-rs/src/linker.rs | 2 +- crates/install-wheel-rs/src/wheel.rs | 9 ++- crates/pypi-types/Cargo.toml | 2 - crates/uv-cache-info/Cargo.toml | 19 ++++++ .../src/cache_info.rs | 65 ++++++------------- .../src/commit_info.rs | 4 +- crates/uv-cache-info/src/lib.rs | 6 ++ .../src/timestamp.rs | 0 crates/uv-cache/Cargo.toml | 1 + crates/uv-cache/src/by_timestamp.rs | 2 +- crates/uv-cache/src/lib.rs | 3 +- crates/uv-configuration/Cargo.toml | 1 + .../uv-configuration/src/config_settings.rs | 2 + .../uv-configuration/src/package_options.rs | 2 +- crates/uv-distribution/Cargo.toml | 1 + .../src/distribution_database.rs | 5 +- crates/uv-distribution/src/download.rs | 6 +- .../src/index/built_wheel_index.rs | 3 +- .../uv-distribution/src/index/cached_wheel.rs | 8 +-- .../src/source/built_wheel_metadata.rs | 3 +- crates/uv-distribution/src/source/mod.rs | 22 ++++--- crates/uv-installer/Cargo.toml | 1 + crates/uv-installer/src/plan.rs | 7 +- crates/uv-installer/src/satisfies.rs | 25 ++++--- crates/uv-python/Cargo.toml | 2 +- crates/uv-python/src/interpreter.rs | 2 +- crates/uv-settings/Cargo.toml | 1 + crates/uv-settings/src/settings.rs | 4 +- crates/uv-types/src/traits.rs | 1 + crates/uv/Cargo.toml | 1 + crates/uv/src/commands/tool/install.rs | 3 +- crates/uv/src/commands/tool/run.rs | 3 +- crates/uv/src/lib.rs | 2 +- crates/uv/tests/pip_install.rs | 4 +- docs/concepts/cache.md | 29 +++++++-- .../build/lib/setuptools_editable/__init__.py | 2 - uv.schema.json | 45 +++++++++++++ 45 files changed, 227 insertions(+), 142 deletions(-) create mode 100644 crates/uv-cache-info/Cargo.toml rename crates/{distribution-types => uv-cache-info}/src/cache_info.rs (74%) rename crates/{distribution-types => uv-cache-info}/src/commit_info.rs (95%) create mode 100644 crates/uv-cache-info/src/lib.rs rename crates/{distribution-types => uv-cache-info}/src/timestamp.rs (100%) delete mode 100644 scripts/packages/setuptools_editable/build/lib/setuptools_editable/__init__.py diff --git a/Cargo.lock b/Cargo.lock index 4ac419417b77..4b1ab17fb8f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1055,10 +1055,10 @@ dependencies = [ "serde", "serde_json", "thiserror", - "toml", "tracing", "url", "urlencoding", + "uv-cache-info", "uv-fs", "uv-git", "uv-normalize", @@ -1773,7 +1773,6 @@ dependencies = [ "csv", "data-encoding", "distribution-filename", - "distribution-types", "fs-err", "indoc", "mailparse", @@ -1792,6 +1791,7 @@ dependencies = [ "tempfile", "thiserror", "tracing", + "uv-cache-info", "uv-fs", "uv-normalize", "uv-warnings", @@ -2799,7 +2799,6 @@ name = "pypi-types" version = "0.0.1" dependencies = [ "anyhow", - "cache-key", "distribution-filename", "indexmap", "itertools 0.13.0", @@ -2810,7 +2809,6 @@ dependencies = [ "regex", "rkyv", "serde", - "serde_json", "thiserror", "toml", "tracing", @@ -4512,6 +4510,7 @@ dependencies = [ "url", "uv-auth", "uv-cache", + "uv-cache-info", "uv-cli", "uv-client", "uv-configuration", @@ -4609,11 +4608,22 @@ dependencies = [ "tempfile", "tracing", "url", + "uv-cache-info", "uv-fs", "uv-normalize", "walkdir", ] +[[package]] +name = "uv-cache-info" +version = "0.0.1" +dependencies = [ + "fs-err", + "schemars", + "serde", + "toml", +] + [[package]] name = "uv-cli" version = "0.0.1" @@ -4711,6 +4721,7 @@ dependencies = [ "url", "uv-auth", "uv-cache", + "uv-cache-info", "uv-normalize", ] @@ -4809,6 +4820,7 @@ dependencies = [ "tracing", "url", "uv-cache", + "uv-cache-info", "uv-client", "uv-configuration", "uv-extract", @@ -4912,6 +4924,7 @@ dependencies = [ "tracing", "url", "uv-cache", + "uv-cache-info", "uv-configuration", "uv-distribution", "uv-extract", @@ -4970,7 +4983,6 @@ dependencies = [ "clap", "configparser", "distribution-filename", - "distribution-types", "fs-err", "futures", "goblin", @@ -5001,6 +5013,7 @@ dependencies = [ "tracing", "url", "uv-cache", + "uv-cache-info", "uv-client", "uv-extract", "uv-fs", @@ -5134,6 +5147,7 @@ dependencies = [ "thiserror", "toml", "tracing", + "uv-cache-info", "uv-configuration", "uv-fs", "uv-macros", diff --git a/Cargo.toml b/Cargo.toml index d22e30e2b26f..c7cf995ad28e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ requirements-txt = { path = "crates/requirements-txt" } uv-auth = { path = "crates/uv-auth" } uv-build = { path = "crates/uv-build" } uv-cache = { path = "crates/uv-cache" } +uv-cache-info = { path = "crates/uv-cache-info" } uv-cli = { path = "crates/uv-cli" } uv-client = { path = "crates/uv-client" } uv-configuration = { path = "crates/uv-configuration" } diff --git a/crates/distribution-types/Cargo.toml b/crates/distribution-types/Cargo.toml index abcb1f77052d..b1791fce4b7c 100644 --- a/crates/distribution-types/Cargo.toml +++ b/crates/distribution-types/Cargo.toml @@ -19,6 +19,7 @@ pep440_rs = { workspace = true } pep508_rs = { workspace = true, features = ["serde"] } platform-tags = { workspace = true } pypi-types = { workspace = true } +uv-cache-info = { workspace = true } uv-fs = { workspace = true } uv-git = { workspace = true } uv-normalize = { workspace = true } @@ -32,7 +33,6 @@ schemars = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } thiserror = { workspace = true } -toml = { workspace = true } tracing = { workspace = true } url = { workspace = true } -urlencoding = { workspace = true } \ No newline at end of file +urlencoding = { workspace = true } diff --git a/crates/distribution-types/src/cached.rs b/crates/distribution-types/src/cached.rs index 1384ebe58afd..eb00a7598f4e 100644 --- a/crates/distribution-types/src/cached.rs +++ b/crates/distribution-types/src/cached.rs @@ -5,11 +5,12 @@ use anyhow::{anyhow, Result}; use distribution_filename::WheelFilename; use pep508_rs::VerbatimUrl; use pypi_types::{HashDigest, ParsedDirectoryUrl}; +use uv_cache_info::CacheInfo; use uv_normalize::PackageName; use crate::{ - BuiltDist, CacheInfo, Dist, DistributionMetadata, Hashed, InstalledMetadata, InstalledVersion, - Name, ParsedUrl, SourceDist, VersionOrUrlRef, + BuiltDist, Dist, DistributionMetadata, Hashed, InstalledMetadata, InstalledVersion, Name, + ParsedUrl, SourceDist, VersionOrUrlRef, }; /// A built distribution (wheel) that exists in the local cache. diff --git a/crates/distribution-types/src/installed.rs b/crates/distribution-types/src/installed.rs index 5fc14fb46ada..2cdac4802081 100644 --- a/crates/distribution-types/src/installed.rs +++ b/crates/distribution-types/src/installed.rs @@ -10,10 +10,10 @@ use url::Url; use distribution_filename::EggInfoFilename; use pep440_rs::Version; use pypi_types::DirectUrl; +use uv_cache_info::CacheInfo; use uv_fs::Simplified; use uv_normalize::PackageName; -use crate::cache_info::CacheInfo; use crate::{DistributionMetadata, InstalledMetadata, InstalledVersion, Name, VersionOrUrlRef}; /// A built distribution (wheel) that is installed in a virtual environment. @@ -36,7 +36,7 @@ pub struct InstalledRegistryDist { pub name: PackageName, pub version: Version, pub path: PathBuf, - pub cache: Option, + pub cache_info: Option, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -47,7 +47,7 @@ pub struct InstalledDirectUrlDist { pub url: Url, pub editable: bool, pub path: PathBuf, - pub cache: Option, + pub cache_info: Option, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -93,7 +93,7 @@ impl InstalledDist { let name = PackageName::from_str(name)?; let version = Version::from_str(version).map_err(|err| anyhow!(err))?; - let cache = Self::cache_info(path)?; + let cache_info = Self::cache_info(path)?; return if let Some(direct_url) = Self::direct_url(path)? { match Url::try_from(&direct_url) { @@ -104,7 +104,7 @@ impl InstalledDist { direct_url: Box::new(direct_url), url, path: path.to_path_buf(), - cache, + cache_info, }))), Err(err) => { warn!("Failed to parse direct URL: {err}"); @@ -112,7 +112,7 @@ impl InstalledDist { name, version, path: path.to_path_buf(), - cache, + cache_info, }))) } } @@ -121,7 +121,7 @@ impl InstalledDist { name, version, path: path.to_path_buf(), - cache, + cache_info, }))) }; } diff --git a/crates/distribution-types/src/lib.rs b/crates/distribution-types/src/lib.rs index 98bacc3a53f7..c1771ef34c35 100644 --- a/crates/distribution-types/src/lib.rs +++ b/crates/distribution-types/src/lib.rs @@ -50,7 +50,6 @@ use uv_normalize::PackageName; pub use crate::annotation::*; pub use crate::any::*; pub use crate::buildable::*; -pub use crate::cache_info::*; pub use crate::cached::*; pub use crate::diagnostic::*; pub use crate::error::*; @@ -63,15 +62,12 @@ pub use crate::prioritized_distribution::*; pub use crate::resolution::*; pub use crate::resolved::*; pub use crate::specified_requirement::*; -pub use crate::timestamp::*; pub use crate::traits::*; mod annotation; mod any; mod buildable; -mod cache_info; mod cached; -mod commit_info; mod diagnostic; mod error; mod file; @@ -83,7 +79,6 @@ mod prioritized_distribution; mod resolution; mod resolved; mod specified_requirement; -mod timestamp; mod traits; #[derive(Debug, Clone)] diff --git a/crates/install-wheel-rs/Cargo.toml b/crates/install-wheel-rs/Cargo.toml index 9374b6bcc293..a52045ba2e95 100644 --- a/crates/install-wheel-rs/Cargo.toml +++ b/crates/install-wheel-rs/Cargo.toml @@ -21,10 +21,10 @@ name = "install_wheel_rs" [dependencies] distribution-filename = { workspace = true } -distribution-types = { workspace = true } pep440_rs = { workspace = true } platform-tags = { workspace = true } pypi-types = { workspace = true } +uv-cache-info = { workspace = true } uv-fs = { workspace = true } uv-normalize = { workspace = true } uv-warnings = { workspace = true } diff --git a/crates/install-wheel-rs/Readme.md b/crates/install-wheel-rs/Readme.md index 178bb861d78a..f339a109b33a 100644 --- a/crates/install-wheel-rs/Readme.md +++ b/crates/install-wheel-rs/Readme.md @@ -1,15 +1,3 @@ -Reimplementation of wheel installing in rust. Supports both classical venvs and monotrail. +# install-wheel-rs -There are simple python bindings: - -```python -from install_wheel_rs import LockedVenv - -locked_venv = LockedVenv("path/to/.venv") -locked_venv.install_wheel("path/to/some_tagged_wheel.whl") -``` - -and there's only one function: `install_wheels_venv(wheels: List[str], venv: str)`, where `wheels` -is a list of paths to wheel files and `venv` is the location of the venv to install the packages in. - -See monotrail for benchmarks. +Reimplementation of wheel installing in Rust. diff --git a/crates/install-wheel-rs/src/linker.rs b/crates/install-wheel-rs/src/linker.rs index 62defa147a9b..9226474f60a4 100644 --- a/crates/install-wheel-rs/src/linker.rs +++ b/crates/install-wheel-rs/src/linker.rs @@ -12,7 +12,6 @@ use crate::wheel::{ }; use crate::{Error, Layout}; use distribution_filename::WheelFilename; -use distribution_types::CacheInfo; use fs_err as fs; use fs_err::{DirEntry, File}; use pypi_types::{DirectUrl, Metadata12}; @@ -21,6 +20,7 @@ use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use tempfile::tempdir_in; use tracing::{debug, instrument}; +use uv_cache_info::CacheInfo; use uv_warnings::warn_user_once; use walkdir::WalkDir; diff --git a/crates/install-wheel-rs/src/wheel.rs b/crates/install-wheel-rs/src/wheel.rs index 47fff1400ce7..13e73a126a98 100644 --- a/crates/install-wheel-rs/src/wheel.rs +++ b/crates/install-wheel-rs/src/wheel.rs @@ -3,8 +3,10 @@ use std::io::{BufReader, Cursor, Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::{env, io}; +use crate::record::RecordEntry; +use crate::script::Script; +use crate::{Error, Layout}; use data_encoding::BASE64URL_NOPAD; -use distribution_types::CacheInfo; use fs_err as fs; use fs_err::{DirEntry, File}; use mailparse::parse_headers; @@ -12,16 +14,13 @@ use pypi_types::DirectUrl; use rustc_hash::FxHashMap; use sha2::{Digest, Sha256}; use tracing::{instrument, warn}; +use uv_cache_info::CacheInfo; use uv_fs::{relative_to, Simplified}; use uv_normalize::PackageName; use walkdir::WalkDir; use zip::write::FileOptions; use zip::ZipWriter; -use crate::record::RecordEntry; -use crate::script::Script; -use crate::{Error, Layout}; - const LAUNCHER_MAGIC_NUMBER: [u8; 4] = [b'U', b'V', b'U', b'V']; #[cfg(all(windows, target_arch = "x86"))] diff --git a/crates/pypi-types/Cargo.toml b/crates/pypi-types/Cargo.toml index 87d941f31dfa..5e3b42fbcf62 100644 --- a/crates/pypi-types/Cargo.toml +++ b/crates/pypi-types/Cargo.toml @@ -13,7 +13,6 @@ license = { workspace = true } workspace = true [dependencies] -cache-key = { workspace = true } distribution-filename = { workspace = true } pep440_rs = { workspace = true } pep508_rs = { workspace = true } @@ -28,7 +27,6 @@ mailparse = { workspace = true } regex = { workspace = true } rkyv = { workspace = true } serde = { workspace = true } -serde_json = { workspace = true } thiserror = { workspace = true } toml = { workspace = true } tracing = { workspace = true } diff --git a/crates/uv-cache-info/Cargo.toml b/crates/uv-cache-info/Cargo.toml new file mode 100644 index 000000000000..059352554062 --- /dev/null +++ b/crates/uv-cache-info/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "uv-cache-info" +version = "0.0.1" +edition = { workspace = true } +rust-version = { workspace = true } +homepage = { workspace = true } +documentation = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +fs-err = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +toml = { workspace = true } diff --git a/crates/distribution-types/src/cache_info.rs b/crates/uv-cache-info/src/cache_info.rs similarity index 74% rename from crates/distribution-types/src/cache_info.rs rename to crates/uv-cache-info/src/cache_info.rs index 4e5e8182d585..c0e92c056c49 100644 --- a/crates/distribution-types/src/cache_info.rs +++ b/crates/uv-cache-info/src/cache_info.rs @@ -7,6 +7,7 @@ use std::io; use std::path::{Path, PathBuf}; #[derive(Default, Debug, Clone, Hash, PartialEq, Eq, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "kebab-case")] #[serde(try_from = "CacheInfoWire")] pub struct CacheInfo { timestamp: Option, @@ -82,18 +83,20 @@ impl CacheInfo { // Incorporate any additional timestamps or VCS information. for cache_key in &cache_keys { match cache_key { - CacheKey::File(path) => { - let key_timestamp = path - .metadata() - .ok() - .filter(std::fs::Metadata::is_file) - .as_ref() - .map(Timestamp::from_metadata); - timestamp = max(timestamp, key_timestamp); + CacheKey::Path(file) | CacheKey::File { file } => { + timestamp = max( + timestamp, + file.metadata() + .ok() + .filter(std::fs::Metadata::is_file) + .as_ref() + .map(Timestamp::from_metadata), + ); } - CacheKey::Git => { + CacheKey::Git { git: true } => { commit = Commit::from_repository(directory); } + CacheKey::Git { git: false } => {} } } @@ -160,40 +163,14 @@ struct ToolUv { cache_keys: Option>, } -#[derive(Debug)] -enum CacheKey { - /// Ex) `{ file = "Cargo.lock" }` or `"Cargo.lock"` - File(PathBuf), +#[derive(Debug, Clone, serde::Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged, rename_all = "kebab-case", deny_unknown_fields)] +pub enum CacheKey { + /// Ex) `"Cargo.lock"` + Path(PathBuf), + /// Ex) `{ file = "Cargo.lock" }` + File { file: PathBuf }, /// Ex) `{ git = true }` - Git, -} - -impl<'de> serde::de::Deserialize<'de> for CacheKey { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(untagged)] - enum CacheKeyHelper { - FileMap { file: PathBuf }, - GitMap { git: bool }, - SimpleFile(PathBuf), - } - - let helper = CacheKeyHelper::deserialize(deserializer)?; - match helper { - CacheKeyHelper::FileMap { file } => Ok(CacheKey::File(file)), - CacheKeyHelper::GitMap { git } => { - if git { - Ok(CacheKey::Git) - } else { - Err(serde::de::Error::custom( - "Invalid value for git key, expected true", - )) - } - } - CacheKeyHelper::SimpleFile(file) => Ok(CacheKey::File(file)), - } - } + Git { git: bool }, } diff --git a/crates/distribution-types/src/commit_info.rs b/crates/uv-cache-info/src/commit_info.rs similarity index 95% rename from crates/distribution-types/src/commit_info.rs rename to crates/uv-cache-info/src/commit_info.rs index e71b3bab4eb5..de0b620b8d74 100644 --- a/crates/distribution-types/src/commit_info.rs +++ b/crates/uv-cache-info/src/commit_info.rs @@ -1,11 +1,11 @@ use std::path::{Path, PathBuf}; -/// The current commit information for a repository. +/// The current commit for a repository. #[derive(Default, Debug, Clone, Hash, PartialEq, Eq, serde::Deserialize, serde::Serialize)] pub(crate) struct Commit(String); impl Commit { - /// Return the [`CommitInfo`] for the repository at the given path. + /// Return the [`Commit`] for the repository at the given path. pub(crate) fn from_repository(path: &Path) -> Option { // Find the `.git` directory, searching through parent directories if necessary. let git_dir = path diff --git a/crates/uv-cache-info/src/lib.rs b/crates/uv-cache-info/src/lib.rs new file mode 100644 index 000000000000..c09398c7c290 --- /dev/null +++ b/crates/uv-cache-info/src/lib.rs @@ -0,0 +1,6 @@ +pub use crate::cache_info::*; +pub use crate::timestamp::*; + +mod cache_info; +mod commit_info; +mod timestamp; diff --git a/crates/distribution-types/src/timestamp.rs b/crates/uv-cache-info/src/timestamp.rs similarity index 100% rename from crates/distribution-types/src/timestamp.rs rename to crates/uv-cache-info/src/timestamp.rs diff --git a/crates/uv-cache/Cargo.toml b/crates/uv-cache/Cargo.toml index 36851c883da7..3735f95ad26b 100644 --- a/crates/uv-cache/Cargo.toml +++ b/crates/uv-cache/Cargo.toml @@ -17,6 +17,7 @@ workspace = true cache-key = { workspace = true } distribution-types = { workspace = true } pypi-types = { workspace = true } +uv-cache-info = { workspace = true } uv-fs = { workspace = true, features = ["tokio"] } uv-normalize = { workspace = true } diff --git a/crates/uv-cache/src/by_timestamp.rs b/crates/uv-cache/src/by_timestamp.rs index fa504f31c1e9..b6f6b542a045 100644 --- a/crates/uv-cache/src/by_timestamp.rs +++ b/crates/uv-cache/src/by_timestamp.rs @@ -1,5 +1,5 @@ -use distribution_types::Timestamp; use serde::{Deserialize, Serialize}; +use uv_cache_info::Timestamp; #[derive(Deserialize, Serialize)] pub struct CachedByTimestamp { diff --git a/crates/uv-cache/src/lib.rs b/crates/uv-cache/src/lib.rs index 9c0d4af7c91d..0ecf2f39e018 100644 --- a/crates/uv-cache/src/lib.rs +++ b/crates/uv-cache/src/lib.rs @@ -10,8 +10,9 @@ use rustc_hash::FxHashSet; use tracing::debug; pub use archive::ArchiveId; -use distribution_types::{InstalledDist, Timestamp}; +use distribution_types::InstalledDist; use pypi_types::Metadata23; +use uv_cache_info::Timestamp; use uv_fs::{cachedir, directories}; use uv_normalize::PackageName; diff --git a/crates/uv-configuration/Cargo.toml b/crates/uv-configuration/Cargo.toml index ac5ea49e68f0..843c2afe7400 100644 --- a/crates/uv-configuration/Cargo.toml +++ b/crates/uv-configuration/Cargo.toml @@ -20,6 +20,7 @@ platform-tags = { workspace = true } pypi-types = { workspace = true } uv-auth = { workspace = true } uv-cache = { workspace = true } +uv-cache-info = { workspace = true } uv-normalize = { workspace = true } clap = { workspace = true, features = ["derive"], optional = true } diff --git a/crates/uv-configuration/src/config_settings.rs b/crates/uv-configuration/src/config_settings.rs index 053fe3303905..7ace0ac26b90 100644 --- a/crates/uv-configuration/src/config_settings.rs +++ b/crates/uv-configuration/src/config_settings.rs @@ -109,10 +109,12 @@ impl FromIterator for ConfigSettings { } impl ConfigSettings { + /// Returns the number of settings in the configuration. pub fn len(&self) -> usize { self.0.len() } + /// Returns `true` if the configuration contains no settings. pub fn is_empty(&self) -> bool { self.0.is_empty() } diff --git a/crates/uv-configuration/src/package_options.rs b/crates/uv-configuration/src/package_options.rs index f98efe89cfd6..babaa5dadd79 100644 --- a/crates/uv-configuration/src/package_options.rs +++ b/crates/uv-configuration/src/package_options.rs @@ -1,10 +1,10 @@ use either::Either; use pep508_rs::PackageName; -use distribution_types::Timestamp; use pypi_types::Requirement; use rustc_hash::FxHashMap; use uv_cache::Refresh; +use uv_cache_info::Timestamp; /// Whether to reinstall packages. #[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] diff --git a/crates/uv-distribution/Cargo.toml b/crates/uv-distribution/Cargo.toml index b381ecf40d0c..26d445d8a211 100644 --- a/crates/uv-distribution/Cargo.toml +++ b/crates/uv-distribution/Cargo.toml @@ -22,6 +22,7 @@ pep508_rs = { workspace = true } platform-tags = { workspace = true } pypi-types = { workspace = true } uv-cache = { workspace = true } +uv-cache-info = { workspace = true } uv-client = { workspace = true } uv-configuration = { workspace = true } uv-extract = { workspace = true } diff --git a/crates/uv-distribution/src/distribution_database.rs b/crates/uv-distribution/src/distribution_database.rs index b44ed8034406..c23ea5a4c76c 100644 --- a/crates/uv-distribution/src/distribution_database.rs +++ b/crates/uv-distribution/src/distribution_database.rs @@ -16,12 +16,13 @@ use url::Url; use distribution_filename::WheelFilename; use distribution_types::{ - BuildableSource, BuiltDist, CacheInfo, Dist, FileLocation, HashPolicy, Hashed, IndexLocations, - Name, SourceDist, Timestamp, + BuildableSource, BuiltDist, Dist, FileLocation, HashPolicy, Hashed, IndexLocations, Name, + SourceDist, }; use platform_tags::Tags; use pypi_types::HashDigest; use uv_cache::{ArchiveId, CacheBucket, CacheEntry, WheelCache}; +use uv_cache_info::{CacheInfo, Timestamp}; use uv_client::{ CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient, }; diff --git a/crates/uv-distribution/src/download.rs b/crates/uv-distribution/src/download.rs index 2ac9413a55a7..94692ed2d027 100644 --- a/crates/uv-distribution/src/download.rs +++ b/crates/uv-distribution/src/download.rs @@ -1,10 +1,10 @@ use std::path::{Path, PathBuf}; +use crate::Error; use distribution_filename::WheelFilename; -use distribution_types::{CacheInfo, CachedDist, Dist, Hashed}; +use distribution_types::{CachedDist, Dist, Hashed}; use pypi_types::{HashDigest, Metadata23}; - -use crate::Error; +use uv_cache_info::CacheInfo; /// A locally available wheel. #[derive(Debug, Clone)] diff --git a/crates/uv-distribution/src/index/built_wheel_index.rs b/crates/uv-distribution/src/index/built_wheel_index.rs index 7ba97b011389..1f5caf94ce4b 100644 --- a/crates/uv-distribution/src/index/built_wheel_index.rs +++ b/crates/uv-distribution/src/index/built_wheel_index.rs @@ -2,10 +2,11 @@ use crate::index::cached_wheel::CachedWheel; use crate::source::{HttpRevisionPointer, LocalRevisionPointer, HTTP_REVISION, LOCAL_REVISION}; use crate::Error; use distribution_types::{ - CacheInfo, DirectUrlSourceDist, DirectorySourceDist, GitSourceDist, Hashed, PathSourceDist, + DirectUrlSourceDist, DirectorySourceDist, GitSourceDist, Hashed, PathSourceDist, }; use platform_tags::Tags; use uv_cache::{Cache, CacheBucket, CacheShard, WheelCache}; +use uv_cache_info::CacheInfo; use uv_configuration::ConfigSettings; use uv_fs::symlinks; use uv_types::HashStrategy; diff --git a/crates/uv-distribution/src/index/cached_wheel.rs b/crates/uv-distribution/src/index/cached_wheel.rs index 2d857234d875..461df70da50b 100644 --- a/crates/uv-distribution/src/index/cached_wheel.rs +++ b/crates/uv-distribution/src/index/cached_wheel.rs @@ -1,13 +1,13 @@ use std::path::Path; +use crate::archive::Archive; +use crate::{HttpArchivePointer, LocalArchivePointer}; use distribution_filename::WheelFilename; -use distribution_types::{CacheInfo, CachedDirectUrlDist, CachedRegistryDist, Hashed}; +use distribution_types::{CachedDirectUrlDist, CachedRegistryDist, Hashed}; use pep508_rs::VerbatimUrl; use pypi_types::HashDigest; use uv_cache::{Cache, CacheBucket, CacheEntry}; - -use crate::archive::Archive; -use crate::{HttpArchivePointer, LocalArchivePointer}; +use uv_cache_info::CacheInfo; #[derive(Debug, Clone)] pub struct CachedWheel { diff --git a/crates/uv-distribution/src/source/built_wheel_metadata.rs b/crates/uv-distribution/src/source/built_wheel_metadata.rs index 72ab2df19f81..7a14f0d9805e 100644 --- a/crates/uv-distribution/src/source/built_wheel_metadata.rs +++ b/crates/uv-distribution/src/source/built_wheel_metadata.rs @@ -2,10 +2,11 @@ use std::path::PathBuf; use std::str::FromStr; use distribution_filename::WheelFilename; -use distribution_types::{CacheInfo, Hashed}; +use distribution_types::Hashed; use platform_tags::Tags; use pypi_types::HashDigest; use uv_cache::CacheShard; +use uv_cache_info::CacheInfo; use uv_fs::files; /// The information about the wheel we either just built or got from the cache. diff --git a/crates/uv-distribution/src/source/mod.rs b/crates/uv-distribution/src/source/mod.rs index 215ec4b95683..9c5fd27fd50d 100644 --- a/crates/uv-distribution/src/source/mod.rs +++ b/crates/uv-distribution/src/source/mod.rs @@ -5,9 +5,16 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; +use crate::distribution_database::ManagedClient; +use crate::error::Error; +use crate::metadata::{ArchiveMetadata, Metadata}; +use crate::reporter::Facade; +use crate::source::built_wheel_metadata::BuiltWheelMetadata; +use crate::source::revision::Revision; +use crate::{Reporter, RequiresDist}; use distribution_filename::{SourceDistExtension, WheelFilename}; use distribution_types::{ - BuildableSource, CacheInfo, DirectorySourceUrl, FileLocation, GitSourceUrl, HashPolicy, Hashed, + BuildableSource, DirectorySourceUrl, FileLocation, GitSourceUrl, HashPolicy, Hashed, PathSourceUrl, RemoteSource, SourceDist, SourceUrl, }; use fs_err::tokio as fs; @@ -20,6 +27,7 @@ use tokio_util::compat::FuturesAsyncReadCompatExt; use tracing::{debug, info_span, instrument, Instrument}; use url::Url; use uv_cache::{Cache, CacheBucket, CacheEntry, CacheShard, Removal, WheelCache}; +use uv_cache_info::CacheInfo; use uv_client::{ CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient, }; @@ -29,14 +37,6 @@ use uv_fs::{rename_with_retry, write_atomic, LockedFile}; use uv_types::{BuildContext, SourceBuildTrait}; use zip::ZipArchive; -use crate::distribution_database::ManagedClient; -use crate::error::Error; -use crate::metadata::{ArchiveMetadata, Metadata}; -use crate::reporter::Facade; -use crate::source::built_wheel_metadata::BuiltWheelMetadata; -use crate::source::revision::Revision; -use crate::{Reporter, RequiresDist}; - mod built_wheel_metadata; mod revision; @@ -1826,15 +1826,17 @@ impl LocalRevisionPointer { .map_err(Error::CacheWrite) } + /// Return the [`CacheInfo`] for the pointer. pub(crate) fn cache_info(&self) -> &CacheInfo { &self.cache_info } + /// Return the [`Revision`] for the pointer. pub(crate) fn revision(&self) -> &Revision { &self.revision } - /// Return the [`Revision`] from the pointer. + /// Return the [`Revision`] for the pointer. pub(crate) fn into_revision(self) -> Revision { self.revision } diff --git a/crates/uv-installer/Cargo.toml b/crates/uv-installer/Cargo.toml index 8f1663a03004..c6ee2679710c 100644 --- a/crates/uv-installer/Cargo.toml +++ b/crates/uv-installer/Cargo.toml @@ -22,6 +22,7 @@ pep508_rs = { workspace = true } platform-tags = { workspace = true } pypi-types = { workspace = true } uv-cache = { workspace = true } +uv-cache-info = { workspace = true } uv-configuration = { workspace = true } uv-distribution = { workspace = true } uv-extract = { workspace = true } diff --git a/crates/uv-installer/src/plan.rs b/crates/uv-installer/src/plan.rs index 9660eb1405e0..26bcb051d4c6 100644 --- a/crates/uv-installer/src/plan.rs +++ b/crates/uv-installer/src/plan.rs @@ -7,13 +7,14 @@ use tracing::debug; use distribution_filename::{DistExtension, WheelFilename}; use distribution_types::{ - CacheInfo, CachedDirectUrlDist, CachedDist, DirectUrlBuiltDist, DirectUrlSourceDist, - DirectorySourceDist, Error, GitSourceDist, Hashed, IndexLocations, InstalledDist, Name, - PathBuiltDist, PathSourceDist, RemoteSource, Timestamp, Verbatim, + CachedDirectUrlDist, CachedDist, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist, + Error, GitSourceDist, Hashed, IndexLocations, InstalledDist, Name, PathBuiltDist, + PathSourceDist, RemoteSource, Verbatim, }; use platform_tags::Tags; use pypi_types::{Requirement, RequirementSource, ResolverMarkerEnvironment}; use uv_cache::{Cache, CacheBucket, WheelCache}; +use uv_cache_info::{CacheInfo, Timestamp}; use uv_configuration::{BuildOptions, ConfigSettings, Reinstall}; use uv_distribution::{ BuiltWheelIndex, HttpArchivePointer, LocalArchivePointer, RegistryWheelIndex, diff --git a/crates/uv-installer/src/satisfies.rs b/crates/uv-installer/src/satisfies.rs index 43708f34493e..c6d8afe752dc 100644 --- a/crates/uv-installer/src/satisfies.rs +++ b/crates/uv-installer/src/satisfies.rs @@ -5,8 +5,9 @@ use tracing::{debug, trace}; use url::Url; use cache_key::{CanonicalUrl, RepositoryUrl}; -use distribution_types::{CacheInfo, InstalledDirectUrlDist, InstalledDist}; +use distribution_types::{InstalledDirectUrlDist, InstalledDist}; use pypi_types::{DirInfo, DirectUrl, RequirementSource, VcsInfo, VcsKind}; +use uv_cache_info::CacheInfo; #[derive(Debug, Copy, Clone)] pub(crate) enum RequirementSatisfaction { @@ -49,7 +50,7 @@ impl RequirementSatisfaction { let InstalledDist::Url(InstalledDirectUrlDist { direct_url, editable, - cache, + cache_info, .. }) = &distribution else { @@ -81,10 +82,10 @@ impl RequirementSatisfaction { // If the requirement came from a local path, check freshness. if requested_url.scheme() == "file" { if let Ok(archive) = requested_url.to_file_path() { - let Some(cache) = cache.as_ref() else { + let Some(cache_info) = cache_info.as_ref() else { return Ok(Self::OutOfDate); }; - if *cache != CacheInfo::from_path(&archive)? { + if *cache_info != CacheInfo::from_path(&archive)? { return Ok(Self::OutOfDate); } } @@ -154,7 +155,9 @@ impl RequirementSatisfaction { url: _, } => { let InstalledDist::Url(InstalledDirectUrlDist { - direct_url, cache, .. + direct_url, + cache_info, + .. }) = &distribution else { return Ok(Self::Mismatch); @@ -186,10 +189,10 @@ impl RequirementSatisfaction { return Ok(Self::Mismatch); } - let Some(cache) = cache.as_ref() else { + let Some(cache_info) = cache_info.as_ref() else { return Ok(Self::OutOfDate); }; - if *cache != CacheInfo::from_path(&requested_path)? { + if *cache_info != CacheInfo::from_path(requested_path)? { return Ok(Self::OutOfDate); } @@ -202,7 +205,9 @@ impl RequirementSatisfaction { url: _, } => { let InstalledDist::Url(InstalledDirectUrlDist { - direct_url, cache, .. + direct_url, + cache_info, + .. }) = &distribution else { return Ok(Self::Mismatch); @@ -245,10 +250,10 @@ impl RequirementSatisfaction { return Ok(Self::Mismatch); } - let Some(cache) = cache.as_ref() else { + let Some(cache_info) = cache_info.as_ref() else { return Ok(Self::OutOfDate); }; - if *cache != CacheInfo::from_path(&requested_path)? { + if *cache_info != CacheInfo::from_path(requested_path)? { return Ok(Self::OutOfDate); } diff --git a/crates/uv-python/Cargo.toml b/crates/uv-python/Cargo.toml index 5d916c68a6cf..75ecc9aceec1 100644 --- a/crates/uv-python/Cargo.toml +++ b/crates/uv-python/Cargo.toml @@ -15,13 +15,13 @@ workspace = true [dependencies] cache-key = { workspace = true } distribution-filename = { workspace = true } -distribution-types = { workspace = true } install-wheel-rs = { workspace = true } pep440_rs = { workspace = true } pep508_rs = { workspace = true } platform-tags = { workspace = true } pypi-types = { workspace = true } uv-cache = { workspace = true } +uv-cache-info = { workspace = true } uv-client = { workspace = true } uv-extract = { workspace = true } uv-fs = { workspace = true } diff --git a/crates/uv-python/src/interpreter.rs b/crates/uv-python/src/interpreter.rs index d63cbad0fa21..40a9d0397c81 100644 --- a/crates/uv-python/src/interpreter.rs +++ b/crates/uv-python/src/interpreter.rs @@ -12,7 +12,6 @@ use thiserror::Error; use tracing::{trace, warn}; use cache_key::cache_digest; -use distribution_types::Timestamp; use install_wheel_rs::Layout; use pep440_rs::Version; use pep508_rs::{MarkerEnvironment, StringVersion}; @@ -20,6 +19,7 @@ use platform_tags::Platform; use platform_tags::{Tags, TagsError}; use pypi_types::{ResolverMarkerEnvironment, Scheme}; use uv_cache::{Cache, CacheBucket, CachedByTimestamp, Freshness}; +use uv_cache_info::Timestamp; use uv_fs::{write_atomic_sync, PythonExt, Simplified}; use crate::implementation::LenientImplementationName; diff --git a/crates/uv-settings/Cargo.toml b/crates/uv-settings/Cargo.toml index ea893bde5b60..6be4b49b758f 100644 --- a/crates/uv-settings/Cargo.toml +++ b/crates/uv-settings/Cargo.toml @@ -17,6 +17,7 @@ distribution-types = { workspace = true, features = ["schemars"] } install-wheel-rs = { workspace = true, features = ["schemars", "clap"] } pep508_rs = { workspace = true } pypi-types = { workspace = true } +uv-cache-info = { workspace = true, features = ["schemars"] } uv-configuration = { workspace = true, features = ["schemars", "clap"] } uv-fs = { workspace = true } uv-macros = { workspace = true } diff --git a/crates/uv-settings/src/settings.rs b/crates/uv-settings/src/settings.rs index b3ba6d805a47..44c5fdfeaff4 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -6,6 +6,7 @@ use distribution_types::{FlatIndexLocation, IndexUrl}; use install_wheel_rs::linker::LinkMode; use pep508_rs::Requirement; use pypi_types::{SupportedEnvironments, VerbatimParsedUrl}; +use uv_cache_info::CacheKey; use uv_configuration::{ ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple, TrustedHost, @@ -66,8 +67,7 @@ pub struct Options { "# )] #[serde(default, skip_serializing)] - #[cfg_attr(feature = "schemars", schemars(skip))] - cache_keys: serde::de::IgnoredAny, + cache_keys: Option>, // NOTE(charlie): These fields are shared with `ToolUv` in // `crates/uv-workspace/src/pyproject.rs`, and the documentation lives on that struct. diff --git a/crates/uv-types/src/traits.rs b/crates/uv-types/src/traits.rs index 84438be03eb5..4408a266bdd0 100644 --- a/crates/uv-types/src/traits.rs +++ b/crates/uv-types/src/traits.rs @@ -63,6 +63,7 @@ pub trait BuildContext { /// This method exists to avoid fetching source distributions if we know we can't build them. fn build_options(&self) -> &BuildOptions; + /// The [`ConfigSettings`] used to build distributions. fn config_settings(&self) -> &ConfigSettings; /// Whether to incorporate `tool.uv.sources` when resolving requirements. diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index 07bd1d7a16da..d6b43515d202 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -24,6 +24,7 @@ platform-tags = { workspace = true } pypi-types = { workspace = true } uv-auth = { workspace = true } uv-cache = { workspace = true } +uv-cache-info = { workspace = true } uv-cli = { workspace = true } uv-client = { workspace = true } uv-configuration = { workspace = true } diff --git a/crates/uv/src/commands/tool/install.rs b/crates/uv/src/commands/tool/install.rs index d698f44bdedc..cba65fc909fc 100644 --- a/crates/uv/src/commands/tool/install.rs +++ b/crates/uv/src/commands/tool/install.rs @@ -2,13 +2,14 @@ use std::fmt::Write; use std::str::FromStr; use anyhow::{bail, Result}; -use distribution_types::{Timestamp, UnresolvedRequirementSpecification}; +use distribution_types::UnresolvedRequirementSpecification; use owo_colors::OwoColorize; use pep440_rs::{VersionSpecifier, VersionSpecifiers}; use pep508_rs::MarkerTree; use pypi_types::{Requirement, RequirementSource}; use tracing::debug; use uv_cache::{Cache, Refresh}; +use uv_cache_info::Timestamp; use uv_client::{BaseClientBuilder, Connectivity}; use uv_configuration::{Concurrency, Upgrade}; use uv_normalize::PackageName; diff --git a/crates/uv/src/commands/tool/run.rs b/crates/uv/src/commands/tool/run.rs index 0f371da9299b..66008d36f5ba 100644 --- a/crates/uv/src/commands/tool/run.rs +++ b/crates/uv/src/commands/tool/run.rs @@ -10,11 +10,12 @@ use owo_colors::OwoColorize; use tokio::process::Command; use tracing::{debug, warn}; -use distribution_types::{Name, Timestamp, UnresolvedRequirementSpecification}; +use distribution_types::{Name, UnresolvedRequirementSpecification}; use pep440_rs::{VersionSpecifier, VersionSpecifiers}; use pep508_rs::MarkerTree; use pypi_types::{Requirement, RequirementSource}; use uv_cache::{Cache, Refresh}; +use uv_cache_info::Timestamp; use uv_cli::ExternalCommand; use uv_client::{BaseClientBuilder, Connectivity}; use uv_configuration::Concurrency; diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 261f365bf782..12cf10047236 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -7,11 +7,11 @@ use anstream::eprintln; use anyhow::Result; use clap::error::{ContextKind, ContextValue}; use clap::{CommandFactory, Parser}; -use distribution_types::Timestamp; use owo_colors::OwoColorize; use settings::PipTreeSettings; use tracing::{debug, instrument}; use uv_cache::{Cache, Refresh}; +use uv_cache_info::Timestamp; use uv_cli::{ compat::CompatArgs, CacheCommand, CacheNamespace, Cli, Commands, PipCommand, PipNamespace, ProjectCommand, diff --git a/crates/uv/tests/pip_install.rs b/crates/uv/tests/pip_install.rs index 297d0f97ea33..511461427bab 100644 --- a/crates/uv/tests/pip_install.rs +++ b/crates/uv/tests/pip_install.rs @@ -2782,7 +2782,7 @@ fn config_settings() { ); // Uninstall the package. - uv_snapshot!(context.pip_uninstall() + uv_snapshot!(context.filters(), context.pip_uninstall() .arg("setuptools-editable"), @r###" success: true exit_code: 0 @@ -2790,7 +2790,7 @@ fn config_settings() { ----- stderr ----- Uninstalled 1 package in [TIME] - - setuptools-editable==0.1.0 (from file:///Users/crmarsh/workspace/uv/scripts/packages/setuptools_editable) + - setuptools-editable==0.1.0 (from file://[WORKSPACE]/scripts/packages/setuptools_editable) "###); // Install the editable package with `--editable_mode=compat`. We should ignore the cached diff --git a/docs/concepts/cache.md b/docs/concepts/cache.md index 3297633d6ff7..fa45fe1976f0 100644 --- a/docs/concepts/cache.md +++ b/docs/concepts/cache.md @@ -28,12 +28,33 @@ If you're running into caching issues, uv includes a few escape hatches: ## Dynamic metadata -Note that for local directory dependencies in particular (e.g., editables), uv will _only_ reinstall -the package if its `pyproject.toml`, `setup.py`, or `setup.cfg` file has changed. This is a +By default, uv will _only_ rebuild and reinstall local directory dependencies (e.g., editables) if +the `pyproject.toml`, `setup.py`, or `setup.cfg` file in the directory root has changed. This is a heuristic and, in some cases, may lead to fewer re-installs than desired. -For example, if a local dependency uses `dynamic` metadata, you can instruct uv to _always_ -reinstall the package by adding `reinstall-package` to the `uv` section of your `pyproject.toml`: +To incorporate other information into the cache key for a given package, you can add cache key +entries under `tool.uv.cache-key`, which can include both file paths and Git commit hashes. + +For example, if a project uses [`setuptools-scm`](https://pypi.org/project/setuptools-scm/), and +should be rebuilt whenever the commit hash changes, you can add the following to the project's +`pyproject.toml`: + +```toml title="pyproject.toml" +[tool.uv] +cache-key = [{ git = true }] +``` + +Similarly, if a project reads from a `requirements.txt` to populate its dependencies, you can add +the following to the project's `pyproject.toml`: + +```toml title="pyproject.toml" +[tool.uv] +cache-key = [{ file = "requirements.txt" }] +``` + +As an escape hatch, if a project uses `dynamic` metadata that isn't covered by `tool.uv.cache-key`, +you can instruct uv to _always_ rebuild and reinstall it by adding the project to the +`tool.uv.reinstall-package` list: ```toml title="pyproject.toml" [tool.uv] diff --git a/scripts/packages/setuptools_editable/build/lib/setuptools_editable/__init__.py b/scripts/packages/setuptools_editable/build/lib/setuptools_editable/__init__.py deleted file mode 100644 index b2dde251b1b4..000000000000 --- a/scripts/packages/setuptools_editable/build/lib/setuptools_editable/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -def a(): - pass diff --git a/uv.schema.json b/uv.schema.json index d983c13e44e3..e665be65939a 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -21,6 +21,17 @@ "null" ] }, + "cache-keys": { + "description": "The keys to consider when caching builds for the project.\n\nBy default, uv will rebuild a project whenever the `pyproject.toml`, `setup.py`, or `setup.cfg` files in the project directory are modified. Cache keys enable you to specify additional files or directories that should trigger a rebuild when modified.\n\nFor example, if a project uses dynamic metadata to read its dependencies from a `requirements.txt` file, you can specify `cache-keys = [{ file = \"requirements.txt\" }]` to ensure that the project is rebuilt whenever the `requirements.txt` file is modified.\n\nCache keys can also include version control information. For example, if a project uses `setuptools_scm` to read its version from a Git tag, you can specify `cache-keys = [{ git = true }]` to include the current Git commit hash in the cache key.\n\nCache keys only affect the project defined by the `pyproject.toml` in which they're specified (as opposed to, e.g., affecting all members in a workspace).", + "writeOnly": true, + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/CacheKey" + } + }, "compile-bytecode": { "description": "Compile Python files to bytecode after installation.\n\nBy default, uv does not compile Python (`.py`) files to bytecode (`__pycache__/*.pyc`); instead, compilation is performed lazily the first time a module is imported. For use-cases in which start time is critical, such as CLI applications and Docker containers, this option can be enabled to trade longer installation times for faster start times.\n\nWhen enabled, uv will process the entire site-packages directory (including packages that are not being modified by the current operation) for consistency. Like pip, it will also ignore errors.", "type": [ @@ -418,6 +429,40 @@ } ] }, + "CacheKey": { + "anyOf": [ + { + "description": "Ex) `\"Cargo.lock\"`", + "type": "string" + }, + { + "description": "Ex) `{ file = \"Cargo.lock\" }`", + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "description": "Ex) `{ git = true }`", + "type": "object", + "required": [ + "git" + ], + "properties": { + "git": { + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + }, "ConfigSettingValue": { "oneOf": [ {