Fix searching (both AUR and repo)

Add Printable trait
Improve wrapping
i18n
Michal S 2 years ago committed by Michal
parent de9a51aa27
commit bc80df4946

@ -1 +1 @@
use flake
use flake || use nix shell.nix

17
.gitignore vendored

@ -1,6 +1,11 @@
target/
.vscode
.idea
result
.DS_Store
.direnv
# Rust
/target/
**/*.rs.bk
# Nix
/result*
/nix/result*
# Direnv
/.direnv
/.envrc

126
Cargo.lock generated

@ -6,8 +6,11 @@ version = 3
name = "Amethyst"
version = "4.0.0"
dependencies = [
"alpm",
"alpm-utils",
"async-recursion",
"aur-rpc",
"chrono",
"clap",
"clap_complete",
"color-eyre",
@ -23,6 +26,7 @@ dependencies = [
"lazy_static",
"libc",
"native-tls",
"pacmanconf",
"parking_lot",
"regex",
"serde",
@ -58,6 +62,44 @@ dependencies = [
"memchr",
]
[[package]]
name = "alpm"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bedac9e074b9368777268cff76c02d8b26d3e567642a52379aadd5c5e204e120"
dependencies = [
"alpm-sys",
"bitflags",
]
[[package]]
name = "alpm-sys"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fee1afe3484685ecedf03aefd7904428befed7815687e48aa4b21b3417eeecf0"
dependencies = [
"pkg-config",
]
[[package]]
name = "alpm-utils"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c6892a7ced000868007e9ee99a80680c96f5b3e535e9ade81a54501e391232"
dependencies = [
"alpm",
"pacmanconf",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
@ -158,6 +200,27 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
"time",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "cini"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8628d1f5b9a7b1196ce1aa660e3ba7e2559d350649cbe94993519c127df667f2"
[[package]]
name = "clap"
version = "3.2.20"
@ -510,7 +573,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
@ -630,6 +693,20 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"js-sys",
"once_cell",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "idna"
version = "0.2.3"
@ -797,7 +874,7 @@ checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
@ -819,6 +896,25 @@ dependencies = [
"tempfile",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
@ -907,6 +1003,15 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "pacmanconf"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba64fdfa5d4589657dc8c8497b67322d8a64c162357ea0359656bfe23eec6185"
dependencies = [
"cini",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1367,6 +1472,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1607,6 +1723,12 @@ dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

@ -23,6 +23,10 @@ codegen-units = 1
opt-level = 0
[dependencies]
alpm = "2.2.1"
alpm-utils = "2.0.0"
pacmanconf = "2.0.0"
chrono = "0.4.22"
clap = { version = "3.2.17", features = [ "derive", "wrap_help" ] }
regex = { version = "1.6.0", default-features = false, features = [ "std", "unicode-perl" ] }
colored = "2.0.0"

@ -22,16 +22,15 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1662096612,
"narHash": "sha256-R+Q8l5JuyJryRPdiIaYpO5O3A55rT+/pItBrKcy7LM4=",
"lastModified": 1662309212,
"narHash": "sha256-gTDq4vSC4XUr5UDlmdsTYCJNeE1JNWWvQB8ViiNdyFI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "21de2b973f9fee595a7a1ac4693efff791245c34",
"rev": "1ed43116cdb9670e9241138996a2c72d357de70e",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}

@ -1,6 +1,6 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
nixpkgs.url = "github:nixos/nixpkgs";
utils.url = "github:numtide/flake-utils";
naersk = {
url = "github:nix-community/naersk";
@ -40,7 +40,13 @@
cargo-audit
rustfmt
clippy
# For `alpm` libs
pkg-config
pacman
openssl
];
# For rust-analyzer
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
};

@ -17,7 +17,7 @@ impl AmeTheme {
impl Theme for AmeTheme {
fn format_prompt(&self, f: &mut dyn std::fmt::Write, prompt: &str) -> std::fmt::Result {
let prompt = wrap_text(prompt).join("\n ");
let prompt = wrap_text(prompt, 4).join("\n");
write!(f, "{} {}:", PROMPT_SYMBOL.magenta(), prompt.bold())
}
@ -31,7 +31,7 @@ impl Theme for AmeTheme {
prompt: &str,
default: Option<bool>,
) -> std::fmt::Result {
let prompt = wrap_text(prompt).join("\n ");
let prompt = wrap_text(prompt, 4).join("\n");
if !prompt.is_empty() {
write!(f, "{} {} ", PROMPT_SYMBOL.magenta(), &prompt.bold())?;
}
@ -49,7 +49,7 @@ impl Theme for AmeTheme {
prompt: &str,
selection: Option<bool>,
) -> std::fmt::Result {
let prompt = wrap_text(prompt).join("\n ");
let prompt = wrap_text(prompt, 4).join("\n");
let selection = selection.map(|b| if b { "yes" } else { "no" });
match selection {

@ -0,0 +1,30 @@
use std::path::Path;
use alpm::Alpm;
use alpm_utils::alpm_with_conf;
use pacmanconf::Config;
#[derive(Debug)]
pub enum Error {
Alpm(alpm::Error),
Pacmanconf(pacmanconf::Error),
}
impl From<alpm::Error> for Error {
fn from(err: alpm::Error) -> Self {
Error::Alpm(err)
}
}
impl From<pacmanconf::Error> for Error {
fn from(err: pacmanconf::Error) -> Self {
Error::Pacmanconf(err)
}
}
pub fn get_handler() -> Result<Alpm, Error> {
let config = Config::from_file(Path::new("/etc/pacman.conf"))?;
let alpm = alpm_with_conf(&config)?;
Ok(alpm)
}

@ -17,6 +17,7 @@ mod sort;
pub mod structs;
#[macro_use]
pub mod utils;
pub mod alpm;
mod sudoloop;
#[macro_export]

@ -63,14 +63,12 @@ fn create_if_not_exist(dir: &Path) -> &Path {
dir
}
pub fn wrap_text<S: AsRef<str>>(s: S) -> Vec<String> {
wrap(s.as_ref(), get_wrap_options())
pub fn wrap_text<S: AsRef<str>>(s: S, padding: usize) -> Vec<String> {
let subsequent_padding = " ".repeat(padding);
let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - padding)
.subsequent_indent(&subsequent_padding);
wrap(s.as_ref(), opts)
.into_iter()
.map(String::from)
.collect()
}
fn get_wrap_options() -> textwrap::Options<'static> {
textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2)
.subsequent_indent(" ")
}

@ -99,7 +99,7 @@ impl LogHandler {
format!("{}{}{}", acc, separator, line)
});
let lines = wrap_text(lines).join("\n");
let lines = wrap_text(lines, 2).join("\n");
self.log(lines)
}
@ -214,7 +214,7 @@ impl LogHandler {
fn preformat_msg(&self, msg: String) -> String {
let msg = self.apply_uwu(msg);
wrap_text(msg).join("\n")
wrap_text(msg, 2).join("\n")
}
fn apply_uwu(&self, msg: String) -> String {

@ -1,5 +1,8 @@
use std::sync::Arc;
mod printable;
pub use printable::Printable;
use lazy_static::lazy_static;
use tracing::Level;
use tracing_error::ErrorLayer;

@ -0,0 +1,7 @@
use std::fmt::Display;
pub trait Printable: Display {
fn to_print_string(&self) -> String {
self.to_string()
}
}

@ -8,6 +8,8 @@ use crate::args::{InstallArgs, Operation, QueryArgs, RemoveArgs, SearchArgs};
use crate::internal::detect;
use crate::internal::exit_code::AppExitCode;
use crate::internal::{sort, start_sudoloop, structs::Options};
use crate::logging::Printable;
use clap_complete::{Generator, Shell};
use std::str::FromStr;
@ -108,19 +110,28 @@ async fn cmd_remove(args: RemoveArgs, options: Options) {
async fn cmd_search(args: SearchArgs, options: Options) {
let query_string = args.search;
if args.aur {
let mut results = Vec::new();
let both = !args.aur && !args.repo;
let aur = args.aur || both;
let repo = args.repo || both;
if aur {
tracing::info!("Searching AUR for {}", &query_string);
operations::aur_search(&query_string, args.by, options).await;
let res = operations::aur_search(&query_string, args.by, options).await;
results.extend(res);
}
if args.repo {
if repo {
tracing::info!("Searching repos for {}", &query_string);
operations::search(&query_string, options).await;
let res = operations::search(&query_string, options).await;
results.extend(res);
}
if !args.aur && !args.repo {
tracing::info!("Searching AUR and repos for {}", &query_string);
operations::search(&query_string, options).await;
operations::aur_search(&query_string, args.by, options).await;
if results.is_empty() {
tracing::info!("No results found");
} else {
tracing::info!("Results:");
}
}

@ -258,7 +258,7 @@ async fn show_and_log_stdio(
let _ = out_writer.write(&[b'\n']).await?;
tracing::trace!("{package_name}: {line}");
let line = format!("{}: {}", package_name.clone().bold(), line);
let lines = wrap_text(line);
let lines = wrap_text(line, 2);
let line = lines.into_iter().next().unwrap();
pb.set_message(line);
}

@ -1,51 +1,147 @@
use std::fmt::Display;
use std::fmt::Formatter;
use std::str::FromStr;
use crate::internal::commands::ShellCommand;
use crate::internal::alpm::get_handler;
use crate::internal::error::SilentUnwrap;
use crate::internal::exit_code::AppExitCode;
use crate::internal::rpc::rpcsearch;
use crate::internal::utils::wrap_text;
use crate::logging::Printable;
use crate::Options;
use aur_rpc::SearchField;
use chrono::Local;
use chrono::TimeZone;
use colored::Colorize;
#[derive(Debug)]
pub struct PackageSearchResult {
pub repo: String,
pub name: String,
pub version: String,
pub group: Option<String>,
pub out_of_date: Option<u64>,
pub description: String,
}
impl Display for PackageSearchResult {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let repo = &self.repo;
let name = &self.name;
let version = &self.version;
let group = self.group.clone().unwrap_or_default();
let out_of_date = self.out_of_date.unwrap_or(0);
let description = &self.description;
format!("{repo}/{name} {version} {group} {out_of_date}\n {description}").fmt(f)
}
}
impl Printable for PackageSearchResult {
fn to_print_string(&self) -> String {
let repo = if &self.repo == "aur" {
(self.repo.clone() + "/").bold().cyan()
} else {
(self.repo.clone() + "/").bold().purple()
};
let name = &self.name.bold();
let version = &self.version.bold().green();
let group = if self.group.is_some() {
format!("({})", self.group.clone().unwrap()).bold().blue()
} else {
"".bold()
};
let out_of_date = if self.out_of_date.is_some() {
format!(
"[out of date: since {}]",
Local
.timestamp(self.out_of_date.unwrap().try_into().unwrap(), 0)
.date_naive()
)
.bold()
.red()
} else {
"".bold()
};
let description = wrap_text(&self.description, 4).join("\n");
format!("{repo}{name} {version} {group} {out_of_date}\n {description}")
}
}
#[tracing::instrument(level = "trace")]
pub async fn aur_search(query: &str, by_field: Option<SearchBy>, options: Options) {
pub async fn aur_search(
query: &str,
by_field: Option<SearchBy>,
options: Options,
) -> Vec<PackageSearchResult> {
let packages = rpcsearch(query.to_string(), by_field.map(SearchBy::into))
.await
.silent_unwrap(AppExitCode::RpcError);
let total_results = packages.len();
for package in &packages {
let description = if let Some(desc) = &package.description {
desc
} else {
""
};
println!(
"aur/{} {}\n {}",
package.name, package.version, description
)
}
tracing::debug!("Found {total_results} resuls for \"{query}\" in AUR",);
let results: Vec<PackageSearchResult> = packages
.into_iter()
.map(|package| {
let name = package.name;
let version = package.version;
let group = None;
let out_of_date = package.out_of_date;
let description = package.description;
PackageSearchResult {
repo: "aur".to_string(),
name,
version,
group,
out_of_date,
description: description.unwrap_or_else(|| "No description".to_string()),
}
})
.collect();
results
}
#[tracing::instrument(level = "trace")]
pub async fn repo_search(query: &str, options: Options) {
let output = ShellCommand::pacman()
.arg("-Ss")
.arg(query)
.wait_with_output()
.await
.silent_unwrap(AppExitCode::PacmanError)
.stdout;
pub async fn repo_search(query: &str, options: Options) -> Vec<PackageSearchResult> {
let alpm = get_handler().unwrap();
let dbs = alpm.syncdbs();
let mut results = Vec::new();
for db in dbs {
let packages = db.search(vec![query].iter()).unwrap();
for package in packages {
let name = package.name();
let version = package.version();
let description = package.desc();
let group = package.groups().first().map(|s| s.to_string());
let out_of_date = None;
let result = PackageSearchResult {
repo: db.name().to_string(),
name: name.to_string(),
version: version.to_string(),
group,
out_of_date,
description: description.unwrap_or("No description").to_string(),
};
results.push(result);
}
}
tracing::debug!(
"Found {} results for \"{}\" in repos",
&output.split('\n').count() / 2,
&results.len(),
&query
);
println!("{}", output)
results
}
/// Represents a field to search by

@ -7,6 +7,7 @@ use crate::internal::error::SilentUnwrap;
use crate::internal::exit_code::AppExitCode;
use crate::Options;
/// Uninstalls the given packages
#[tracing::instrument(level = "trace")]
pub async fn uninstall(packages: Vec<String>, options: Options) {
let mut pacman_args = vec!["-Rs"];

Loading…
Cancel
Save