Skip to content

Commit be70411

Browse files
Update main.rs
1 parent e68efa2 commit be70411

File tree

1 file changed

+174
-187
lines changed

1 file changed

+174
-187
lines changed

src/main.rs

Lines changed: 174 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -1,195 +1,182 @@
1-
use std::io::{self, Write};
2-
use std::process::{Command, Stdio};
3-
use std::thread;
4-
use std::time::Duration;
5-
use colored::*;
6-
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
7-
use crossterm::{
8-
event::{self, Event, KeyCode},
9-
execute,
10-
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
11-
};
12-
use std::fs;
1+
use std::process::{Command, ExitStatus};
2+
use std::env;
3+
use std::os::unix::fs::PermissionsExt;
134

14-
fn main() -> io::Result<()> {
15-
// Enter alternate screen and enable raw mode for key input
16-
execute!(io::stdout(), EnterAlternateScreen)?;
17-
enable_raw_mode()?;
18-
// Print stylized header with gradient-like effect
19-
println!("{}", "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓".bright_green().bold());
20-
println!("{}", "┃ Hacker-Update ┃".bright_cyan().bold().on_bright_black());
21-
println!("{}", "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛".bright_green().bold());
22-
println!("{}", " Initializing system updates...".bright_blue().italic());
23-
println!();
24-
// Define update commands with associated colors for visual distinction
25-
let update_commands = vec![
26-
("DNF System Update", vec![
27-
("sudo /usr/lib/HackerOS/dnf update -y", Color::BrightMagenta),
28-
("sudo /usr/lib/HackerOS/dnf upgrade -y", Color::BrightMagenta),
29-
("sudo /usr/lib/HackerOS/dnf autoremove -y", Color::BrightMagenta),
30-
]),
31-
("Flatpak Update", vec![("flatpak update -y", Color::BrightYellow)]),
32-
("Snap Update", vec![("sudo snap refresh", Color::BrightBlue)]),
33-
("Firmware Update", vec![
34-
("sudo fwupdmgr refresh", Color::BrightGreen),
35-
("sudo fwupdmgr update", Color::BrightGreen),
36-
]),
37-
];
38-
// Store logs
39-
let mut logs: Vec<String> = Vec::new();
40-
// Initialize MultiProgress for concurrent progress bars
41-
let multi_pb = MultiProgress::new();
42-
// Run each update command with enhanced progress bar
43-
for (update_name, commands) in update_commands {
44-
println!("{}", format!(" Starting {} ", update_name).white().bold().on_color(update_name_color(update_name)));
45-
let pb = multi_pb.add(ProgressBar::new(100));
46-
pb.set_style(
47-
ProgressStyle::default_bar()
48-
.template("{spinner:.cyan} [{elapsed_precise}] {bar:50.green/blue} {msg} {percent:>3}%")
49-
.unwrap()
50-
.progress_chars("█▉▊▋▌▍▎▏ ")
51-
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈"),
52-
);
53-
for (_i, (cmd, color)) in commands.iter().enumerate() {
54-
pb.set_message(format!("{}", cmd.color(*color).bold()).to_string());
55-
let output = Command::new("sh")
56-
.arg("-c")
57-
.arg(cmd)
58-
.stdout(Stdio::piped())
59-
.stderr(Stdio::piped())
60-
.output();
61-
match output {
62-
Ok(output) => {
63-
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
64-
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
65-
logs.push(format!("{} Output:\n{}", cmd, stdout));
66-
if !stderr.is_empty() {
67-
logs.push(format!("{} Errors:\n{}", cmd, stderr));
68-
}
69-
if !output.status.success() {
70-
println!("{}", format!(" Error running {} ", cmd).white().bold().on_bright_red());
71-
} else {
72-
println!("{}", format!(" Completed {} ", cmd).white().bold().on_bright_green());
73-
}
74-
}
75-
Err(e) => {
76-
logs.push(format!("Failed to execute {}: {}", cmd, e));
77-
println!("{}", format!(" Failed to execute {}: {} ", cmd, e).white().bold().on_bright_red());
78-
}
79-
}
80-
pb.inc(100 / commands.len() as u64);
81-
thread::sleep(Duration::from_millis(200));
82-
}
83-
pb.finish_with_message(format!(" {} completed ", update_name).white().bold().to_string());
84-
println!();
5+
const DNF_PATH: &str = "/usr/lib/HackerOS/dnf";
6+
7+
fn print_help() {
8+
println!("hacker: A simple package management tool");
9+
println!("Usage: hacker <command> [arguments]");
10+
println!("\nAvailable commands:");
11+
println!(" autoremove Remove unneeded packages");
12+
println!(" install <packages> Install one or more packages");
13+
println!(" remove <packages> Remove one or more packages");
14+
println!(" list List installed packages");
15+
println!(" search <term> Search for packages");
16+
println!(" clean Clean package cache");
17+
println!(" info <package> Show package information");
18+
println!(" repolist List enabled repositories");
19+
println!(" copr-enable <repo> Enable a COPR repository");
20+
println!(" copr-disable <repo> Disable a COPR repository");
21+
println!(" ? Show this help message");
22+
println!("\nNote: Use 'hacker-update' for system updates and upgrades.");
23+
}
24+
25+
fn execute_dnf(args: Vec<&str>, use_sudo: bool) -> Result<ExitStatus, String> {
26+
let mut command = if use_sudo {
27+
let mut cmd = Command::new("sudo");
28+
cmd.arg(DNF_PATH);
29+
cmd
30+
} else {
31+
Command::new(DNF_PATH)
32+
};
33+
34+
let output = command
35+
.args(&args)
36+
.status()
37+
.map_err(|e| format!("Failed to execute dnf: {}", e))?;
38+
Ok(output)
39+
}
40+
41+
fn can_run_without_sudo() -> bool {
42+
// Check if user has write permissions to /usr/lib/HackerOS/dnf
43+
if let Ok(metadata) = std::fs::metadata(DNF_PATH) {
44+
let permissions = metadata.permissions();
45+
let mode = permissions.mode();
46+
// Check if executable and writable by user or group
47+
(mode & 0o111) != 0 && (mode & 0o600) != 0
48+
} else {
49+
false
50+
}
51+
}
52+
53+
fn main() {
54+
let args: Vec<String> = env::args().collect();
55+
if args.len() < 2 {
56+
println!("Error: No command provided");
57+
print_help();
58+
std::process::exit(1);
8559
}
86-
// Run the custom script
87-
let script_path = "/usr/share/HackerOS/Scripts/Bin/Update-usrshare.sh";
88-
if fs::metadata(script_path).is_ok() {
89-
println!("{}", " Starting custom update script ".white().bold().on_bright_purple());
90-
let pb = multi_pb.add(ProgressBar::new_spinner());
91-
pb.set_style(
92-
ProgressStyle::default_spinner()
93-
.template("{spinner:.purple} {msg} [{elapsed_precise}]")
94-
.unwrap()
95-
.tick_chars("⣾⣷⣯⣟⡿⢿⣻⣽"),
96-
);
97-
pb.set_message("Executing Update-usrshare.sh".to_string());
98-
let output = Command::new("sh")
99-
.arg(script_path)
100-
.stdout(Stdio::piped())
101-
.stderr(Stdio::piped())
102-
.output();
103-
match output {
104-
Ok(output) => {
105-
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
106-
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
107-
logs.push(format!("Update-usrshare.sh Output:\n{}", stdout));
108-
if !stderr.is_empty() {
109-
logs.push(format!("Update-usrshare.sh Errors:\n{}", stderr));
110-
}
111-
if !output.status.success() {
112-
println!("{}", " Error running custom script ".white().bold().on_bright_red());
113-
} else {
114-
println!("{}", " Completed custom script ".white().bold().on_bright_green());
115-
}
116-
}
117-
Err(e) => {
118-
logs.push(format!("Failed to execute script: {}", e));
119-
println!("{}", format!(" Failed to execute script: {} ", e).white().bold().on_bright_red());
60+
61+
let command = &args[1];
62+
let use_sudo = !can_run_without_sudo();
63+
64+
match command.as_str() {
65+
"autoremove" => {
66+
match execute_dnf(vec!["autoremove", "-y"], use_sudo) {
67+
Ok(status) if status.success() => println!("Autoremove completed successfully"),
68+
Ok(_) => println!("Autoremove failed"),
69+
Err(e) => println!("Error: {}", e),
12070
}
12171
}
122-
pb.finish_with_message(" Script execution completed ".to_string());
123-
} else {
124-
println!("{}", " Custom script not found ".white().bold().on_bright_red());
125-
logs.push("Custom script not found!".to_string());
126-
}
127-
// Display stylized menu with gradient borders
128-
loop {
129-
println!();
130-
println!("{}", "╔════════════════════════════════════════════════╗".bright_cyan().bold());
131-
println!("{}", "║ Update Completed! ║".white().bold().on_bright_black());
132-
println!("{}", "╠════════════════════════════════════════════════╣".bright_cyan().bold());
133-
println!("{}", "║ (E)xit (S)hutdown (R)eboot ║".bright_yellow().bold());
134-
println!("{}", "║ (L)og Out (T)ry again (S)ow logs ║".bright_yellow().bold());
135-
println!("{}", "╚════════════════════════════════════════════════╝".bright_cyan().bold());
136-
println!("{}", " Select an option: ".white().italic());
137-
io::stdout().flush()?;
138-
if let Event::Key(key_event) = event::read()? {
139-
match key_event.code {
140-
KeyCode::Char('e') | KeyCode::Char('E') => {
141-
println!("{}", " Exiting ".white().bold().on_bright_blue());
142-
break;
143-
}
144-
KeyCode::Char('s') | KeyCode::Char('S') => {
145-
println!("{}", " Shutting down ".white().bold().on_bright_blue());
146-
let _ = Command::new("sudo").arg("poweroff").output();
147-
break;
148-
}
149-
KeyCode::Char('r') | KeyCode::Char('R') => {
150-
println!("{}", " Rebooting ".white().bold().on_bright_blue());
151-
let _ = Command::new("sudo").arg("reboot").output();
152-
break;
153-
}
154-
KeyCode::Char('l') | KeyCode::Char('L') => {
155-
println!("{}", " Logging out ".white().bold().on_bright_blue());
156-
let _ = Command::new("pkill").arg("-u").arg(&whoami::username()).output();
157-
break;
158-
}
159-
KeyCode::Char('t') | KeyCode::Char('T') => {
160-
println!("{}", " Restarting updates ".white().bold().on_bright_blue());
161-
let _ = execute!(io::stdout(), LeaveAlternateScreen)?;
162-
disable_raw_mode()?;
163-
main()?;
164-
return Ok(());
165-
}
166-
KeyCode::Char('h') | KeyCode::Char('H') => {
167-
println!("{}", " Update Logs ".white().bold().on_bright_cyan());
168-
println!("{}", "╔════════════════════════════════════════════════╗".bright_cyan().bold());
169-
for log in &logs {
170-
println!("{}", format!("║ {} ", log).white().on_bright_black());
171-
}
172-
println!("{}", "╚════════════════════════════════════════════════╝".bright_cyan().bold());
173-
}
174-
_ => {
175-
println!("{}", " Invalid option, try again. ".white().bold().on_bright_red());
176-
}
72+
"install" => {
73+
if args.len() < 3 {
74+
println!("Error: At least one package name required for install");
75+
std::process::exit(1);
76+
}
77+
let packages = &args[2..];
78+
let mut dnf_args = vec!["install", "-y"];
79+
dnf_args.extend(packages.iter().map(|s| s.as_str()));
80+
match execute_dnf(dnf_args, use_sudo) {
81+
Ok(status) if status.success() => println!("Package(s) {} installed successfully", packages.join(" ")),
82+
Ok(_) => println!("Failed to install package(s) {}", packages.join(" ")),
83+
Err(e) => println!("Error: {}", e),
17784
}
17885
}
179-
}
180-
// Cleanup
181-
execute!(io::stdout(), LeaveAlternateScreen)?;
182-
disable_raw_mode()?;
183-
Ok(())
184-
}
185-
186-
// Helper function to assign background colors based on update type
187-
fn update_name_color(update_name: &str) -> Color {
188-
match update_name {
189-
"DNF System Update" => Color::BrightMagenta,
190-
"Flatpak Update" => Color::BrightYellow,
191-
"Snap Update" => Color::BrightBlue,
192-
"Firmware Update" => Color::BrightGreen,
193-
_ => Color::BrightBlack,
86+
"remove" => {
87+
if args.len() < 3 {
88+
println!("Error: At least one package name required for remove");
89+
std::process::exit(1);
90+
}
91+
let packages = &args[2..];
92+
let mut dnf_args = vec!["remove", "-y"];
93+
dnf_args.extend(packages.iter().map(|s| s.as_str()));
94+
match execute_dnf(dnf_args, use_sudo) {
95+
Ok(status) if status.success() => println!("Package(s) {} removed successfully", packages.join(" ")),
96+
Ok(_) => println!("Failed to remove package(s) {}", packages.join(" ")),
97+
Err(e) => println!("Error: {}", e),
98+
}
99+
}
100+
"list" => {
101+
match execute_dnf(vec!["list", "installed"], use_sudo) {
102+
Ok(status) if status.success() => println!("Listed installed packages"),
103+
Ok(_) => println!("Failed to list packages"),
104+
Err(e) => println!("Error: {}", e),
105+
}
106+
}
107+
"search" => {
108+
if args.len() < 3 {
109+
println!("Error: Search term required");
110+
std::process::exit(1);
111+
}
112+
let term = &args[2];
113+
match execute_dnf(vec!["search", term], use_sudo) {
114+
Ok(status) if status.success() => println!("Search completed"),
115+
Ok(_) => println!("Search failed"),
116+
Err(e) => println!("Error: {}", e),
117+
}
118+
}
119+
"clean" => {
120+
match execute_dnf(vec!["clean", "all"], use_sudo) {
121+
Ok(status) if status.success() => println!("Package cache cleaned successfully"),
122+
Ok(_) => println!("Failed to clean package cache"),
123+
Err(e) => println!("Error: {}", e),
124+
}
125+
}
126+
"info" => {
127+
if args.len() < 3 {
128+
println!("Error: Package name required for info");
129+
std::process::exit(1);
130+
}
131+
let package = &args[2];
132+
match execute_dnf(vec!["info", package], use_sudo) {
133+
Ok(status) if status.success() => println!("Package information displayed"),
134+
Ok(_) => println!("Failed to display package information"),
135+
Err(e) => println!("Error: {}", e),
136+
}
137+
}
138+
"repolist" => {
139+
match execute_dnf(vec!["repolist"], use_sudo) {
140+
Ok(status) if status.success() => println!("Repository list displayed"),
141+
Ok(_) => println!("Failed to display repository list"),
142+
Err(e) => println!("Error: {}", e),
143+
}
144+
}
145+
"copr-enable" => {
146+
if args.len() < 3 {
147+
println!("Error: COPR repository name required");
148+
std::process::exit(1);
149+
}
150+
let repo = &args[2];
151+
match execute_dnf(vec!["copr", "enable", repo], use_sudo) {
152+
Ok(status) if status.success() => println!("COPR repository {} enabled", repo),
153+
Ok(_) => println!("Failed to enable COPR repository {}", repo),
154+
Err(e) => println!("Error: {}", e),
155+
}
156+
}
157+
"copr-disable" => {
158+
if args.len() < 3 {
159+
println!("Error: COPR repository name required");
160+
std::process::exit(1);
161+
}
162+
let repo = &args[2];
163+
match execute_dnf(vec!["copr", "disable", repo], use_sudo) {
164+
Ok(status) if status.success() => println!("COPR repository {} disabled", repo),
165+
Ok(_) => println!("Failed to disable COPR repository {}", repo),
166+
Err(e) => println!("Error: {}", e),
167+
}
168+
}
169+
"update" | "upgrade" => {
170+
println!("Error: Use 'hacker-update' for system updates and upgrades.");
171+
std::process::exit(1);
172+
}
173+
"?" => {
174+
print_help();
175+
}
176+
_ => {
177+
println!("Error: Unknown command '{}'", command);
178+
print_help();
179+
std::process::exit(1);
180+
}
194181
}
195182
}

0 commit comments

Comments
 (0)