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:
1 parent
e4abe79276
commit
0042430a36
2 files changed
+92
-11
No files matched your search
@@ -1,5 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use cargo_generate::{GenerateArgs, TemplatePath};
|
use cargo_generate::{GenerateArgs, TemplatePath};
|
||||||
|
use cargo_metadata::Metadata;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub(crate) static DEFAULT_TEMPLATE: &str = "gh:dioxuslabs/dioxus-template";
|
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 {
|
pub struct Create {
|
||||||
/// Project name (required when `--yes` is used)
|
/// Project name (required when `--yes` is used)
|
||||||
name: Option<String>,
|
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
|
/// Template path
|
||||||
#[clap(default_value = DEFAULT_TEMPLATE, short, long)]
|
#[clap(default_value = DEFAULT_TEMPLATE, short, long)]
|
||||||
template: String,
|
template: String,
|
||||||
|
|
||||||
/// Pass <option>=<value> for the used template (e.g., `foo=bar`)
|
/// Pass <option>=<value> for the used template (e.g., `foo=bar`)
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
option: Vec<String>,
|
option: Vec<String>,
|
||||||
|
|
||||||
/// Specify a sub-template within the template repository to be used as the actual template
|
/// Specify a sub-template within the template repository to be used as the actual template
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
subtemplate: Option<String>,
|
subtemplate: Option<String>,
|
||||||
|
|
||||||
/// Skip user interaction by using the default values for the used template.
|
/// Skip user interaction by using the default values for the used template.
|
||||||
/// Default values can be overridden with `--option`
|
/// Default values can be overridden with `--option`
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
yes: bool,
|
yes: bool,
|
||||||
// TODO: turn on/off cargo-generate's output (now is invisible)
|
|
||||||
// #[clap(default_value = "false", short, long)]
|
|
||||||
// silent: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Create {
|
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 {
|
let args = GenerateArgs {
|
||||||
define: self.option,
|
define: self.option,
|
||||||
name: self.name,
|
name: self.name,
|
||||||
@@ -37,11 +83,20 @@ impl Create {
|
|||||||
subfolder: self.subtemplate,
|
subfolder: self.subtemplate,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
init: self.init,
|
||||||
|
destination: Some(destination),
|
||||||
|
vcs: if metadata.is_some() {
|
||||||
|
Some(cargo_generate::Vcs::None)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.yes && args.name.is_none() {
|
if self.yes && args.name.is_none() {
|
||||||
return Err("You have to provide the project's name when using `--yes` option.".into());
|
return Err("You have to provide the project's name when using `--yes` option.".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/console-rs/dialoguer/issues/294
|
// https://github.com/console-rs/dialoguer/issues/294
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
let _ = console::Term::stdout().show_cursor();
|
let _ = console::Term::stdout().show_cursor();
|
||||||
@@ -49,13 +104,32 @@ impl Create {
|
|||||||
})
|
})
|
||||||
.expect("ctrlc::set_handler");
|
.expect("ctrlc::set_handler");
|
||||||
let path = cargo_generate::generate(args)?;
|
let path = cargo_generate::generate(args)?;
|
||||||
post_create(&path)
|
|
||||||
|
post_create(&path, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// being also used by `init`
|
/// Post-creation actions for newly setup crates.
|
||||||
pub fn post_create(path: &PathBuf) -> Result<()> {
|
// Also used by `init`.
|
||||||
// first run cargo fmt
|
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 mut cmd = Command::new("cargo");
|
||||||
let cmd = cmd.arg("fmt").current_dir(path);
|
let cmd = cmd.arg("fmt").current_dir(path);
|
||||||
let output = cmd.output().expect("failed to execute process");
|
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));
|
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")];
|
let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")];
|
||||||
for toml_path in &toml_paths {
|
for toml_path in &toml_paths {
|
||||||
let toml = std::fs::read_to_string(toml_path)?;
|
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())?;
|
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_path = path.join("README.md");
|
||||||
let readme = std::fs::read_to_string(&readme_path)?;
|
let readme = std::fs::read_to_string(&readme_path)?;
|
||||||
let new_readme = remove_triple_newlines(&readme);
|
let new_readme = remove_triple_newlines(&readme);
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ pub struct Init {
|
|||||||
|
|
||||||
impl Init {
|
impl Init {
|
||||||
pub fn init(self) -> Result<()> {
|
pub fn init(self) -> Result<()> {
|
||||||
|
let metadata = cargo_metadata::MetadataCommand::new().exec().ok();
|
||||||
|
|
||||||
// Get directory name.
|
// Get directory name.
|
||||||
let name = std::env::current_dir()?
|
let name = std::env::current_dir()?
|
||||||
.file_name()
|
.file_name()
|
||||||
@@ -45,9 +47,14 @@ impl Init {
|
|||||||
subfolder: self.subtemplate,
|
subfolder: self.subtemplate,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
vcs: if metadata.is_some() {
|
||||||
|
Some(cargo_generate::Vcs::None)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let path = cargo_generate::generate(args)?;
|
let path = cargo_generate::generate(args)?;
|
||||||
create::post_create(&path)
|
create::post_create(&path, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user