Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for specifying cargo manifest path in pyproject.toml #781

Merged
merged 3 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Add support for using [`zig cc`](https://andrewkelley.me/post/zig-cc-powerful-drop-in-replacement-gcc-clang.html) as linker for easier cross compiling and manylinux compliance in [#756](https://github.com/PyO3/maturin/pull/756)
* Switch from reqwest to ureq to reduce dependencies in [#767](https://github.com/PyO3/maturin/pull/767)
* Fix missing Python submodule in wheel in [#772](https://github.com/PyO3/maturin/pull/772)
* Add support for specifying cargo manifest path in pyproject.toml in [#781](https://github.com/PyO3/maturin/pull/781)

## [0.12.6] - 2021-12-31

Expand Down
66 changes: 42 additions & 24 deletions src/build_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,9 @@ pub struct BuildOptions {
/// Which kind of bindings to use. Possible values are pyo3, rust-cpython, cffi and bin
#[clap(short, long)]
pub bindings: Option<String>,
#[clap(
short = 'm',
long = "manifest-path",
parse(from_os_str),
default_value = "Cargo.toml",
name = "PATH"
)]
#[clap(short = 'm', long = "manifest-path", parse(from_os_str), name = "PATH")]
/// The path to the Cargo.toml
pub manifest_path: PathBuf,
pub manifest_path: Option<PathBuf>,
/// The directory to store the built wheels in. Defaults to a new "wheels"
/// directory in the project's target directory
#[clap(short, long, parse(from_os_str))]
Expand Down Expand Up @@ -99,7 +93,7 @@ impl Default for BuildOptions {
platform_tag: None,
interpreter: Some(vec![]),
bindings: None,
manifest_path: PathBuf::from("Cargo.toml"),
manifest_path: None,
out: None,
skip_auditwheel: false,
zig: false,
Expand All @@ -112,28 +106,52 @@ impl Default for BuildOptions {
}

impl BuildOptions {
/// Get cargo manifest file path
fn manifest_path(&self) -> Result<PathBuf> {
// use command line argument if specified
if let Some(path) = &self.manifest_path {
return Ok(path.clone());
}
// check `manifest-path` option in pyproject.toml
let current_dir = env::current_dir()
.context("Failed to detect current directory ಠ_ಠ")?
.canonicalize()?;
let pyproject = PyProjectToml::new(&current_dir).context("pyproject.toml is invalid")?;
if let Some(path) = pyproject.manifest_path() {
println!("🔗 Found cargo manifest path in pyproject.toml");
// pyproject.toml must be placed at top directory
let manifest_dir = path
.parent()
.context("missing parent directory")?
.canonicalize()?;
if !manifest_dir.starts_with(&current_dir) {
bail!("Cargo.toml can not be placed outside of the directory containing pyproject.toml");
}
return Ok(path.to_path_buf());
}
// check Cargo.toml in current directory
let path = PathBuf::from("Cargo.toml");
if path.exists() {
Ok(path)
} else {
Err(format_err!(
"Can't find {} (in {})",
path.display(),
current_dir.display()
))
}
}
/// Tries to fill the missing metadata for a BuildContext by querying cargo and python
pub fn into_build_context(
self,
release: bool,
strip: bool,
editable: bool,
) -> Result<BuildContext> {
let manifest_file = &self.manifest_path;
if !manifest_file.exists() {
let current_dir =
env::current_dir().context("Failed to detect current directory ಠ_ಠ")?;
bail!(
"Can't find {} (in {})",
self.manifest_path.display(),
current_dir.display()
);
}

let manifest_file = self.manifest_path()?;
if !manifest_file.is_file() {
bail!(
"{} (resolved to {}) is not the path to a Cargo.toml",
self.manifest_path.display(),
"{} is not the path to a Cargo.toml",
manifest_file.display()
);
}
Expand Down Expand Up @@ -195,7 +213,7 @@ impl BuildOptions {
let cargo_metadata_extra_args = extract_cargo_metadata_args(&cargo_extra_args)?;

let result = MetadataCommand::new()
.manifest_path(&self.manifest_path)
.manifest_path(&manifest_file)
.other_options(cargo_metadata_extra_args)
.exec();

Expand Down Expand Up @@ -318,7 +336,7 @@ impl BuildOptions {
metadata21,
crate_name: crate_name.to_string(),
module_name,
manifest_path: self.manifest_path,
manifest_path: manifest_file,
out: wheel_dir,
release,
strip,
Expand Down
2 changes: 1 addition & 1 deletion src/develop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn develop(
platform_tag: Some(PlatformTag::Linux),
interpreter: Some(vec![python.clone()]),
bindings,
manifest_path: manifest_file.to_path_buf(),
manifest_path: Some(manifest_file.to_path_buf()),
out: Some(wheel_dir.path().to_path_buf()),
skip_auditwheel: false,
zig: false,
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ fn pep517(subcommand: Pep517Command) -> Result<()> {
manifest_path,
} => {
let build_options = BuildOptions {
manifest_path,
manifest_path: Some(manifest_path),
out: Some(sdist_directory),
..Default::default()
};
Expand Down Expand Up @@ -405,7 +405,7 @@ fn run() -> Result<()> {
}
Opt::SDist { manifest_path, out } => {
let build_options = BuildOptions {
manifest_path,
manifest_path: Some(manifest_path),
out,
..Default::default()
};
Expand Down
13 changes: 12 additions & 1 deletion src/pyproject_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use anyhow::{format_err, Context, Result};
use pyproject_toml::PyProjectToml as ProjectToml;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;
use std::path::{Path, PathBuf};

/// The `[tool]` section of a pyproject.toml
#[derive(Serialize, Deserialize, Debug, Clone)]
Expand All @@ -16,6 +16,7 @@ pub struct Tool {
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct ToolMaturin {
manifest_path: Option<PathBuf>,
sdist_include: Option<Vec<String>>,
bindings: Option<String>,
cargo_extra_args: Option<String>,
Expand Down Expand Up @@ -119,6 +120,16 @@ impl PyProjectToml {
.unwrap_or_default()
}

/// Returns the value of `[tool.maturin.manifest-path]` in pyproject.toml
pub fn manifest_path(&self) -> Option<&Path> {
self.tool
.as_ref()?
.maturin
.as_ref()?
.manifest_path
.as_deref()
}

/// Having a pyproject.toml without a version constraint is a bad idea
/// because at some point we'll have to do breaking changes and then source
/// distributions would break
Expand Down
1 change: 0 additions & 1 deletion tests/common/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ fn create_conda_env(name: &str, major: usize, minor: usize) {

#[cfg(target_os = "windows")]
pub fn test_integration_conda(package: impl AsRef<Path>, bindings: Option<String>) -> Result<()> {
use std::env;
use std::process::Stdio;

let package_string = package.as_ref().join("Cargo.toml").display().to_string();
Expand Down
2 changes: 1 addition & 1 deletion tests/common/other.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub fn test_source_distribution(
let sdist_directory = Path::new("test-crates").join("wheels").join(unique_name);

let build_options = BuildOptions {
manifest_path,
manifest_path: Some(manifest_path),
out: Some(sdist_directory),
cargo_extra_args: vec![
"--quiet".to_string(),
Expand Down