mirror of
https://github.com/rust-lang/cargo
synced 2024-10-05 23:39:47 +00:00
Enable shallow clones and fetches for registry and git dependencies.
The implementation hinges on passing information about the kind of clone and fetch to the `fetch()` method, which then configures the fetch accordingly. Note that it doesn't differentiate between initial clones and fetches as the shallow-ness of the repository is maintained nonetheless.
This commit is contained in:
parent
0ad289b264
commit
c7ff94fce8
130
Cargo.lock
generated
130
Cargo.lock
generated
|
@ -284,6 +284,7 @@ dependencies = [
|
|||
"pathdiff",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"rustc-workspace-hack",
|
||||
"rustfix",
|
||||
"same-file",
|
||||
"semver",
|
||||
|
@ -920,7 +921,7 @@ checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
|
@ -1028,9 +1029,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix"
|
||||
version = "0.39.0"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dabfac58aecb4a38cdd2568de66eb1f0d968fd6726f5a80cb8bea7944ef10cc0"
|
||||
checksum = "fd5e0d9c5df90c9b4d325ec716762beb7d6c1465a4049fec5c4f6b72e7824656"
|
||||
dependencies = [
|
||||
"gix-actor",
|
||||
"gix-attributes",
|
||||
|
@ -1129,9 +1130,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-config"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52c62e26ce11f607712e4f49a0a192ed87675d30187fd61be070abbd607d12f1"
|
||||
checksum = "6aa7d7dd60256b7a0c0506a1d708ec92767c2662ee57b3301b538eaa3e064f8a"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-config-value",
|
||||
|
@ -1163,9 +1164,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-credentials"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be32b5fe339a31b8e53fa854081dc914c45020dcb64637f3c21baf69c96fc1b"
|
||||
checksum = "750b684197374518ea057e0a0594713e07683faa0a3f43c0f93d97f64130ad8d"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-command",
|
||||
|
@ -1203,9 +1204,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-discover"
|
||||
version = "0.15.0"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91c204adba5ebd211c74735cbb65817d277e154486bac0dffa3701f163b80350"
|
||||
checksum = "6eba8ba458cb8f4a6c33409b0fe650b1258655175a7ffd1d24fafd3ed31d880b"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"dunce",
|
||||
|
@ -1269,9 +1270,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-index"
|
||||
version = "0.14.0"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c12caf7886c7ba06f2b28835cdc2be1dca86bd047d00299d2d49e707ce1c2616"
|
||||
checksum = "717ab601ece7921f59fe86849dbe27d44a46ebb883b5885732c4f30df4996177"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bstr",
|
||||
|
@ -1291,9 +1292,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-lock"
|
||||
version = "4.0.0"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66119ff8a4a395d0ea033fef718bc85f8b4f0855874f4ce1e005fc16cfe1f66e"
|
||||
checksum = "41b80172055c5d8017a48ddac5cc7a95421c00211047db0165c97853c4f05194"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"gix-tempfile",
|
||||
|
@ -1332,9 +1333,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-odb"
|
||||
version = "0.42.0"
|
||||
version = "0.43.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9a5f9e1afbd509761977a2ea02869cedaaba500b4e783deb2e4de5179a55a80"
|
||||
checksum = "e83af2e3e36005bfe010927f0dff41fb5acc3e3d89c6f1174135b3a34086bda2"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"gix-features",
|
||||
|
@ -1350,9 +1351,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-pack"
|
||||
version = "0.32.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51db84e1459a8022e518d40a8778028d793dbb28e4d35c9a5eaf92658fb0775"
|
||||
checksum = "9401911c7fe032ad7b31c6a6b5be59cb283d1d6c999417a8215056efe6d635f3"
|
||||
dependencies = [
|
||||
"clru",
|
||||
"gix-chunk",
|
||||
|
@ -1372,9 +1373,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-packetline"
|
||||
version = "0.14.3"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d63e5e5a9a92d4fc6b63ff9d94954d25c779ce25c98d5bbe2e4399aa42f7073c"
|
||||
checksum = "3841ff51b395ab481c05d77551f5b41956022f50c1efba9d84fcd422f579ecd4"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"hex",
|
||||
|
@ -1406,9 +1407,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-protocol"
|
||||
version = "0.28.0"
|
||||
version = "0.30.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d372ab11d5d28ac21800e3f1a6603a67c1ead57f6f5fab07e1e73e960f331c1"
|
||||
checksum = "7bd38498bfdd5cd6dffa4477f78d43ac2b921bccf0aa7158994d252aaf825f40"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"btoi",
|
||||
|
@ -1434,9 +1435,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-ref"
|
||||
version = "0.26.0"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90a0ed29e581f04b904ecd0c32b11f33b8209b5a0af9c43f415249a4f2fba632"
|
||||
checksum = "e4e909396ed3b176823991ccc391c276ae2a015e54edaafa3566d35123cfac9d"
|
||||
dependencies = [
|
||||
"gix-actor",
|
||||
"gix-features",
|
||||
|
@ -1494,9 +1495,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-tempfile"
|
||||
version = "4.1.1"
|
||||
version = "5.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88751f247234b1f73c8e8056fd835a0999b04e596e052302cb71186005dc4b27"
|
||||
checksum = "c2ceb30a610e3f5f2d5f9a5114689fde507ba9417705a8cf3429604275b2153c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"once_cell",
|
||||
|
@ -1508,9 +1509,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-transport"
|
||||
version = "0.27.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d633947b36a2fbbc089195bdc71621158f1660c2ff2a6b12b0279c16e2f764bc"
|
||||
checksum = "a6c9094646b467be7198cf7663cb532ea2adbc05cc114da7097f8682ac4ca739"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bstr",
|
||||
|
@ -1539,9 +1540,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-url"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "044072b7ce8601b62dcec841b92129f5cc677072823324121b395d766ac5f528"
|
||||
checksum = "b6a22b4b32ad14d68f7b7fb6458fa58d44b01797d94c1b8f4db2d9c7b3c366b5"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-features",
|
||||
|
@ -1563,9 +1564,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-worktree"
|
||||
version = "0.14.0"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7cb9af6e56152953d8fe113c4f9d7cf60cf7a982362711e9200a255579b49cb"
|
||||
checksum = "54ec9a000b4f24af706c3cc680c7cda235656cbe3216336522f5692773b8a301"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-attributes",
|
||||
|
@ -1892,9 +1893,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.142"
|
||||
version = "0.2.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
|
@ -1954,9 +1955,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.2"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f508063cc7bb32987c71511216bd5a32be15bccb6a80b52df8b9d7f01fc3aa2"
|
||||
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
|
@ -2162,9 +2163,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "111.25.3+1.1.1t"
|
||||
version = "111.25.2+1.1.1t"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c"
|
||||
checksum = "320708a054ad9b3bf314688b5db87cf4d6683d64cfc835e2337924ae62bf4431"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
@ -2252,7 +2253,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
@ -2321,9 +2322,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
|||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.5.7"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122"
|
||||
checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
|
@ -2331,9 +2332,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.5.7"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15"
|
||||
checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
|
@ -2341,9 +2342,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.5.7"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e"
|
||||
checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
|
@ -2354,9 +2355,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.5.7"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e"
|
||||
checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
|
@ -2594,6 +2595,15 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
|
@ -2601,7 +2611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -2628,15 +2638,6 @@ version = "0.6.29"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resolver-tests"
|
||||
version = "0.0.0"
|
||||
|
@ -2665,6 +2666,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-workspace-hack"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
|
||||
|
||||
[[package]]
|
||||
name = "rustfix"
|
||||
version = "0.6.1"
|
||||
|
@ -3060,16 +3067,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -42,7 +42,7 @@ filetime = "0.2.9"
|
|||
flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] }
|
||||
git2 = "0.17.0"
|
||||
git2-curl = "0.18.0"
|
||||
gix = { version = "0.39.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] }
|
||||
gix = { version = "0.42.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] }
|
||||
gix-features-for-configuration-only = { version = "0.28.0", package = "gix-features", features = [ "parallel" ] }
|
||||
glob = "0.3.0"
|
||||
hex = "0.4"
|
||||
|
@ -63,6 +63,7 @@ libgit2-sys = "0.15.0"
|
|||
log = "0.4.6"
|
||||
memchr = "2.1.3"
|
||||
opener = "0.5"
|
||||
openssl = { version = '0.10.11', optional = true }
|
||||
os_info = "3.5.0"
|
||||
pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] }
|
||||
pathdiff = "0.2"
|
||||
|
@ -88,8 +89,10 @@ unicode-xid = "0.2.0"
|
|||
url = "2.2.2"
|
||||
walkdir = "2.2"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
openssl = { version = "0.10.50", optional = true }
|
||||
# A noop dependency that changes in the Rust repository, it's a bit of a hack.
|
||||
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
|
||||
# for more information.
|
||||
rustc-workspace-hack = "1.0.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
fwdansi = "1.1.0"
|
||||
|
@ -126,5 +129,3 @@ doc = false
|
|||
vendored-openssl = ["openssl/vendored"]
|
||||
vendored-libgit2 = ["libgit2-sys/vendored"]
|
||||
pretty-env-logger = ["pretty_env_logger"]
|
||||
# This is primarily used by rust-lang/rust distributing cargo the executable.
|
||||
all-static = ['vendored-openssl', 'curl/static-curl', 'curl/force-system-lib-on-osx']
|
||||
|
|
|
@ -6,5 +6,66 @@ mod source;
|
|||
mod utils;
|
||||
|
||||
pub mod fetch {
|
||||
use crate::core::features::GitoxideFeatures;
|
||||
use crate::Config;
|
||||
|
||||
/// The kind remote repository to fetch.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum RemoteKind {
|
||||
/// A repository belongs to a git dependency.
|
||||
GitDependency,
|
||||
/// A repository belongs to a git dependency, and due to usage of checking out specific revisions we can't
|
||||
/// use shallow clones.
|
||||
GitDependencyForbidShallow,
|
||||
/// A repository belongs to a Cargo registry.
|
||||
Registry,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum History {
|
||||
Shallow(gix::remote::fetch::Shallow),
|
||||
Unshallow,
|
||||
}
|
||||
|
||||
impl From<History> for gix::remote::fetch::Shallow {
|
||||
fn from(value: History) -> Self {
|
||||
match value {
|
||||
History::Unshallow => gix::remote::fetch::Shallow::undo(),
|
||||
History::Shallow(how) => how,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RemoteKind {
|
||||
/// Obtain the kind of history we would want for a fetch from our remote knowing if the target repo is already shallow
|
||||
/// via `repo_is_shallow` along with gitoxide-specific feature configuration via `config`.
|
||||
pub(crate) fn to_history(&self, repo_is_shallow: bool, config: &Config) -> History {
|
||||
let has_feature = |cb: &dyn Fn(GitoxideFeatures) -> bool| {
|
||||
config
|
||||
.cli_unstable()
|
||||
.gitoxide
|
||||
.map_or(false, |features| cb(features))
|
||||
};
|
||||
let how = if repo_is_shallow {
|
||||
if matches!(self, RemoteKind::GitDependencyForbidShallow) {
|
||||
return History::Unshallow;
|
||||
} else {
|
||||
gix::remote::fetch::Shallow::NoChange
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
RemoteKind::GitDependency if has_feature(&|git| git.shallow_deps) => {
|
||||
gix::remote::fetch::Shallow::DepthAtRemote(1.try_into().expect("non-zero"))
|
||||
}
|
||||
RemoteKind::Registry if has_feature(&|git| git.shallow_index) => {
|
||||
gix::remote::fetch::Shallow::DepthAtRemote(1.try_into().expect("non-zero"))
|
||||
}
|
||||
_ => gix::remote::fetch::Shallow::NoChange,
|
||||
}
|
||||
};
|
||||
History::Shallow(how)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Error = gix::env::collate::fetch::Error<gix::refspec::parse::Error>;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@ pub fn with_retry_and_progress(
|
|||
) -> CargoResult<()> {
|
||||
std::thread::scope(|s| {
|
||||
let mut progress_bar = Progress::new("Fetch", config);
|
||||
let is_shallow = config
|
||||
.cli_unstable()
|
||||
.gitoxide
|
||||
.map_or(false, |gix| gix.shallow_deps || gix.shallow_index);
|
||||
network::retry::with_retry(config, || {
|
||||
let progress_root: Arc<gix::progress::tree::Root> =
|
||||
gix::progress::tree::root::Options {
|
||||
|
@ -50,7 +54,7 @@ pub fn with_retry_and_progress(
|
|||
);
|
||||
amend_authentication_hints(res, urls.get_mut().take())
|
||||
});
|
||||
translate_progress_to_bar(&mut progress_bar, root)?;
|
||||
translate_progress_to_bar(&mut progress_bar, root, is_shallow)?;
|
||||
thread.join().expect("no panic in scoped thread")
|
||||
})
|
||||
})
|
||||
|
@ -59,7 +63,9 @@ pub fn with_retry_and_progress(
|
|||
fn translate_progress_to_bar(
|
||||
progress_bar: &mut Progress<'_>,
|
||||
root: Weak<gix::progress::tree::Root>,
|
||||
is_shallow: bool,
|
||||
) -> CargoResult<()> {
|
||||
let remote_progress: gix::progress::Id = gix::remote::fetch::ProgressId::RemoteProgress.into();
|
||||
let read_pack_bytes: gix::progress::Id =
|
||||
gix::odb::pack::bundle::write::ProgressId::ReadPackBytes.into();
|
||||
let delta_index_objects: gix::progress::Id =
|
||||
|
@ -88,6 +94,7 @@ fn translate_progress_to_bar(
|
|||
"progress should be smoother by keeping these as multiples of each other"
|
||||
);
|
||||
|
||||
let num_phases = if is_shallow { 3 } else { 2 }; // indexing + delta-resolution, both with same amount of objects to handle
|
||||
while let Some(root) = root.upgrade() {
|
||||
std::thread::sleep(sleep_interval);
|
||||
let needs_update = last_fast_update.elapsed() >= fast_check_interval;
|
||||
|
@ -102,31 +109,37 @@ fn translate_progress_to_bar(
|
|||
fn progress_by_id(
|
||||
id: gix::progress::Id,
|
||||
task: &gix::progress::Task,
|
||||
) -> Option<&gix::progress::Value> {
|
||||
(task.id == id).then(|| task.progress.as_ref()).flatten()
|
||||
) -> Option<(&str, &gix::progress::Value)> {
|
||||
(task.id == id)
|
||||
.then(|| task.progress.as_ref())
|
||||
.flatten()
|
||||
.map(|value| (task.name.as_str(), value))
|
||||
}
|
||||
fn find_in<K>(
|
||||
tasks: &[(K, gix::progress::Task)],
|
||||
cb: impl Fn(&gix::progress::Task) -> Option<&gix::progress::Value>,
|
||||
) -> Option<&gix::progress::Value> {
|
||||
cb: impl Fn(&gix::progress::Task) -> Option<(&str, &gix::progress::Value)>,
|
||||
) -> Option<(&str, &gix::progress::Value)> {
|
||||
tasks.iter().find_map(|(_, t)| cb(t))
|
||||
}
|
||||
|
||||
const NUM_PHASES: usize = 2; // indexing + delta-resolution, both with same amount of objects to handle
|
||||
if let Some(objs) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) {
|
||||
// Resolving deltas.
|
||||
if let Some((_, objs)) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) {
|
||||
// Phase 3: Resolving deltas.
|
||||
let objects = objs.step.load(Ordering::Relaxed);
|
||||
let total_objects = objs.done_at.expect("known amount of objects");
|
||||
let msg = format!(", ({objects}/{total_objects}) resolving deltas");
|
||||
|
||||
progress_bar.tick(total_objects + objects, total_objects * NUM_PHASES, &msg)?;
|
||||
progress_bar.tick(
|
||||
(total_objects * (num_phases - 1)) + objects,
|
||||
total_objects * num_phases,
|
||||
&msg,
|
||||
)?;
|
||||
} else if let Some((objs, read_pack)) =
|
||||
find_in(&tasks, |t| progress_by_id(read_pack_bytes, t)).and_then(|read| {
|
||||
find_in(&tasks, |t| progress_by_id(delta_index_objects, t))
|
||||
.map(|delta| (delta, read))
|
||||
.map(|delta| (delta.1, read.1))
|
||||
})
|
||||
{
|
||||
// Receiving objects.
|
||||
// Phase 2: Receiving objects.
|
||||
let objects = objs.step.load(Ordering::Relaxed);
|
||||
let total_objects = objs.done_at.expect("known amount of objects");
|
||||
let received_bytes = read_pack.step.load(Ordering::Relaxed);
|
||||
|
@ -139,7 +152,25 @@ fn translate_progress_to_bar(
|
|||
let (rate, unit) = human_readable_bytes(counter.rate() as u64);
|
||||
let msg = format!(", {rate:.2}{unit}/s");
|
||||
|
||||
progress_bar.tick(objects, total_objects * NUM_PHASES, &msg)?;
|
||||
progress_bar.tick(
|
||||
(total_objects * (num_phases - 2)) + objects,
|
||||
total_objects * num_phases,
|
||||
&msg,
|
||||
)?;
|
||||
} else if let Some((action, remote)) =
|
||||
find_in(&tasks, |t| progress_by_id(remote_progress, t))
|
||||
{
|
||||
if !is_shallow {
|
||||
continue;
|
||||
}
|
||||
// phase 1: work on the remote side
|
||||
|
||||
// Resolving deltas.
|
||||
let objects = remote.step.load(Ordering::Relaxed);
|
||||
if let Some(total_objects) = remote.done_at {
|
||||
let msg = format!(", ({objects}/{total_objects}) {action}");
|
||||
progress_bar.tick(objects, total_objects * num_phases, &msg)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
//! authentication/cloning.
|
||||
|
||||
use crate::core::{GitReference, Verbosity};
|
||||
use crate::sources::git::fetch::{History, RemoteKind};
|
||||
use crate::sources::git::oxide;
|
||||
use crate::sources::git::oxide::cargo_config_to_gitoxide_overrides;
|
||||
use crate::util::errors::CargoResult;
|
||||
|
@ -96,9 +97,21 @@ impl GitRemote {
|
|||
// if we can. If that can successfully load our revision then we've
|
||||
// populated the database with the latest version of `reference`, so
|
||||
// return that database and the rev we resolve to.
|
||||
let remote_kind = if locked_rev.is_some() || matches!(reference, GitReference::Rev(_)) {
|
||||
RemoteKind::GitDependencyForbidShallow
|
||||
} else {
|
||||
RemoteKind::GitDependency
|
||||
};
|
||||
if let Some(mut db) = db {
|
||||
fetch(&mut db.repo, self.url.as_str(), reference, cargo_config)
|
||||
.context(format!("failed to fetch into: {}", into.display()))?;
|
||||
let history = remote_kind.to_history(db.repo.is_shallow(), cargo_config);
|
||||
fetch(
|
||||
&mut db.repo,
|
||||
self.url.as_str(),
|
||||
reference,
|
||||
cargo_config,
|
||||
history,
|
||||
)
|
||||
.context(format!("failed to fetch into: {}", into.display()))?;
|
||||
match locked_rev {
|
||||
Some(rev) => {
|
||||
if db.contains(rev) {
|
||||
|
@ -121,8 +134,15 @@ impl GitRemote {
|
|||
}
|
||||
paths::create_dir_all(into)?;
|
||||
let mut repo = init(into, true)?;
|
||||
fetch(&mut repo, self.url.as_str(), reference, cargo_config)
|
||||
.context(format!("failed to clone into: {}", into.display()))?;
|
||||
let history = remote_kind.to_history(repo.is_shallow(), cargo_config);
|
||||
fetch(
|
||||
&mut repo,
|
||||
self.url.as_str(),
|
||||
reference,
|
||||
cargo_config,
|
||||
history,
|
||||
)
|
||||
.context(format!("failed to clone into: {}", into.display()))?;
|
||||
let rev = match locked_rev {
|
||||
Some(rev) => rev,
|
||||
None => reference.resolve(&repo)?,
|
||||
|
@ -282,6 +302,12 @@ impl<'a> GitCheckout<'a> {
|
|||
.with_checkout(checkout)
|
||||
.fetch_options(fopts)
|
||||
.clone(url.as_str(), into)?;
|
||||
if database.repo.is_shallow() {
|
||||
std::fs::copy(
|
||||
database.repo.path().join("shallow"),
|
||||
r.path().join("shallow"),
|
||||
)?;
|
||||
}
|
||||
repo = Some(r);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -432,7 +458,8 @@ impl<'a> GitCheckout<'a> {
|
|||
cargo_config
|
||||
.shell()
|
||||
.status("Updating", format!("git submodule `{}`", url))?;
|
||||
fetch(&mut repo, &url, &reference, cargo_config).with_context(|| {
|
||||
let history = RemoteKind::GitDependency.to_history(repo.is_shallow(), cargo_config);
|
||||
fetch(&mut repo, &url, &reference, cargo_config, history).with_context(|| {
|
||||
format!(
|
||||
"failed to fetch submodule `{}` from {}",
|
||||
child.name().unwrap_or(""),
|
||||
|
@ -803,11 +830,15 @@ pub fn with_fetch_options(
|
|||
})
|
||||
}
|
||||
|
||||
/// Note that `history` is a complex computed value to determine whether it's acceptable to perform shallow clones
|
||||
/// at all. It's needed to allow the caller to determine the correct position of the destination repository or move it
|
||||
/// into place should its position change.
|
||||
pub fn fetch(
|
||||
repo: &mut git2::Repository,
|
||||
orig_url: &str,
|
||||
reference: &GitReference,
|
||||
config: &Config,
|
||||
history: History,
|
||||
) -> CargoResult<()> {
|
||||
if config.frozen() {
|
||||
anyhow::bail!(
|
||||
|
@ -952,6 +983,7 @@ pub fn fetch(
|
|||
);
|
||||
let outcome = connection
|
||||
.prepare_fetch(gix::remote::ref_map::Options::default())?
|
||||
.with_shallow(history.clone().into())
|
||||
.receive(should_interrupt)?;
|
||||
Ok(outcome)
|
||||
});
|
||||
|
@ -967,6 +999,7 @@ pub fn fetch(
|
|||
// folder before writing files into it, or else not even open a directory as git repository (which is
|
||||
// also handled here).
|
||||
&& err.is_corrupted()
|
||||
|| has_shallow_lock_file(&err)
|
||||
{
|
||||
repo_reinitialized.store(true, Ordering::Relaxed);
|
||||
debug!(
|
||||
|
@ -1005,6 +1038,12 @@ pub fn fetch(
|
|||
// again. If it looks like any other kind of error, or if we've already
|
||||
// blown away the repository, then we want to return the error as-is.
|
||||
let mut repo_reinitialized = false;
|
||||
// while shallow repos aren't officially supported, don't risk fetching them.
|
||||
// We are in this situation only when `gitoxide` is cloning but then disabled to use `git2`
|
||||
// for fetching.
|
||||
if repo.is_shallow() {
|
||||
reinitialize(repo)?;
|
||||
}
|
||||
loop {
|
||||
debug!("initiating fetch of {:?} from {}", refspecs, orig_url);
|
||||
let res = repo
|
||||
|
@ -1036,6 +1075,17 @@ pub fn fetch(
|
|||
}
|
||||
}
|
||||
|
||||
/// `gitoxide` uses shallow locks to assure consistency when fetching to and to avoid races, and to write
|
||||
/// files atomically.
|
||||
/// Cargo has its own lock files and doesn't need that mechanism for race protection, so a stray lock means
|
||||
/// a signal interrupted a previous shallow fetch and doesn't mean a race is happening.
|
||||
fn has_shallow_lock_file(err: &crate::sources::git::fetch::Error) -> bool {
|
||||
matches!(
|
||||
err,
|
||||
gix::env::collate::fetch::Error::Fetch(gix::remote::fetch::Error::LockShallowFile(_))
|
||||
)
|
||||
}
|
||||
|
||||
fn fetch_with_cli(
|
||||
repo: &mut git2::Repository,
|
||||
url: &str,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::core::{GitReference, PackageId, SourceId};
|
||||
use crate::sources::git;
|
||||
use crate::sources::git::fetch::RemoteKind;
|
||||
use crate::sources::registry::download;
|
||||
use crate::sources::registry::MaybeLock;
|
||||
use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData};
|
||||
|
@ -304,8 +305,15 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
|
|||
// checkout.
|
||||
let url = self.source_id.url();
|
||||
let repo = self.repo.borrow_mut().unwrap();
|
||||
git::fetch(repo, url.as_str(), &self.index_git_ref, self.config)
|
||||
.with_context(|| format!("failed to fetch `{}`", url))?;
|
||||
let history = RemoteKind::Registry.to_history(repo.is_shallow(), self.config);
|
||||
git::fetch(
|
||||
repo,
|
||||
url.as_str(),
|
||||
&self.index_git_ref,
|
||||
self.config,
|
||||
history,
|
||||
)
|
||||
.with_context(|| format!("failed to fetch `{}`", url))?;
|
||||
|
||||
// Create a dummy file to record the mtime for when we updated the
|
||||
// index.
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use crate::git_gc::find_index;
|
||||
use cargo_test_support::git::cargo_uses_gitoxide;
|
||||
use cargo_test_support::paths::{self, CargoPathExt};
|
||||
use cargo_test_support::registry::Package;
|
||||
|
@ -548,7 +549,11 @@ Caused by:
|
|||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn two_revs_same_deps() {
|
||||
fn gitoxide_clones_shallow_two_revs_same_deps() {
|
||||
perform_two_revs_same_deps(true)
|
||||
}
|
||||
|
||||
fn perform_two_revs_same_deps(shallow: bool) {
|
||||
let bar = git::new("meta-dep", |project| {
|
||||
project
|
||||
.file("Cargo.toml", &basic_manifest("bar", "0.0.0"))
|
||||
|
@ -626,11 +631,23 @@ fn two_revs_same_deps() {
|
|||
)
|
||||
.build();
|
||||
|
||||
foo.cargo("build -v").run();
|
||||
let args = if shallow {
|
||||
"build -v -Zgitoxide=fetch,shallow-deps"
|
||||
} else {
|
||||
"build -v"
|
||||
};
|
||||
foo.cargo(args)
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
assert!(foo.bin("foo").is_file());
|
||||
foo.process(&foo.bin("foo")).run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn two_revs_same_deps() {
|
||||
perform_two_revs_same_deps(false)
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn recompilation() {
|
||||
let git_project = git::new("bar", |project| {
|
||||
|
@ -1828,6 +1845,680 @@ fn fetch_downloads() {
|
|||
p.cargo("fetch").with_stdout("").run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch(
|
||||
) -> anyhow::Result<()> {
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
p.cargo("fetch")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?;
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"shallow clones always start at depth of 1 to minimize download size"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
|
||||
Package::new("bar", "1.1.0").publish();
|
||||
p.cargo("update")
|
||||
.env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0")
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
3,
|
||||
"the repo was forcefully reinitialized and fetch again with full history - that way we take control and know the state of the repo \
|
||||
instead of allowing a non-shallow aware implementation to cause trouble later"
|
||||
);
|
||||
assert!(!repo.is_shallow());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches(
|
||||
) -> anyhow::Result<()> {
|
||||
// Example where an old lockfile with an explicit branch="master" in Cargo.toml.
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let (bar, bar_repo) = git::new_repo("bar", |p| {
|
||||
p.file("Cargo.toml", &basic_manifest("bar", "1.0.0"))
|
||||
.file("src/lib.rs", "")
|
||||
});
|
||||
|
||||
bar.change_file("src/lib.rs", "// change");
|
||||
git::add(&bar_repo);
|
||||
git::commit(&bar_repo);
|
||||
|
||||
{
|
||||
let mut walk = bar_repo.revwalk()?;
|
||||
walk.push_head()?;
|
||||
assert_eq!(
|
||||
walk.count(),
|
||||
2,
|
||||
"original repo has initial commit and change commit"
|
||||
);
|
||||
}
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
&format!(
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = {{ version = "1.0", git = "{}", branch = "master" }}
|
||||
"#,
|
||||
bar.url()
|
||||
),
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch,shallow-deps")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let db_clone = gix::open_opts(
|
||||
glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())?
|
||||
.next()
|
||||
.unwrap()?,
|
||||
gix::open::Options::isolated(),
|
||||
)?;
|
||||
assert!(db_clone.is_shallow());
|
||||
assert_eq!(
|
||||
db_clone
|
||||
.rev_parse_single("origin/master")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"db clones are shallow and have a shortened history"
|
||||
);
|
||||
|
||||
let dep_checkout = gix::open_opts(
|
||||
glob::glob(
|
||||
paths::home()
|
||||
.join(".cargo/git/checkouts/bar-*/*/.git")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)?
|
||||
.next()
|
||||
.unwrap()?,
|
||||
gix::open::Options::isolated(),
|
||||
)?;
|
||||
assert!(dep_checkout.is_shallow());
|
||||
assert_eq!(
|
||||
dep_checkout.head_id()?.ancestors().all()?.count(),
|
||||
1,
|
||||
"db checkouts are hard-linked clones with the shallow file copied separately."
|
||||
);
|
||||
|
||||
bar.change_file("src/lib.rs", "// another change");
|
||||
git::add(&bar_repo);
|
||||
git::commit(&bar_repo);
|
||||
{
|
||||
let mut walk = bar_repo.revwalk()?;
|
||||
walk.push_head()?;
|
||||
assert_eq!(
|
||||
walk.count(),
|
||||
3,
|
||||
"original repo has initial commit and change commit, and another change"
|
||||
);
|
||||
}
|
||||
|
||||
p.cargo("update")
|
||||
.env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0")
|
||||
.run();
|
||||
|
||||
let db_clone = gix::open_opts(
|
||||
glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())?
|
||||
.next()
|
||||
.unwrap()?,
|
||||
gix::open::Options::isolated(),
|
||||
)?;
|
||||
assert_eq!(
|
||||
db_clone
|
||||
.rev_parse_single("origin/master")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
3,
|
||||
"the db clone was re-initialized and has all commits"
|
||||
);
|
||||
assert!(
|
||||
!db_clone.is_shallow(),
|
||||
"shallow-ness was removed as git2 does not support it"
|
||||
);
|
||||
assert_eq!(
|
||||
dep_checkout.head_id()?.ancestors().all()?.count(),
|
||||
1,
|
||||
"the original dep checkout didn't change - there is a new one for each update we get locally"
|
||||
);
|
||||
|
||||
let max_history_depth = glob::glob(
|
||||
paths::home()
|
||||
.join(".cargo/git/checkouts/bar-*/*/.git")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)?
|
||||
.map(|path| -> anyhow::Result<usize> {
|
||||
let dep_checkout = gix::open_opts(path?, gix::open::Options::isolated())?;
|
||||
let depth = dep_checkout.head_id()?.ancestors().all()?.count();
|
||||
assert_eq!(dep_checkout.is_shallow(), depth == 1, "the first checkout is done with gitoxide and shallow, the second one is git2 non-shallow");
|
||||
Ok(depth)
|
||||
})
|
||||
.map(Result::unwrap)
|
||||
.max()
|
||||
.expect("two checkout repos");
|
||||
|
||||
assert_eq!(
|
||||
max_history_depth, 3,
|
||||
"the new checkout sees all commits of the non-shallow DB repository"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_clones_git_dependency_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness(
|
||||
) -> anyhow::Result<()> {
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let (bar, bar_repo) = git::new_repo("bar", |p| {
|
||||
p.file("Cargo.toml", &basic_manifest("bar", "1.0.0"))
|
||||
.file("src/lib.rs", "")
|
||||
});
|
||||
|
||||
bar.change_file("src/lib.rs", "// change");
|
||||
git::add(&bar_repo);
|
||||
git::commit(&bar_repo);
|
||||
|
||||
{
|
||||
let mut walk = bar_repo.revwalk()?;
|
||||
walk.push_head()?;
|
||||
assert_eq!(
|
||||
walk.count(),
|
||||
2,
|
||||
"original repo has initial commit and change commit"
|
||||
);
|
||||
}
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
&format!(
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = {{ version = "1.0", git = "{}", branch = "master" }}
|
||||
"#,
|
||||
bar.url()
|
||||
),
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch,shallow-deps")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let db_clone = gix::open_opts(
|
||||
glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())?
|
||||
.next()
|
||||
.unwrap()?,
|
||||
gix::open::Options::isolated(),
|
||||
)?;
|
||||
assert!(db_clone.is_shallow());
|
||||
assert_eq!(
|
||||
db_clone
|
||||
.rev_parse_single("origin/master")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"db clones are shallow and have a shortened history"
|
||||
);
|
||||
|
||||
let dep_checkout = gix::open_opts(
|
||||
glob::glob(
|
||||
paths::home()
|
||||
.join(".cargo/git/checkouts/bar-*/*/.git")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)?
|
||||
.next()
|
||||
.unwrap()?,
|
||||
gix::open::Options::isolated(),
|
||||
)?;
|
||||
assert!(dep_checkout.is_shallow());
|
||||
assert_eq!(
|
||||
dep_checkout.head_id()?.ancestors().all()?.count(),
|
||||
1,
|
||||
"db checkouts are hard-linked clones with the shallow file copied separately."
|
||||
);
|
||||
|
||||
bar.change_file("src/lib.rs", "// another change");
|
||||
git::add(&bar_repo);
|
||||
git::commit(&bar_repo);
|
||||
{
|
||||
let mut walk = bar_repo.revwalk()?;
|
||||
walk.push_head()?;
|
||||
assert_eq!(
|
||||
walk.count(),
|
||||
3,
|
||||
"original repo has initial commit and change commit, and another change"
|
||||
);
|
||||
}
|
||||
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch") // shallow-deps is omitted intentionally
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
db_clone
|
||||
.rev_parse_single("origin/master")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
2,
|
||||
"the new commit was fetched into our DB clone"
|
||||
);
|
||||
assert!(db_clone.is_shallow());
|
||||
assert_eq!(
|
||||
dep_checkout.head_id()?.ancestors().all()?.count(),
|
||||
1,
|
||||
"the original dep checkout didn't change - there is a new one for each update we get locally"
|
||||
);
|
||||
|
||||
let max_history_depth = glob::glob(
|
||||
paths::home()
|
||||
.join(".cargo/git/checkouts/bar-*/*/.git")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)?
|
||||
.map(|path| -> anyhow::Result<usize> {
|
||||
let dep_checkout = gix::open_opts(path?, gix::open::Options::isolated())?;
|
||||
assert!(dep_checkout.is_shallow());
|
||||
let depth = dep_checkout.head_id()?.ancestors().all()?.count();
|
||||
Ok(depth)
|
||||
})
|
||||
.map(Result::unwrap)
|
||||
.max()
|
||||
.expect("two checkout repos");
|
||||
|
||||
assert_eq!(
|
||||
max_history_depth, 2,
|
||||
"the new checkout sees all commits of the DB"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness(
|
||||
) -> anyhow::Result<()> {
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
p.cargo("fetch")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?;
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"shallow clones always start at depth of 1 to minimize download size"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
|
||||
Package::new("bar", "1.1.0").publish();
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch") // NOTE: intentionally missing shallow flag
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
2,
|
||||
"follow-up fetches maintain shallow-ness, whether it's specified or not, keeping shallow boundary where it is"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
|
||||
Package::new("bar", "1.2.0").publish();
|
||||
Package::new("bar", "1.3.0").publish();
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
4,
|
||||
"even if depth (at remote) is specified again, the current shallow boundary is maintained and not moved"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness(
|
||||
) -> anyhow::Result<()> {
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
p.cargo("fetch")
|
||||
.arg("-Zgitoxide=fetch")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?;
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
2,
|
||||
"initial commit and the first crate"
|
||||
);
|
||||
assert!(!repo.is_shallow());
|
||||
|
||||
Package::new("bar", "1.1.0").publish();
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"follow-up fetches maintain can shallow an existing unshallow repo - this doesn't have any benefit as we still have the objects locally"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
|
||||
Package::new("bar", "1.2.0").publish();
|
||||
Package::new("bar", "1.3.0").publish();
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
3,
|
||||
"even if depth (at remote) is specified again, the current shallow boundary is maintained and not moved"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_unshallows_git_dependencies_that_may_not_be_shallow_anymore() -> anyhow::Result<()> {
|
||||
// db exists from previous build, then dependency changes to refer to revision that isn't
|
||||
// available in the shallow clone.
|
||||
|
||||
let (bar, bar_repo) = git::new_repo("bar", |p| {
|
||||
p.file("Cargo.toml", &basic_manifest("bar", "1.0.0"))
|
||||
.file("src/lib.rs", "")
|
||||
});
|
||||
|
||||
// this commit would not be available in a shallow clone.
|
||||
let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap();
|
||||
|
||||
bar.change_file("src/lib.rs", "// change");
|
||||
git::add(&bar_repo);
|
||||
git::commit(&bar_repo);
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
&format!(
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = {{ git = "{}", branch = "master" }}
|
||||
"#,
|
||||
bar.url(),
|
||||
),
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check")
|
||||
.arg("-Zgitoxide=fetch,shallow-deps")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let db_clone = gix::open_opts(
|
||||
glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())?
|
||||
.next()
|
||||
.unwrap()?,
|
||||
gix::open::Options::isolated(),
|
||||
)?;
|
||||
assert!(db_clone.is_shallow());
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
&format!(
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = {{ git = "{}", rev = "{}" }}
|
||||
"#,
|
||||
bar.url(),
|
||||
first_commit_pre_change
|
||||
),
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check")
|
||||
.arg("-Zgitoxide=fetch,shallow-deps")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert!(
|
||||
!db_clone.is_shallow(),
|
||||
"the clone was unshallowed as we need the entire history for revision based checkouts"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_uses_shallow_deps_only_when_no_revision_is_specified() -> anyhow::Result<()> {
|
||||
let (bar, bar_repo) = git::new_repo("bar", |p| {
|
||||
p.file("Cargo.toml", &basic_manifest("bar", "1.0.0"))
|
||||
.file("src/lib.rs", "")
|
||||
});
|
||||
|
||||
// this commit would not be available in a shallow clone.
|
||||
let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap();
|
||||
|
||||
bar.change_file("src/lib.rs", "// change");
|
||||
git::add(&bar_repo);
|
||||
git::commit(&bar_repo);
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
&format!(
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar-renamed = {{ package = "bar", git = "{}", rev = "{}" }}
|
||||
bar = {{ git = "{}", branch = "master" }}
|
||||
"#,
|
||||
bar.url(),
|
||||
first_commit_pre_change,
|
||||
bar.url(),
|
||||
),
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check")
|
||||
.arg("-Zgitoxide=fetch,shallow-deps")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let db_paths = glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())?
|
||||
.map(Result::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
db_paths.len(),
|
||||
1,
|
||||
"only one db checkout source is used per dependency"
|
||||
);
|
||||
let db_clone = gix::open_opts(&db_paths[0], gix::open::Options::isolated())?;
|
||||
assert!(
|
||||
!db_clone.is_shallow(),
|
||||
"despite there being two checkouts, it manages to see that the db must not be shallow"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again(
|
||||
) -> anyhow::Result<()> {
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
p.cargo("fetch")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?;
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"shallow clones always start at depth of 1 to minimize download size"
|
||||
);
|
||||
assert!(repo.is_shallow());
|
||||
let shallow_lock = repo.shallow_file().with_extension("lock");
|
||||
// adding a lock file and deleting the original simulates a left-over clone that was aborted, leaving a lock file
|
||||
// in place without ever having moved it to the right location.
|
||||
std::fs::write(&shallow_lock, &[])?;
|
||||
std::fs::remove_file(repo.shallow_file())?;
|
||||
|
||||
Package::new("bar", "1.1.0").publish();
|
||||
p.cargo("update")
|
||||
.arg("-Zgitoxide=fetch,shallow-index")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"])
|
||||
.run();
|
||||
|
||||
assert!(!shallow_lock.is_file(), "the repository was re-initialized");
|
||||
assert!(repo.is_shallow());
|
||||
assert_eq!(
|
||||
repo.rev_parse_single("origin/HEAD")?
|
||||
.ancestors()
|
||||
.all()?
|
||||
.count(),
|
||||
1,
|
||||
"it's a fresh shallow clone - otherwise it would have 2 commits if the previous shallow clone would still be present"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn fetch_downloads_with_git2_first_then_with_gitoxide_and_vice_versa() {
|
||||
let bar = git::new("bar", |project| {
|
||||
|
|
|
@ -2466,7 +2466,11 @@ fn can_update_with_alt_reg() {
|
|||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn old_git_patch() {
|
||||
fn gitoxide_clones_shallow_old_git_patch() {
|
||||
perform_old_git_patch(true)
|
||||
}
|
||||
|
||||
fn perform_old_git_patch(shallow: bool) {
|
||||
// Example where an old lockfile with an explicit branch="master" in Cargo.toml.
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
let (bar, bar_repo) = git::new_repo("bar", |p| {
|
||||
|
@ -2524,7 +2528,13 @@ dependencies = [
|
|||
git::commit(&bar_repo);
|
||||
|
||||
// This *should* keep the old lock.
|
||||
p.cargo("tree")
|
||||
let mut cargo = p.cargo("tree");
|
||||
if shallow {
|
||||
cargo
|
||||
.arg("-Zgitoxide=fetch,shallow-deps")
|
||||
.masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]);
|
||||
}
|
||||
cargo
|
||||
// .env("CARGO_LOG", "trace")
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -2542,6 +2552,11 @@ foo v0.1.0 [..]
|
|||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn old_git_patch() {
|
||||
perform_old_git_patch(false)
|
||||
}
|
||||
|
||||
// From https://github.com/rust-lang/cargo/issues/7463
|
||||
#[cargo_test]
|
||||
fn patch_eq_conflict_panic() {
|
||||
|
|
Loading…
Reference in a new issue