imag/libimagstore/src/storeid.rs

219 lines
5.4 KiB
Rust
Raw Normal View History

use std::path::PathBuf;
use semver::Version;
2016-06-30 09:02:58 +00:00
use std::fmt::{Display, Debug, Formatter};
2016-04-18 16:40:59 +00:00
use std::fmt::Error as FmtError;
use std::result::Result as RResult;
2016-08-24 13:55:26 +00:00
use libimagerror::into::IntoError;
use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;
/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
2016-08-07 14:45:41 +00:00
pub struct StoreId {
2016-08-07 14:53:33 +00:00
base: Option<PathBuf>,
id: PathBuf,
2016-08-07 14:45:41 +00:00
}
impl StoreId {
pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
if id.is_absolute() {
Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
} else {
Ok(StoreId {
base: base,
id: id
})
}
2016-08-07 14:54:36 +00:00
}
pub fn storified(self, store: &Store) -> StoreId {
2016-08-22 10:03:31 +00:00
StoreId {
base: Some(store.path().clone()),
id: self.id
}
}
pub fn exists(&self) -> bool {
let pb : PathBuf = self.clone().into();
pb.exists()
}
pub fn is_file(&self) -> bool {
true
}
pub fn is_dir(&self) -> bool {
false
}
2016-08-24 13:55:26 +00:00
pub fn to_str(&self) -> Result<String> {
if self.base.is_some() {
let mut base = self.base.as_ref().cloned().unwrap();
base.push(self.id.clone());
base
} else {
self.id.clone()
}
.to_str()
.map(String::from)
.ok_or(SEK::StoreIdHandlingError.into_error())
}
}
impl Into<PathBuf> for StoreId {
fn into(self) -> PathBuf {
2016-08-07 14:53:33 +00:00
let mut base = self.base.unwrap_or(PathBuf::from("/"));
2016-08-07 14:46:21 +00:00
base.push(self.id);
base
}
}
2016-06-30 09:02:58 +00:00
impl Display for StoreId {
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
2016-08-07 14:46:31 +00:00
match self.id.to_str() {
2016-06-30 09:02:58 +00:00
Some(s) => write!(fmt, "{}", s),
2016-08-07 14:46:31 +00:00
None => write!(fmt, "{}", self.id.to_string_lossy()),
2016-06-30 09:02:58 +00:00
}
}
}
/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
2016-01-29 16:00:29 +00:00
pub trait IntoStoreId {
fn into_storeid(self) -> StoreId;
}
2016-05-03 13:45:06 +00:00
impl IntoStoreId for StoreId {
fn into_storeid(self) -> StoreId {
self
}
}
pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
debug!("Checking path element for version");
if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
debug!("Version cannot be parsed from {:?}", path_elem);
debug!("Path does not contain version!");
return Err(SEK::StorePathLacksVersion.into());
}
debug!("Version checking succeeded");
debug!("Building path from {:?}", path_elem);
let mut path = store.path().clone();
if path_elem.starts_with('/') {
path.push(&path_elem[1..]);
} else {
path.push(path_elem);
}
Ok(path)
}
#[macro_export]
macro_rules! module_entry_path_mod {
($name:expr, $version:expr) => (
#[deny(missing_docs,
missing_copy_implementations,
trivial_casts, trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces, unused_qualifications,
unused_imports)]
/// A helper module to create valid module entry paths
pub mod module_path {
use semver::Version;
use std::convert::AsRef;
use std::path::Path;
use std::path::PathBuf;
2016-05-03 12:53:14 +00:00
use $crate::storeid::StoreId;
/// A Struct giving you the ability to choose store entries assigned
/// to it.
///
/// It is created through a call to `new`.
pub struct ModuleEntryPath(PathBuf);
impl ModuleEntryPath {
/// Path has to be a valid UTF-8 string or this will panic!
pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
let mut path = PathBuf::new();
path.push(format!("{}", $name));
path.push(pa.as_ref().clone());
let version = Version::parse($version).unwrap();
let name = pa.as_ref().file_name().unwrap()
.to_str().unwrap();
path.set_file_name(format!("{}~{}",
name,
version));
ModuleEntryPath(path)
}
}
impl $crate::storeid::IntoStoreId for ModuleEntryPath {
2016-03-21 18:40:19 +00:00
fn into_storeid(self) -> $crate::storeid::StoreId {
2016-08-07 14:54:48 +00:00
StoreId::new(None, self.0)
}
}
}
)
}
pub struct StoreIdIterator {
iter: Box<Iterator<Item = StoreId>>,
}
2016-04-18 16:40:59 +00:00
impl Debug for StoreIdIterator {
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
write!(fmt, "StoreIdIterator")
}
}
2016-01-24 11:17:25 +00:00
impl StoreIdIterator {
pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
2016-01-24 11:17:25 +00:00
StoreIdIterator {
iter: iter,
2016-01-24 11:17:25 +00:00
}
}
}
impl Iterator for StoreIdIterator {
type Item = StoreId;
fn next(&mut self) -> Option<StoreId> {
self.iter.next()
2016-01-24 11:17:25 +00:00
}
}
#[cfg(test)]
mod test {
use storeid::IntoStoreId;
module_entry_path_mod!("test", "0.2.0-alpha+leet1337");
#[test]
fn correct_path() {
let p = module_path::ModuleEntryPath::new("test");
assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
}
}