bakare/src/index.rs
2020-11-07 10:21:07 +00:00

153 lines
4.7 KiB
Rust

use std::collections::hash_map::Iter;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;
use serde::{Deserialize, Serialize};
use crate::error::BakareError;
use crate::repository::{ItemId, Version};
use crate::repository_item::RepositoryItem;
#[derive(Clone, Debug, PartialOrd, PartialEq, Ord, Eq, Serialize, Deserialize)]
pub struct IndexItem {
relative_path: String,
original_source_path: String,
id: ItemId,
version: Version,
}
#[derive(Serialize, Deserialize)]
pub struct Index {
newest_items_by_source_path: HashMap<String, IndexItem>,
items_by_file_id: HashMap<ItemId, IndexItem>,
index_path: String,
repository_path: String,
}
pub struct IndexItemIterator<'a> {
iterator: Iter<'a, String, IndexItem>,
}
impl<'a> Iterator for IndexItemIterator<'a> {
type Item = IndexItem;
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next().map(|i| i.1.clone())
}
}
impl IndexItem {
fn from(original_source_path: String, relative_path: String, id: ItemId, version: Version) -> IndexItem {
IndexItem {
relative_path,
original_source_path,
id,
version,
}
}
fn next_version(&self, id: ItemId, relative_path: String) -> IndexItem {
IndexItem {
original_source_path: self.original_source_path.clone(),
version: self.version.next(),
relative_path,
id,
}
}
}
impl Index {
pub fn new(repository_path: &Path) -> Self {
Index {
newest_items_by_source_path: Default::default(),
items_by_file_id: Default::default(),
index_path: repository_path.join("index").to_string_lossy().to_string(),
repository_path: repository_path.to_string_lossy().to_string(),
}
}
pub fn load(path: &Path) -> Result<Self, BakareError> {
let index_file_path = path.join("index");
let index_file = File::open(index_file_path)?;
let index: Index = serde_cbor::from_reader(index_file)?;
Ok(index)
}
pub fn save(&self) -> Result<(), BakareError> {
let index_file = File::create(self.index_file_path())?;
serde_cbor::to_writer(index_file, &self)?;
Ok(())
}
pub fn index_file_path(&self) -> &Path {
Path::new(&self.index_path)
}
pub fn remember(&mut self, original_source_path: &Path, relative_path: &Path, id: ItemId) {
let item = if let Some(old) = self
.newest_items_by_source_path
.get(&original_source_path.to_string_lossy().to_string())
{
old.next_version(id, relative_path.to_string_lossy().to_string())
} else {
IndexItem::from(
original_source_path.to_string_lossy().to_string(),
relative_path.to_string_lossy().to_string(),
id,
Version::default(),
)
};
self.items_by_file_id.insert(item.id.clone(), item.clone());
self.newest_items_by_source_path
.insert(original_source_path.to_string_lossy().to_string(), item);
}
pub fn repository_item(&self, i: &IndexItem) -> RepositoryItem {
let index_item = i.clone();
let relative_path = Path::new(&index_item.relative_path);
let repository_path = Path::new(&self.repository_path);
let original_source_path = Path::new(&index_item.original_source_path);
let absolute_path = repository_path.join(relative_path);
let absolute_path = absolute_path.as_path();
RepositoryItem::from(
original_source_path,
absolute_path,
relative_path,
index_item.id,
index_item.version,
)
}
pub fn newest_item_by_source_path(&self, path: &Path) -> Result<Option<IndexItem>, BakareError> {
if !path.is_absolute() {
return Err(BakareError::RepositoryPathNotAbsolute);
}
Ok(self
.newest_items_by_source_path
.get(&path.to_string_lossy().to_string())
.cloned())
}
pub fn item_by_id(&self, id: &ItemId) -> Result<Option<IndexItem>, BakareError> {
Ok(self.items_by_file_id.get(id).cloned())
}
pub fn newest_items(&self) -> IndexItemIterator {
IndexItemIterator {
iterator: self.newest_items_by_source_path.iter(),
}
}
}
impl From<RepositoryItem> for IndexItem {
fn from(i: RepositoryItem) -> Self {
IndexItem {
relative_path: i.relative_path().to_string_lossy().to_string(),
original_source_path: i.original_source_path().to_string_lossy().to_string(),
id: i.id().clone(),
version: i.version().clone(),
}
}
}