Skip to content

Commit 7a3b56b

Browse files
committed
Auto merge of #10553 - sourcefrog:cachedir, r=weihanglo
Mark .cargo/git and .cargo/registry as cache dirs Fixes #10457 ### What does this PR try to resolve? As we previously discussed in #10457 this marks `~/.cargo/git` and `~/.cargo/registry` as not to be included in backups, and not subject to content indexing. These directories can be fairly large and frequently changed, and should only contain content that can be re-downloaded if necessary. ### How should we test and review this PR? I did two manual tests: 1. Using the binary built from this tree, run `cargo update` in a source tree that has a git dependency, and observe that afterwards, there is a `CACHEDIR.TAG` in `~/.cargo/git`. 2. Similarly, run `cargo update` and observe that there's a `CACHEDIR.TAG` in `~/.cargo/registry`. (I ran this on Linux. This code should also trigger OS-specific behavior on macOS and Windows that's the same as is currently applied to `target/`.) I added some test assertions.
2 parents f3a4448 + 4bcfd9e commit 7a3b56b

File tree

6 files changed

+71
-6
lines changed

6 files changed

+71
-6
lines changed

crates/cargo-util/src/paths.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ pub fn create_dir_all_excluded_from_backups_atomic(p: impl AsRef<Path>) -> Resul
632632
let parent = path.parent().unwrap();
633633
let base = path.file_name().unwrap();
634634
create_dir_all(parent)?;
635-
// We do this in two steps (first create a temporary directory and exlucde
635+
// We do this in two steps (first create a temporary directory and exclude
636636
// it from backups, then rename it to the desired name. If we created the
637637
// directory directly where it should be and then excluded it from backups
638638
// we would risk a situation where cargo is interrupted right after the directory
@@ -660,6 +660,15 @@ pub fn create_dir_all_excluded_from_backups_atomic(p: impl AsRef<Path>) -> Resul
660660
Ok(())
661661
}
662662

663+
/// Mark an existing directory as excluded from backups and indexing.
664+
///
665+
/// Errors in marking it are ignored.
666+
pub fn exclude_from_backups_and_indexing(p: impl AsRef<Path>) {
667+
let path = p.as_ref();
668+
exclude_from_backups(path);
669+
exclude_from_content_indexing(path);
670+
}
671+
663672
/// Marks the directory as excluded from archives/backups.
664673
///
665674
/// This is recommended to prevent derived/temporary files from bloating backups. There are two

src/cargo/sources/git/source.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::util::errors::CargoResult;
77
use crate::util::hex::short_hash;
88
use crate::util::Config;
99
use anyhow::Context;
10+
use cargo_util::paths::exclude_from_backups_and_indexing;
1011
use log::trace;
1112
use std::fmt::{self, Debug, Formatter};
1213
use std::task::Poll;
@@ -122,8 +123,22 @@ impl<'cfg> Source for GitSource<'cfg> {
122123
return Ok(());
123124
}
124125

125-
let git_path = self.config.git_path();
126-
let git_path = self.config.assert_package_cache_locked(&git_path);
126+
let git_fs = self.config.git_path();
127+
// Ignore errors creating it, in case this is a read-only filesystem:
128+
// perhaps the later operations can succeed anyhow.
129+
let _ = git_fs.create_dir();
130+
let git_path = self.config.assert_package_cache_locked(&git_fs);
131+
132+
// Before getting a checkout, make sure that `<cargo_home>/git` is
133+
// marked as excluded from indexing and backups. Older versions of Cargo
134+
// didn't do this, so we do it here regardless of whether `<cargo_home>`
135+
// exists.
136+
//
137+
// This does not use `create_dir_all_excluded_from_backups_atomic` for
138+
// the same reason: we want to exclude it even if the directory already
139+
// exists.
140+
exclude_from_backups_and_indexing(&git_path);
141+
127142
let db_path = git_path.join("db").join(&self.ident);
128143

129144
let db = self.remote.db_at(&db_path).ok();

src/cargo/sources/registry/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ use std::path::{Path, PathBuf};
167167
use std::task::Poll;
168168

169169
use anyhow::Context as _;
170+
use cargo_util::paths::exclude_from_backups_and_indexing;
170171
use flate2::read::GzDecoder;
171172
use log::debug;
172173
use semver::Version;
@@ -552,6 +553,7 @@ impl<'cfg> RegistrySource<'cfg> {
552553
} else {
553554
Box::new(remote::RemoteRegistry::new(source_id, config, &name)) as Box<_>
554555
};
556+
555557
Ok(RegistrySource::new(
556558
source_id,
557559
config,
@@ -812,6 +814,21 @@ impl<'cfg> Source for RegistrySource<'cfg> {
812814
}
813815

814816
fn block_until_ready(&mut self) -> CargoResult<()> {
817+
// Before starting to work on the registry, make sure that
818+
// `<cargo_home>/registry` is marked as excluded from indexing and
819+
// backups. Older versions of Cargo didn't do this, so we do it here
820+
// regardless of whether `<cargo_home>` exists.
821+
//
822+
// This does not use `create_dir_all_excluded_from_backups_atomic` for
823+
// the same reason: we want to exclude it even if the directory already
824+
// exists.
825+
//
826+
// IO errors in creating and marking it are ignored, e.g. in case we're on a
827+
// read-only filesystem.
828+
let registry_base = self.config.registry_base_path();
829+
let _ = registry_base.create_dir();
830+
exclude_from_backups_and_indexing(&registry_base.into_path_unlocked());
831+
815832
self.ops.block_until_ready()
816833
}
817834
}

src/cargo/util/config/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,19 +315,24 @@ impl Config {
315315
self.home_path.join("git")
316316
}
317317

318+
/// Gets the Cargo base directory for all registry information (`<cargo_home>/registry`).
319+
pub fn registry_base_path(&self) -> Filesystem {
320+
self.home_path.join("registry")
321+
}
322+
318323
/// Gets the Cargo registry index directory (`<cargo_home>/registry/index`).
319324
pub fn registry_index_path(&self) -> Filesystem {
320-
self.home_path.join("registry").join("index")
325+
self.registry_base_path().join("index")
321326
}
322327

323328
/// Gets the Cargo registry cache directory (`<cargo_home>/registry/path`).
324329
pub fn registry_cache_path(&self) -> Filesystem {
325-
self.home_path.join("registry").join("cache")
330+
self.registry_base_path().join("cache")
326331
}
327332

328333
/// Gets the Cargo registry source directory (`<cargo_home>/registry/src`).
329334
pub fn registry_source_path(&self) -> Filesystem {
330-
self.home_path.join("registry").join("src")
335+
self.registry_base_path().join("src")
331336
}
332337

333338
/// Gets the default Cargo registry.

tests/testsuite/git.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,8 @@ fn add_a_git_dep() {
22472247

22482248
p.cargo("build").run();
22492249

2250+
assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file());
2251+
22502252
p.change_file(
22512253
"a/Cargo.toml",
22522254
&format!(
@@ -2580,6 +2582,7 @@ fn use_the_cli() {
25802582
";
25812583

25822584
project.cargo("build -v").with_stderr(stderr).run();
2585+
assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file());
25832586
}
25842587

25852588
#[cargo_test]

tests/testsuite/registry.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ fn simple(cargo: fn(&Project, &str) -> Execs) {
9393

9494
cargo(&p, "clean").run();
9595

96+
assert!(paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file());
97+
9698
// Don't download a second time
9799
cargo(&p, "build")
98100
.with_stderr(
@@ -150,6 +152,8 @@ fn deps(cargo: fn(&Project, &str) -> Execs) {
150152
",
151153
)
152154
.run();
155+
156+
assert!(paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file());
153157
}
154158

155159
#[cargo_test]
@@ -1231,6 +1235,13 @@ fn updating_a_dep(cargo: fn(&Project, &str) -> Execs) {
12311235
",
12321236
)
12331237
.run();
1238+
assert!(paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file());
1239+
1240+
// Now delete the CACHEDIR.TAG file: this is the situation we'll be in after
1241+
// upgrading from a version of Cargo that doesn't mark this directory, to one that
1242+
// does. It should be recreated.
1243+
fs::remove_file(paths::home().join(".cargo/registry/CACHEDIR.TAG"))
1244+
.expect("remove CACHEDIR.TAG");
12341245

12351246
p.change_file(
12361247
"a/Cargo.toml",
@@ -1260,6 +1271,11 @@ fn updating_a_dep(cargo: fn(&Project, &str) -> Execs) {
12601271
",
12611272
)
12621273
.run();
1274+
1275+
assert!(
1276+
paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file(),
1277+
"CACHEDIR.TAG recreated in existing registry"
1278+
);
12631279
}
12641280

12651281
#[cargo_test]

0 commit comments

Comments
 (0)