Skip to content

Commit b2f2b6d

Browse files
committed
refactor(source): Pull in read_packages
This is tied to the `Source` and only used there.
1 parent 9b016a1 commit b2f2b6d

File tree

3 files changed

+253
-251
lines changed

3 files changed

+253
-251
lines changed

src/cargo/ops/cargo_read_manifest.rs

Lines changed: 3 additions & 246 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
use std::collections::{HashMap, HashSet};
2-
use std::fs;
3-
use std::io;
4-
use std::path::{Path, PathBuf};
1+
use std::path::Path;
52

6-
use crate::core::{EitherManifest, Manifest, Package, PackageId, SourceId};
3+
use crate::core::{EitherManifest, Package, SourceId};
74
use crate::util::errors::CargoResult;
8-
use crate::util::important_paths::find_project_manifest_exact;
95
use crate::util::toml::read_manifest;
106
use crate::util::GlobalContext;
11-
use cargo_util::paths;
12-
use tracing::{info, trace};
7+
use tracing::trace;
138

149
pub fn read_package(
1510
path: &Path,
@@ -33,241 +28,3 @@ pub fn read_package(
3328

3429
Ok(Package::new(manifest, path))
3530
}
36-
37-
pub fn read_packages(
38-
path: &Path,
39-
source_id: SourceId,
40-
gctx: &GlobalContext,
41-
) -> CargoResult<Vec<Package>> {
42-
let mut all_packages = HashMap::new();
43-
let mut visited = HashSet::<PathBuf>::new();
44-
let mut errors = Vec::<anyhow::Error>::new();
45-
46-
trace!(
47-
"looking for root package: {}, source_id={}",
48-
path.display(),
49-
source_id
50-
);
51-
52-
walk(path, &mut |dir| {
53-
trace!("looking for child package: {}", dir.display());
54-
55-
// Don't recurse into hidden/dot directories unless we're at the toplevel
56-
if dir != path {
57-
let name = dir.file_name().and_then(|s| s.to_str());
58-
if name.map(|s| s.starts_with('.')) == Some(true) {
59-
return Ok(false);
60-
}
61-
62-
// Don't automatically discover packages across git submodules
63-
if dir.join(".git").exists() {
64-
return Ok(false);
65-
}
66-
}
67-
68-
// Don't ever look at target directories
69-
if dir.file_name().and_then(|s| s.to_str()) == Some("target")
70-
&& has_manifest(dir.parent().unwrap())
71-
{
72-
return Ok(false);
73-
}
74-
75-
if has_manifest(dir) {
76-
read_nested_packages(
77-
dir,
78-
&mut all_packages,
79-
source_id,
80-
gctx,
81-
&mut visited,
82-
&mut errors,
83-
)?;
84-
}
85-
Ok(true)
86-
})?;
87-
88-
if all_packages.is_empty() {
89-
match errors.pop() {
90-
Some(err) => Err(err),
91-
None => {
92-
if find_project_manifest_exact(path, "cargo.toml").is_ok() {
93-
Err(anyhow::format_err!(
94-
"Could not find Cargo.toml in `{}`, but found cargo.toml please try to rename it to Cargo.toml",
95-
path.display()
96-
))
97-
} else {
98-
Err(anyhow::format_err!(
99-
"Could not find Cargo.toml in `{}`",
100-
path.display()
101-
))
102-
}
103-
}
104-
}
105-
} else {
106-
Ok(all_packages.into_iter().map(|(_, v)| v).collect())
107-
}
108-
}
109-
110-
fn nested_paths(manifest: &Manifest) -> Vec<PathBuf> {
111-
let mut nested_paths = Vec::new();
112-
let resolved = manifest.resolved_toml();
113-
let dependencies = resolved
114-
.dependencies
115-
.iter()
116-
.chain(resolved.build_dependencies())
117-
.chain(resolved.dev_dependencies())
118-
.chain(
119-
resolved
120-
.target
121-
.as_ref()
122-
.into_iter()
123-
.flat_map(|t| t.values())
124-
.flat_map(|t| {
125-
t.dependencies
126-
.iter()
127-
.chain(t.build_dependencies())
128-
.chain(t.dev_dependencies())
129-
}),
130-
);
131-
for dep_table in dependencies {
132-
for dep in dep_table.values() {
133-
let cargo_util_schemas::manifest::InheritableDependency::Value(dep) = dep else {
134-
continue;
135-
};
136-
let cargo_util_schemas::manifest::TomlDependency::Detailed(dep) = dep else {
137-
continue;
138-
};
139-
let Some(path) = dep.path.as_ref() else {
140-
continue;
141-
};
142-
nested_paths.push(PathBuf::from(path.as_str()));
143-
}
144-
}
145-
nested_paths
146-
}
147-
148-
fn walk(path: &Path, callback: &mut dyn FnMut(&Path) -> CargoResult<bool>) -> CargoResult<()> {
149-
if !callback(path)? {
150-
trace!("not processing {}", path.display());
151-
return Ok(());
152-
}
153-
154-
// Ignore any permission denied errors because temporary directories
155-
// can often have some weird permissions on them.
156-
let dirs = match fs::read_dir(path) {
157-
Ok(dirs) => dirs,
158-
Err(ref e) if e.kind() == io::ErrorKind::PermissionDenied => return Ok(()),
159-
Err(e) => {
160-
let cx = format!("failed to read directory `{}`", path.display());
161-
let e = anyhow::Error::from(e);
162-
return Err(e.context(cx));
163-
}
164-
};
165-
for dir in dirs {
166-
let dir = dir?;
167-
if dir.file_type()?.is_dir() {
168-
walk(&dir.path(), callback)?;
169-
}
170-
}
171-
Ok(())
172-
}
173-
174-
fn has_manifest(path: &Path) -> bool {
175-
find_project_manifest_exact(path, "Cargo.toml").is_ok()
176-
}
177-
178-
fn read_nested_packages(
179-
path: &Path,
180-
all_packages: &mut HashMap<PackageId, Package>,
181-
source_id: SourceId,
182-
gctx: &GlobalContext,
183-
visited: &mut HashSet<PathBuf>,
184-
errors: &mut Vec<anyhow::Error>,
185-
) -> CargoResult<()> {
186-
if !visited.insert(path.to_path_buf()) {
187-
return Ok(());
188-
}
189-
190-
let manifest_path = find_project_manifest_exact(path, "Cargo.toml")?;
191-
192-
let manifest = match read_manifest(&manifest_path, source_id, gctx) {
193-
Err(err) => {
194-
// Ignore malformed manifests found on git repositories
195-
//
196-
// git source try to find and read all manifests from the repository
197-
// but since it's not possible to exclude folders from this search
198-
// it's safer to ignore malformed manifests to avoid
199-
//
200-
// TODO: Add a way to exclude folders?
201-
info!(
202-
"skipping malformed package found at `{}`",
203-
path.to_string_lossy()
204-
);
205-
errors.push(err.into());
206-
return Ok(());
207-
}
208-
Ok(tuple) => tuple,
209-
};
210-
211-
let manifest = match manifest {
212-
EitherManifest::Real(manifest) => manifest,
213-
EitherManifest::Virtual(..) => return Ok(()),
214-
};
215-
let nested = nested_paths(&manifest);
216-
let pkg = Package::new(manifest, &manifest_path);
217-
218-
let pkg_id = pkg.package_id();
219-
use std::collections::hash_map::Entry;
220-
match all_packages.entry(pkg_id) {
221-
Entry::Vacant(v) => {
222-
v.insert(pkg);
223-
}
224-
Entry::Occupied(_) => {
225-
// We can assume a package with publish = false isn't intended to be seen
226-
// by users so we can hide the warning about those since the user is unlikely
227-
// to care about those cases.
228-
if pkg.publish().is_none() {
229-
let _ = gctx.shell().warn(format!(
230-
"skipping duplicate package `{}` found at `{}`",
231-
pkg.name(),
232-
path.display()
233-
));
234-
}
235-
}
236-
}
237-
238-
// Registry sources are not allowed to have `path=` dependencies because
239-
// they're all translated to actual registry dependencies.
240-
//
241-
// We normalize the path here ensure that we don't infinitely walk around
242-
// looking for crates. By normalizing we ensure that we visit this crate at
243-
// most once.
244-
//
245-
// TODO: filesystem/symlink implications?
246-
if !source_id.is_registry() {
247-
for p in nested.iter() {
248-
let path = paths::normalize_path(&path.join(p));
249-
let result =
250-
read_nested_packages(&path, all_packages, source_id, gctx, visited, errors);
251-
// Ignore broken manifests found on git repositories.
252-
//
253-
// A well formed manifest might still fail to load due to reasons
254-
// like referring to a "path" that requires an extra build step.
255-
//
256-
// See https://github.com/rust-lang/cargo/issues/6822.
257-
if let Err(err) = result {
258-
if source_id.is_git() {
259-
info!(
260-
"skipping nested package found at `{}`: {:?}",
261-
path.display(),
262-
&err,
263-
);
264-
errors.push(err);
265-
} else {
266-
return Err(err);
267-
}
268-
}
269-
}
270-
}
271-
272-
Ok(())
273-
}

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub use self::cargo_new::{init, new, NewOptions, NewProjectKind, VersionControl}
1212
pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadataOptions};
1313
pub use self::cargo_package::{check_yanked, package, package_one, PackageOpts};
1414
pub use self::cargo_pkgid::pkgid;
15-
pub use self::cargo_read_manifest::{read_package, read_packages};
15+
pub use self::cargo_read_manifest::read_package;
1616
pub use self::cargo_run::run;
1717
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
1818
pub use self::cargo_uninstall::uninstall;

0 commit comments

Comments
 (0)