Skip to content

Commit 6ce1f8d

Browse files
committed
Clone but do not checkout repositories
1 parent 6823e01 commit 6ce1f8d

4 files changed

Lines changed: 74 additions & 14 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ sha1_smol = { version = "1.0", features = ["std"] }
2727
tempfile = "3.14"
2828
termcolor = "1.4"
2929
toml = "0.8"
30-
walkdir = "2.5"
3130

3231
[target.'cfg(unix)'.dependencies]
3332
libc = { version = "0.2", optional = true }

src/main.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,17 @@ use std::{
1414
collections::{HashMap, HashSet},
1515
env::args,
1616
ffi::OsStr,
17-
fs::{read_to_string, File},
18-
io::IsTerminal,
17+
fs::File,
18+
io::{BufRead, IsTerminal},
1919
path::{Path, PathBuf},
20-
process::{exit, Command},
20+
process::{exit, Command, Stdio},
2121
str::FromStr,
2222
sync::atomic::{AtomicBool, Ordering},
2323
time::{Duration, SystemTime},
2424
};
2525
use tempfile::TempDir;
2626
use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};
2727
use toml::{Table, Value};
28-
use walkdir::WalkDir;
2928

3029
mod curl;
3130
mod flush;
@@ -809,14 +808,30 @@ fn clone_repository(pkg: &Package, purpose: Purpose) -> Result<RepoStatus<PathBu
809808
}
810809
}
811810

811+
const LINE_PREFIX: &str = "D ";
812+
812813
fn membership_in_clone(pkg: &Package, repo_dir: &Path) -> Result<bool> {
813-
for entry in WalkDir::new(repo_dir) {
814-
let entry = entry?;
815-
let path = entry.path();
814+
let mut command = Command::new("git");
815+
command.args(["status", "--porcelain"]);
816+
command.current_dir(repo_dir);
817+
command.stdout(Stdio::piped());
818+
let mut child = command
819+
.spawn()
820+
.with_context(|| format!("command failed: {command:?}"))?;
821+
#[allow(clippy::unwrap_used)]
822+
let stdout = child.stdout.take().unwrap();
823+
let reader = std::io::BufReader::new(stdout);
824+
for result in reader.lines() {
825+
let line = result.with_context(|| format!("failed to read `{}`", repo_dir.display()))?;
826+
#[allow(clippy::panic)]
827+
let path = line.strip_prefix(LINE_PREFIX).map_or_else(
828+
|| panic!("cache is corrupt at `{}`", repo_dir.display()),
829+
Path::new,
830+
);
816831
if path.file_name() != Some(OsStr::new("Cargo.toml")) {
817832
continue;
818833
}
819-
let contents = read_to_string(path).with_context(|| format!("failed to read {path:?}"))?;
834+
let contents = show(repo_dir, path)?;
820835
let Ok(table) = contents.parse::<Table>()
821836
/* smoelius: This "failed to parse" warning is a little too noisy.
822837
.map_err(|error| {
@@ -843,6 +858,26 @@ fn membership_in_clone(pkg: &Package, repo_dir: &Path) -> Result<bool> {
843858
Ok(false)
844859
}
845860

861+
fn show(repo_dir: &Path, path: &Path) -> Result<String> {
862+
let mut command = Command::new("git");
863+
command.args(["show", &format!("HEAD:{}", path.display())]);
864+
command.current_dir(repo_dir);
865+
command.stdout(Stdio::piped());
866+
let output = command
867+
.output()
868+
.with_context(|| format!("failed to run command: {command:?}"))?;
869+
if !output.status.success() {
870+
let error = String::from_utf8(output.stderr)?;
871+
bail!(
872+
"failed to read `{}` in `{}`: {}",
873+
path.display(),
874+
repo_dir.display(),
875+
error
876+
);
877+
}
878+
String::from_utf8(output.stdout).map_err(Into::into)
879+
}
880+
846881
fn display_unmaintained_pkgs(unmaintained_pkgs: &[UnmaintainedPkg]) -> Result<()> {
847882
let mut pkgs_needing_warning = Vec::new();
848883
let mut at_least_one_newer_version_is_available = false;

src/on_disk_cache.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
//!
2424
//! A similar statement applies to versions.
2525
//!
26-
//! The on-disk cache resides at `$HOME/.cache/cargo-unmaintained/v1`.
26+
//! The on-disk cache resides at `$HOME/.cache/cargo-unmaintained/v2`.
2727
2828
use super::{urls, SECS_PER_DAY};
29-
use anyhow::{anyhow, ensure, Context, Result};
29+
use anyhow::{anyhow, bail, ensure, Context, Result};
3030
use cargo_metadata::Package;
3131
use crates_io_api::{SyncClient, Version};
3232
use once_cell::{sync::Lazy, unsync::OnceCell};
@@ -72,7 +72,7 @@ thread_local! {
7272
static CACHE_DIRECTORY: Lazy<PathBuf> = Lazy::new(|| {
7373
let base_directories = xdg::BaseDirectories::new().unwrap();
7474
base_directories
75-
.create_cache_directory("cargo-unmaintained/v1")
75+
.create_cache_directory("cargo-unmaintained/v2")
7676
.unwrap()
7777
});
7878

@@ -170,15 +170,23 @@ impl Cache {
170170
let repo_dir = self.repositories_dir().join(url_digest(url.as_str()));
171171
let exists = repository_existence(&repo_dir)?;
172172
let mut command = if exists {
173+
let branch_name = branch_name(&repo_dir)?;
173174
let mut command = Command::new("git");
174-
command.args(["pull", "--ff-only"]);
175+
command.args([
176+
"fetch",
177+
"--update-head-ok",
178+
"origin",
179+
&format!("{branch_name}:{branch_name}"),
180+
]);
175181
command.current_dir(&repo_dir);
176182
command
177183
} else {
178184
let mut command = Command::new("git");
185+
// smoelius: The full repository is no longer checked out.
179186
command.args([
180187
"clone",
181188
"--depth=1",
189+
"--no-checkout",
182190
"--quiet",
183191
url.as_str(),
184192
&repo_dir.to_string_lossy(),
@@ -379,3 +387,22 @@ fn repository_existence(repo_dir: &Path) -> Result<bool> {
379387
)
380388
})
381389
}
390+
391+
fn branch_name(repo_dir: &Path) -> Result<String> {
392+
let mut command = Command::new("git");
393+
command.args(["rev-parse", "--abbrev-ref", "HEAD"]);
394+
command.current_dir(repo_dir);
395+
let output = command
396+
.output()
397+
.with_context(|| format!("failed to run command: {command:?}"))?;
398+
if !output.status.success() {
399+
let error = String::from_utf8(output.stderr)?;
400+
bail!(
401+
"failed to get `{}` branch name: {}",
402+
repo_dir.display(),
403+
error
404+
);
405+
}
406+
let stdout = std::str::from_utf8(&output.stdout)?;
407+
Ok(stdout.trim_end().to_owned())
408+
}

0 commit comments

Comments
 (0)