use clap::Parser;
use regex::Regex;
use std::fs;
use std::path::{Path, PathBuf};
use crate::scrypto::*;
#[derive(Parser, Debug)]
pub struct NewPackage {
package_name: String,
#[clap(long)]
path: Option<PathBuf>,
#[clap(short, long)]
local: bool,
}
impl NewPackage {
pub fn run(&self) -> Result<(), String> {
let wasm_name = self.package_name.replace("-", "_");
let path = self
.path
.clone()
.unwrap_or(PathBuf::from(&self.package_name));
let simulator_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let (sbor, scrypto, scrypto_test) = if self.local {
let scrypto_dir = simulator_dir
.parent()
.unwrap()
.to_string_lossy()
.replace("\\", "/");
(
format!("{{ path = \"{}/sbor\" }}", scrypto_dir),
format!("{{ path = \"{}/scrypto\" }}", scrypto_dir),
format!("{{ path = \"{}/scrypto-test\" }}", scrypto_dir),
)
} else {
let s = format!("{{ version = \"{}\" }}", env!("CARGO_PKG_VERSION"));
(s.clone(), s.clone(), s.clone())
};
if path.exists() {
Err(Error::PackageAlreadyExists.into())
} else {
fs::create_dir_all(child_of(&path, "src")).map_err(Error::IOError)?;
fs::create_dir_all(child_of(&path, "tests")).map_err(Error::IOError)?;
fs::write(
child_of(&path, "Cargo.toml"),
include_str!("../../assets/template/Cargo.toml_template")
.replace("${package_name}", &self.package_name)
.replace("${sbor}", &sbor)
.replace("${scrypto}", &scrypto)
.replace("${scrypto-test}", &scrypto_test),
)
.map_err(Error::IOError)?;
let cargo_lock = Self::insert_own_entry_into_cargo_lock(
include_str!("../../assets/template/Cargo.lock_template"),
&self.package_name,
);
fs::write(child_of(&path, "Cargo.lock"), cargo_lock).map_err(Error::IOError)?;
fs::write(
child_of(&path, ".gitignore"),
include_str!("../../assets/template/.gitignore"),
)
.map_err(Error::IOError)?;
fs::write(
child_of(&child_of(&path, "src"), "lib.rs"),
include_str!("../../assets/template/src/lib.rs"),
)
.map_err(Error::IOError)?;
fs::write(
child_of(&child_of(&path, "tests"), "lib.rs"),
include_str!("../../assets/template/tests/lib.rs")
.replace("${wasm_name}", &wasm_name),
)
.map_err(Error::IOError)?;
fs::write(
child_of(&path, "rust-toolchain.toml"),
include_str!("../../assets/template/rust-toolchain.toml_template"),
)
.map_err(Error::IOError)?;
Ok(())
}
}
fn insert_own_entry_into_cargo_lock(lock_file_contents: &str, package_name: &str) -> String {
let name_regex = Regex::new(r#"name = "([^"]+)""#).unwrap();
let name_line_to_inject_before = name_regex
.captures_iter(lock_file_contents)
.find(|captures| {
let dependency_name = captures.get(1).unwrap();
dependency_name.as_str() > package_name
})
.map(|captures| captures.get(0).unwrap().as_str());
if let Some(line) = name_line_to_inject_before {
lock_file_contents.replace(
line,
&format!(
r#"name = "{package_name}"
version = "1.0.0"
dependencies = [
"scrypto",
"scrypto-test",
]
[[package]]
{line}"#
),
)
} else {
let mut contents = lock_file_contents.to_string();
contents.push_str(&format!(
r#"
[[package]]
name = "{package_name}"
version = "1.0.0"
dependencies = [
"scrypto",
"scrypto-test",
]
"#
));
contents
}
}
}
fn child_of(path: &Path, name: &str) -> PathBuf {
path.join(name)
}