From 79d803386bbc08826d51040a2fe5fd209578267a Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Thu, 26 Sep 2019 10:33:28 +0200 Subject: [PATCH] First steps in install package method --- src/package/default.rs | 125 ++++++++++++++++++++++-- src/package/mod.rs | 13 ++- src/res/test/get_package_index.json | 27 +++++ src/res/test/install_package_index.json | 27 +++++ 4 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 src/res/test/get_package_index.json create mode 100644 src/res/test/install_package_index.json diff --git a/src/package/default.rs b/src/package/default.rs index 783bcc5..841f51c 100644 --- a/src/package/default.rs +++ b/src/package/default.rs @@ -18,13 +18,15 @@ */ use std::path::{PathBuf, Path}; -use crate::package::{PackageIndex, UpdateResult}; +use crate::package::{PackageIndex, UpdateResult, Package, InstallResult}; use std::error::Error; use std::fs::File; use std::io::BufReader; use chrono::{NaiveDateTime, Timelike}; use std::time::{SystemTime, UNIX_EPOCH}; use crate::package::UpdateResult::{NotOutdated, Updated}; +use crate::package::InstallResult::{NotFound, AlreadyInstalled}; +use std::fs; const DEFAULT_PACKAGE_INDEX_FILE : &str = "package_index.json"; @@ -91,9 +93,39 @@ impl DefaultPackageManager { return 0; } + + fn list_local_packages(&self) -> Vec { + let dir = fs::read_dir(&self.package_dir); + let mut output = Vec::new(); + if let Ok(dir) = dir { + for entry in dir { + if let Ok(entry) = entry { + let path = entry.path(); + if path.is_dir() { + let name = path.file_name(); + if let Some(name) = name { + output.push(name.to_str().unwrap().to_owned()) + } + } + } + } + } + + output + } } impl super::PackageManager for DefaultPackageManager { + fn is_index_outdated(&self) -> bool { + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); + let current_timestamp = current_time.as_secs(); + + let local_index_timestamp = self.local_index_timestamp(); + + // Local index is outdated if older than a day + local_index_timestamp + 60*60*24 < current_timestamp + } + fn update_index(&mut self, force: bool) -> Result> { if force || self.is_index_outdated() { let updated_index = DefaultPackageManager::request_index()?; @@ -105,14 +137,35 @@ impl super::PackageManager for DefaultPackageManager { } } - fn is_index_outdated(&self) -> bool { - let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); - let current_timestamp = current_time.as_secs(); + fn get_package(&self, name: &str) -> Option { + if let Some(local_index) = &self.local_index { + let result = local_index.packages.iter().find(|package| { + package.name == name + }); + if let Some(package) = result { + return Some(package.clone()) + } + } - let local_index_timestamp = self.local_index_timestamp(); + None + } - // Local index is outdated if older than a day - local_index_timestamp + 60*60*24 < current_timestamp + fn install_package(&self, name: &str) -> Result> { + let package = self.get_package(name); + match package { + Some(package) => { + // Check if package is already present + let packages = self.list_local_packages(); + if packages.iter().any(|p| p == name) { // Package already installed + Ok(AlreadyInstalled) + }else{ // Package not installed + unimplemented!() + } + }, + None => { + Ok(NotFound) + }, + } } } @@ -122,9 +175,12 @@ mod tests { use tempfile::TempDir; use std::path::Path; use crate::package::PackageManager; + use std::fs::create_dir; const OUTDATED_INDEX_CONTENT : &str = include_str!("../res/test/outdated_index.json"); const INDEX_CONTENT_WITHOUT_UPDATE: &str = include_str!("../res/test/index_without_update.json"); + const GET_PACKAGE_INDEX: &str = include_str!("../res/test/get_package_index.json"); + const INSTALL_PACKAGE_INDEX: &str = include_str!("../res/test/install_package_index.json"); struct TempPackageManager { package_dir: TempDir, @@ -204,4 +260,59 @@ mod tests { assert_eq!(temp.package_manager.update_index(false).unwrap(), UpdateResult::Updated); } + + #[test] + fn test_get_package_should_be_found() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, GET_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.get_package("italian-accents").unwrap().title, "Italian Accents"); + } + + #[test] + fn test_get_package_should_not_be_found() { + let mut temp = create_temp_package_manager(|_, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, GET_PACKAGE_INDEX); + }); + + assert!(temp.package_manager.get_package("not-existing").is_none()); + } + + #[test] + fn test_list_local_packages() { + let mut temp = create_temp_package_manager(|package_dir, _| { + create_dir(package_dir.join("package-1")); + create_dir(package_dir.join("package2")); + std::fs::write(package_dir.join("dummyfile.txt"), "test"); + }); + + let packages = temp.package_manager.list_local_packages(); + assert_eq!(packages.len(), 2); + assert!(packages.iter().any(|p| p == "package-1")); + assert!(packages.iter().any(|p| p == "package2")); + } + + #[test] + fn test_install_package_not_found() { + let mut temp = create_temp_package_manager(|package_dir, data_dir| { + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("not-existing").unwrap(), NotFound); + } + + #[test] + fn test_install_package_already_installed() { + let mut temp = create_temp_package_manager(|package_dir, data_dir| { + create_dir(package_dir.join("italian-accents")); + let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE); + std::fs::write(index_file, INSTALL_PACKAGE_INDEX); + }); + + assert_eq!(temp.package_manager.install_package("italian-accents").unwrap(), AlreadyInstalled); + } } \ No newline at end of file diff --git a/src/package/mod.rs b/src/package/mod.rs index 856252a..b90062b 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -22,8 +22,12 @@ use serde::{Serialize, Deserialize}; use std::error::Error; pub trait PackageManager { - fn update_index(&mut self, force: bool) -> Result>; fn is_index_outdated(&self) -> bool; + fn update_index(&mut self, force: bool) -> Result>; + + fn get_package(&self, name: &str) -> Option; + + fn install_package(&self, name: &str) -> Result>; } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -49,4 +53,11 @@ pub struct PackageIndex { pub enum UpdateResult { NotOutdated, Updated, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum InstallResult { + NotFound, + AlreadyInstalled, + Installed } \ No newline at end of file diff --git a/src/res/test/get_package_index.json b/src/res/test/get_package_index.json new file mode 100644 index 0000000..7512f40 --- /dev/null +++ b/src/res/test/get_package_index.json @@ -0,0 +1,27 @@ +{ + "lastUpdate": 1565437389, + "packages": [ + + { + "name": "basic-emojis", + "title": "Basic Emojis", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "A package to include some basic emojis in espanso.", + "author": "Federico Terzi" + + }, + + + { + "name": "italian-accents", + "title": "Italian Accents", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Include Italian accents substitutions to espanso.", + "author": "Federico Terzi" + + } + + +]} \ No newline at end of file diff --git a/src/res/test/install_package_index.json b/src/res/test/install_package_index.json new file mode 100644 index 0000000..7512f40 --- /dev/null +++ b/src/res/test/install_package_index.json @@ -0,0 +1,27 @@ +{ + "lastUpdate": 1565437389, + "packages": [ + + { + "name": "basic-emojis", + "title": "Basic Emojis", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "A package to include some basic emojis in espanso.", + "author": "Federico Terzi" + + }, + + + { + "name": "italian-accents", + "title": "Italian Accents", + "version": "0.1.0", + "repo": "https://github.com/federico-terzi/espanso-hub-core", + "desc": "Include Italian accents substitutions to espanso.", + "author": "Federico Terzi" + + } + + +]} \ No newline at end of file