rust_nrm/utils/
registries.rsuse colored::Colorize;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::env;
use std::{collections::HashMap, path::Path};
use tokio::fs::{read_to_string, write};
use toml;
use super::speed_test::{SpeedTestResult, SpeedTester};
use super::Logger;
#[derive(Serialize, Deserialize, Debug)]
pub struct Registry {
pub registry: String,
pub home: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Store {
#[serde(flatten)]
pub registries: HashMap<String, Registry>,
}
impl Store {
pub async fn load() -> Store {
let file_path = "registries.toml";
if let Ok(current_dir) = env::current_dir() {
let absolute_path: std::path::PathBuf = current_dir.join(file_path);
Logger::info(&format!(
"Absolute path of registries list: {}",
absolute_path.display()
));
}
if Path::new(file_path).exists() {
let content = read_to_string(file_path).await.unwrap_or_default();
let value: Store = toml::from_str(&content).unwrap_or_default();
value
} else {
Store {
registries: HashMap::new(),
}
}
}
pub async fn save(&self) {
let content = toml::to_string_pretty(self).unwrap();
write("registries.toml", content).await.unwrap();
}
pub async fn get_current_registry(&self, is_local: bool) -> Option<String> {
let npmrc_path = if is_local {
".npmrc".to_string()
} else {
let home_dir = env::var("HOME").expect("Failed to get HOME directory");
format!("{}/.npmrc", home_dir)
};
if Path::new(&npmrc_path).exists() {
if let Ok(content) = read_to_string(&npmrc_path).await {
let re = Regex::new(r"(?m)^\s*registry\s*=\s*(.+?)\s*$").unwrap();
if let Some(captures) = re.captures(&content) {
let registry_url = captures.get(1).unwrap().as_str().to_string();
for (name, registry) in &self.registries {
if registry.registry == registry_url {
return Some(name.clone());
}
}
}
}
}
None
}
pub async fn list_registries(&self) {
Logger::list("Available registries:");
let current_global = self.get_current_registry(false).await;
let current_local = self.get_current_registry(true).await;
for (name, registry) in self.registries.iter() {
let mut tags = Vec::new();
if let Some(current_global_name) = ¤t_global {
if name == current_global_name {
tags.push("[GLOBAL]".white().on_blue());
}
}
if let Some(current_local_name) = ¤t_local {
if name == current_local_name {
tags.push("[LOCAL]".white().on_green());
}
}
let tags_str = if !tags.is_empty() {
format!(
" {}",
tags.iter()
.map(|t| t.to_string())
.collect::<Vec<_>>()
.join(" ")
)
} else {
String::new()
};
println!(
"{} -> {}{}",
name.green().bold(),
registry.registry.yellow(),
tags_str
);
}
}
pub fn set_current_use(&mut self, name: &str, is_local: bool) {
if self.registries.contains_key(name) {
Logger::info(&format!(
"Switched to registry: {} ({})",
name.green().bold(),
if is_local {
"local".yellow()
} else {
"global".yellow()
}
));
} else {
Logger::error(&format!("Registry not found: {}", name));
}
}
pub async fn test_registry_speed(&self) -> Vec<SpeedTestResult> {
let tester = SpeedTester::new();
let registries: Vec<(String, String)> = self
.registries
.iter()
.map(|(name, reg)| (name.clone(), reg.registry.clone()))
.collect();
tester.test_all(®istries).await
}
}