From 038b2160bc8ec6d9699372c20d5cb6ccfa931688 Mon Sep 17 00:00:00 2001 From: Daniel-I-Am Date: Tue, 16 Feb 2021 15:34:28 +0100 Subject: [PATCH] Basic structure reworked --- .gitignore | 3 +- Cargo.lock | 72 ++++++++++-------- Cargo.toml | 5 +- aur_config.toml | 6 ++ contents/.gitkeep | 0 src/argument_parser.rs | 14 ---- src/config_file_actions.rs | 80 ------------------- src/main.rs | 152 ++++++++++++++++++++++++++++--------- src/ops.rs | 19 ----- 9 files changed, 168 insertions(+), 183 deletions(-) create mode 100644 aur_config.toml create mode 100644 contents/.gitkeep delete mode 100644 src/argument_parser.rs delete mode 100644 src/config_file_actions.rs delete mode 100644 src/ops.rs diff --git a/.gitignore b/.gitignore index 40d9aca..4dc4bd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -/.idea \ No newline at end of file +/.idea +contents/packages \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8c07757..0ec9358 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,56 +4,68 @@ name = "aur-helper" version = "0.1.0" dependencies = [ - "rustc-serialize", - "toml-config", + "serde", + "serde_derive", + "toml", ] [[package]] -name = "cfg-if" -version = "0.1.10" +name = "proc-macro2" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "log 0.4.11", + "unicode-xid", ] [[package]] -name = "log" -version = "0.4.11" +name = "quote" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "cfg-if", + "proc-macro2", ] [[package]] -name = "rustc-serialize" -version = "0.3.24" +name = "serde" +version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] [[package]] name = "toml" -version = "0.1.30" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "rustc-serialize", + "serde", ] [[package]] -name = "toml-config" -version = "0.4.0" +name = "unicode-xid" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de5e51a3b687866a2af93d043ff056f797b8c49e2d9d93376eeeaaf66682871" -dependencies = [ - "log 0.3.9", - "rustc-serialize", - "toml", -] +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/Cargo.toml b/Cargo.toml index 3476044..e452922 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -toml-config = "0.4.0" -rustc-serialize = "0.3.24" \ No newline at end of file +toml = "0.5.8" +serde = "1.0.123" +serde_derive = "1.0.123" \ No newline at end of file diff --git a/aur_config.toml b/aur_config.toml new file mode 100644 index 0000000..7e2a337 --- /dev/null +++ b/aur_config.toml @@ -0,0 +1,6 @@ +packages_directory = "contents/packages" + +[packages] +authy = "https://aur.archlinux.org/authy.git" + +[pre_install_script] diff --git a/contents/.gitkeep b/contents/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/argument_parser.rs b/src/argument_parser.rs deleted file mode 100644 index eb267eb..0000000 --- a/src/argument_parser.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::env; - -pub struct Args { - pub(crate) operation: Option, - pub(crate) argument: Option -} - -pub fn get_argument_settings() -> Args { - let args: Vec = env::args().collect(); - Args { - operation: args.get(1).cloned(), - argument: args.get(2).cloned() - } -} \ No newline at end of file diff --git a/src/config_file_actions.rs b/src/config_file_actions.rs deleted file mode 100644 index 203d3e5..0000000 --- a/src/config_file_actions.rs +++ /dev/null @@ -1,80 +0,0 @@ -extern crate rustc_serialize; -extern crate toml_config; - -use std::path::Path; -use toml_config::ConfigFactory; -use std::fs::{create_dir_all, OpenOptions}; -use std::{env, io}; -use std::io::{ErrorKind, Write}; - -#[derive(RustcEncodable, RustcDecodable)] -pub struct Config { - pub nested: NestedConfig -} - -// Defaults will be used for missing/invalid configurations in the TOML config file -impl Default for Config { - fn default() -> Config { - Config { - nested: NestedConfig::default() - } - } -} - -impl Config { - const PATH: &'static str = "config.toml"; - - fn serialize(&self) -> String { - format!("[nested]\ninstall_directory = \"{}\"\ninstalled_packages = [\"{}\"]", self.nested.install_directory, self.nested.installed_packages.to_owned().join("\",\"")) - } - - pub fn write(&self) -> Result<(), io::Error> { - let path_string = Config::PATH; - let path = Path::new(path_string); - if path.exists() && !path.is_file() { - Err(io::Error::new(ErrorKind::InvalidInput, format!("The given path is not a file: {}", path_string).as_str())) - } else { - let dir = path.parent().expect(format!("Config path does not have a parent directory: {}", path_string).as_str()); - - create_dir_all(dir).expect(format!("Could not create directory {}", dir.display()).as_str()); - - let mut config_buffer = OpenOptions::new() - .write(true) - .truncate(true) - .open(path) - .unwrap(); - - config_buffer.write_all(self.serialize().as_bytes()).expect(format!("Could not write to config file {}", path_string).as_str()); - Ok(()) - } - } -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct NestedConfig { - pub install_directory: String, - pub installed_packages: Vec -} - -impl Default for NestedConfig { - fn default() -> NestedConfig { - NestedConfig { - install_directory: "~/.cache/aur-helper/packages".to_owned(), - installed_packages: Vec::new() - } - } -} - -pub fn load_config() -> Config { - let cfg: Config = ConfigFactory::load(Path::new(Config::PATH)); - let home_env = env::var("HOME").expect("Could not find HOME environment variable."); - let relative_home_dir = home_env.as_str(); - let absolute_home_dir = cfg.nested.install_directory.replace("~", relative_home_dir); - let package_path = Path::new(absolute_home_dir.as_str()); - - create_dir_all(package_path).expect(format!("Could not create package directory {}", package_path.display()).as_str()); - - cfg.write().expect("Cannot write configuration to file"); - - cfg -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index ce14aa8..4e6fe57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,47 +1,125 @@ -use crate::argument_parser::get_argument_settings; -use crate::config_file_actions::Config; +use std::env::args; +use std::fs::{File, create_dir_all, remove_dir_all}; +use std::io::Read; +use serde_derive::Deserialize; +use std::collections::HashMap; +use std::path::Path; +use std::process::Command; -mod config_file_actions; -mod argument_parser; -mod ops; +#[derive(Deserialize, Debug)] +struct Config { + packages_directory: Option, + packages: Option>, + pre_install_script: Option> +} +// git --version >= 2.25.0 fn main() { - let args = get_argument_settings(); + let config: Config = get_configuration(); - let mut cfg: Config = config_file_actions::load_config(); - println!("{}", cfg.nested.install_directory); - println!("{:?}", cfg.nested.installed_packages); + let packages_directory_path = &config.packages_directory.clone().unwrap(); + let packages_directory = Path::new(packages_directory_path); + create_dir_all(packages_directory).unwrap(); - if let Some(operation) = args.operation { - let argument = args.argument; - - match operation.to_lowercase().as_str() { - "install" => { - require_argument(&argument); - ops::install(argument.unwrap()); - }, - "list" => { - ops::list_installed(); - }, - "update" => { - require_argument(&argument); - ops::update(argument.unwrap()); - }, - "remove" => { - require_argument(&argument); - ops::remove(argument.unwrap()); - } - _ => { - ops::help(); - } + for (package_name, url) in &config.packages.unwrap() { + let result = process_package(&config.packages_directory.clone().unwrap(), package_name, url); + if result.is_err() { + println!("Processing package '{}' threw an error: {}", package_name, result.err().unwrap()) } - } else { - ops::help(); } } -fn require_argument(argument: &Option) { - if argument.is_none() { - panic!("This option requires an additional argument."); +fn process_package(packages_path: &String, package_name: &String, url: &String) -> Result<(), String> { + println!("Processing package '{}' ({}) in directory {}", package_name, url, packages_path); + + let folder_path = Path::new(packages_path).join(package_name); + let folder_exists = folder_path. exists(); + let repo_exists = folder_path. join(".git") . exists(); + + if folder_exists && !repo_exists { + println!("Removing directory '{}' as it is not a valid git repository.", folder_path.clone().to_str().unwrap()); + remove_dir_all(folder_path.clone()).unwrap(); } -} \ No newline at end of file + + if !folder_exists { + println!("Cloning package '{}' from '{}'.", package_name, url); + Command::new("git") + .arg("clone") + .arg(url) + .arg(folder_path.clone().to_str().unwrap()) + .output() + .expect(&*format!("Could not clone '{}' to '{}'", url, package_name)); + } + + // let status_information = Command::new("git") + // .arg("-C") + // .arg(folder_path.clone().to_str().unwrap()) + // .arg("status") + // .arg("--porcelain=v1") + // .output() + // .expect(&*format!("Could not get repository status for repository root at {}", folder_path.clone().to_str().unwrap())) + // .stdout; + + Command::new("git") + .arg("-C") + .arg(folder_path.clone().to_str().unwrap()) + .arg("clean") + .arg("-f") + .arg("-x") + .output() + .expect(&*format!("Could not clean repository for repository root at {}", folder_path.clone().to_str().unwrap())); + + Command::new("git") + .arg("-C") + .arg(folder_path.clone().to_str().unwrap()) + .arg("restore") + .arg(".") + .output() + .expect(&*format!("Could not clean repository for repository root at {}", folder_path.clone().to_str().unwrap())); + + // for file_status in std::str::from_utf8(&*status_information).unwrap().split('\n').into_iter() { + // if file_status.len() < 3 { + // continue; + // } + // + // let status_code = file_status.chars().into_iter().take(2).collect::(); + // let status_path = file_status.chars().rev().into_iter().take(file_status.len() - 3).collect::().chars().rev().collect::(); + // + // println!("{} {}", status_code, status_path); + // + // + // } + + if !folder_path.join("PKGBUILD").is_file() { + return Err(format!("Package '{}' does not seem to have a PKGBUILD file, if this is a mistake, please delete/update the package manually.", package_name)); + } + + println!("This package does {}have a folder and does {}have a repository.", if folder_exists { "" } else { "not " }, if repo_exists { "" } else { "not " }); + + Ok(()) +} + +fn get_configuration_file_path() -> String { + args().nth(1).expect("Required parameter configuration file missing.") +} + +fn get_configuration_file_contents() -> std::io::Result { + let file_name = get_configuration_file_path(); + let file = File::open(file_name)?; + let mut file_copy = file.try_clone()?; + + let mut contents: Vec = vec![]; + file_copy.read_to_end(&mut contents)?; + Ok(std::str::from_utf8(&*contents) + .expect("Found data in the configuration file that is not according to UTF8").to_string()) +} + +fn get_configuration() -> Config { + let configuration_contents = get_configuration_file_contents().unwrap(); + let config: Config = toml::from_str(&*configuration_contents).unwrap(); + + config.packages_directory.clone().expect("Configuration does not contain string `packages_directory`."); + config.packages.clone().expect("Configuration does not contain array `packages`"); + + config +} diff --git a/src/ops.rs b/src/ops.rs deleted file mode 100644 index 94a5d5c..0000000 --- a/src/ops.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub fn install(argument: String) { - println!("Argument: {}", argument); -} - -pub fn list_installed() { - println!("Here's packages!"); -} - -pub fn update(argument: String) { - println!("Argument: {}", argument); -} - -pub fn remove(argument: String) { - println!("Argument: {}", argument); -} - -pub fn help() { - println!("Help!"); -} \ No newline at end of file