everything pretty much

i18n
michal 3 years ago
parent 79340f2e6b
commit bba02caf7d

@ -11,5 +11,6 @@ description = "A fast and efficient aur helper."
clap = "2.34.0"
regex = "1.5.4"
runas = "0.2.1"
rusqlite = "0.26.3"
reqwest = { version = "0.11.7", default-features = false, features = [ "blocking", "json", "default-tls" ] }
serde = { version = "1.0.90", default-features = false, features = [ "derive", "serde_derive" ] }

@ -15,18 +15,13 @@ Made for Crystal, compatible with any Arch-based Linux distribution.</p>
![](screenshot.png)
## Basic usage
| Action | FreeBSD pkg-style alias | Pacman-style flag(s) |
| ------ | ------ | ------ |
| Install a package | ame ins | ame -S |
| Remove a package | ame rm | ame -R |
| Remove a package with its dependencies | ame purge | ame -Rs |
| Update repository | ame upd | ame -Sy |
| Upgrade a package | ame upg | ame -Syu |
| Search for a package in general | ame sea | ame -Ss |
| Search for a package in the official arch repos | ame repsea | ame -Sr |
| Search for a package in aur | ame aursea | ame -Sa |
You can also use any pacman flag!
| Action | FreeBSD pkg-style alias | Pacman-style flag(s) |
|----------------------|-------------------------|----------------------|
| Install a package | ame ins/install | ame -S |
| Remove a package | ame rm/remove | ame -R/-Rs |
| Upgrade a package | ame upg/upgrade | ame -Syu |
| Search for a package | ame sea | ame -Ss |
## How to build:
(Install cargo)
@ -48,4 +43,3 @@ echo "AME_UWU=YES" >> ~/.zshrc # for zsh
echo "AME_UWU=YES" >> ~/.bashrc # for bash
set -Ux AME_UWU YES # for fish
```
self explanatory

@ -1,7 +1,23 @@
use crate::internal::rpc::Package;
use crate::Options;
use rusqlite::Connection;
use std::env;
use std::path::Path;
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn add(a: String, options: Options) {
// TODO: the actual database code lmao
pub fn add(pkg: Package, options: Options) {
let conn = Connection::open(Path::new(&format!(
"{}/.local/share/ame/db.sqlite",
env::var("HOME").unwrap()
)))
.expect("Couldn't connect to database.");
if options.verbosity >= 1 {
eprintln!("Adding package {} to database", pkg.name);
}
conn.execute("INSERT OR REPLACE INTO packages (name, version, description, depends, make_depends) VALUES (?1, ?2, ?3, ?4, ?5)",
[&pkg.name, &pkg.version, &pkg.description.unwrap_or_else(|| "No description found.".parse().unwrap()), &pkg.depends.join(" "), &pkg.make_depends.join(" ")]
).unwrap_or_else(|e| {
panic!("Failed adding package {} to the database: {}", pkg.name, e);
});
}

@ -0,0 +1,35 @@
use crate::Options;
use rusqlite::Connection;
use std::env;
use std::path::Path;
pub fn init(options: Options) {
let path = format!("{}/.local/share/ame/db.sqlite", env::var("HOME").unwrap());
let dbpath = Path::new(&path);
let verbosity = options.verbosity;
if verbosity >= 1 {
eprintln!("Creating database at {}", &path);
}
let conn =
Connection::open(dbpath).expect("Couldn't create database at ~/.local/share/ame/db.sqlite");
if verbosity >= 1 {
eprintln!("Populating database with table")
}
conn.execute(
"CREATE TABLE packages (
name TEXT PRIMARY KEY NOT NULL,
version TEXT NOT NULL,
description TEXT,
depends BLOB,
make_depends BLOB
)",
[],
)
.unwrap_or_else(|e| {
panic!("Couldn't initialise database: {}", e);
});
}

@ -1,8 +1,23 @@
use crate::internal::rpc::Package;
use crate::Options;
mod add;
mod initialise;
mod query;
mod remove;
#[allow(dead_code)]
pub fn add(a: String, options: Options) {
pub fn add(a: Package, options: Options) {
add::add(a, options);
}
pub fn remove(a: &str, options: Options) {
remove::remove(a, options);
}
pub fn init(options: Options) {
initialise::init(options);
}
pub fn query(a: &str, options: Options) -> Vec<Package> {
query::query(a, options)
}

@ -0,0 +1,64 @@
use crate::internal::rpc::Package;
use crate::Options;
use rusqlite::Connection;
use std::env;
use std::path::Path;
pub fn query(a: &str, options: Options) -> Vec<Package> {
let verbosity = options.verbosity;
if verbosity >= 1 {
eprintln!("Connecting to database");
}
let conn = Connection::open(Path::new(&format!(
"{}/.local/share/ame/db.sqlite",
env::var("HOME").unwrap()
)))
.expect("Couldn't connect to database.");
if verbosity >= 1 {
eprintln!("Querying database for input")
}
let mut rs = conn
.prepare("SELECT name, version, description, depends, make_depends FROM packages WHERE name LIKE \"?\"")
.unwrap();
let packages_iter = rs
.query_map([a], |row| {
Ok(Package {
name: row.get(0).unwrap(),
version: row.get(1).unwrap(),
description: row.get(2).unwrap(),
depends: row
.get::<usize, String>(3)
.unwrap()
.split(' ')
.map(|s| s.to_string())
.collect::<Vec<String>>(),
make_depends: row
.get::<usize, String>(4)
.unwrap()
.split(' ')
.map(|s| s.to_string())
.collect::<Vec<String>>(),
})
})
.expect("Couldn't query database for packages.");
if verbosity >= 1 {
eprintln!("Retrieved results");
}
let mut results: Vec<Package> = vec![];
for package in packages_iter {
results.push(package.unwrap());
}
if verbosity >= 1 {
eprintln!("Collected results")
}
results
}

@ -0,0 +1,28 @@
use crate::Options;
use rusqlite::Connection;
use std::env;
use std::path::Path;
pub fn remove(pkg: &str, options: Options) {
let conn = Connection::open(Path::new(&format!(
"{}/.local/share/ame/db.sqlite",
env::var("HOME").unwrap()
)))
.expect("Couldn't connect to database.");
let verbosity = options.verbosity;
if verbosity >= 1 {
eprintln!("Removing package {} from database", pkg);
}
conn.execute(
"DELETE FROM packages
WHERE EXISTS
(SELECT *
FROM packages
WHERE name = ?);",
[pkg],
)
.expect("Couldn't delete package from database.");
}

@ -20,6 +20,10 @@ pub fn init(options: Options) {
}
}
if !Path::new(&format!("{}/.local/share/ame/db.sqlite", homedir)).exists() {
crate::database::init(options);
}
if !Path::new(&format!("{}/.cache/ame/", homedir)).exists() {
let r = std::fs::create_dir_all(format!("{}/.cache/ame", homedir));
match r {

@ -8,11 +8,11 @@ pub struct Package {
pub version: String,
#[serde(rename = "Description")]
pub description: Option<String>,
#[serde(default)]
#[serde(rename = "Depends")]
pub depends: Vec<String>,
#[serde(default)]
pub depends: Vec<String>,
#[serde(rename = "MakeDepends")]
#[serde(default)]
pub make_depends: Vec<String>,
}
@ -22,26 +22,32 @@ pub struct SearchResults {
pub results: Vec<Package>,
}
#[derive(Clone)]
pub struct InfoResults {
pub found: bool,
pub package: Option<Package>
pub package: Option<Package>,
}
pub const URL: &str = "https://aur.archlinux.org/";
pub fn rpcinfo(pkg: String) -> InfoResults {
let res = reqwest::blocking::get(&format!(
"https://aur.archlinux.org/rpc/?v=5&type=info&arg={}",
pkg
)).unwrap().json::<SearchResults>().unwrap();
))
.unwrap()
.json::<SearchResults>()
.unwrap();
if res.results.is_empty() {
InfoResults {
found: false,
package: None
package: None,
}
} else {
InfoResults {
found: true,
package: Some(res.results[0].clone())
package: Some(res.results[0].clone()),
}
}
}
@ -50,5 +56,8 @@ pub fn rpcsearch(pkg: String) -> SearchResults {
reqwest::blocking::get(&format!(
"https://aur.archlinux.org/rpc/?v=5&type=search&arg={}",
pkg
)).unwrap().json().unwrap()
))
.unwrap()
.json()
.unwrap()
}

@ -25,7 +25,6 @@ pub fn sort(input: &[String], options: Options) -> structs::Sorted {
}
for b in a {
#[cfg(unix)]
let rs = Command::new("pacman")
.arg("-Ss")
.arg(format!("^{}$", &b))
@ -33,16 +32,6 @@ pub fn sort(input: &[String], options: Options) -> structs::Sorted {
.status()
.expect("Something has gone wrong.");
#[cfg(windows)]
let rs = Command::new("pwsh")
.arg("-nop")
.arg("-c")
.arg("exit")
.arg("1")
.stdout(Stdio::null())
.status()
.expect("Something has gone wrong.");
if rpc::rpcinfo(b.to_string()).found {
if verbosity >= 1 {
eprintln!("{} found in AUR.", b);

@ -19,15 +19,5 @@ impl Sorted {
pub struct Options {
pub verbosity: i32,
pub noconfirm: bool,
}
impl Options {
#[allow(dead_code)]
pub fn new(verbosity: i32, noconfirm: bool) -> Self {
let a: Options = Options {
verbosity,
noconfirm,
};
a
}
pub asdeps: bool,
}

@ -72,6 +72,11 @@ fn main() {
.index(1),
),
)
.subcommand(
SubCommand::with_name("upgrade")
.about("Upgrades locally installed packages to their latest versions")
.aliases(&["-Syu", "upg"]),
)
.settings(&[
AppSettings::GlobalVersion,
AppSettings::VersionlessSubcommands,
@ -85,6 +90,7 @@ fn main() {
let options = Options {
verbosity,
noconfirm,
asdeps: false,
};
init(options);
@ -102,8 +108,12 @@ fn main() {
if let true = matches.is_present("install") {
let sorted = sort(&packages, options);
operations::install(sorted.repo, options);
operations::aur_install(sorted.aur, options);
if !sorted.repo.is_empty() {
operations::install(sorted.repo, options);
}
if !sorted.aur.is_empty() {
operations::aur_install(sorted.aur, options);
}
if !sorted.nf.is_empty() {
eprintln!(
"Couldn't find packages: {} in repos or the AUR.",
@ -118,6 +128,11 @@ fn main() {
exit(0);
}
if let true = matches.is_present("upgrade") {
operations::upgrade(options);
exit(0);
}
if let true = matches.is_present("search") {
if matches
.subcommand_matches("search")

@ -1,7 +1,16 @@
use crate::internal::rpc::rpcinfo;
use crate::Options;
use std::env;
use std::env::set_current_dir;
use std::fs::remove_dir_all;
use std::path::Path;
use std::process::Command;
pub fn aur_install(a: Vec<String>, options: Options) {
let url = crate::internal::rpc::URL;
let cachedir = format!("{}/.cache/ame/", env::var("HOME").unwrap());
let verbosity = options.verbosity;
let noconfirm = options.noconfirm;
match verbosity {
0 => {}
1 => {
@ -10,9 +19,102 @@ pub fn aur_install(a: Vec<String>, options: Options) {
}
_ => {
eprintln!("Installing from AUR:");
for b in a {
for b in &a {
eprintln!("{:?}", b);
}
}
}
for package in a {
let rpcres = rpcinfo(package);
if !rpcres.found {
break;
}
let pkg = &rpcres.package.as_ref().unwrap().name;
if verbosity >= 1 {
eprintln!("Cloning {} into cachedir", pkg);
}
// cloning
set_current_dir(Path::new(&cachedir)).unwrap();
Command::new("git")
.arg("clone")
.arg(format!("{}/{}", url, pkg))
.status()
.expect("Something has gone wrong.");
if verbosity >= 1 {
eprintln!(
"Cloned {} into cachedir, moving on to resolving dependencies",
pkg
);
eprintln!(
"Raw dependencies for package {} are:\n{:?}",
pkg,
rpcres.package.as_ref().unwrap().depends.join(", ")
)
}
// dep sorting
let sorted = crate::internal::sort(&rpcres.package.as_ref().unwrap().depends, options);
if verbosity >= 1 {
eprintln!("Sorted depndencies for {} are:\n{:?}", pkg, &sorted)
}
let newopts = Options {
verbosity,
noconfirm,
asdeps: true,
};
if !sorted.nf.is_empty() {
panic!(
"Could not find dependencies {} for package {}. Aborting",
sorted.nf.join(", "),
pkg
);
}
if !noconfirm {
let editor = env::var("EDITOR").unwrap_or_else(|_| "nano".parse().unwrap());
Command::new(editor)
.arg(format!("{}/PKGBUILD", pkg))
.spawn()
.unwrap()
.wait()
.unwrap();
}
// dep installing
crate::operations::install(sorted.repo, newopts);
crate::operations::aur_install(sorted.aur, newopts);
let mut makepkg_args = vec!["-rsic", "--needed"];
if options.asdeps {
makepkg_args.push("--asdeps")
}
if options.noconfirm {
makepkg_args.push("--noconfirm")
}
// package building and installing
set_current_dir(format!("{}/{}", cachedir, pkg)).unwrap();
Command::new("makepkg")
.args(&makepkg_args)
.status()
.expect("Something has gone wrong.");
if makepkg_args.contains(&"--asdeps") {
set_current_dir(&cachedir).unwrap();
remove_dir_all(format!("{}/{}", cachedir, pkg)).unwrap();
}
// pushes package to database
crate::database::add(rpcres.package.unwrap(), options);
}
}

@ -5,6 +5,9 @@ pub fn install(mut a: Vec<String>, options: Options) {
if options.noconfirm {
a.push("--noconfirm".to_string());
}
if options.asdeps {
a.push("--asdeps".to_string());
}
let verbosity = options.verbosity;
match verbosity {
0 => {}
@ -22,6 +25,7 @@ pub fn install(mut a: Vec<String>, options: Options) {
let r = runas::Command::new("pacman")
.arg("-S")
.arg("--needed")
.args(&a)
.status()
.expect("Something has gone wrong.");

@ -4,6 +4,7 @@ mod aur_install;
mod install;
mod search;
mod uninstall;
mod upgrade;
pub fn install(a: Vec<String>, options: Options) {
install::install(a, options);
@ -24,3 +25,7 @@ pub fn aur_install(a: Vec<String>, options: Options) {
pub fn aur_search(a: &str, options: Options) {
search::aur_search(a, options);
}
pub fn upgrade(options: Options) {
upgrade::upgrade(options);
}

@ -1,4 +1,6 @@
use crate::Options;
use std::path::Path;
use std::{env, fs};
pub fn uninstall(mut a: Vec<String>, options: Options) {
let b = a.clone();
@ -31,4 +33,19 @@ pub fn uninstall(mut a: Vec<String>, options: Options) {
eprintln!("Uninstalling packages: {:?} exited with code {}.", &b, x)
}
}
for b in a {
crate::database::remove(&b, options);
if Path::new(&format!("{}/.cache/ame/{}", env::var("HOME").unwrap(), b)).exists() {
if verbosity >= 1 {
eprintln!("Old cache directory found, deleting")
}
fs::remove_dir_all(Path::new(&format!(
"{}/.cache/ame/{}",
env::var("HOME").unwrap(),
b
)))
.unwrap();
}
}
}

@ -0,0 +1,40 @@
use crate::internal::rpc::rpcinfo;
use crate::operations::aur_install::aur_install;
use crate::Options;
use runas::Command;
pub fn upgrade(options: Options) {
let verbosity = options.verbosity;
let noconfirm = options.noconfirm;
let mut pacman_args = vec!["-Syu"];
if noconfirm {
pacman_args.push("--noconfirm");
}
if verbosity >= 1 {
eprintln!("Upgrading repo packages")
}
Command::new("pacman")
.args(&pacman_args)
.status()
.expect("Something has gone wrong.");
if verbosity >= 1 {
eprintln!("Upgrading AUR packages")
}
let res = crate::database::query("\"%\"", options);
let mut aur_upgrades = vec![];
for r in res {
let re = r.clone();
let ver = rpcinfo(r.name);
if ver.package.unwrap().version != r.version {
aur_upgrades.push(re.name);
}
}
aur_install(aur_upgrades, options);
}
Loading…
Cancel
Save