Skip to content

Commit

Permalink
init: new command similar to cargo init
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Nov 30, 2021
1 parent fc039bd commit 08142db
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 28 deletions.
4 changes: 3 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* Add a `maturin init` command as a companion to `maturin new` in [#719](https://github.com/PyO3/maturin/pull/719)

## [0.12.3] - 2021-11-29

* Use platform tag from `sysconfig.platform` on non-portable Linux in [#709](https://github.com/PyO3/maturin/pull/709)
Expand Down Expand Up @@ -122,7 +124,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.10.3] - 2021-04-13

* The `upload` command is now implemented, it is mostly similar to `twine upload`. [#484](https://github.com/PyO3/maturin/pull/484)
* Interpreter search now uses python 3.6 to 3.12
* Interpreter search now uses python 3.6 to 3.12
* Add basic support for OpenBSD in [#496](https://github.com/PyO3/maturin/pull/496)
* Fix the PowerPC platform by messense in [#503](https://github.com/PyO3/maturin/pull/503)

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub use crate::metadata::{Metadata21, WheelMetadata};
pub use crate::module_writer::{
write_dist_info, ModuleWriter, PathWriter, SDistWriter, WheelWriter,
};
pub use crate::new_project::new_project;
pub use crate::new_project::{new_project, init_project};
pub use crate::pyproject_toml::PyProjectToml;
pub use crate::python_interpreter::PythonInterpreter;
pub use crate::target::Target;
Expand Down
23 changes: 22 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use human_panic::setup_panic;
#[cfg(feature = "password-storage")]
use keyring::{Keyring, KeyringError};
use maturin::{
develop, new_project, source_distribution, write_dist_info, BridgeModel, BuildOptions,
develop, init_project, new_project, source_distribution, write_dist_info, BridgeModel, BuildOptions,
CargoToml, Metadata21, PathWriter, PlatformTag, PyProjectToml, PythonInterpreter, Target,
};
use std::env;
Expand Down Expand Up @@ -270,6 +270,21 @@ enum Opt {
#[structopt(short, long, parse(from_os_str))]
out: Option<PathBuf>,
},
/// Create a new cargo project in an existing directory
#[structopt(name = "init")]
InitProject {
/// Project path
path: Option<String>,
/// Set the resulting package name, defaults to the directory name
#[structopt(long)]
name: Option<String>,
/// Use mixed Rust/Python project layout
#[structopt(long)]
mixed: bool,
/// Which kind of bindings to use
#[structopt(short, long, possible_values = &["pyo3", "rust-cpython", "cffi", "bin"])]
bindings: Option<String>,
},
/// Create a new cargo project
#[structopt(name = "new")]
NewProject {
Expand Down Expand Up @@ -636,6 +651,12 @@ fn run() -> Result<()> {
.context("Failed to build source distribution")?;
}
Opt::Pep517(subcommand) => pep517(subcommand)?,
Opt::InitProject {
path,
name,
mixed,
bindings,
} => init_project(path, name, mixed, bindings)?,
Opt::NewProject {
path,
name,
Expand Down
82 changes: 57 additions & 25 deletions src/new_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ struct ProjectGenerator<'a> {
crate_name: String,
bindings: String,
mixed: bool,
overwrite: bool,
}

impl<'a> ProjectGenerator<'a> {
fn new(project_name: String, mixed: bool, bindings: String) -> Result<Self> {
fn new(project_name: String, mixed: bool, bindings: String, overwrite: bool) -> Result<Self> {
let crate_name = project_name.replace('-', "_");
let mut env = Environment::new();
env.add_template(".gitignore", include_str!("templates/.gitignore.j2"))?;
Expand All @@ -33,48 +34,34 @@ impl<'a> ProjectGenerator<'a> {
crate_name,
bindings,
mixed,
overwrite,
})
}

fn generate(&self, project_path: &Path) -> Result<()> {
let src_path = project_path.join("src");
fs::create_dir_all(&src_path)?;

let gitignore = self.render_template(".gitignore")?;
fs::write(project_path.join(".gitignore"), gitignore)?;

let cargo_toml = self.render_template("Cargo.toml")?;
fs::write(project_path.join("Cargo.toml"), cargo_toml)?;

let pyproject_toml = self.render_template("pyproject.toml")?;
fs::write(project_path.join("pyproject.toml"), pyproject_toml)?;
self.write_project_file(project_path, ".gitignore")?;
self.write_project_file(project_path, "Cargo.toml")?;
self.write_project_file(project_path, "pyproject.toml")?;

if self.bindings == "bin" {
let main_rs = self.render_template("main.rs")?;
fs::write(src_path.join("main.rs"), main_rs)?;
self.write_project_file(&src_path, "main.rs")?;
} else {
let lib_rs = self.render_template("lib.rs")?;
fs::write(src_path.join("lib.rs"), lib_rs)?;
self.write_project_file(&src_path, "lib.rs")?;
}

let gh_action_path = project_path.join(".github").join("workflows");
fs::create_dir_all(&gh_action_path)?;
let ci_yml = self.render_template("CI.yml")?;
fs::write(gh_action_path.join("CI.yml"), ci_yml)?;
self.write_project_file(&gh_action_path, "CI.yml")?;

if self.mixed {
let py_path = project_path.join(&self.crate_name);
fs::create_dir_all(&py_path)?;
let init_py = self.render_template("__init__.py")?;
fs::write(py_path.join("__init__.py"), init_py)?;
self.write_project_file(&py_path, "__init__.py")?;
}

println!(
" ✨ {} {} {}",
style("Done!").bold().green(),
style("New project created").bold(),
style(&project_path.display()).underlined()
);
Ok(())
}

Expand All @@ -91,6 +78,14 @@ impl<'a> ProjectGenerator<'a> {
))?;
Ok(out)
}

fn write_project_file(&self, directory: &Path, file: &str) -> Result<()> {
let path = directory.join(file);
if self.overwrite || !path.exists() {
fs::write(path, self.render_template(file)?)?;
}
Ok(())
}
}

/// Generate a new cargo project
Expand All @@ -104,13 +99,50 @@ pub fn new_project(
if project_path.exists() {
bail!("destination `{}` already exists", project_path.display());
}
generate_project(project_path, name, mixed,bindings, true)?;
println!(
" ✨ {} {} {}",
style("Done!").bold().green(),
style("New project created").bold(),
style(&project_path.display()).underlined()
);
Ok(())
}

/// Generate a new cargo project in an existing directory
pub fn init_project(
path: Option<String>,
name: Option<String>,
mixed: bool,
bindings: Option<String>,
) -> Result<()> {
let project_path = path.map(Into::into).map_or_else(std::env::current_dir, Ok)?;
if project_path.join("pyproject.toml").exists() || project_path.join("Cargo.toml").exists() {
bail!("`maturin init` cannot be run on existing projects");
}
generate_project(&project_path, name, mixed,bindings, false)?;
println!(
" ✨ {} {} {}",
style("Done!").bold().green(),
style("Initialized project").bold(),
style(&project_path.display()).underlined()
);
Ok(())
}

fn generate_project(
project_path: &Path,
name: Option<String>,
mixed: bool,
bindings: Option<String>,
overwrite: bool,
) -> Result<()> {
let name = if let Some(name) = name {
name
} else {
let file_name = project_path
.file_name()
.context("Fail to get name from path")?;
.with_context(|| format!("Failed to get name from path '{}'", project_path.display()))?;
file_name
.to_str()
.context("Filename isn't valid Unicode")?
Expand All @@ -135,6 +167,6 @@ pub fn new_project(
bindings_items[selection].to_string()
};

let generator = ProjectGenerator::new(name, mixed, bindings)?;
let generator = ProjectGenerator::new(name, mixed, bindings, overwrite)?;
generator.generate(project_path)
}

0 comments on commit 08142db

Please sign in to comment.