finish WIP

This commit is contained in:
Luke Harding 2024-05-07 20:05:12 -04:00
parent c024f85f46
commit f6e7c01093
6 changed files with 201 additions and 22 deletions

2
Cargo.lock generated
View File

@ -20,7 +20,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "rust-archlinux-update"
version = "0.1.1"
version = "1.0.0"
dependencies = [
"colored",
]

View File

@ -1,6 +1,6 @@
[package]
name = "rust-archlinux-update"
version = "0.1.1"
version = "1.0.0"
edition = "2021"
license = "GPL-3"

View File

@ -2,27 +2,42 @@
A program that automates the arch update process with cleanup and auto removal.
***Currently, a WIP. USE AT OWN RISK***
## Setup
The current state requires that you build it yourself. The most up-to-date version will be on the development branch.
Download the binary from the releases tab. The pre-compiled binary works on x86_64 only.
Just run `cargo build --release` and copy the executable from `./target/release/rust-archlinux-update` to wherever you
need it.
Recommended Installation:
Distribution on pre-built binaries, cargo, etc. is in the works.
1. Place the binary in the `~/local/bin` folder
2. Run `chmod +x` on the binary
3. Add `/home/<USER>/local/bin` to your PATH variable
This installation allows it to be run anywhere on your system.
If you need a different target please see the next section on compilation.
## Compilation
It's simple.
Steps:
1. Download the source code. (git clone or release tarball)
2. Ensure that rustup is up-to-date and has the correct toolchain installed and selected.
3. Run `cargo build --release` and find the binary at `./target/release/rust-archlinux-update`
## Usage
The default behavior of the command is to use pacman to run a package update, auto-removal, and cache clear in that
order.
rust-archlinux-updater [OPTIONS]
In the future the command will support AUR helpers like paru and those will need to be activated with a flag.
Options:
-h, --help | Show this help message
-u | preform a regular update
-p | Use paru to update the AUR packages on your system
## Issue Reporting
I don't allow random sign-ups on my gitea instance. Please email me at [luke@lukeh990.io](mailto:luke@lukeh990.io).
I don't allow random sign-ups on my gitea instance. Please email me at <luke@lukeh990.io>.
If you have any suggestions for how to better handle issue reporting please email me.

View File

@ -11,35 +11,97 @@
This file contains the primary logic of the application
*/
use std::env;
use std::{env, error};
use colored::{ColoredString, Colorize};
use wrappers::pacman;
use crate::wrappers::paru;
mod shell_commands;
mod wrappers;
#[derive(Debug, Clone)]
struct RunOptions {
pub help: bool,
pub update: bool,
pub paru: bool,
}
fn main() {
println!("{}", copyright_notice());
match get_run_options() {
Ok(options) => {
if options.help {
print_help_text();
return;
}
if options.update {
update(options.paru);
return;
}
print_help_text();
}
Err(e) => {
error_println("Failed to detect arguments.");
eprintln!("{}", e);
}
}
}
fn get_run_options() -> Result<RunOptions, Box<dyn error::Error>> {
let mut args = env::args();
// Drop the file location from args
// Remove unneeded first entry
if args.next().is_none() {
error_println("Unexpected error in argument collection. Aborting.");
return;
return Err("No args found".into());
}
let args: Vec<String> = args.collect();
for arg in &args {}
let blank_options = RunOptions {
help: false,
update: false,
paru: false,
};
let mut options = blank_options.clone();
if args.is_empty() {
print_help_text();
} else {
update();
return Ok(blank_options);
}
for arg in args {
if arg[..2].eq("--") {
let flag = &arg[2..];
if flag.eq("help") {
options.help = true;
} else {
return Ok(blank_options);
}
} else if arg[..1].eq("-") {
let mut selected: Vec<&str> = arg[1..].split("").collect();
selected.retain_mut(|x| !x.is_empty());
for selected_option in selected {
match selected_option {
"h" => options.help = true,
"u" => options.update = true,
"p" => options.paru = true,
_ => return Ok(blank_options),
}
}
} else {
return Ok(blank_options);
}
}
Ok(options)
}
fn print_help_text() {
@ -52,20 +114,39 @@ fn print_help_text() {
);
}
fn update() {
fn update(paru: bool) {
if let Err(e) = pacman::check() {
error_println(e.to_string());
return;
} else {
notice_println("Pacman is installed\n")
notice_println("Pacman is installed")
}
if paru {
if let Err(e) = paru::check() {
error_println(e.to_string());
return;
} else {
notice_println("Paru is installed")
}
}
println!();
notice_println("Running pacman update");
if let Err(e) = pacman::update_all() {
error_println(e.to_string());
return;
}
if paru {
notice_println("Updating AUR with paru");
if let Err(e) = paru::update_aur() {
error_println(e.to_string());
return;
}
}
notice_println("Getting orphaned packages");
let result = match pacman::get_unused() {
Ok(result) => result,

View File

@ -12,3 +12,4 @@
*/
pub mod pacman;
pub mod paru;

82
src/wrappers/paru.rs Normal file
View File

@ -0,0 +1,82 @@
/*
Rust Arch Linux Updater
Copyright (C) 2024 Luke Harding <luke@lukeh990.io>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/*
wrappers/paru.rs
This module provides a wrapper to make working with paru much easier.
*/
use std::{error, fmt, result};
use std::fmt::Formatter;
use std::path::Path;
use std::process::ExitStatus;
use crate::shell_commands;
type Result<T> = result::Result<T, Box<dyn error::Error>>;
#[derive(Debug, Clone)]
enum ParuError {
NotInstalled,
ExitCode(i32),
Other(&'static str),
}
impl fmt::Display for ParuError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let out = match self {
ParuError::NotInstalled => "Paru not installed.".to_string(),
ParuError::ExitCode(code) => format!("Paru exited with an exit code: {}", code),
ParuError::Other(msg) => msg.to_string(),
};
write!(f, "ParuError: {}", out)
}
}
impl error::Error for ParuError {}
pub fn check() -> Result<()> {
let out = shell_commands::execute_quiet("which", ["paru"])?;
let path = if out.status.success() {
let mut stdout = out.stdout;
stdout.pop(); // Remove \n from stdout
String::from_utf8(stdout)?
} else {
String::from("/usr/bin/paru")
};
let path = Path::new(&path);
if !path.exists() {
return Err(ParuError::NotInstalled.into());
}
Ok(())
}
pub fn update_aur() -> Result<()> {
let exit_status = shell_commands::execute_in_sh("paru -Sua")?;
check_exit_code(exit_status)
}
fn check_exit_code(exit_status: ExitStatus) -> Result<()> {
if !exit_status.success() {
let exit_code = match exit_status.code() {
Some(exit_code) => exit_code,
None => return Err(ParuError::Other("No Exit Code Found").into()),
};
return Err(ParuError::ExitCode(exit_code).into());
}
Ok(())
}