Add new crate to workspace members (#2775)

* Add new crate to workspace members

* Replace DioxusCrate with cargo metadata

* Skip initializing git repo in already existing workspace

* Fix init in workspace

* Fix naming issues with new packages

Changes how we parse names so `dx new packages/blah`creates a subdirectory instead

---------

Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
Matt HunzingerandJonathan Kelley authored and GitHub committed 2024-08-06 20:52:33 +00:00
1 parent e4abe79276
commit 0042430a36
2 files changed
+92 -11

No files matched your search

+84 -10
View File
@@ -1,5 +1,7 @@
use super::*;
use cargo_generate::{GenerateArgs, TemplatePath};
use cargo_metadata::Metadata;
use std::path::Path;
pub(crate) static DEFAULT_TEMPLATE: &str = "gh:dioxuslabs/dioxus-template";
@@ -8,26 +10,70 @@ pub(crate) static DEFAULT_TEMPLATE: &str = "gh:dioxuslabs/dioxus-template";
pub struct Create {
/// Project name (required when `--yes` is used)
name: Option<String>,
/// Generate the template directly at the given path.
#[arg(long, value_parser)]
destination: Option<PathBuf>,
/// Generate the template directly into the current dir. No subfolder will be created and no vcs is initialized.
#[arg(long, action)]
init: bool,
/// Template path
#[clap(default_value = DEFAULT_TEMPLATE, short, long)]
template: String,
/// Pass <option>=<value> for the used template (e.g., `foo=bar`)
#[clap(short, long)]
option: Vec<String>,
/// Specify a sub-template within the template repository to be used as the actual template
#[clap(long)]
subtemplate: Option<String>,
/// Skip user interaction by using the default values for the used template.
/// Default values can be overridden with `--option`
#[clap(short, long)]
yes: bool,
// TODO: turn on/off cargo-generate's output (now is invisible)
// #[clap(default_value = "false", short, long)]
// silent: bool,
}
impl Create {
pub fn create(self) -> Result<()> {
pub fn create(mut self) -> Result<()> {
let metadata = cargo_metadata::MetadataCommand::new().exec().ok();
// If we're getting pass a `.` name, that's actually a path
// We're actually running an init - we should clear the name
if self.name.as_deref() == Some(".") {
self.name = None;
self.init = true;
}
// A default destination is set for nameless projects
if self.name.is_none() {
self.destination = Some(PathBuf::from("."));
}
// Split the name into path components
// such that dx new packages/app will create a directory called packages/app
let destination = self.destination.unwrap_or_else(|| {
let mut path = PathBuf::from(self.name.as_deref().unwrap());
if path.is_relative() {
path = std::env::current_dir().unwrap().join(path);
}
// split the path into the parent and the name
let parent = path.parent().unwrap();
let name = path.file_name().unwrap();
self.name = Some(name.to_str().unwrap().to_string());
// create the parent directory if it doesn't exist
std::fs::create_dir_all(parent).unwrap();
// And then the "destination" is the parent directory
parent.to_path_buf()
});
let args = GenerateArgs {
define: self.option,
name: self.name,
@@ -37,11 +83,20 @@ impl Create {
subfolder: self.subtemplate,
..Default::default()
},
init: self.init,
destination: Some(destination),
vcs: if metadata.is_some() {
Some(cargo_generate::Vcs::None)
} else {
None
},
..Default::default()
};
if self.yes && args.name.is_none() {
return Err("You have to provide the project's name when using `--yes` option.".into());
}
// https://github.com/console-rs/dialoguer/issues/294
ctrlc::set_handler(move || {
let _ = console::Term::stdout().show_cursor();
@@ -49,13 +104,32 @@ impl Create {
})
.expect("ctrlc::set_handler");
let path = cargo_generate::generate(args)?;
post_create(&path)
post_create(&path, metadata)
}
}
// being also used by `init`
pub fn post_create(path: &PathBuf) -> Result<()> {
// first run cargo fmt
/// Post-creation actions for newly setup crates.
// Also used by `init`.
pub fn post_create(path: &Path, metadata: Option<Metadata>) -> Result<()> {
// 1. Add the new project to the workspace, if it exists.
// This must be executed first in order to run `cargo fmt` on the new project.
metadata.and_then(|metadata| {
let cargo_toml_path = &metadata.workspace_root.join("Cargo.toml");
let cargo_toml_str = std::fs::read_to_string(cargo_toml_path).ok()?;
let relative_path = path.strip_prefix(metadata.workspace_root).ok()?;
let mut cargo_toml: toml_edit::DocumentMut = cargo_toml_str.parse().ok()?;
cargo_toml
.get_mut("workspace")?
.get_mut("members")?
.as_array_mut()?
.push(relative_path.display().to_string());
std::fs::write(cargo_toml_path, cargo_toml.to_string()).ok()
});
// 2. Run `cargo fmt` on the new project.
let mut cmd = Command::new("cargo");
let cmd = cmd.arg("fmt").current_dir(path);
let output = cmd.output().expect("failed to execute process");
@@ -65,7 +139,7 @@ pub fn post_create(path: &PathBuf) -> Result<()> {
tracing::error!("stderr: {}", String::from_utf8_lossy(&output.stderr));
}
// then format the toml
// 3. Format the `Cargo.toml` and `Dioxus.toml` files.
let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")];
for toml_path in &toml_paths {
let toml = std::fs::read_to_string(toml_path)?;
@@ -85,7 +159,7 @@ pub fn post_create(path: &PathBuf) -> Result<()> {
file.write_all(new_string.as_bytes())?;
}
// remove any triple newlines from the readme
// 4. Remove any triple newlines from the readme.
let readme_path = path.join("README.md");
let readme = std::fs::read_to_string(&readme_path)?;
let new_readme = remove_triple_newlines(&readme);
+8 -1
View File
@@ -25,6 +25,8 @@ pub struct Init {
impl Init {
pub fn init(self) -> Result<()> {
let metadata = cargo_metadata::MetadataCommand::new().exec().ok();
// Get directory name.
let name = std::env::current_dir()?
.file_name()
@@ -45,9 +47,14 @@ impl Init {
subfolder: self.subtemplate,
..Default::default()
},
vcs: if metadata.is_some() {
Some(cargo_generate::Vcs::None)
} else {
None
},
..Default::default()
};
let path = cargo_generate::generate(args)?;
create::post_create(&path)
create::post_create(&path, metadata)
}
}