1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
use anyhow::Result; use serde::Deserialize; use std::process::{Command, Stdio}; #[derive(Deserialize, Debug)] struct PackageJson { name: String, version: String, main: Option<String>, types: Option<String>, } pub enum PackageType { NPM, NPX, Package(String), } pub struct Package { package_type: PackageType, } impl Package { pub fn new(package_type: PackageType) -> Self { Self { package_type } } pub fn name(&self) -> &str { match &self.package_type { PackageType::NPM => "npm", PackageType::NPX => "npx", PackageType::Package(s) => s, } } pub fn install(&self, version: Option<&str>) -> Result<()> { if self.installed().is_ok() { return Ok(()); } let install = match &self.package_type { PackageType::Package(s) => { let npm = Self::new(PackageType::NPM); npm.installed()?; if let Some(version) = version { npm.execute_to_string(&format!( "npm install {}@{} --save", &self.name(), version ))?; } else { npm.execute_to_string(&format!( "npm install {} --save --silent", &self.name() ))?; } Ok(()) } _ => Err(anyhow::format_err!("Cant install this package")), }; install?; Ok(()) } pub fn installed(&self) -> Result<()> { match self.version() { Ok(_) => Ok(()), Err(e) => Err(e), } } pub fn version(&self) -> Result<String> { let version = match &self.package_type { PackageType::NPM => self.execute_to_string(&format!("{} -v", self.name())), PackageType::NPX => self.execute_to_string(&format!("{} -v", self.name())), PackageType::Package(s) => match self.package_json() { Ok(x) => Ok(x.version), Err(e) => Err(e), }, }?; Ok(version) } fn package_json(&self) -> Result<PackageJson> { let file = std::fs::File::open(format!("./node_modules/{}/package.json", self.name()))?; let reader = std::io::BufReader::new(file); let json = serde_json::from_reader(reader)?; Ok(json) } pub fn execute_to_stdout(&self, arg: &str) -> Result<()> { let mut output = self .program() .arg("-c") .arg(arg) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn()?; match output.wait() { Ok(_e) => Ok(()), Err(e) => Err(e.into()), } } pub fn execute_to_string(&self, arg: &str) -> Result<String> { let output = self .program() .arg("-c") .arg(arg) .stderr(Stdio::inherit()) .output()?; Ok(std::str::from_utf8(&output.stdout)?.trim().to_string()) } fn program(&self) -> Command { if cfg!(target_os = "windows") { Command::new("cmd") } else { Command::new("sh") } } }