Skip to content

Commit

Permalink
stash
Browse files Browse the repository at this point in the history
  • Loading branch information
ityuany committed Jul 18, 2024
1 parent e2d686f commit b0667b9
Show file tree
Hide file tree
Showing 12 changed files with 337 additions and 14 deletions.
3 changes: 2 additions & 1 deletion crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ path = "src/main.rs"

[dependencies]
log = "0.4.20"
ansi_term = "0.12.1"
anyhow = "1.0"
colored = "2.1.0"
dirs = "5.0.1"
Expand All @@ -23,7 +24,7 @@ env_logger = "0.11.2"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0.0", features = ["full"] }
clap = { version = "4.5.7", features = ["derive","cargo"] }
ansi_term = "0.12.1"
reqwest = { version = "0.12.3", features = ["json", "blocking", "stream","native-tls-vendored"] }
regex = "1.10.4"
glob = "0.3.1"
clap_complete = "4.5.1"
Expand Down
6 changes: 4 additions & 2 deletions crates/cli/src/execute_cli.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use snm_config::SnmConfig;
use snm_ni::trait_transform::IArgs;
use snm_ni::{CommandArgsCreatorTrait, NpmArgsTransform, PnpmArgsTransform, YarnArgsTransform};
use snm_node::snm_node::SnmNode;
use snm_node::snm_node::NodeAtom;
use snm_utils::snm_error::SnmError;
use std::process::{Command, Stdio};

use crate::fig::fig_spec_impl;
use crate::manage_command::ManageCommands;
// use crate::node_manager::node_manager::NodeManager;
use crate::snm_command::SnmCommands;
use crate::SnmCli;

pub async fn execute_cli(cli: SnmCli, snm_config: SnmConfig) -> Result<(), SnmError> {
match cli.command {
// manage start
SnmCommands::Node { command } => {
let snm_node = SnmNode::new(snm_config);
let snm_node = NodeAtom::new(snm_config);
// let x = NodeManager::new();
match command {
ManageCommands::Default { version } => {
snm_node.set_default(version.as_str()).await?;
Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use snm_command::SnmCommands;

pub mod fig;
pub mod manage_command;
// pub mod node_manager;
pub mod snm_command;

pub mod execute_cli;
Expand Down
3 changes: 3 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::env::current_dir;

use clap::Parser;
// use node_manager::NodeManager;
use snm::{execute_cli::execute_cli, SnmCli};
use snm_config::parse_snm_config;
use snm_utils::snm_error::{friendly_error_message, SnmError};

pub mod node_manager;

#[tokio::main]
async fn main() {
// color_backtrace::install();
Expand Down
3 changes: 3 additions & 0 deletions crates/cli/src/node_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod node_manager;
pub mod node_model;
pub mod node_schedule;
201 changes: 201 additions & 0 deletions crates/cli/src/node_manager/node_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
use dialoguer::Confirm;
use snm_core::traits::atom::AtomTrait;
use snm_download_builder::{DownloadBuilder, WriteStrategy};
use snm_utils::snm_error::SnmError;
use std::{collections::HashMap, fs, ops::Not as _, path::PathBuf, time::Duration};

use super::{node_model::NodeModel, node_schedule::NodeSchedule};

pub struct NodeManager<'a, T: AtomTrait> {
node_atom: &'a T,
}

impl<'a, T> NodeManager<'a, T>
where
T: AtomTrait,
{
async fn internal_download(&self, version: &str) -> Result<(), SnmError> {
let download_url = self.node_atom.get_download_url(version);
let downloaded_file_path_buf = self.node_atom.get_downloaded_file_path_buf(version)?;

DownloadBuilder::new()
.retries(3)
.write_strategy(WriteStrategy::Nothing)
.download(&download_url, &downloaded_file_path_buf)
.await?;

let runtime = self.node_atom.get_runtime_dir_path_buf(version)?;

if runtime.exists() {
fs::remove_dir_all(&runtime)?;
}

self.node_atom
.decompress_download_file(&downloaded_file_path_buf, &runtime)?;

fs::remove_file(&downloaded_file_path_buf)?;

Ok(())
}

fn internal_set_default(&self, version: &str) -> Result<PathBuf, SnmError> {
let default_dir = self.node_atom.get_runtime_dir_for_default_path_buf()?;
if default_dir.exists() {
fs::remove_dir_all(&default_dir)?;
}

let from_dir = self.node_atom.get_runtime_dir_path_buf(version)?;

#[cfg(unix)]
{
std::os::unix::fs::symlink(&from_dir, &default_dir)?;
}
#[cfg(windows)]
{
std::os::windows::fs::symlink_dir(&version_dir, &default_dir)?;
}
Ok(default_dir)
}

async fn get_node_list_remote(&self) -> Result<Vec<NodeModel>, SnmError> {
let host = self.node_atom.get_snm_config().get_node_dist_url();
let node_list_url = format!("{}/index.json", host);

let client = reqwest::Client::new();

let node_vec: Vec<NodeModel> = client
.get(&node_list_url)
.timeout(Duration::from_secs(10))
.send()
.await?
.json::<Vec<NodeModel>>()
.await?;
Ok(node_vec)
}

async fn get_node_schedule(&self) -> Result<Vec<NodeSchedule>, SnmError> {
let host = self
.node_atom
.get_snm_config()
.get_node_github_resource_host();

let node_schedule_url = format!("{}/nodejs/Release/main/schedule.json", host);

let client = reqwest::Client::new();

let node_schedule_vec: Vec<NodeSchedule> = client
.get(&node_schedule_url)
.timeout(Duration::from_secs(10))
.send()
.await?
.json::<std::collections::HashMap<String, NodeSchedule>>()
.await?
.into_iter()
.map(|(v, mut schedule)| {
schedule.version = Some(v[1..].to_string());
schedule
})
.collect();

Ok(node_schedule_vec)
}

async fn get_node_sha256_hashmap(
&self,
node_version: &str,
) -> Result<HashMap<String, String>, SnmError> {
let host = self.node_atom.get_snm_config().get_node_dist_url();
let url = format!("{}/v{}/SHASUMS256.txt", host, node_version);

let sha256_str = reqwest::get(&url).await?.text().await?;

let sha256_map: std::collections::HashMap<String, String> = sha256_str
.lines()
.map(|line| {
let mut iter = line.split_whitespace();
let sha256 = iter.next().unwrap();
let file = iter.next().unwrap();
(file.to_string(), sha256.to_string())
})
.collect();

Ok(sha256_map)
}
}

impl<'a, T> NodeManager<'a, T>
where
T: AtomTrait,
{
pub fn new(node_atom: &'a T) -> Self {
Self { node_atom }
}

pub async fn set_default(&self, version: &str) -> Result<(), SnmError> {
if self
.node_atom
.get_anchor_file_path_buf(version)?
.exists()
.not()
{
let msg = format!(
"🤔 v{} is not installed, do you want to install it ?",
version
);
if Confirm::new().with_prompt(msg).interact()? {
self.install(version).await?;
}
}

self.internal_set_default(version)?;

Ok(())
}

pub async fn install(&self, version: &str) -> Result<(), SnmError> {
let anchor_file = self.node_atom.get_anchor_file_path_buf(&version)?;
let version_dir = self.node_atom.get_runtime_dir_path_buf(&version)?;

if anchor_file.exists() {
let confirm = Confirm::new()
.with_prompt(format!(
"🤔 v{} is already installed, do you want to reinstall it ?",
&version
))
.interact()?;

if confirm {
fs::remove_dir_all(&version_dir)?;
self.internal_download(version).await?;
}
} else {
self.internal_download(version).await?;
}

self.internal_set_default(version)?;

Ok(())
}

pub async fn un_install(&self, version: &str) -> Result<(), SnmError> {
let default_dir = self.node_atom.get_runtime_dir_for_default_path_buf()?;
let version_dir = self.node_atom.get_runtime_dir_path_buf(&version)?;
if fs::read_link(&default_dir)?.eq(&version_dir) {
let msg = format!(
"🤔 {} is default instance, do you want to uninstall it ?",
version
);
if Confirm::new().with_prompt(msg).interact()? {
fs::remove_file(&default_dir)?;
fs::remove_dir_all(version_dir)?;
}
} else {
fs::remove_dir_all(version_dir)?;
}
Ok(())
}

pub async fn list(&self) -> Result<(), SnmError> {
Ok(())
}
}
76 changes: 76 additions & 0 deletions crates/cli/src/node_manager/node_model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use serde::{Deserialize, Deserializer, Serialize};
use std::{borrow::Cow, fmt};

#[derive(Deserialize, Debug, Serialize)]
pub struct NodeModel {
pub version: String,
pub date: String,
pub files: Vec<String>,
pub npm: Option<String>,
pub v8: String,
pub uv: Option<String>,
pub zlib: Option<String>,
pub openssl: Option<String>,
pub modules: Option<String>,
pub lts: Lts,
pub security: bool,
pub end: Option<String>,
pub current: Option<String>,
pub deprecated: Option<bool>,
}

impl fmt::Display for NodeModel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"version: {:<10}, lts: {:<10}, date: {:<12}, end: {:<12}, npm: {:<14}, v8: {:<14}, uv: {:<12}, zlib: {:<18}, openssl: {:<14}, modules: {:<12}, deprecated: {}",
self.version,
match &self.lts {
Lts::Str(s) => Cow::Borrowed(s),
Lts::Bool(b) => Cow::Owned(b.to_string()),
},
self.date,
self.end.as_deref().unwrap_or("None"),
self.npm.as_deref().unwrap_or("None"),
self.v8,
self.uv.as_deref().unwrap_or("None"),
self.zlib.as_deref().unwrap_or("None"),
self.openssl.as_deref().unwrap_or("None"),
self.modules.as_deref().unwrap_or("None"),
self.deprecated.map_or("None".to_string(), |v| v.to_string())
)
}
}

#[derive(Debug)]
pub enum Lts {
Str(String),
Bool(bool),
}

impl Serialize for Lts {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
match self {
Lts::Str(s) => serializer.serialize_str(s),
Lts::Bool(b) => serializer.serialize_bool(*b),
}
}
}

// 自定义反序列化
impl<'de> Deserialize<'de> for Lts {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = serde_json::Value::deserialize(deserializer)?;
match value {
serde_json::Value::String(s) => Ok(Lts::Str(s)),
serde_json::Value::Bool(b) => Ok(Lts::Bool(b)),
_ => Err(serde::de::Error::custom("expected a string or a bool")),
}
}
}
37 changes: 37 additions & 0 deletions crates/cli/src/node_manager/node_schedule.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use colored::*;
use core::fmt;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct NodeSchedule {
pub start: String,
pub end: String,
pub maintenance: Option<String>,
pub lts: Option<String>,
pub codename: Option<String>,
pub version: Option<String>,
}

impl fmt::Display for NodeSchedule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let lts = self
.lts
.as_deref()
.map_or_else(|| format!(""), |lts| format!("Lts by {:<12}", lts));

let codename = self.codename.as_deref().map_or_else(
|| format!("{:<20}", ""),
|codename| format!("{:<10} {:<10}", codename.bright_black(), lts.bright_black()),
);

write!(
f,
"Create by: {:<12}, Death by: {:<12}, Maintenance By {:<12}, Version {:<5} {}",
self.start.bright_green(),
self.end.bright_magenta(),
self.maintenance.as_deref().unwrap_or("none").bright_green(),
self.version.as_deref().unwrap_or("none").bright_green(),
codename,
)
}
}
Loading

0 comments on commit b0667b9

Please sign in to comment.