Browse Source

initial commit

master
张兴洋 2 years ago
commit
c0328b5e1a
  1. 2
      .gitignore
  2. 238
      Cargo.lock
  3. 9
      Cargo.toml
  4. 320
      src/main.rs

2
.gitignore

@ -0,0 +1,2 @@
/target
.vscode

238
Cargo.lock

@ -0,0 +1,238 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "clap"
version = "3.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "fcp"
version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

9
Cargo.toml

@ -0,0 +1,9 @@
[package]
name = "fcp"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3.1.8", features = ["derive"] }

320
src/main.rs

@ -0,0 +1,320 @@
// Note: this requires the `derive` feature
extern crate clap;
use clap::Parser;
use std::fs;
use std::path::{Path, PathBuf};
// use std::ffi::OsStr;
use std::fs::File;
use std::io::prelude::*;
use std::process::Command;
/// Create Compose project from template
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Name of your project. It's be converted to lowercases as part of project package name.
#[clap(short, long)]
name: String,
/// organization of your project, should be like com.fcp. It'll be used as part of project package name.
#[clap(short, long, default_value = "com.fcp")]
organization: String,
/// Path of your template, default is ./template
#[clap(short, long, default_value = "./template")]
template: String,
/// Path of your output project, default is current folder.
#[clap(short, long, default_value = ".")]
destination: String,
}
fn main() {
let args = Args::parse();
let name_lowercase = args.name.to_lowercase();
let template_path = args.template;
let destination_path = args.destination + "/" + &args.name;
let package = args.organization + "." + &name_lowercase;
// print!("hello project {} {}", name_lowercase, args.org);
let template_dir = Path::new(&template_path);
let destination_dir = Path::new(&destination_path);
if destination_dir.exists() {
let dir = &destination_dir.to_str();
println!("destination folder {:?} already exsit", dir);
return;
}
if !template_dir.exists() {
let dir = &template_dir.to_str();
println!("template folder {:?} not exsit", dir);
return;
}
let result = copy_dir_all(template_dir, &destination_dir);
match result {
Ok(_) => {
println!("project copied!!!")
}
Err(_) => {}
}
let package_dir = package.replace(".", "/");
println!("creating android test folder...");
let android_test_folder = format!("{}/app/src/androidTest/java", &destination_path);
let path_android_test = format!("{}/{}", &android_test_folder, &package_dir);
let android_test_dir_result = fs::create_dir_all(Path::new(&path_android_test));
println!(
"crate android test folder result {:?} ",
android_test_dir_result
);
// let catalog_path = format!("{}/androidVersionCatalog", &destination_path);
// let _ = fs::create_dir_all(Path::new(&catalog_path));
println!("creating source folder...");
let folder_test = format!("{}/app/src/test/java", &destination_path);
let path_test = format!("{}/{}", &folder_test, &package_dir);
let test_dir_result = fs::create_dir_all(Path::new(&path_test));
println!("crate unit test folder result {:?} ", test_dir_result);
println!("creating source folder...");
let java_folder = format!("{}/app/src/main/java", &destination_path);
let path_source = format!("{}/{}", &java_folder, &package_dir);
let source_dir_result = fs::create_dir_all(Path::new(&path_source));
println!("crate source folder result {:?} ", source_dir_result);
println!("moving source files...");
let source_dir = format!("{}/source", java_folder);
let source_dir = Path::new(&source_dir);
let _r = copy_and_remove(&source_dir, &path_source);
let source_dir = format!("{}/source", &android_test_folder);
let source_dir = Path::new(&source_dir);
let _r = copy_and_remove(&source_dir, &path_android_test);
let source_dir = format!("{}/source", &folder_test);
let source_dir = Path::new(&source_dir);
let _r = copy_and_remove(&source_dir, &path_test);
println!("source files moved");
println!("replacing placeholders...");
let _r = replace_placeholders(destination_dir, &package, &args.name, &name_lowercase);
println!("placeholders replaced...");
println!("integrating version catalog...");
let which_shell = if cfg!(target_os = "windows") {
"powershell"
} else {
"sh"
};
let _ = format!("cannot enter path {}", destination_path);
// let _ = Command::new(&which_shell)
// .arg("cd")
// .arg(&destination_path)
// .status()
// .expect(&err);
let _ = Command::new(&which_shell)
.current_dir(Path::new(&destination_path))
.arg("git")
.arg("init")
.status()
.expect("cannot add init git");
// let _ = Command::new(&which_shell)
// .current_dir(Path::new(&destination_path))
// .arg("git")
// .arg("config")
// .arg("core.filemode=false")
// .status()
// .expect("cannot add init git");
// let _ = Command::new(&which_shell)
// .current_dir(Path::new(&destination_path))
// .arg("git")
// .arg("rm")
// .arg("-r")
// .arg("--cached")
// .arg("androidVersionCatalog")
// .status()
// .expect("cannot remove cached dir");
let _ = Command::new(&which_shell)
.current_dir(Path::new(&destination_path))
.arg("git")
.arg("submodule")
.arg("add")
.arg("http://git.cnyanglao.com:6666/JarvanMo/AndroidVersionCatalog.git")
.arg("androidVersionCatalog")
.status()
.expect("cannot add submodule");
// keytool -genkeypair -alias $formatted_project_name -keyalg RSA -keypass $key_pass -storepass $stor_epass -keysize 2048 -keystore $jks_file_name -validity 18250
let alias = format!("-alias {}", args.name);
let key_pass = format!("-keypass {}123456", name_lowercase);
let store_pass = format!("-storepass {}123456", name_lowercase);
let keystore = format!("-keystore {}/app/{}.jks", &destination_path, name_lowercase);
// println!("--> {} {} {} {}", alias, key_pass, store_pass, keystore);
let _ = Command::new(&which_shell)
.arg("keytool")
.arg("-genkeypair")
.arg(alias)
.arg("-keyalg RSA")
.arg(key_pass)
.arg(store_pass)
.arg("-keysize 2048")
.arg(keystore)
.arg("-validity 18250")
.status();
// let output = String::from_utf8(output.stdout);
// println!("craete jks {:?}", output.unwrap());
println!("finished!!!")
}
pub fn copy_dir_all<U: AsRef<Path>, V: AsRef<Path>>(from: U, to: V) -> Result<(), std::io::Error> {
let mut stack = Vec::new();
stack.push(PathBuf::from(from.as_ref()));
let output_root = PathBuf::from(to.as_ref());
let input_root = PathBuf::from(from.as_ref()).components().count();
while let Some(working_path) = stack.pop() {
println!("process: {:?}", &working_path);
// Generate a relative path
let src: PathBuf = working_path.components().skip(input_root).collect();
// Create a destination if missing
let dest = if src.components().count() == 0 {
output_root.clone()
} else {
output_root.join(&src)
};
if fs::metadata(&dest).is_err() {
println!(" mkdir: {:?}", dest);
fs::create_dir_all(&dest)?;
}
for entry in fs::read_dir(working_path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
stack.push(path);
} else {
match path.file_name() {
Some(filename) => {
let dest_path = dest.join(filename);
println!(" copy: {:?} -> {:?}", &path, &dest_path);
fs::copy(&path, &dest_path)?;
}
None => {
println!("failed: {:?}", path);
}
}
}
}
}
Ok(())
}
fn copy_and_remove<U: AsRef<Path>, V: AsRef<Path>>(from: U, to: V) -> Result<(), std::io::Error> {
let result = copy_dir_all(&from, to);
match result {
Ok(_) => {
let result = fs::remove_dir_all(from);
match result {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}
Err(e) => Err(e),
}
}
pub fn replace_placeholders<U: AsRef<Path>>(
from: U,
package: &str,
project_name: &str,
project_name_lowercase: &String,
) -> Result<(), std::io::Error> {
const PLACEHOLDER_PACKAGE: &str = "###package###";
const PLACEHOLDER_PROJECTNAME: &str = "###ProjectName###";
const PLACEHOLDER_STORE_FILE: &str = "###StoreFile###";
const PLACEHOLDER_STORE_PASSWORD: &str = "###StorePassword###";
const PLACEHOLDER_KEY_ALIAS: &str = "###KeyAlias###";
const PLACEHOLDER_KEY_PASSWORD: &str = "###KeyPassword###";
let mut stack = Vec::new();
stack.push(PathBuf::from(from.as_ref()));
while let Some(working_path) = stack.pop() {
println!("replacing: {:?}", &working_path);
for entry in fs::read_dir(working_path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
stack.push(path);
} else {
match path.file_name() {
Some(file_name) => {
if file_name.to_str().unwrap_or("").contains(".kt")
|| file_name.to_str().unwrap_or("").contains(".kts")
|| file_name.to_str().unwrap_or("").contains(".xml")
|| file_name.to_str().unwrap_or("").contains(".gradle")
{
let content = fs::read_to_string(&path).unwrap();
let content = content
.replace(PLACEHOLDER_PACKAGE, package)
.replace(
PLACEHOLDER_STORE_FILE,
&format!("{}.jks", project_name_lowercase),
)
.replace(
PLACEHOLDER_STORE_PASSWORD,
&format!("{}123456", project_name_lowercase),
)
.replace(PLACEHOLDER_KEY_ALIAS, project_name_lowercase)
.replace(
PLACEHOLDER_KEY_PASSWORD,
&format!("{}123456", project_name_lowercase),
)
.replace(PLACEHOLDER_PROJECTNAME, project_name);
let mut file = File::create(path).unwrap();
file.write(content.as_bytes()).unwrap();
}
// let suffix = path.file_stem().unwrap();
// println!("file name--> {:?} -- {:?}",filename.to_str(),suffix.to_str())
// println!("file name--> {:?}",filename.to_str())
}
None => {
println!("failed: {:?}", path);
}
}
}
}
}
Ok(())
}
// fn get_extension_from_filename(filename: &str) -> Option<&str> {
// Path::new(filename)
// .extension()
// .and_then(OsStr::to_str)
// }
Loading…
Cancel
Save