@@ 0,0 1,46 @@
+use std::path::PathBuf;
+use crate::types::{Database, PackageName};
+
+/// show package information for given package (if available)
+pub fn info(name: PackageName, db: Option<PathBuf>, show_provides: bool, show_depends: bool) {
+ let db = Database::from_file(db.unwrap_or(PathBuf::from("db.yml")))
+ .expect("Unable to open database");
+
+ {
+ let pkg = db.packages.get(&name).expect("Package not found");
+
+ println!("{}-{}-r{}", pkg.name, pkg.version, pkg.rel);
+ println!("{}", pkg.description);
+ println!("license: {}", pkg.license);
+ println!("url: {}", pkg.url);
+ println!("path: {}", pkg.path.to_str().unwrap_or(""));
+
+ {
+ print!("arch: ");
+ for a in &pkg.arch {
+ print!("{}", a);
+ }
+ println!();
+ }
+ }
+
+ if show_depends {
+ println!("---Dependencies---");
+ if let Some(deps) = db.depends.get(&name) {
+ for dep in deps {
+ println!("{}", dep);
+ }
+ }
+ }
+
+ if show_provides {
+ println!("---Provides---");
+ if let Some(prv) = db.provides.get(&name) {
+ for pr in prv {
+ println!("{}", pr);
+ }
+ }
+
+ }
+
+}
@@ 1,4 1,4 @@
-use std::{path::PathBuf, collections::HashMap};
+use std::path::PathBuf;
use clap::Parser;
mod cmds;
@@ 30,7 30,13 @@ enum Commands {
/// the packagename
package: String,
/// package database path
- db: Option<PathBuf>
+ db: Option<PathBuf>,
+ /// prints the dependencies after the package info
+ #[arg(short='d',long)]
+ show_depends: bool,
+ /// prints the packages provided by the package after the package info
+ #[arg(short='p', long)]
+ show_provides: bool
},
/// Searches the database for a package with the name
/// or containing the name
@@ 47,6 53,8 @@ fn main() {
match cli {
Commands::Scan { folder, db } => cmds::scan(folder, db),
+ Commands::List { db } => cmds::list(db),
+ Commands::Info { package, db, show_depends, show_provides } => cmds::info(package, db, show_provides, show_depends),
_ => panic!("Unimplemented")
}
}
@@ 1,5 1,4 @@
-use std::{path::PathBuf, collections::{HashMap, HashSet}, fs::{FileType, DirEntry, self}};
-
+use std::{path::PathBuf, collections::{HashMap, HashSet}, fs};
use regex::Regex;
use serde::{Deserialize, Serialize};
use walkdir::WalkDir;
@@ 12,21 11,21 @@ pub type PackageName = String;
#[derive(Serialize, Deserialize, Debug)]
pub struct Package {
/// the name of the package
- name: String,
+ pub name: String,
/// the version of the package
- version: String,
+ pub version: String,
/// license used by the package
- license: String,
+ pub license: String,
/// project url
- url: String,
+ pub url: String,
/// package description
- description: String,
+ pub description: String,
/// package release number (starts at zero)
- rel: usize,
+ pub rel: usize,
/// list? of supported/disabled architectures
- arch: HashSet<String>,
+ pub arch: HashSet<String>,
/// relative path to APKBUILD
- path: PathBuf
+ pub path: PathBuf
}
/// Package information collection
@@ 34,73 33,80 @@ pub struct Package {
pub struct Database {
/// dictionary of package names associated with a dictionary
/// of additional package info
- packages: HashMap<PackageName, Package>,
+ pub packages: HashMap<PackageName, Package>,
/// dictionary of package names associated with a dependency list
/// the dependencies may not create cycles
/// all dependencies of a given package have to be build,
/// before the package can be build
- depends: HashMap<PackageName, HashSet<PackageName>>,
+ pub depends: HashMap<PackageName, HashSet<PackageName>>,
/// dictionary of provide names associated with a list of packages,
/// which provide the given package
/// in case multiple packages provide the same provider,
/// all of them should be build
/// (runtime apk should take care of the rest)
- provides: HashMap<PackageName, HashSet<PackageName>>
+ pub provides: HashMap<PackageName, HashSet<PackageName>>
}
impl Database {
pub fn from_scan(folder: PathBuf) -> Self {
let mut db = Self {
- packages: HashMap::new(),
- depends: HashMap::new(),
- provides: HashMap::new(),
+ packages: HashMap::new(),
+ depends: HashMap::new(),
+ provides: HashMap::new(),
};
- for entry in WalkDir::new(folder).follow_links(true) {
- // ignore broken entries
- if let Ok(entry) = entry {
- if entry.file_type().is_dir() {
- // ignore folders themselves
- continue;
- }
- if entry.file_type().is_file() && entry.file_name() != "APKBUILD" {
- // ignore every file that is not the APKBUILD file itself
- continue;
- }
-
-
- let file = entry.into_path();
- let folder = file.parent().expect("Unable to get APKBUILD dir").to_path_buf();
-
- let apk = APKBUILD::from_file(file);
- let depends = apk.depends;
- let mut provides = apk.provides;
- for sub in apk.subs {
- provides.insert(sub);
- }
- let pkg = Package {
- name: apk.name.to_string(),
- arch: apk.arch,
- version: apk.version,
- license: apk.license,
- description: apk.description,
- url: apk.url,
- rel: apk.rel,
- path: folder
- };
-
- db.packages.insert(apk.name.to_string(), pkg);
- db.depends.insert(apk.name.to_string(), depends);
- db.provides.insert(apk.name.to_string(), provides);
+ // loop through all folders, but ignore broken entries
+ for entry in WalkDir::new(folder).follow_links(true).into_iter().flatten(){
+ if entry.file_type().is_dir() {
+ // ignore folders themselves
+ continue;
+ }
+ if entry.file_type().is_file() && entry.file_name() != "APKBUILD" {
+ // ignore every file that is not the APKBUILD file itself
+ continue;
}
+
+
+ let file = entry.into_path();
+ let folder = file.parent().expect("Unable to get APKBUILD dir").to_path_buf();
+
+ let apk = Apkbuild::from_file(file);
+ let depends = apk.depends;
+ let mut provides = apk.provides;
+ for sub in apk.subs {
+ provides.insert(sub);
+ }
+ let pkg = Package {
+ name: apk.name.to_string(),
+ arch: apk.arch,
+ version: apk.version,
+ license: apk.license,
+ description: apk.description,
+ url: apk.url,
+ rel: apk.rel,
+ path: folder
+ };
+
+ db.packages.insert(apk.name.to_string(), pkg);
+ db.depends.insert(apk.name.to_string(), depends);
+ db.provides.insert(apk.name.to_string(), provides);
}
db
}
+ pub fn from_file(file: PathBuf) -> Option<Self> {
+ if let Ok(content) = fs::read_to_string(file) {
+ if let Ok(yml) = serde_yaml::from_str(&content) {
+ return Some(yml);
+ }
+ }
+
+ None
+ }
}
/// unprocessed Data directly extracted from APKBUILD
#[derive(Debug)]
-struct APKBUILD {
+struct Apkbuild {
/// the name of the package
name: String,
/// the version of the package
@@ 122,12 128,12 @@ struct APKBUILD {
/// list of subpackages
subs: Vec<String>
}
-impl APKBUILD {
+impl Apkbuild {
fn from_file(file: PathBuf) -> Self{
let cont = fs::read_to_string(file)
.expect("Failed to open APKBUILD");
- let mut apk = APKBUILD {
+ let mut apk = Self {
name: easy_match("pkgname", &cont),
description: easy_match("pkgdesc", &cont),
rel: easy_match("pkgrel", &cont).parse()
@@ 167,7 173,7 @@ impl APKBUILD {
fn easy_match(var: &str, text: &str) -> String {
let re = Regex::new(&format!("{}=\"[^\"]+\"|{}=[^\"\n]+\n", var,var)).unwrap();
let extr = re.find(text)
- .expect(&format!("Invalid APKBUILD, expected to find {}", var)).as_str();
+ .unwrap_or_else(|| panic!("Invalid APKBUILD, expected to find {}", var)).as_str();
// tidy up the value, by removing unneccesarry characters
// var="<want>"