Skip to content

Commit

Permalink
feat(source): wrap PathBuf with PathEntry
Browse files Browse the repository at this point in the history
This gives us more room to store file metadata.
For example,

* knowing a source file is a symlink and resolving it when packaging,
* providing a rich JSON output for `cargo package --list`
* enriching the `.cargo-vcs-info.json` with copied/symlinked file info
  • Loading branch information
weihanglo committed Dec 30, 2024
1 parent 0499e31 commit 42dc4ef
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 16 deletions.
5 changes: 3 additions & 2 deletions src/cargo/ops/cargo_package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::core::Workspace;
use crate::core::{Package, PackageId, PackageSet, Resolve, SourceId};
use crate::ops::lockfile::LOCKFILE_NAME;
use crate::ops::registry::{infer_registry, RegistryOrIndex};
use crate::sources::path::PathEntry;
use crate::sources::registry::index::{IndexPackage, RegistryDependency};
use crate::sources::{PathSource, CRATES_IO_REGISTRY};
use crate::util::cache_lock::CacheLockMode;
Expand Down Expand Up @@ -396,7 +397,7 @@ fn prepare_archive(
fn build_ar_list(
ws: &Workspace<'_>,
pkg: &Package,
src_files: Vec<PathBuf>,
src_files: Vec<PathEntry>,
vcs_info: Option<vcs::VcsInfo>,
) -> CargoResult<Vec<ArchiveFile>> {
let mut result = HashMap::new();
Expand All @@ -420,7 +421,7 @@ fn build_ar_list(
.push(ArchiveFile {
rel_path: rel_path.to_owned(),
rel_str: rel_str.to_owned(),
contents: FileContents::OnDisk(src_file.clone()),
contents: FileContents::OnDisk(src_file.to_path_buf()),
});
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/cargo/ops/cargo_package/vcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use serde::Serialize;
use tracing::debug;

use crate::core::Package;
use crate::sources::PathEntry;
use crate::CargoResult;
use crate::GlobalContext;

Expand Down Expand Up @@ -41,7 +42,7 @@ pub struct GitVcsInfo {
#[tracing::instrument(skip_all)]
pub fn check_repo_state(
p: &Package,
src_files: &[PathBuf],
src_files: &[PathEntry],
gctx: &GlobalContext,
opts: &PackageOpts<'_>,
) -> CargoResult<Option<VcsInfo>> {
Expand Down Expand Up @@ -114,7 +115,7 @@ pub fn check_repo_state(
fn git(
pkg: &Package,
gctx: &GlobalContext,
src_files: &[PathBuf],
src_files: &[PathEntry],
repo: &git2::Repository,
opts: &PackageOpts<'_>,
) -> CargoResult<Option<GitVcsInfo>> {
Expand All @@ -136,6 +137,7 @@ fn git(
let mut dirty_src_files: Vec<_> = src_files
.iter()
.filter(|src_file| dirty_files.iter().any(|path| src_file.starts_with(path)))
.map(|p| p.as_ref())
.chain(dirty_metadata_paths(pkg, repo)?.iter())
.map(|path| {
pathdiff::diff_paths(path, cwd)
Expand Down
4 changes: 3 additions & 1 deletion src/cargo/ops/vendor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::core::shell::Verbosity;
use crate::core::{GitReference, Package, Workspace};
use crate::ops;
use crate::sources::path::PathSource;
use crate::sources::PathEntry;
use crate::sources::CRATES_IO_REGISTRY;
use crate::util::cache_lock::CacheLockMode;
use crate::util::{try_canonicalize, CargoResult, GlobalContext};
Expand Down Expand Up @@ -315,13 +316,14 @@ fn sync(
fn cp_sources(
pkg: &Package,
src: &Path,
paths: &[PathBuf],
paths: &[PathEntry],
dst: &Path,
cksums: &mut BTreeMap<String, String>,
tmp_buf: &mut [u8],
gctx: &GlobalContext,
) -> CargoResult<()> {
for p in paths {
let p = p.as_ref();
let relative = p.strip_prefix(&src).unwrap();

match relative.to_str() {
Expand Down
1 change: 1 addition & 0 deletions src/cargo/sources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
pub use self::config::SourceConfigMap;
pub use self::directory::DirectorySource;
pub use self::git::GitSource;
pub use self::path::PathEntry;
pub use self::path::PathSource;
pub use self::path::RecursivePathSource;
pub use self::registry::{
Expand Down
52 changes: 41 additions & 11 deletions src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl<'gctx> PathSource<'gctx> {
/// use other methods like `.gitignore`, `package.include`, or
/// `package.exclude` to filter the list of files.
#[tracing::instrument(skip_all)]
pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> {
pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<PathEntry>> {
list_files(pkg, self.gctx)
}

Expand Down Expand Up @@ -278,7 +278,7 @@ impl<'gctx> RecursivePathSource<'gctx> {
/// are relevant for building this package, but it also contains logic to
/// use other methods like `.gitignore`, `package.include`, or
/// `package.exclude` to filter the list of files.
pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> {
pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<PathEntry>> {
list_files(pkg, self.gctx)
}

Expand Down Expand Up @@ -404,6 +404,32 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
}
}

/// [`PathBuf`] with extra metadata.
#[derive(Clone, Debug)]
pub struct PathEntry {
path: PathBuf,
}

impl PathEntry {
pub fn into_path_buf(self) -> PathBuf {
self.path
}
}

impl std::ops::Deref for PathEntry {
type Target = Path;

fn deref(&self) -> &Self::Target {
self.path.as_path()
}
}

impl AsRef<PathBuf> for PathEntry {
fn as_ref(&self) -> &PathBuf {
&self.path
}
}

fn first_package<'p>(
pkg_id: PackageId,
pkgs: &'p Vec<Package>,
Expand Down Expand Up @@ -446,7 +472,7 @@ fn first_package<'p>(
/// are relevant for building this package, but it also contains logic to
/// use other methods like `.gitignore`, `package.include`, or
/// `package.exclude` to filter the list of files.
pub fn list_files(pkg: &Package, gctx: &GlobalContext) -> CargoResult<Vec<PathBuf>> {
pub fn list_files(pkg: &Package, gctx: &GlobalContext) -> CargoResult<Vec<PathEntry>> {
_list_files(pkg, gctx).with_context(|| {
format!(
"failed to determine list of files in {}",
Expand All @@ -456,7 +482,7 @@ pub fn list_files(pkg: &Package, gctx: &GlobalContext) -> CargoResult<Vec<PathBu
}

/// See [`PathSource::list_files`].
fn _list_files(pkg: &Package, gctx: &GlobalContext) -> CargoResult<Vec<PathBuf>> {
fn _list_files(pkg: &Package, gctx: &GlobalContext) -> CargoResult<Vec<PathEntry>> {
let root = pkg.root();
let no_include_option = pkg.manifest().include().is_empty();
let git_repo = if no_include_option {
Expand Down Expand Up @@ -580,7 +606,7 @@ fn list_files_gix(
repo: &gix::Repository,
filter: &dyn Fn(&Path, bool) -> bool,
gctx: &GlobalContext,
) -> CargoResult<Vec<PathBuf>> {
) -> CargoResult<Vec<PathEntry>> {
debug!("list_files_gix {}", pkg.package_id());
let options = repo
.dirwalk_options()?
Expand Down Expand Up @@ -619,7 +645,7 @@ fn list_files_gix(
vec![include, exclude]
};

let mut files = Vec::<PathBuf>::new();
let mut files = Vec::<PathEntry>::new();
let mut subpackages_found = Vec::new();
for item in repo
.dirwalk_iter(index.clone(), pathspec, Default::default(), options)?
Expand Down Expand Up @@ -701,7 +727,7 @@ fn list_files_gix(
} else if (filter)(&file_path, is_dir) {
assert!(!is_dir);
trace!(" found {}", file_path.display());
files.push(file_path);
files.push(PathEntry { path: file_path });
}
}

Expand All @@ -715,7 +741,7 @@ fn list_files_gix(
/// is not tracked under a Git repository.
fn list_files_walk(
path: &Path,
ret: &mut Vec<PathBuf>,
ret: &mut Vec<PathEntry>,
is_root: bool,
filter: &dyn Fn(&Path, bool) -> bool,
gctx: &GlobalContext,
Expand Down Expand Up @@ -756,7 +782,9 @@ fn list_files_walk(
Ok(entry) => {
let file_type = entry.file_type();
if file_type.is_file() || file_type.is_symlink() {
ret.push(entry.into_path());
ret.push(PathEntry {
path: entry.into_path(),
});
}
}
Err(err) if err.loop_ancestor().is_some() => {
Expand All @@ -770,7 +798,9 @@ fn list_files_walk(
// Otherwise, simply recover from it.
// Don't worry about error skipping here, the callers would
// still hit the IO error if they do access it thereafter.
Some(path) => ret.push(path.to_path_buf()),
Some(path) => ret.push(PathEntry {
path: path.to_path_buf(),
}),
None => return Err(err.into()),
},
}
Expand Down Expand Up @@ -801,7 +831,7 @@ fn last_modified_file(
let mtime = paths::mtime(&file).unwrap_or_else(|_| FileTime::zero());
if mtime > max {
max = mtime;
max_path = file;
max_path = file.into_path_buf();
}
}
trace!("last modified file {}: {}", path.display(), max);
Expand Down

0 comments on commit 42dc4ef

Please sign in to comment.