You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amethyst/src/main.rs

299 lines
8.8 KiB
Rust

use args::{Args, GenCompArgs};
use builder::pacman::{PacmanColor, PacmanQueryBuilder};
use clap::Parser;
use internal::commands::ShellCommand;
use internal::{detect, utils};
use crate::args::{InstallArgs, Operation, QueryArgs, RemoveArgs};
use crate::error::SilentUnwrap;
use crate::interact::page_string;
use crate::internal::config::Config;
use crate::internal::exit_code::AppExitCode;
use crate::internal::{sort, start_sudoloop, structs::Options};
use crate::logging::get_logger;
use crate::logging::Printable;
use clap_complete::Shell;
use clap_complete_fig::Fig;
use alpm::vercmp;
use std::str::FromStr;
mod args;
mod builder;
mod error;
mod interact;
mod internal;
mod logging;
mod operations;
use crate::internal::rpc::rpcinfo;
use logging::init_logger;
#[tokio::main]
async fn main() {
color_eyre::install().unwrap();
if utils::is_run_with_root() {
fl_crash!(AppExitCode::RunAsRoot, "run-as-root");
}
let args: Args = Args::parse();
init_logger(usize::from(args.verbose).into());
let noconfirm = args.no_confirm;
let quiet = args.quiet;
let options = Options {
noconfirm,
quiet,
asdeps: false,
upgrade: false,
};
if args.sudoloop {
start_sudoloop().await;
}
match args.subcommand.unwrap_or_default() {
Operation::Install(install_args) => cmd_install(install_args, options).await,
Operation::Remove(remove_args) => cmd_remove(remove_args, options).await,
Operation::Search(search_args) => {
let args = InstallArgs {
search: true,
..search_args
};
cmd_install(args, options).await;
}
Operation::Query(query_args) => cmd_query(query_args).await,
Operation::Upgrade(upgrade_args) => {
fl_info!("system-upgrade");
operations::upgrade(upgrade_args, options).await;
}
Operation::Clean => {
fl_info!("removing-orphans");
operations::clean(options).await;
}
Operation::CheckUpdates => cmd_checkupdates().await,
Operation::GenComp(gen_args) => cmd_gencomp(&gen_args),
Operation::Diff => detect().await,
}
}
#[tracing::instrument(level = "trace")]
async fn cmd_install(args: InstallArgs, options: Options) {
let packages = &args.packages;
let both = !args.aur && !args.repo;
let noconfirm = options.noconfirm;
match args.search {
true => {
cmd_search(args, options).await;
}
false => {
if args.repo && !args.aur {
operations::install(packages.to_vec(), options).await;
return;
}
if args.aur && !args.repo {
operations::aur_install(packages.to_vec(), options).await;
return;
}
if both {
let sorted = sort(packages, options).await;
if !sorted.nf.is_empty() {
fl_crash!(
AppExitCode::PacmanError,
"couldnt-find-packages",
packages = sorted.nf.join(", ")
);
}
if !sorted.repo.is_empty() {
operations::install(sorted.repo, options).await;
}
if !sorted.aur.is_empty() {
if Config::read().base.aur_verification_prompt {
fl_info!("following-packages");
get_logger().print_list(&sorted.aur, " ", 2);
newline!();
fl_warn!("aur-warning");
let cont = noconfirm || fl_prompt!(default no, "are-you-sure");
if !cont {
fl_info!("exiting");
std::process::exit(AppExitCode::PacmanError as i32);
}
}
operations::aur_install(sorted.aur, options).await;
}
}
}
};
}
#[tracing::instrument(level = "trace")]
async fn cmd_remove(args: RemoveArgs, options: Options) {
let packages = args.packages;
fl_info!("uninstalling-packages", packages = packages.join(", "));
operations::uninstall(packages, options).await;
}
#[tracing::instrument(level = "trace")]
async fn cmd_search(args: InstallArgs, options: Options) {
let query_string = args.packages.join(" ");
let both = !args.aur && !args.repo;
let mut results = Vec::new();
if args.repo || both {
fl_info!("searching-repos", query = query_string.clone());
let res = operations::search(&query_string, options).await;
results.extend(res);
}
if args.aur || both {
fl_info!("searching-aur", query = query_string.clone());
let res = operations::aur_search(&query_string, args.by, options).await;
results.extend(res);
}
if results.is_empty() {
fl_info!("no-results");
} else {
fl_info!("results");
results.sort_by(|a, b| {
let a_score = a.score(&query_string);
let b_score = b.score(&query_string);
b_score
.partial_cmp(&a_score)
.unwrap_or(std::cmp::Ordering::Equal)
});
let list: Vec<String> = results.iter().map(|x| x.to_print_string()).collect();
get_logger().print_list(&list, "\n", 0);
if list.join("\n").lines().count() > crossterm::terminal::size().unwrap().1 as usize {
page_string(list.join("\n")).silent_unwrap(AppExitCode::Other);
}
}
}
#[tracing::instrument(level = "trace")]
async fn cmd_query(args: QueryArgs) {
let both = !args.aur && !args.repo && args.info.is_none() && args.owns.is_none();
if args.repo {
fl_info!("installed-repo-packages");
PacmanQueryBuilder::native()
.color(PacmanColor::Always)
.explicit(args.explicit)
.query()
.await
.silent_unwrap(AppExitCode::PacmanError);
}
if args.aur {
fl_info!("installed-aur-packages");
PacmanQueryBuilder::foreign()
.color(PacmanColor::Always)
.explicit(args.explicit)
.query()
.await
.silent_unwrap(AppExitCode::PacmanError);
}
if both {
fl_info!("installed-packages");
PacmanQueryBuilder::all()
.color(PacmanColor::Always)
.explicit(args.explicit)
.query()
.await
.silent_unwrap(AppExitCode::PacmanError);
}
if let Some(info) = args.info {
PacmanQueryBuilder::info()
.package(info)
.explicit(args.explicit)
.query()
.await
.silent_unwrap(AppExitCode::PacmanError);
}
if let Some(owns) = args.owns {
let result = PacmanQueryBuilder::owns()
.package(owns.clone())
.query()
.await;
if result.is_err() {
fl_crash!(AppExitCode::PacmanError, "error-occurred");
}
}
}
#[tracing::instrument(level = "trace")]
async fn cmd_checkupdates() {
// TODO: Implement AUR update checking, which would then respectively display in crystal-update
print!(
"{}",
ShellCommand::checkupdates()
.wait_with_output()
.await
.silent_unwrap(AppExitCode::Other)
.stdout
);
let non_native_pkgs = PacmanQueryBuilder::foreign()
.color(PacmanColor::Never)
.query_with_output()
.await
.silent_unwrap(AppExitCode::PacmanError);
tracing::debug!("aur packages: {non_native_pkgs:?}");
for pkg in non_native_pkgs {
let remote_package = rpcinfo(&pkg.name)
.await
.silent_unwrap(AppExitCode::RpcError);
if let Some(remote_package) = remote_package {
if vercmp(remote_package.metadata.version.clone(), pkg.version.clone()).is_gt() {
println!(
"{} {} -> {}",
pkg.name, pkg.version, remote_package.metadata.version
)
}
}
}
}
#[tracing::instrument(level = "trace")]
fn cmd_gencomp(args: &GenCompArgs) {
if args.shell == "fig" {
clap_complete::generate(
Fig,
&mut <args::Args as clap::CommandFactory>::command(),
"ame",
&mut std::io::stderr(),
);
} else {
let shell: Shell = Shell::from_str(&args.shell).unwrap_or_else(|e| {
fl_crash!(AppExitCode::Other, "invalid-shell", shell = e);
});
if shell == Shell::Zsh {
fl_crash!(AppExitCode::Other, "zsh-error");
};
clap_complete::generate(
shell,
&mut <args::Args as clap::CommandFactory>::command(),
"ame",
&mut std::io::stderr(),
);
}
}