]> git.proxmox.com Git - cargo.git/blame - src/cargo/ops/cargo_read_manifest.rs
Ignore malformed manifests on git dependencies
[cargo.git] / src / cargo / ops / cargo_read_manifest.rs
CommitLineData
06a0605f 1use std::collections::{HashMap, HashSet};
f28c7872 2use std::fs;
a6dad622
AC
3use std::io;
4use std::path::{Path, PathBuf};
a09ad635 5
58ddb28a 6use core::{Package, SourceId, PackageId, EitherManifest};
f28c7872 7use util::{self, paths, CargoResult, human, Config, ChainError};
ea3cb31c 8use util::important_paths::find_project_manifest_exact;
1e01f489 9use util::toml::Layout;
62bff631 10
58ddb28a
AC
11pub fn read_manifest(path: &Path, source_id: &SourceId, config: &Config)
12 -> CargoResult<(EitherManifest, Vec<PathBuf>)> {
13 trace!("read_package; path={}; source-id={}", path.display(), source_id);
82655b46 14 let contents = paths::read(path)?;
58ddb28a
AC
15
16 let layout = Layout::from_project_path(path.parent().unwrap());
ed58e0be 17 let root = layout.root.clone();
58ddb28a 18 util::toml::to_manifest(&contents, source_id, layout, config).chain_error(|| {
d73a110d
AC
19 human(format!("failed to parse manifest at `{}`",
20 root.join("Cargo.toml").display()))
ed58e0be 21 })
b3c23503
CL
22}
23
5d0cb3f2 24pub fn read_package(path: &Path, source_id: &SourceId, config: &Config)
a6dad622 25 -> CargoResult<(Package, Vec<PathBuf>)> {
98854f6f 26 trace!("read_package; path={}; source-id={}", path.display(), source_id);
82655b46 27 let (manifest, nested) = read_manifest(path, source_id, config)?;
58ddb28a
AC
28 let manifest = match manifest {
29 EitherManifest::Real(manifest) => manifest,
30 EitherManifest::Virtual(..) => {
31 bail!("found a virtual manifest at `{}` instead of a package \
32 manifest", path.display())
33 }
34 };
bbbf2dea 35
346df29a 36 Ok((Package::new(manifest, path), nested))
62bff631 37}
bcf90287 38
5d0cb3f2
AC
39pub fn read_packages(path: &Path, source_id: &SourceId, config: &Config)
40 -> CargoResult<Vec<Package>> {
06a0605f 41 let mut all_packages = HashMap::new();
a6dad622 42 let mut visited = HashSet::<PathBuf>::new();
bcf90287 43
98854f6f 44 trace!("looking for root package: {}, source_id={}", path.display(), source_id);
71e4252a 45
82655b46 46 walk(path, &mut |dir| {
98854f6f 47 trace!("looking for child package: {}", dir.display());
c84bc16b 48
4cd3c567
PG
49 // Don't recurse into hidden/dot directories unless we're at the toplevel
50 if dir != path {
51 let name = dir.file_name().and_then(|s| s.to_str());
52 if name.map(|s| s.starts_with(".")) == Some(true) {
53 return Ok(false)
54 }
c84bc16b 55
4cd3c567
PG
56 // Don't automatically discover packages across git submodules
57 if fs::metadata(&dir.join(".git")).is_ok() {
58 return Ok(false)
59 }
97a2f271 60 }
c84bc16b
AC
61
62 // Don't ever look at target directories
a6dad622
AC
63 if dir.file_name().and_then(|s| s.to_str()) == Some("target") &&
64 has_manifest(dir.parent().unwrap()) {
c84bc16b
AC
65 return Ok(false)
66 }
67
68 if has_manifest(dir) {
82655b46
SG
69 read_nested_packages(dir, &mut all_packages, source_id, config,
70 &mut visited)?;
c84bc16b 71 }
ea3cb31c 72 Ok(true)
82655b46 73 })?;
bcf90287 74
ea3cb31c
YK
75 if all_packages.is_empty() {
76 Err(human(format!("Could not find Cargo.toml in `{}`", path.display())))
77 } else {
06a0605f 78 Ok(all_packages.into_iter().map(|(_, v)| v).collect())
ea3cb31c
YK
79 }
80}
81
e595e877
AC
82fn walk(path: &Path, callback: &mut FnMut(&Path) -> CargoResult<bool>)
83 -> CargoResult<()> {
82655b46 84 if !callback(path)? {
a6dad622 85 trace!("not processing {}", path.display());
97a2f271 86 return Ok(())
a6dad622 87 }
71e4252a 88
a6dad622
AC
89 // Ignore any permission denied errors because temporary directories
90 // can often have some weird permissions on them.
91 let dirs = match fs::read_dir(path) {
92 Ok(dirs) => dirs,
93 Err(ref e) if e.kind() == io::ErrorKind::PermissionDenied => {
94 return Ok(())
ea3cb31c 95 }
d1e640d7
AC
96 Err(e) => {
97 return Err(human(e)).chain_error(|| {
98 human(format!("failed to read directory `{}`", path.display()))
99 })
100 }
a6dad622
AC
101 };
102 for dir in dirs {
82655b46
SG
103 let dir = dir?;
104 if dir.file_type()?.is_dir() {
105 walk(&dir.path(), callback)?;
e595e877 106 }
ea3cb31c 107 }
ea3cb31c
YK
108 Ok(())
109}
110
ea3cb31c
YK
111fn has_manifest(path: &Path) -> bool {
112 find_project_manifest_exact(path, "Cargo.toml").is_ok()
113}
114
c84bc16b 115fn read_nested_packages(path: &Path,
06a0605f 116 all_packages: &mut HashMap<PackageId, Package>,
c84bc16b 117 source_id: &SourceId,
5d0cb3f2 118 config: &Config,
a6dad622
AC
119 visited: &mut HashSet<PathBuf>) -> CargoResult<()> {
120 if !visited.insert(path.to_path_buf()) { return Ok(()) }
ea3cb31c 121
82655b46 122 let manifest_path = find_project_manifest_exact(path, "Cargo.toml")?;
9243f06d 123
3d6de417
FA
124 let result = read_manifest(&manifest_path, source_id, config);
125
126 // Ignore malformed manifests
127 if result.is_err() {
128 info!("skipping malformed package found at `{}`",
129 path.to_string_lossy());
130 return Ok(());
131 }
132
133 let (manifest, nested) = result.unwrap();
9243f06d
AC
134 let manifest = match manifest {
135 EitherManifest::Real(manifest) => manifest,
136 EitherManifest::Virtual(..) => return Ok(()),
137 };
138 let pkg = Package::new(manifest, &manifest_path);
ea3cb31c 139
cdbaa749
SF
140 let pkg_id = pkg.package_id().clone();
141 if !all_packages.contains_key(&pkg_id) {
142 all_packages.insert(pkg_id, pkg);
143 } else {
8790c820
SF
144 info!("skipping nested package `{}` found at `{}`",
145 pkg.name(), path.to_string_lossy());
cdbaa749 146 }
ea3cb31c 147
9fba127e
AC
148 // Registry sources are not allowed to have `path=` dependencies because
149 // they're all translated to actual registry dependencies.
a6dad622
AC
150 //
151 // We normalize the path here ensure that we don't infinitely walk around
152 // looking for crates. By normalizing we ensure that we visit this crate at
153 // most once.
154 //
155 // TODO: filesystem/symlink implications?
9fba127e
AC
156 if !source_id.is_registry() {
157 for p in nested.iter() {
a6dad622 158 let path = util::normalize_path(&path.join(p));
82655b46
SG
159 read_nested_packages(&path, all_packages, source_id,
160 config, visited)?;
9fba127e 161 }
ea3cb31c
YK
162 }
163
c84bc16b 164 Ok(())
bcf90287 165}