Skip to content

Commit eb0d40c

Browse files
committed
added install command
1 parent 8934513 commit eb0d40c

2 files changed

Lines changed: 134 additions & 1 deletion

File tree

src/main.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::cli::{Arg, Cli, Command};
66
use crate::commands::all::all_command;
77
use crate::commands::releases::releases_command;
88
use crate::commands::user::user_command;
9-
use crate::utils::validate_and_convert_path;
9+
use crate::utils::{install, validate_and_convert_path, OS};
1010

1111
fn main() {
1212
let cli = Cli::new().with_default_command("help").with_commands(vec![
@@ -128,6 +128,15 @@ fn main() {
128128

129129
match command.name {
130130
"version" => cli.version(),
131+
"install" => {
132+
let os = match std::env::consts::OS {
133+
"windows" => OS::Windows,
134+
"macos" => OS::Mac,
135+
_ => panic!("Unsupported OS"),
136+
};
137+
138+
install(&os);
139+
}
131140
"all" => {
132141
let user = command.get_value_of("user").throw_if_none();
133142
let repo = command.get_value_of("repository").throw_if_none();

src/utils.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
use reqwest::header::{HeaderMap, ACCEPT, USER_AGENT};
22
use serde_json::Value;
3+
use std::env;
4+
use std::fs;
35
use std::fs::{create_dir_all, remove_file, File};
46
use std::io::{BufWriter, Write};
57
use std::path::{Path, PathBuf};
68

9+
#[derive(Debug)]
10+
pub enum OS {
11+
Windows,
12+
Mac,
13+
}
14+
15+
impl OS {
16+
fn get_name(&self) -> &str {
17+
match self {
18+
OS::Windows => "Windows",
19+
OS::Mac => "Mac",
20+
}
21+
}
22+
}
23+
724
pub fn request(url: String) -> Result<Value, Box<dyn std::error::Error>> {
825
let headers = construct_header();
926
let client = reqwest::blocking::Client::new();
@@ -96,3 +113,110 @@ pub fn bytes_to_best_size(bytes: i64) -> String {
96113

97114
format!("{:.2} {}", size, unit)
98115
}
116+
117+
pub fn install(os: &OS) {
118+
println!("starting install on {}", os.get_name());
119+
120+
let home_dir = get_user_home_dir(os);
121+
let bin_path = match os {
122+
OS::Windows => "AppData/Roaming/gstats",
123+
OS::Mac => ".local/bin",
124+
};
125+
126+
let local_bin_path = format!("{}/{}", home_dir, bin_path);
127+
128+
// Create directory if it doesn't exist
129+
if !Path::new(&local_bin_path).exists() {
130+
println!("Creating {} directory", local_bin_path);
131+
fs::create_dir_all(&local_bin_path).unwrap();
132+
}
133+
134+
let binary_name = match os {
135+
OS::Windows => "gstats.exe",
136+
OS::Mac => "gstats",
137+
};
138+
139+
let new_binary_path = format!("{}/{}", local_bin_path, binary_name);
140+
141+
if Path::new(&new_binary_path).exists() {
142+
println!("Replacing binary in {}", &local_bin_path);
143+
fs::remove_file(&new_binary_path).unwrap();
144+
}
145+
146+
println!("Moving binary to {}", local_bin_path);
147+
fs::copy(
148+
format!("{}/{}", get_current_directory_path(), binary_name),
149+
&new_binary_path,
150+
)
151+
.unwrap();
152+
153+
match os {
154+
OS::Windows => {
155+
if let Err(e) = add_registry_path(&local_bin_path) {
156+
eprintln!("Failed to modify system PATH: {}", e);
157+
eprintln!("This action may require administrator permissions.");
158+
return;
159+
}
160+
}
161+
OS::Mac => {
162+
let zprofile_path = format!("{}/.zprofile", home_dir);
163+
if let Ok(zprofile_content) = fs::read_to_string(&zprofile_path) {
164+
if !zprofile_content.contains("export PATH=\"$PATH:$HOME/.local/bin\"") {
165+
println!("Adding .local/bin to path in .zprofile");
166+
let mut zprofile_file = File::create(&zprofile_path).unwrap();
167+
writeln!(zprofile_file, "export PATH=\"$PATH:$HOME/.local/bin\"").unwrap();
168+
}
169+
}
170+
}
171+
}
172+
173+
println!("install complete");
174+
}
175+
176+
fn add_registry_path(new_path: &str) -> std::io::Result<()> {
177+
use std::process::Command;
178+
179+
// Escape percent signs by doubling them
180+
let escaped_path = new_path.replace("%", "%%");
181+
182+
// Prepare the command to modify the registry
183+
let status = Command::new("reg")
184+
.args(&[
185+
"ADD",
186+
"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
187+
"/v",
188+
"Path",
189+
"/t",
190+
"REG_EXPAND_SZ",
191+
"/d",
192+
&escaped_path,
193+
"/f",
194+
])
195+
.status()?;
196+
197+
if !status.success() {
198+
return Err(std::io::Error::new(
199+
std::io::ErrorKind::Other,
200+
"Failed to modify registry",
201+
));
202+
}
203+
204+
Ok(())
205+
}
206+
207+
fn get_current_directory_path() -> String {
208+
let current_dir_path = match env::current_dir() {
209+
Ok(path) => path,
210+
Err(_) => panic!("Could not get current directory path"),
211+
};
212+
213+
current_dir_path.to_str().unwrap().to_string()
214+
}
215+
216+
fn get_user_home_dir(os: &OS) -> String {
217+
let user_dir = match os {
218+
OS::Windows => "USERPROFILE",
219+
OS::Mac => "HOME",
220+
};
221+
std::env::var(format!("{}", user_dir)).unwrap()
222+
}

0 commit comments

Comments
 (0)