Skip to content

Commit 5184099

Browse files
committed
Fix transitive path dependencies in sdist
1 parent 089b79d commit 5184099

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

src/source_distribution.rs

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::module_writer::ModuleWriter;
22
use crate::{Metadata21, SDistWriter};
33
use anyhow::{bail, Context, Result};
4-
use cargo_metadata::Metadata;
4+
use cargo_metadata::{Metadata, PackageId};
55
use fs_err as fs;
66
use std::collections::HashMap;
77
use std::path::{Path, PathBuf};
@@ -10,6 +10,13 @@ use std::str;
1010

1111
const LOCAL_DEPENDENCIES_FOLDER: &str = "local_dependencies";
1212

13+
#[derive(Debug, Clone)]
14+
struct PathDependency {
15+
id: PackageId,
16+
name: String,
17+
path: PathBuf,
18+
}
19+
1320
/// We need cargo to load the local dependencies from the location where we put them in the source
1421
/// distribution. Since there is no cargo-backed way to replace dependencies
1522
/// (see https://github.com/rust-lang/cargo/issues/9170), we do a simple
@@ -19,7 +26,7 @@ const LOCAL_DEPENDENCIES_FOLDER: &str = "local_dependencies";
1926
/// This method is rather frail, but unfortunately I don't know a better solution.
2027
fn rewrite_cargo_toml(
2128
manifest_path: impl AsRef<Path>,
22-
known_path_deps: &HashMap<String, PathBuf>,
29+
known_path_deps: &HashMap<String, PathDependency>,
2330
root_crate: bool,
2431
) -> Result<String> {
2532
let text = fs::read_to_string(&manifest_path).context(format!(
@@ -87,7 +94,7 @@ fn add_crate_to_source_distribution(
8794
writer: &mut SDistWriter,
8895
manifest_path: impl AsRef<Path>,
8996
prefix: impl AsRef<Path>,
90-
known_path_deps: &HashMap<String, PathBuf>,
97+
known_path_deps: &HashMap<String, PathDependency>,
9198
root_crate: bool,
9299
) -> Result<()> {
93100
let output = Command::new("cargo")
@@ -157,7 +164,45 @@ fn add_crate_to_source_distribution(
157164
Ok(())
158165
}
159166

160-
/// Creates aif source distribution, packing the root crate and all local dependencies
167+
/// Get path dependencies for a cargo package
168+
fn get_path_deps(
169+
cargo_metadata: &Metadata,
170+
resolve: &cargo_metadata::Resolve,
171+
pkg_id: &cargo_metadata::PackageId,
172+
visited: &HashMap<String, PathDependency>,
173+
) -> Result<HashMap<String, PathDependency>> {
174+
// Parse ids in the format:
175+
// on unix: some_path_dep 0.1.0 (path+file:///home/konsti/maturin/test-crates/some_path_dep)
176+
// on windows: some_path_dep 0.1.0 (path+file:///C:/konsti/maturin/test-crates/some_path_dep)
177+
// This is not a good way to identify path dependencies, but I don't know a better one
178+
let node = resolve
179+
.nodes
180+
.iter()
181+
.find(|node| &node.id == pkg_id)
182+
.context("Expected to get a node of dependency graph from cargo")?;
183+
let path_deps = node
184+
.deps
185+
.iter()
186+
.filter(|node| node.pkg.repr.contains("path+file://"))
187+
.filter_map(|node| {
188+
cargo_metadata.packages.iter().find_map(|pkg| {
189+
if pkg.id.repr == node.pkg.repr && !visited.contains_key(&pkg.name) {
190+
let path_dep = PathDependency {
191+
id: pkg.id.clone(),
192+
name: pkg.name.clone(),
193+
path: PathBuf::from(&pkg.manifest_path),
194+
};
195+
Some((pkg.name.clone(), path_dep))
196+
} else {
197+
None
198+
}
199+
})
200+
})
201+
.collect();
202+
Ok(path_deps)
203+
}
204+
205+
/// Creates a source distribution, packing the root crate and all local dependencies
161206
///
162207
/// The source distribution format is specified in
163208
/// [PEP 517 under "build_sdist"](https://www.python.org/dev/peps/pep-0517/#build-sdist)
@@ -170,37 +215,24 @@ pub fn source_distribution(
170215
cargo_metadata: &Metadata,
171216
sdist_include: Option<&Vec<String>>,
172217
) -> Result<PathBuf> {
173-
// Parse ids in the format:
174-
// on unix: some_path_dep 0.1.0 (path+file:///home/konsti/maturin/test-crates/some_path_dep)
175-
// on windows: some_path_dep 0.1.0 (path+file:///C:/konsti/maturin/test-crates/some_path_dep)
176-
// This is not a good way to identify path dependencies, but I don't know a better one
177218
let resolve = cargo_metadata
178219
.resolve
179220
.as_ref()
180221
.context("Expected to get a dependency graph from cargo")?;
181222
let root = resolve
182223
.root
183-
.as_ref()
224+
.clone()
184225
.context("Expected to get a root package id of dependency graph from cargo")?;
185-
let root_node = resolve
186-
.nodes
187-
.iter()
188-
.find(|node| &node.id == root)
189-
.context("Expected to get a root node of dependency graph from cargo")?;
190-
let known_path_deps: HashMap<String, PathBuf> = root_node
191-
.deps
192-
.iter()
193-
.filter(|node| node.pkg.repr.contains("path+file://"))
194-
.filter_map(|node| {
195-
cargo_metadata.packages.iter().find_map(|pkg| {
196-
if pkg.id.repr == node.pkg.repr {
197-
Some((pkg.name.clone(), PathBuf::from(&pkg.manifest_path)))
198-
} else {
199-
None
200-
}
201-
})
202-
})
203-
.collect();
226+
let mut known_path_deps = HashMap::new();
227+
let mut stack = vec![root];
228+
while let Some(pkg_id) = stack.pop() {
229+
let path_deps = get_path_deps(cargo_metadata, resolve, &pkg_id, &known_path_deps)?;
230+
if path_deps.is_empty() {
231+
continue;
232+
}
233+
stack.extend(path_deps.values().map(|dep| dep.id.clone()));
234+
known_path_deps.extend(path_deps);
235+
}
204236

205237
let mut writer = SDistWriter::new(wheel_dir, metadata21)?;
206238
let root_dir = PathBuf::from(format!(
@@ -210,18 +242,18 @@ pub fn source_distribution(
210242
));
211243

212244
// Add local path dependencies
213-
for (name, path) in known_path_deps.iter() {
245+
for (name, path_dep) in known_path_deps.iter() {
214246
add_crate_to_source_distribution(
215247
&mut writer,
216-
&path,
248+
&path_dep.path,
217249
&root_dir.join(LOCAL_DEPENDENCIES_FOLDER).join(name),
218250
&known_path_deps,
219251
false,
220252
)
221253
.context(format!(
222254
"Failed to add local dependency {} at {} to the source distribution",
223255
name,
224-
path.display()
256+
path_dep.path.display()
225257
))?;
226258
}
227259

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Cargo.lock

0 commit comments

Comments
 (0)