Skip to content

Commit

Permalink
feat: add
Browse files Browse the repository at this point in the history
  • Loading branch information
1739616529 committed Jul 17, 2024
1 parent 5159514 commit 4369a5b
Show file tree
Hide file tree
Showing 5 changed files with 313 additions and 27 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
node_modules
cache
node
*-lock.*
*local*
*.d.ts
Expand Down
27 changes: 26 additions & 1 deletion crates/nsv/src/command/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,32 @@ pub struct Add {
#[async_trait]
impl Command for Add {
async fn apply(&self, core: &mut NsvCore) -> Result<(), NsvCoreError> {
core.sync_version_by_str(&self.version).await
let version = core.format_version(&self.version)?;
core.set_version_target(&version)?;
let local_node_version = core.get_version_by_local(&version).await;
if local_node_version.is_some() {
return Err(NsvCoreError::NodeVersionLocalExist)
}
drop(local_node_version);

let mut remote_node_version = None;

{
remote_node_version = core.get_version_by_remote().await
}

if remote_node_version.is_none() {
return Err(NsvCoreError::NodeVersionRemoteNotFound);
};
let remote_node_version = remote_node_version.unwrap();

core.context.version = core.format_version(&remote_node_version.version)?;

let download_node_info = core.sync_node_by_remote().await;

core.unzip_node_file(&download_node_info.target).await;

Ok(())
}
}

Expand Down
26 changes: 5 additions & 21 deletions crates/nsv/src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
mod add;
mod r#use;
use crate::print_log_err;
use add::Add;
use async_trait::async_trait;
use r#use::Use;
use root::core::{ NsvCore};
use root::node;
use root::core::NsvCore;
use root::node::NsvCoreError;
use crate::print_log_err;

#[derive(clap::Parser, Debug)]
pub enum Commands {
Expand All @@ -33,31 +32,16 @@ pub trait Command {
match self.apply(core).await {
Ok(()) => (),
Err(err) => {
println!("err: {:?}", err);
match err {
NsvCoreError::NodeItemExisted => {
println!("nsv: version is existed")
}
_ => {
core.context.node_version_list = None;
println!(
"err: {:?}\n{:?}\n{:?}",
err,
core.context,
core.config,
);
panic!()
}
}
},
self.handle_err(err, core);
}
}
}

async fn apply(&self, core: &mut NsvCore) -> Result<(), NsvCoreError>;

fn handle_err(&self, err: NsvCoreError, core: &mut NsvCore) {
let err_s = format!("{:?}", err);
print_log_err!("{}.\ncontext: {:?}", err_s, core.context);
print_log_err!("{}.\n{:?}\n{:?}", err_s, core.context, core.config);
std::process::exit(1);
}
}
16 changes: 12 additions & 4 deletions crates/nsv/src/command/use.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
use async_trait::async_trait;
use root::core::{NsvCore};
use root::{core::NsvCore, node::NodeDispose};

use thiserror::Error;
use root::node::NsvCoreError;
use super::Command;
use root::node::NsvCoreError;
use thiserror::Error;

#[derive(clap::Parser, Debug)]
pub struct Use {
version: String,
}


#[async_trait]
impl Command for Use {
async fn apply(&self, core: &mut NsvCore) -> Result<(), NsvCoreError> {
core.format_version_str(&self.version)?;

// let version = core.find_version_by_local(&self.version).await;

// if version.is_none() {
// return Err(NsvCoreError::NodeVersionLocalNotFound)
// }




Ok(())
Expand Down
270 changes: 270 additions & 0 deletions crates/root/src/node/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
use crate::core::NsvCore;
use crate::util::create_node_version_vaildate_reg;
use crate::util::dir::ensure_dir;
use crate::util::download::{download_file, unzip_file};
use async_trait::async_trait;
use serde::Deserialize;
use tokio::fs::rename;
use std::fs::{read_dir, DirEntry};
use std::path::{Path, PathBuf};

#[derive(PartialEq, Debug, Clone)]
pub enum VersionTarget {
Lts,
Latest,
Assign(String),
}

#[derive(PartialEq, Debug)]
pub enum NsvCoreError {
/**
* 自定义报错信息
*/
String(String),

/**
* 空值
*/
Empty,

/**
* 非法版本
*/
IllegalityVersion(String),

/**
* node 版本远程不存在
*/
NodeVersionRemoteNotFound,

/**
* node版本本地不存在
*/
NodeVersionLocalNotFound,

/**
* 本地已存在
*/
NodeVersionLocalExist,
}

#[async_trait]
pub trait NodeDispose {
/// 根据版本str获取本地 node dir
fn get_local_node_dir_2_dir_entry(&self, version: &str) -> Option<DirEntry>;

/// 格式化用户输入的 版本
fn set_version_target(&mut self, version: &str) -> Result<(), NsvCoreError>;

/// 格式化node版本
fn format_version(&self, version: &str) -> Result<String, NsvCoreError>;

/// 获取远程 node列表
async fn get_version_list_by_remote(&mut self);

/// 查找node版本 通过远程
async fn get_version_by_remote(&mut self) -> Option<&NodeVersionItem>;


/// 下载node
async fn download_node_by_remote(&mut self, version: &DownloadNodeItem);

/// 从远程同步 node 版本 到本地
async fn sync_node_by_remote(&mut self) -> DownloadNodeItem;

/// 解压 本地node压缩包
async fn unzip_node_file(&self, file_dir: &Path);

/// 获取本地node版本
async fn get_version_by_local(&mut self, version: &str) -> Option<String>;
}

#[async_trait]
impl NodeDispose for NsvCore {

fn format_version(&self, version: &str) -> Result<String, NsvCoreError>{
let (char, ver) = version.split_at(1);
if char == "v" {
return Ok(ver.to_string());
}
return Ok(ver.to_string());
}
fn get_local_node_dir_2_dir_entry(&self, version: &str) -> Option<DirEntry> {
let version_reg = regex::Regex::new(&format!("^{}", version)).unwrap();
for entry in read_dir(&self.context.node_dir).unwrap() {
let entry = entry.unwrap();
if version_reg.is_match(entry.file_name().to_str().unwrap()) {
return Some(entry);
}
}
return None;
}

fn set_version_target(&mut self, version: &str) -> Result<(), NsvCoreError> {
if version.len() == 0 {
return Err(NsvCoreError::Empty);
}

let target = match version {
"lts" => Ok(VersionTarget::Lts),
"latest" => Ok(VersionTarget::Latest),
_ => {
if !create_node_version_vaildate_reg("").is_match(version) {
return Err(NsvCoreError::IllegalityVersion(version.to_string()))
}
Ok(VersionTarget::Assign(version.to_string()))
}
};

if target.is_err() {
return Err(target.err().unwrap());
};
self.context.target = target.unwrap();
Ok(())
}

async fn get_version_list_by_remote(&mut self) {
if self.context.node_version_list.is_some() {
return;
}
let url = format!("{}/index.json", self.config.origin);
let resp = reqwest::get(url).await.unwrap();
let resp_json: Vec<NodeVersionItem> = resp.json().await.unwrap();
self.context.node_version_list = Some(resp_json);
}

async fn get_version_by_remote(&mut self) -> Option<&NodeVersionItem> {
self.get_version_list_by_remote().await;
match &self.context.target {
VersionTarget::Lts => self
.context
.node_version_list
.as_ref()
.unwrap()
.iter()
.find(|item| match item.lts {
NodeLtsTarget::Str(_) => true,
_ => false,
}),
VersionTarget::Latest => self.context.node_version_list.as_ref().unwrap().first(),
VersionTarget::Assign(version) => {
let assign_version_reg = create_node_version_vaildate_reg(version);
self.context
.node_version_list
.as_ref()
.unwrap()
.iter()
.find(|item| assign_version_reg.is_match(&*item.version))
}
}
}


async fn download_node_by_remote(&mut self, download_fine_info: &DownloadNodeItem) {
download_file(&download_fine_info.url, &download_fine_info.target)
.await
.unwrap();
}
async fn sync_node_by_remote(&mut self) -> DownloadNodeItem {
let file_name = format!(
"node-v{}-{}-{}.{}",
self.context.version, self.context.os, self.context.arch, self.context.rar_extension
);
let url = format!(
"{}/v{}/{}",
self.config.origin, self.context.version, file_name
);
let mut target = self.context.node_file.clone();
target.push(&file_name);

let download_fine_info = DownloadNodeItem {
file_name,
url,
target,
};

println!("{:?}", download_fine_info);

self.download_node_by_remote(&download_fine_info).await;

return download_fine_info
}

async fn unzip_node_file(&self, file_dir: &Path) {
let mut output_dir = self.context.temp.clone();
ensure_dir(&output_dir).await.unwrap();
unzip_file(file_dir, &output_dir).await.unwrap();


let node_dir_file_name = file_dir.file_name().unwrap().to_str().unwrap().replace(&format!(".{}", self.context.rar_extension), "");

output_dir.push(node_dir_file_name.clone());

let mut node_dir = self.context.node_dir.clone();
node_dir.push(self.context.version.clone());
rename(&output_dir, &node_dir).await.unwrap();
}

async fn get_version_by_local(&mut self, version: &str) -> Option<String> {

let version: Option<String> = match &self.context.target {
// 输入 lts latest 等
VersionTarget::Latest | VersionTarget::Lts => {
let node_version_item = self.get_version_by_remote().await;
if node_version_item.is_none() {
return None;
}
Some(node_version_item.unwrap().version.clone())
}
// 输入的是精准node版本
_ => Some(version.to_string()),
};

if version.is_none() {
return None;
};

let local_node_dir = self.get_local_node_dir_2_dir_entry(&version.unwrap());
if local_node_dir.is_some() {
Some(
local_node_dir
.unwrap()
.file_name()
.to_str()
.unwrap()
.to_string(),
)
} else {
None
}
}
}

#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum NodeLtsTarget {
Bool(bool),
Str(String),
}

#[derive(Deserialize, Clone, Debug)]
pub struct NodeVersionItem {
/// 版本
pub version: String,

/// 日期
pub date: String,

/// lts
pub lts: NodeLtsTarget,

/// 安全版本
pub security: bool,
}

#[derive(Clone, Debug)]
pub struct DownloadNodeItem {
pub url: String,
pub file_name: String,
pub target: PathBuf,
}

0 comments on commit 4369a5b

Please sign in to comment.