feat(package): complete archiver implementation

This commit is contained in:
Federico Terzi 2021-09-03 23:13:37 +02:00
parent 2c955198ff
commit 64350de3a9
3 changed files with 153 additions and 15 deletions
espanso-package/src

View File

@ -20,9 +20,11 @@
use anyhow::{bail, Context, Result};
use std::path::{Path, PathBuf};
use crate::{ArchivedPackage, Archiver, Package, PackageSpecifier, SaveOptions};
use crate::{
manifest::Manifest, ArchivedPackage, Archiver, Package, PackageSpecifier, SaveOptions,
};
use super::StoredPackage;
use super::{LegacyPackage, PackageSource, StoredPackage, PACKAGE_SOURCE_FILE};
pub struct DefaultArchiver {
package_dir: PathBuf,
@ -92,16 +94,58 @@ impl Archiver for DefaultArchiver {
Ok(archived_package)
}
fn get(&self, name: &str) -> Result<ArchivedPackage> {
todo!()
fn get(&self, name: &str) -> Result<StoredPackage> {
let target_dir = self.package_dir.join(name);
if !target_dir.is_dir() {
bail!("package '{}' not found", name);
}
let manifest_path = target_dir.join("_manifest.yml");
if !manifest_path.is_file() {
return Ok(StoredPackage::Legacy(LegacyPackage {
name: name.to_string(),
}));
}
let manifest = Manifest::parse(&manifest_path).context("unable to parse package manifest")?;
let source_path = target_dir.join(PACKAGE_SOURCE_FILE);
let source =
PackageSource::parse(&source_path).context("unable to parse package source file")?;
Ok(StoredPackage::Modern(ArchivedPackage { manifest, source }))
}
fn list(&self) -> Result<Vec<StoredPackage>> {
todo!()
let mut output = Vec::new();
for path in std::fs::read_dir(&self.package_dir)? {
let path = path?.path();
if !path.is_dir() {
continue;
}
if let Some(package_name) = path.file_name() {
let package_name = package_name.to_string_lossy().to_string();
output.push(self.get(&package_name)?);
}
}
Ok(output)
}
fn delete(&self, name: &str) -> Result<()> {
todo!()
let target_dir = self.package_dir.join(name);
if !target_dir.is_dir() {
bail!("package {} not found", name);
}
std::fs::remove_dir_all(&target_dir).context("unable to remove package directory")?;
Ok(())
}
}
@ -232,4 +276,71 @@ matches:
assert!(result.is_ok());
});
}
#[test]
fn test_delete_package() {
run_with_two_temp_dirs(|package_dir, dest_dir| {
let package = create_fake_package(package_dir);
let archiver = DefaultArchiver::new(dest_dir);
let result = archiver.save(
&*package,
&PackageSpecifier {
name: "package1".to_string(),
git_repo_url: Some("https://github.com/espanso/dummy-package".to_string()),
git_branch: Some("main".to_string()),
..Default::default()
},
&SaveOptions::default(),
);
assert!(result.is_ok());
let package_out_dir = dest_dir.join("package1");
assert!(package_out_dir.is_dir());
archiver.delete("package1").unwrap();
assert!(!package_out_dir.is_dir());
});
}
#[test]
fn test_list_packages() {
run_with_two_temp_dirs(|package_dir, dest_dir| {
let package = create_fake_package(package_dir);
let archiver = DefaultArchiver::new(dest_dir);
let result = archiver.save(
&*package,
&PackageSpecifier {
name: "package1".to_string(),
git_repo_url: Some("https://github.com/espanso/dummy-package".to_string()),
git_branch: Some("main".to_string()),
..Default::default()
},
&SaveOptions::default(),
);
assert!(result.is_ok());
let package_out_dir = dest_dir.join("package1");
assert!(package_out_dir.is_dir());
let legacy_package = dest_dir.join("z_legacypackage1");
create_dir_all(&legacy_package).unwrap();
let package_list = archiver.list().unwrap();
assert!(package_list.iter().any(|package| *package
== StoredPackage::Modern(ArchivedPackage {
manifest: Manifest::parse(&package_out_dir.join("_manifest.yml")).unwrap(),
source: PackageSource::parse(&package_out_dir.join(PACKAGE_SOURCE_FILE)).unwrap(),
})));
assert!(package_list.iter().any(|package| *package
== StoredPackage::Legacy(LegacyPackage {
name: "z_legacypackage1".to_string()
})));
});
}
}

View File

@ -17,10 +17,12 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use std::path::Path;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use crate::{Package, PackageSpecifier, manifest::Manifest};
use crate::{manifest::Manifest, Package, PackageSpecifier};
pub mod default;
mod read;
@ -28,7 +30,7 @@ mod util;
pub const PACKAGE_SOURCE_FILE: &str = "_pkgsource.yml";
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct ArchivedPackage {
// Metadata
pub manifest: Manifest,
@ -37,20 +39,25 @@ pub struct ArchivedPackage {
pub source: PackageSource,
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct LegacyPackage {
pub name: String,
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum StoredPackage {
Legacy(LegacyPackage),
Modern(ArchivedPackage),
}
pub trait Archiver {
fn get(&self, name: &str) -> Result<ArchivedPackage>;
fn save(&self, package: &dyn Package, specifier: &PackageSpecifier, save_options: &SaveOptions) -> Result<ArchivedPackage>;
fn get(&self, name: &str) -> Result<StoredPackage>;
fn save(
&self,
package: &dyn Package,
specifier: &PackageSpecifier,
save_options: &SaveOptions,
) -> Result<ArchivedPackage>;
fn list(&self) -> Result<Vec<StoredPackage>>;
fn delete(&self, name: &str) -> Result<()>;
}
@ -60,7 +67,7 @@ pub struct SaveOptions {
pub overwrite_existing: bool,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum PackageSource {
Hub,
@ -71,6 +78,26 @@ pub enum PackageSource {
},
}
impl PackageSource {
pub fn parse(source_path: &Path) -> Result<Self> {
let source_str = std::fs::read_to_string(source_path)?;
Ok(serde_yaml::from_str(&source_str)?)
}
}
impl std::fmt::Display for PackageSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PackageSource::Hub => write!(f, "espanso-hub"),
PackageSource::Git {
repo_url,
repo_branch: _,
use_native_git: _,
} => write!(f, "git: {}", repo_url),
}
}
}
impl From<&PackageSpecifier> for PackageSource {
fn from(package: &PackageSpecifier) -> Self {
if let Some(git_repo_url) = package.git_repo_url.as_deref() {

View File

@ -28,7 +28,7 @@ mod provider;
mod resolver;
mod util;
pub use archive::{ArchivedPackage, Archiver, SaveOptions};
pub use archive::{ArchivedPackage, Archiver, SaveOptions, StoredPackage};
pub use provider::{PackageSpecifier, PackageProvider};
pub use package::Package;
@ -74,7 +74,7 @@ pub fn get_provider(package: &PackageSpecifier) -> Result<Box<dyn PackageProvide
Ok(Box::new(provider::git::GitPackageProvider::new()))
} else {
// TODO: use espanso-hub method
todo!();
bail!("espanso hub method not yet implemented")
}
}