mirror of
https://github.com/jht5945/buildj.git
synced 2025-12-27 17:20:06 +08:00
first public version
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,9 +2,5 @@
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
1699
Cargo.lock
generated
Normal file
1699
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "buildj"
|
||||
version = "0.1.0"
|
||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
json = "0.11.14"
|
||||
term = "0.5.2"
|
||||
reqwest = "0.9.18"
|
||||
urlencoding = "1.0.0"
|
||||
dirs = "2.0.1"
|
||||
rust-crypto = "0.2.36"
|
||||
rust_util = { git = "https://github.com/jht5945/rust_util" }
|
||||
99
src/build_json.rs
Normal file
99
src/build_json.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use std::{
|
||||
fs,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use super::rust_util::{
|
||||
print_message,
|
||||
MessageType,
|
||||
};
|
||||
|
||||
pub const BUILD_JSON: &str = "build.json";
|
||||
|
||||
pub fn create_build_json(args: &Vec<String>) {
|
||||
match find_build_json_in_current() {
|
||||
Some(_) => {
|
||||
print_message(MessageType::ERROR, &format!("File exits: {}", BUILD_JSON));
|
||||
return;
|
||||
},
|
||||
None => (), // OK
|
||||
}
|
||||
|
||||
let mut java_version = "";
|
||||
let mut builder = "";
|
||||
let mut builder_version = "";
|
||||
for arg in args {
|
||||
if arg.starts_with("--java") && arg.len() > 6 {
|
||||
java_version = &arg.as_str()[6..];
|
||||
} else if arg.starts_with("--maven") && arg.len() > 7 {
|
||||
builder = "maven";
|
||||
builder_version = &arg.as_str()[7..];
|
||||
} else if arg.starts_with("--gradle") && arg.len() > 8 {
|
||||
builder = "gradle";
|
||||
builder_version = &arg.as_str()[8..];
|
||||
}
|
||||
}
|
||||
if java_version == "" || builder == "" || builder_version == "" {
|
||||
print_message(MessageType::ERROR, "Args java version, builder or builder version is not assigned or format error.");
|
||||
return;
|
||||
}
|
||||
let build_json_object = object!{
|
||||
"java" => java_version,
|
||||
"builder" => object! {
|
||||
"name" => builder,
|
||||
"version" => builder_version,
|
||||
},
|
||||
};
|
||||
match fs::write(BUILD_JSON, json::stringify_pretty(build_json_object, 4)) {
|
||||
Ok(_) => {
|
||||
print_message(MessageType::OK, &format!("Write file success: {}", BUILD_JSON));
|
||||
},
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Write file failed: {}, error message: {}", BUILD_JSON, err));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn find_build_json_in_current() -> Option<String> {
|
||||
let path = fs::canonicalize(".").ok()?;
|
||||
let p_build_json = &format!("{}/{}", path.to_str()?, BUILD_JSON);
|
||||
let path_build_json = Path::new(p_build_json);
|
||||
if path_build_json.exists() {
|
||||
return Some(p_build_json.to_string());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_build_json_in_parents() -> Option<String> {
|
||||
let mut path = fs::canonicalize(".").ok()?;
|
||||
loop {
|
||||
let p = path.to_str()?;
|
||||
if p == "/" {
|
||||
return None;
|
||||
}
|
||||
let p_build_json = &format!("{}/{}", p, BUILD_JSON);
|
||||
let path_build_json = Path::new(p_build_json);
|
||||
if path_build_json.exists() {
|
||||
return Some(p_build_json.to_string());
|
||||
}
|
||||
path = path.parent()?.to_path_buf();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_build_json() -> Option<String> {
|
||||
match find_build_json_in_current() {
|
||||
Some(p) => {
|
||||
Some(p)
|
||||
},
|
||||
None => match find_build_json_in_parents() {
|
||||
Some(p) => {
|
||||
print_message(MessageType::WARN, &format!("Cannot find {} in current dir, find: {}", BUILD_JSON, p));
|
||||
Some(p)
|
||||
},
|
||||
None => {
|
||||
print_message(MessageType::ERROR, &format!("Cannot find {}", BUILD_JSON));
|
||||
None
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
22
src/http.rs
Normal file
22
src/http.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
};
|
||||
|
||||
use super::rust_util::{
|
||||
copy_io,
|
||||
XResult,
|
||||
};
|
||||
|
||||
pub fn download_url(url: &str, dest: &mut File) -> XResult<()> {
|
||||
let mut response = reqwest::get(url)?;
|
||||
let header_content_length: i64 = match response.headers().get("content-length") {
|
||||
None => -1,
|
||||
Some(len_value) => len_value.to_str().unwrap().parse::<i64>().unwrap(),
|
||||
};
|
||||
copy_io(&mut response, dest, header_content_length)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_url(url: &str) -> XResult<String> {
|
||||
Ok(reqwest::get(url)?.text()?)
|
||||
}
|
||||
157
src/jdk.rs
Normal file
157
src/jdk.rs
Normal file
@@ -0,0 +1,157 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env,
|
||||
fs,
|
||||
str,
|
||||
path::Path,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use super::{
|
||||
rust_util::{
|
||||
is_macos,
|
||||
is_linux,
|
||||
is_macos_or_linux,
|
||||
print_message,
|
||||
MessageType,
|
||||
},
|
||||
local_util,
|
||||
tool,
|
||||
};
|
||||
|
||||
const OPENJDK_MACOS: &str = "openjdk-osx";
|
||||
const OPENJDK_LINUX: &str = "openjdk-linux";
|
||||
|
||||
pub const LOCAL_JAVA_HOME_BASE_DIR: &str = ".jssp/jdks";
|
||||
|
||||
pub fn get_java_home(version: &str) -> Option<String> {
|
||||
match get_macos_java_home(version) {
|
||||
Some(j) => Some(j),
|
||||
None => match get_local_java_home(version) {
|
||||
Some(j) => Some(j),
|
||||
None => match get_cloud_java(version) {
|
||||
true => get_local_java_home(version),
|
||||
false => None,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cloud_java(version: &str) -> bool {
|
||||
if ! is_macos_or_linux() {
|
||||
return false;
|
||||
}
|
||||
let cloud_java_name = if is_macos() {
|
||||
OPENJDK_MACOS
|
||||
} else if is_linux() {
|
||||
OPENJDK_LINUX
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let local_java_home_base_dir = match local_util::get_user_home_dir(LOCAL_JAVA_HOME_BASE_DIR) {
|
||||
Err(_) => return false,
|
||||
Ok(o) => o,
|
||||
};
|
||||
match tool::get_and_extract_tool_package(&local_java_home_base_dir, false, cloud_java_name, version, false) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Get java failed, version: {}, error: {}", version, err));
|
||||
return false;
|
||||
},
|
||||
Ok(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_macos_java_home(version: &str) -> Option<String> {
|
||||
if ! is_macos() {
|
||||
return None;
|
||||
}
|
||||
let output = match Command::new("/usr/libexec/java_home").arg("-version").arg(version).output() {
|
||||
Err(_) => return None,
|
||||
Ok(o) => o,
|
||||
};
|
||||
match str::from_utf8(&output.stderr) {
|
||||
Err(_) => (),
|
||||
Ok(o) => {
|
||||
// Unable to find any JVMs matching version "1.6".
|
||||
if o.contains("Unable to find any JVMs") {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
};
|
||||
Some(str::from_utf8(&output.stdout).ok()?.trim().to_string())
|
||||
}
|
||||
|
||||
pub fn get_local_java_home(version: &str) -> Option<String> {
|
||||
let local_java_home_base_dir = local_util::get_user_home_dir(LOCAL_JAVA_HOME_BASE_DIR).ok()?;
|
||||
let paths = fs::read_dir(Path::new(&local_java_home_base_dir)).ok()?;
|
||||
for path in paths {
|
||||
match path {
|
||||
Err(_) => (),
|
||||
Ok(dir_entry) => match dir_entry.path().to_str() {
|
||||
None => (),
|
||||
Some(p) => {
|
||||
let mut path_name = p;
|
||||
if p.ends_with("/") {
|
||||
path_name = &path_name[..path_name.len() - 1]
|
||||
}
|
||||
let last_index_of_slash = path_name.rfind('/');
|
||||
match last_index_of_slash {
|
||||
None => {},
|
||||
Some(i) => path_name = &path_name[i+1..],
|
||||
};
|
||||
let mut matched_path = "";
|
||||
if path_name.starts_with("jdk-") && (&path_name[4..]).starts_with(version) {
|
||||
matched_path = p;
|
||||
} else if path_name.starts_with("jdk") && (&path_name[3..]).starts_with(version) {
|
||||
matched_path = p;
|
||||
}
|
||||
if matched_path != "" {
|
||||
if local_util::is_path_exists(matched_path, "Contents/Home") {
|
||||
return Some(format!("{}/{}", matched_path, "Contents/Home"));
|
||||
} else {
|
||||
return Some(matched_path.to_string());
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn extract_jdk_and_wait(file_name: &str) {
|
||||
let local_java_home_base_dir = match local_util::get_user_home_dir(LOCAL_JAVA_HOME_BASE_DIR) {
|
||||
Err(_) => return,
|
||||
Ok(o) => o,
|
||||
};
|
||||
match local_util::extract_package_and_wait(&local_java_home_base_dir, file_name) {
|
||||
Err(err) => print_message(MessageType::ERROR, &format!("Extract file: {}, failed: {}", file_name, err)),
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_env() -> HashMap<String, String> {
|
||||
let mut new_env: HashMap<String, String> = HashMap::new();
|
||||
for (key, value) in env::vars() {
|
||||
new_env.insert(key, value);
|
||||
}
|
||||
new_env
|
||||
}
|
||||
|
||||
pub fn get_env_with_java_home(java_home: &str) -> HashMap<String, String> {
|
||||
let mut new_env: HashMap<String, String> = HashMap::new();
|
||||
for (key, value) in env::vars() {
|
||||
let key_str = key.as_str();
|
||||
if "JAVA_HOME" == key_str {
|
||||
// IGNORE JAVA_HOME
|
||||
} else if "PATH" == key_str {
|
||||
let path = value.to_string();
|
||||
let new_path = format!("{}/bin:{}", java_home, path);
|
||||
new_env.insert("PATH".to_string(), new_path);
|
||||
} else {
|
||||
new_env.insert(key, value);
|
||||
}
|
||||
}
|
||||
new_env.insert("JAVA_HOME".to_string(), java_home.to_string());
|
||||
new_env
|
||||
}
|
||||
126
src/local_util.rs
Normal file
126
src/local_util.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use std::{
|
||||
env,
|
||||
fs::{self, File},
|
||||
io::{Read, ErrorKind},
|
||||
path::Path,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use super::rust_util::{
|
||||
new_box_error,
|
||||
print_message,
|
||||
XResult,
|
||||
MessageType,
|
||||
DEFAULT_BUF_SIZE,
|
||||
};
|
||||
|
||||
use crypto::{
|
||||
sha2::Sha256,
|
||||
digest::Digest,
|
||||
};
|
||||
|
||||
pub fn get_args_as_vec() -> Vec<String> {
|
||||
let mut args_vec:Vec<String> = vec![];
|
||||
for arg in env::args() {
|
||||
args_vec.push(arg);
|
||||
}
|
||||
args_vec
|
||||
}
|
||||
|
||||
pub fn is_buildin_args(args: &Vec<String>) -> bool {
|
||||
match args.len() <= 1 {
|
||||
true => false,
|
||||
false => args.get(1).unwrap().starts_with(":::"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_file_integrity(integrity: &str, file_name: &str) -> XResult<bool> {
|
||||
if ! integrity.starts_with("sha256:hex-") {
|
||||
return Err(new_box_error(&format!("Not supported integrigty: {}", integrity)));
|
||||
}
|
||||
let sha256_hex = &integrity[11..];
|
||||
let calc_sha256_hex = calc_file_sha256(file_name)?;
|
||||
let integrity_verify_result = sha256_hex == calc_sha256_hex;
|
||||
if ! integrity_verify_result {
|
||||
print_message(MessageType::ERROR, &format!("Verify integrity failed, expected: {}, actual: {}", sha256_hex, calc_sha256_hex));
|
||||
}
|
||||
Ok(integrity_verify_result)
|
||||
}
|
||||
|
||||
pub fn calc_sha256(d: &[u8]) -> String {
|
||||
let mut sha256 = Sha256::new();
|
||||
sha256.input(d);
|
||||
sha256.result_str()
|
||||
}
|
||||
|
||||
pub fn calc_file_sha256(file_name: &str) -> XResult<String> {
|
||||
let mut sha256 = Sha256::new();
|
||||
let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE];
|
||||
let mut f = File::open(file_name)?;
|
||||
loop {
|
||||
let len = match f.read(&mut buf) {
|
||||
Ok(0) => return Ok(sha256.result_str()),
|
||||
Ok(len) => len,
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(Box::new(e)),
|
||||
};
|
||||
sha256.input(&buf[..len]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_user_home() -> XResult<String> {
|
||||
let home_dir_o = match dirs::home_dir() {
|
||||
None => return Err(new_box_error("Home dir not found!")),
|
||||
Some(home_dir_o) => home_dir_o,
|
||||
};
|
||||
match home_dir_o.to_str() {
|
||||
None => return Err(new_box_error("Home dir not found!")),
|
||||
Some(home_dir_str) => Ok(home_dir_str.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_user_home_dir(dir: &str) -> XResult<String> {
|
||||
Ok(format!("{}/{}", get_user_home()?, dir))
|
||||
}
|
||||
|
||||
pub fn is_path_exists(dir: &str, sub_dir: &str) -> bool {
|
||||
let full_path = &format!("{}/{}", dir, sub_dir);
|
||||
Path::new(full_path).exists()
|
||||
}
|
||||
|
||||
pub fn run_command_and_wait(cmd: &mut Command) -> XResult<()> {
|
||||
cmd.spawn()?.wait()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_package_and_wait(dir: &str, file_name: &str) -> XResult<()> {
|
||||
let mut cmd: Command;
|
||||
if file_name.ends_with(".zip") {
|
||||
cmd = Command::new("unzip");
|
||||
} else if file_name.ends_with(".tar.gz") {
|
||||
cmd = Command::new("tar");
|
||||
cmd.arg("-xzvf");
|
||||
} else {
|
||||
return Err(new_box_error(&format!("Unknown file type: {}", file_name)));
|
||||
}
|
||||
cmd.arg(file_name).current_dir(dir).spawn()?.wait()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_home_dir(home_sub_dir: &str) {
|
||||
match get_user_home_dir(home_sub_dir) {
|
||||
Err(_) => (),
|
||||
Ok(user_home_dir) => init_dir(&user_home_dir),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init_dir(dir: &str) {
|
||||
if ! Path::new(dir).exists() {
|
||||
match fs::create_dir_all(dir) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Init dir {} failed: {}", dir, err));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
241
src/main.rs
Normal file
241
src/main.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
#[macro_use]
|
||||
extern crate json;
|
||||
extern crate term;
|
||||
extern crate dirs;
|
||||
extern crate crypto;
|
||||
extern crate urlencoding;
|
||||
extern crate rust_util;
|
||||
|
||||
pub mod jdk;
|
||||
pub mod local_util;
|
||||
pub mod http;
|
||||
pub mod tool;
|
||||
pub mod build_json;
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use rust_util::{
|
||||
print_message,
|
||||
run_command_and_wait,
|
||||
MessageType,
|
||||
};
|
||||
use tool::*;
|
||||
use jdk::*;
|
||||
use build_json::*;
|
||||
|
||||
const BUILDJ: &str = "buildj";
|
||||
const BUDERJ_VER: &str = "0.1";
|
||||
|
||||
fn print_usage() {
|
||||
print!(r#"
|
||||
buildj ::: - print this message
|
||||
buildj :::help - print this message
|
||||
buildj :::create --java<version> --maven<version> - create java-version, maven-version project
|
||||
buildj :::create --java<version> --gradle<version> - create java-version, gradle-version project
|
||||
buildj :::java<version> [-version] - run java with assigned version, e.g. buildj :::java1.8 -version
|
||||
buildj :::maven<version> [--java<version>] - run maven with assigned version and java version, e.g. buildj :::maven3.5.2 --java1.8 ARGS
|
||||
buildj :::gradle<version> ]--java<version>] - run gradle with assigned version and java version, e.g. buildj :::gradle3.5.1 --java1.8 ARGS
|
||||
buildj - run build, run assigned version builder tool
|
||||
"#);
|
||||
}
|
||||
|
||||
fn do_with_buildin_arg_java(first_arg: &str, args: &Vec<String>) {
|
||||
let ver = &first_arg[7..];
|
||||
if ver == "" {
|
||||
print_message(MessageType::ERROR, &format!("Java version is not assigned!"));
|
||||
return;
|
||||
}
|
||||
match get_java_home(ver) {
|
||||
None => print_message(MessageType::ERROR, &format!("Assigned java version not found: {}", ver)),
|
||||
Some(java_home) => {
|
||||
print_message(MessageType::OK, &format!("Find java home: {}", java_home));
|
||||
let java_bin = &format!("{}/bin/java", java_home);
|
||||
let mut cmd = Command::new(java_bin);
|
||||
cmd.envs(&get_env_with_java_home(&java_home));
|
||||
if args.len() > 2 {
|
||||
cmd.args(&args[2..]);
|
||||
}
|
||||
match run_command_and_wait(&mut cmd) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Exec java failed: {}", err));
|
||||
},
|
||||
Ok(_) => (),
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn do_with_buildin_arg_maven(first_arg: &str, args: &Vec<String>) {
|
||||
do_with_buildin_arg_builder(first_arg, args, "maven", "MAVEN_HOME", "mvn")
|
||||
}
|
||||
|
||||
fn do_with_buildin_arg_gradle(first_arg: &str, args: &Vec<String>) {
|
||||
do_with_buildin_arg_builder(first_arg, args, "gradle", "GRADLE_HOME", "gradle")
|
||||
}
|
||||
|
||||
fn do_with_buildin_arg_builder(first_arg: &str, args: &Vec<String>, builder_name: &str, builder_home: &str, builder_bin: &str) {
|
||||
let builder_version = &first_arg[(builder_name.len() + 3)..];
|
||||
if builder_version == "" {
|
||||
print_message(MessageType::ERROR, &format!("Builder version is not assigned!"));
|
||||
return;
|
||||
}
|
||||
let mut has_java = false;
|
||||
let mut java_home = String::new();
|
||||
if args.len() > 2 && args[2].starts_with("--java") {
|
||||
has_java = true;
|
||||
let java_version = &args[2][6..];
|
||||
if java_version != "" {
|
||||
java_home = match get_java_home(java_version) {
|
||||
None => {
|
||||
print_message(MessageType::ERROR, &format!("Assigned java version not found: {}", java_version));
|
||||
return;
|
||||
},
|
||||
Some(h) => h,
|
||||
};
|
||||
}
|
||||
}
|
||||
let builder_desc = match tool::get_builder_home(builder_name, builder_version) {
|
||||
None => {
|
||||
print_message(MessageType::ERROR, &format!("Assigned builder: {}, version: {} not found.", builder_name, builder_version));
|
||||
return;
|
||||
},
|
||||
Some(h) => h,
|
||||
};
|
||||
if has_java {
|
||||
print_message(MessageType::OK, &format!("JAVA_HOME = {}", java_home));
|
||||
}
|
||||
print_message(MessageType::OK, &format!("BUILDER_HOME = {}", &builder_desc.home));
|
||||
|
||||
let mut new_env = match has_java {
|
||||
true => get_env_with_java_home(&java_home),
|
||||
false => get_env(),
|
||||
};
|
||||
new_env.insert(builder_home.to_string(), builder_desc.home.clone());
|
||||
|
||||
let mut cmd = Command::new(format!("{}/bin/{}", builder_desc.home.clone(), builder_bin));
|
||||
cmd.envs(&new_env);
|
||||
let from_index = match has_java { true => 3, false => 2 };
|
||||
for i in from_index..args.len() {
|
||||
cmd.arg(&args[i]);
|
||||
}
|
||||
match run_command_and_wait(&mut cmd) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Run build command failed: {}", err));
|
||||
return;
|
||||
},
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
|
||||
fn do_with_buildin_args(args: &Vec<String>) {
|
||||
let first_arg = args.get(1).unwrap();
|
||||
if first_arg == ":::" || first_arg == ":::help" {
|
||||
print_usage();
|
||||
} else if first_arg == ":::create" {
|
||||
create_build_json(&args);
|
||||
} else if first_arg.starts_with(":::java") {
|
||||
do_with_buildin_arg_java(first_arg, args);
|
||||
} else if first_arg.starts_with(":::maven") {
|
||||
do_with_buildin_arg_maven(first_arg, args);
|
||||
} else if first_arg.starts_with(":::gradle") {
|
||||
do_with_buildin_arg_gradle(first_arg, args);
|
||||
} else {
|
||||
print_message(MessageType::ERROR, &format!("Unknown args: {:?}", &args));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
print_message(MessageType::INFO, &format!("{} - version {}", BUILDJ, BUDERJ_VER));
|
||||
|
||||
let args = local_util::get_args_as_vec();
|
||||
print_message(MessageType::INFO, &format!("Arguments: {:?}", args));
|
||||
|
||||
if local_util::is_buildin_args(&args) {
|
||||
do_with_buildin_args(&args);
|
||||
return;
|
||||
}
|
||||
local_util::init_home_dir(tool::LOCAL_BUILDER_HOME_BASE_DIR);
|
||||
local_util::init_home_dir(jdk::LOCAL_JAVA_HOME_BASE_DIR);
|
||||
|
||||
let build_json = match find_build_json() {
|
||||
None => return,
|
||||
Some(p) => p,
|
||||
};
|
||||
|
||||
print_message(MessageType::OK, &format!("Find {} @ {}", BUILD_JSON, build_json));
|
||||
|
||||
let build_json_content = match fs::read_to_string(build_json) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Read {} failed: {}", BUILD_JSON, err));
|
||||
return;
|
||||
},
|
||||
Ok(content) => content,
|
||||
};
|
||||
let build_json_object = match json::parse(&build_json_content) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Parse JSON failed: {}", err));
|
||||
return;
|
||||
},
|
||||
Ok(object) => object,
|
||||
};
|
||||
|
||||
let java_version_j = &build_json_object["java"];
|
||||
let builder_name_j = &build_json_object["builder"]["name"];
|
||||
let builder_version_j = &build_json_object["builder"]["version"];
|
||||
if java_version_j.is_null() {
|
||||
print_message(MessageType::ERROR, "Java version is not assigned!");
|
||||
return;
|
||||
}
|
||||
if builder_name_j.is_null() || builder_version_j.is_null() {
|
||||
print_message(MessageType::ERROR, "Builder name or version is not assigned!");
|
||||
return;
|
||||
}
|
||||
let java_version = java_version_j.as_str().unwrap();
|
||||
let builder_name = builder_name_j.as_str().unwrap();
|
||||
let builder_version = builder_version_j.as_str().unwrap();
|
||||
|
||||
let java_home = match get_java_home(java_version) {
|
||||
None => {
|
||||
print_message(MessageType::ERROR, &format!("Assigned java version not found: {}", java_version));
|
||||
return;
|
||||
},
|
||||
Some(h) => h,
|
||||
};
|
||||
let builder_desc = match tool::get_builder_home(builder_name, builder_version) {
|
||||
None => {
|
||||
print_message(MessageType::ERROR, &format!("Assigned builder: {}, version: {} not found.", builder_name, builder_version));
|
||||
return;
|
||||
},
|
||||
Some(h) => h,
|
||||
};
|
||||
print_message(MessageType::OK, &format!("JAVA_HOME = {}", java_home));
|
||||
print_message(MessageType::OK, &format!("BUILDER_HOME = {}", &builder_desc.home));
|
||||
|
||||
let mut new_env = get_env_with_java_home(&java_home);
|
||||
match builder_desc.name {
|
||||
BuilderName::Maven => new_env.insert("MAVEN_HOME".to_string(), builder_desc.home.clone()),
|
||||
BuilderName::Gradle => new_env.insert("GRADLE_HOME".to_string(), builder_desc.home.clone()),
|
||||
};
|
||||
|
||||
let cmd_bin = match builder_desc.name {
|
||||
BuilderName::Maven => builder_desc.bin.unwrap_or(format!("{}/bin/mvn", builder_desc.home.clone())),
|
||||
BuilderName::Gradle => builder_desc.bin.unwrap_or(format!("{}/bin/gradle", builder_desc.home.clone())),
|
||||
};
|
||||
|
||||
let mut cmd = Command::new(cmd_bin);
|
||||
cmd.envs(&new_env);
|
||||
for i in 1..args.len() {
|
||||
cmd.arg(&args[i]);
|
||||
}
|
||||
match run_command_and_wait(&mut cmd) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Run build command failed: {}", err));
|
||||
return;
|
||||
},
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
195
src/tool.rs
Normal file
195
src/tool.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use super::{
|
||||
http,
|
||||
rust_util::{
|
||||
new_box_error,
|
||||
is_macos_or_linux,
|
||||
print_message,
|
||||
MessageType,
|
||||
XResult,
|
||||
},
|
||||
local_util::{self, *},
|
||||
};
|
||||
|
||||
pub const LOCAL_BUILDER_HOME_BASE_DIR: &str = ".jssp/builder";
|
||||
const STANDARD_CONFIG_JSON: &str = ".standard_config.json";
|
||||
const TOOL_PACKAGE_DETAIL_URL: &str = "https://hatter.ink/tool/query_tool_by_name_version.json";
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum BuilderName {
|
||||
Maven,
|
||||
Gradle,
|
||||
}
|
||||
|
||||
pub struct BuilderDesc {
|
||||
pub name: BuilderName,
|
||||
pub home: String,
|
||||
pub bin: Option<String>,
|
||||
}
|
||||
|
||||
pub fn get_builder_home(builder: &str, version: &str) -> Option<BuilderDesc> {
|
||||
let local_builder_home_base_dir = match get_user_home_dir(LOCAL_BUILDER_HOME_BASE_DIR) {
|
||||
Err(_) => return None,
|
||||
Ok(o) => o,
|
||||
};
|
||||
let builder_name = match builder {
|
||||
"maven" => BuilderName::Maven,
|
||||
"gradle" => BuilderName::Gradle,
|
||||
_ => {
|
||||
print_message(MessageType::ERROR, &format!("Unknown builder: {}", builder));
|
||||
return None;
|
||||
},
|
||||
};
|
||||
let local_builder_home_dir = &format!("{}/{}-{}", local_builder_home_base_dir, builder, version);
|
||||
if Path::new(local_builder_home_dir).exists() {
|
||||
return get_local_builder_home_sub(builder_name, local_builder_home_dir);
|
||||
}
|
||||
|
||||
if get_cloud_builder(builder, version) {
|
||||
return get_local_builder_home_sub(builder_name, local_builder_home_dir);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_cloud_builder(builder: &str, version: &str) -> bool {
|
||||
if ! is_macos_or_linux() {
|
||||
return false;
|
||||
}
|
||||
let local_builder_home_base_dir = match local_util::get_user_home_dir(LOCAL_BUILDER_HOME_BASE_DIR) {
|
||||
Err(_) => return false,
|
||||
Ok(o) => o,
|
||||
};
|
||||
match get_and_extract_tool_package(&local_builder_home_base_dir, true, builder, version, true) {
|
||||
Err(err) => {
|
||||
print_message(MessageType::ERROR, &format!("Get builder: {} failed, version: {}, error: {}", builder, version, err));
|
||||
return false;
|
||||
},
|
||||
Ok(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_local_builder_home_sub(builder_name: BuilderName, local_builder_home_dir: &str) -> Option<BuilderDesc> {
|
||||
match get_local_builder_home_sub_first_sub_dir(local_builder_home_dir) {
|
||||
None => {
|
||||
print_message(MessageType::ERROR, &format!("Cannot find builder home in: {}", local_builder_home_dir));
|
||||
return None;
|
||||
},
|
||||
Some(p) => {
|
||||
return Some(BuilderDesc{name: builder_name, home: p, bin: None});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_local_builder_home_sub_first_sub_dir(local_builder_home_dir: &str) -> Option<String> {
|
||||
let paths = fs::read_dir(Path::new(&local_builder_home_dir)).ok()?;
|
||||
for path in paths {
|
||||
match path {
|
||||
Err(_) => (),
|
||||
Ok(p) => {
|
||||
if p.path().is_dir() {
|
||||
return Some(p.path().to_str()?.to_string());
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_extract_dir_name_by_file_name(file_name: &str) -> Option<String> {
|
||||
if file_name != "" {
|
||||
return None;
|
||||
}
|
||||
let mut dir_name = file_name;
|
||||
if file_name.ends_with(".zip") {
|
||||
dir_name = &file_name[..file_name.len()-4];
|
||||
} else if file_name.ends_with(".tgz") {
|
||||
dir_name = &file_name[..file_name.len()-4];
|
||||
} else if file_name.ends_with(".tar.gz") {
|
||||
dir_name = &file_name[..file_name.len()-7];
|
||||
}
|
||||
if dir_name.ends_with("-bin") {
|
||||
dir_name = &dir_name[..dir_name.len()-4];
|
||||
}
|
||||
Some(dir_name.to_string())
|
||||
}
|
||||
|
||||
pub fn get_tool_package_secret() -> XResult<String> {
|
||||
let standard_config_file = get_user_home_dir(STANDARD_CONFIG_JSON)?;
|
||||
let standard_config_json = fs::read_to_string(&standard_config_file)?;
|
||||
let standard_config_object = json::parse(&standard_config_json)?;
|
||||
|
||||
let build_js_auth_token = &standard_config_object["build.js"]["auth_token"];
|
||||
if build_js_auth_token.is_null() {
|
||||
return Err(new_box_error("Standard json#build.js#auth_token is null."));
|
||||
}
|
||||
Ok(build_js_auth_token.to_string())
|
||||
}
|
||||
|
||||
pub fn get_tool_package_detail(name: &str, version: &str) -> XResult<String> {
|
||||
let secret = match get_tool_package_secret() {
|
||||
Err(err) => {
|
||||
let new_err_message: String = format!("Get package detail secret failed: {}, from file: ~/{}", err, STANDARD_CONFIG_JSON);
|
||||
return Err(new_box_error(&new_err_message))
|
||||
},
|
||||
Ok(r) => r,
|
||||
};
|
||||
|
||||
let mut url = String::new();
|
||||
url.push_str(TOOL_PACKAGE_DETAIL_URL);
|
||||
url.push_str("?");
|
||||
url.push_str("__auth_token=");
|
||||
url.push_str(&urlencoding::encode(&secret));
|
||||
url.push_str("&name=");
|
||||
url.push_str(&urlencoding::encode(name));
|
||||
url.push_str("&ver=");
|
||||
url.push_str(&urlencoding::encode(version));
|
||||
Ok(http::get_url(url.as_str())?)
|
||||
}
|
||||
|
||||
pub fn get_and_extract_tool_package(base_dir: &str, dir_with_name: bool, name: &str, version: &str, extract_match: bool) -> XResult<bool> {
|
||||
let tool_package_detail = get_tool_package_detail(name, version)?;
|
||||
let build_json_object = json::parse(&tool_package_detail)?;
|
||||
if build_json_object["status"] != 200 {
|
||||
return Err(new_box_error(&format!("Error in get tool package detail: {}", build_json_object["message"])));
|
||||
}
|
||||
let data = &build_json_object["data"];
|
||||
let integrity = &data["integrity"];
|
||||
let url = &data["url"];
|
||||
let name = &data["name"];
|
||||
if integrity.is_null() || url.is_null() || name.is_null() {
|
||||
return Err(new_box_error(&format!("Parse tool package detail failed: {}", tool_package_detail)));
|
||||
}
|
||||
let n = data["n"].to_string();
|
||||
let v = data["v"].to_string();
|
||||
|
||||
if extract_match && version != &v {
|
||||
return Err(new_box_error(&format!("Required version not match, {}: {} vs {}", name, version, &v)));
|
||||
}
|
||||
|
||||
let mut target_base_dir = String::new();
|
||||
target_base_dir.push_str(base_dir);
|
||||
if dir_with_name {
|
||||
target_base_dir.push_str("/");
|
||||
target_base_dir.push_str(&format!("{}-{}", n, v));
|
||||
}
|
||||
init_dir(&target_base_dir);
|
||||
let target_file_name = format!("{}/{}", &target_base_dir, name.to_string());
|
||||
|
||||
print_message(MessageType::INFO, &format!("Start download: {} -> {}", &url.to_string(), &target_file_name));
|
||||
http::download_url(&url.to_string(), &mut File::create(&target_file_name)?)?;
|
||||
|
||||
print_message(MessageType::INFO, &format!("Start verify integrity: {} ...", &target_file_name));
|
||||
if local_util::verify_file_integrity(&integrity.to_string(), &target_file_name)? {
|
||||
print_message(MessageType::OK, "Verify integrity success.");
|
||||
}
|
||||
|
||||
print_message(MessageType::INFO, &format!("Start extract file: {}", &target_file_name));
|
||||
local_util::extract_package_and_wait(&target_base_dir, &name.to_string())?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
Reference in New Issue
Block a user