Merge pull request #900 from matthiasbeyer/libimagstore/doc
Libimagstore/doc
This commit is contained in:
commit
b67b6f5343
1 changed files with 247 additions and 26 deletions
|
@ -190,14 +190,14 @@ impl StoreEntry {
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
location: PathBuf,
|
location: PathBuf,
|
||||||
|
|
||||||
/**
|
///
|
||||||
* Configuration object of the store
|
/// Configuration object of the store
|
||||||
*/
|
///
|
||||||
configuration: Option<Value>,
|
configuration: Option<Value>,
|
||||||
|
|
||||||
/*
|
//
|
||||||
* Registered hooks
|
// Registered hooks
|
||||||
*/
|
//
|
||||||
|
|
||||||
store_unload_aspects : Arc<Mutex<Vec<Aspect>>>,
|
store_unload_aspects : Arc<Mutex<Vec<Aspect>>>,
|
||||||
|
|
||||||
|
@ -212,19 +212,42 @@ pub struct Store {
|
||||||
pre_move_aspects : Arc<Mutex<Vec<Aspect>>>,
|
pre_move_aspects : Arc<Mutex<Vec<Aspect>>>,
|
||||||
post_move_aspects : Arc<Mutex<Vec<Aspect>>>,
|
post_move_aspects : Arc<Mutex<Vec<Aspect>>>,
|
||||||
|
|
||||||
/**
|
///
|
||||||
* Internal Path->File cache map
|
/// Internal Path->File cache map
|
||||||
*
|
///
|
||||||
* Caches the files, so they remain flock()ed
|
/// Caches the files, so they remain flock()ed
|
||||||
*
|
///
|
||||||
* Could be optimized for a threadsafe HashMap
|
/// Could be optimized for a threadsafe HashMap
|
||||||
*/
|
///
|
||||||
entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
|
entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl Store {
|
||||||
|
|
||||||
/// Create a new Store object
|
/// Create a new Store object
|
||||||
|
///
|
||||||
|
/// This opens a Store in `location` using the configuration from `store_config` (if absent, it
|
||||||
|
/// uses defaults).
|
||||||
|
///
|
||||||
|
/// If the configuration is not valid, this fails.
|
||||||
|
///
|
||||||
|
/// If the location does not exist, creating directories is by default denied and the operation
|
||||||
|
/// fails, if not configured otherwise.
|
||||||
|
/// An error is returned in this case.
|
||||||
|
///
|
||||||
|
/// If the path exists and is a file, the operation is aborted as well, an error is returned.
|
||||||
|
///
|
||||||
|
/// After that, the store hook aspects are created and registered in the store.
|
||||||
|
///
|
||||||
|
/// # Return values
|
||||||
|
///
|
||||||
|
/// - On success: Store object
|
||||||
|
/// - On Failure:
|
||||||
|
/// - ConfigurationError if config is faulty
|
||||||
|
/// - IoError(FileError(CreateStoreDirDenied())) if store location does not exist and creating
|
||||||
|
/// is denied
|
||||||
|
/// - StorePathCreate(_) if creating the store directory failed
|
||||||
|
/// - StorePathExists() if location exists but is a file
|
||||||
pub fn new(location: PathBuf, store_config: Option<Value>) -> Result<Store> {
|
pub fn new(location: PathBuf, store_config: Option<Value>) -> Result<Store> {
|
||||||
use configuration::*;
|
use configuration::*;
|
||||||
|
|
||||||
|
@ -399,6 +422,25 @@ impl Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the Entry at the given location (inside the entry)
|
/// Creates the Entry at the given location (inside the entry)
|
||||||
|
///
|
||||||
|
/// # Executed Hooks
|
||||||
|
///
|
||||||
|
/// - Pre create aspects
|
||||||
|
/// - post create aspects
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success: FileLockEntry
|
||||||
|
///
|
||||||
|
/// On error:
|
||||||
|
/// - Errors StoreId::into_storeid() might return
|
||||||
|
/// - CreateCallError(HookExecutionError(PreHookExecuteError(_)))
|
||||||
|
/// of the first failing pre hook.
|
||||||
|
/// - CreateCallError(HookExecutionError(PostHookExecuteError(_)))
|
||||||
|
/// of the first failing post hook.
|
||||||
|
/// - CreateCallError(LockPoisoned()) if the internal lock is poisened.
|
||||||
|
/// - CreateCallError(EntryAlreadyExists()) if the entry exists already.
|
||||||
|
///
|
||||||
pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
|
pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
|
||||||
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
||||||
if let Err(e) = self.execute_hooks_for_id(self.pre_create_aspects.clone(), &id) {
|
if let Err(e) = self.execute_hooks_for_id(self.pre_create_aspects.clone(), &id) {
|
||||||
|
@ -437,6 +479,24 @@ impl Store {
|
||||||
///
|
///
|
||||||
/// Implicitely creates a entry in the store if there is no entry with the id `id`. For a
|
/// Implicitely creates a entry in the store if there is no entry with the id `id`. For a
|
||||||
/// non-implicitely-create look at `Store::get`.
|
/// non-implicitely-create look at `Store::get`.
|
||||||
|
///
|
||||||
|
/// # Executed Hooks
|
||||||
|
///
|
||||||
|
/// - Pre retrieve aspects
|
||||||
|
/// - post retrieve aspects
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success: FileLockEntry
|
||||||
|
///
|
||||||
|
/// On error:
|
||||||
|
/// - Errors StoreId::into_storeid() might return
|
||||||
|
/// - RetrieveCallError(HookExecutionError(PreHookExecuteError(_)))
|
||||||
|
/// of the first failing pre hook.
|
||||||
|
/// - RetrieveCallError(HookExecutionError(PostHookExecuteError(_)))
|
||||||
|
/// of the first failing post hook.
|
||||||
|
/// - RetrieveCallError(LockPoisoned()) if the internal lock is poisened.
|
||||||
|
///
|
||||||
pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
|
pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
|
||||||
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
||||||
if let Err(e) = self.execute_hooks_for_id(self.pre_retrieve_aspects.clone(), &id) {
|
if let Err(e) = self.execute_hooks_for_id(self.pre_retrieve_aspects.clone(), &id) {
|
||||||
|
@ -470,7 +530,19 @@ impl Store {
|
||||||
|
|
||||||
/// Get an entry from the store if it exists.
|
/// Get an entry from the store if it exists.
|
||||||
///
|
///
|
||||||
/// This executes the {pre,post}_retrieve_aspects hooks.
|
/// # Executed Hooks
|
||||||
|
///
|
||||||
|
/// - Pre get aspects
|
||||||
|
/// - post get aspects
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success: Some(FileLockEntry) or None
|
||||||
|
///
|
||||||
|
/// On error:
|
||||||
|
/// - Errors StoreId::into_storeid() might return
|
||||||
|
/// - Errors Store::retrieve() might return
|
||||||
|
///
|
||||||
pub fn get<'a, S: IntoStoreId + Clone>(&'a self, id: S) -> Result<Option<FileLockEntry<'a>>> {
|
pub fn get<'a, S: IntoStoreId + Clone>(&'a self, id: S) -> Result<Option<FileLockEntry<'a>>> {
|
||||||
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
||||||
|
|
||||||
|
@ -490,6 +562,16 @@ impl Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all StoreIds for one module name
|
/// Iterate over all StoreIds for one module name
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// On success: An iterator over all entries in the module
|
||||||
|
///
|
||||||
|
/// On failure:
|
||||||
|
/// - RetrieveForModuleCallError(GlobError(EncodingError())) if the path string cannot be
|
||||||
|
/// encoded
|
||||||
|
/// - GRetrieveForModuleCallError(GlobError(lobError())) if the glob() failed.
|
||||||
|
///
|
||||||
pub fn retrieve_for_module(&self, mod_name: &str) -> Result<StoreIdIterator> {
|
pub fn retrieve_for_module(&self, mod_name: &str) -> Result<StoreIdIterator> {
|
||||||
let mut path = self.path().clone();
|
let mut path = self.path().clone();
|
||||||
path.push(mod_name);
|
path.push(mod_name);
|
||||||
|
@ -506,12 +588,18 @@ impl Store {
|
||||||
.map_err_into(SEK::RetrieveForModuleCallError)
|
.map_err_into(SEK::RetrieveForModuleCallError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the store tree for the module
|
/// Walk the store tree for the module
|
||||||
|
///
|
||||||
|
/// The difference between a `Walk` and a `StoreIdIterator` is that with a `Walk`, one can find
|
||||||
|
/// "collections" (folders).
|
||||||
pub fn walk<'a>(&'a self, mod_name: &str) -> Walk {
|
pub fn walk<'a>(&'a self, mod_name: &str) -> Walk {
|
||||||
Walk::new(self.path().clone(), mod_name)
|
Walk::new(self.path().clone(), mod_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the `FileLockEntry` and write to disk
|
/// Return the `FileLockEntry` and write to disk
|
||||||
|
///
|
||||||
|
/// See `Store::_update()`.
|
||||||
|
///
|
||||||
pub fn update<'a>(&'a self, mut entry: FileLockEntry<'a>) -> Result<()> {
|
pub fn update<'a>(&'a self, mut entry: FileLockEntry<'a>) -> Result<()> {
|
||||||
self._update(&mut entry, false).map_err_into(SEK::UpdateCallError)
|
self._update(&mut entry, false).map_err_into(SEK::UpdateCallError)
|
||||||
}
|
}
|
||||||
|
@ -519,8 +607,29 @@ impl Store {
|
||||||
/// Internal method to write to the filesystem store.
|
/// Internal method to write to the filesystem store.
|
||||||
///
|
///
|
||||||
/// # Assumptions
|
/// # Assumptions
|
||||||
|
///
|
||||||
/// This method assumes that entry is dropped _right after_ the call, hence
|
/// This method assumes that entry is dropped _right after_ the call, hence
|
||||||
/// it is not public.
|
/// it is not public.
|
||||||
|
///
|
||||||
|
/// # Executed Hooks
|
||||||
|
///
|
||||||
|
/// - Pre update aspects
|
||||||
|
/// - post update aspects
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success: Entry
|
||||||
|
///
|
||||||
|
/// On error:
|
||||||
|
/// - UpdateCallError(HookExecutionError(PreHookExecuteError(_)))
|
||||||
|
/// of the first failing pre hook.
|
||||||
|
/// - UpdateCallError(HookExecutionError(PostHookExecuteError(_)))
|
||||||
|
/// of the first failing post hook.
|
||||||
|
/// - UpdateCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
|
||||||
|
/// - IdNotFound() if the entry was not found in the stor
|
||||||
|
/// - Errors Entry::verify() might return
|
||||||
|
/// - Errors StoreEntry::write_entry() might return
|
||||||
|
///
|
||||||
fn _update<'a>(&'a self, mut entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
|
fn _update<'a>(&'a self, mut entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
|
||||||
let _ = try!(self.execute_hooks_for_mut_file(self.pre_update_aspects.clone(), &mut entry)
|
let _ = try!(self.execute_hooks_for_mut_file(self.pre_update_aspects.clone(), &mut entry)
|
||||||
.map_err_into(SEK::PreHookExecuteError)
|
.map_err_into(SEK::PreHookExecuteError)
|
||||||
|
@ -546,7 +655,6 @@ impl Store {
|
||||||
se.status = StoreEntryStatus::Present;
|
se.status = StoreEntryStatus::Present;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self.execute_hooks_for_mut_file(self.post_update_aspects.clone(), &mut entry)
|
self.execute_hooks_for_mut_file(self.post_update_aspects.clone(), &mut entry)
|
||||||
.map_err_into(SEK::PostHookExecuteError)
|
.map_err_into(SEK::PostHookExecuteError)
|
||||||
.map_err_into(SEK::HookExecutionError)
|
.map_err_into(SEK::HookExecutionError)
|
||||||
|
@ -555,6 +663,22 @@ impl Store {
|
||||||
|
|
||||||
/// Retrieve a copy of a given entry, this cannot be used to mutate
|
/// Retrieve a copy of a given entry, this cannot be used to mutate
|
||||||
/// the one on disk
|
/// the one on disk
|
||||||
|
///
|
||||||
|
/// TODO: Create Hooks for retrieving a copy
|
||||||
|
///
|
||||||
|
/// # Executed Hooks
|
||||||
|
///
|
||||||
|
/// - (none yet)
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success: Entry
|
||||||
|
///
|
||||||
|
/// On error:
|
||||||
|
/// - RetrieveCopyCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
|
||||||
|
/// - RetrieveCopyCallError(IdLocked()) if the Entry is borrowed currently
|
||||||
|
/// - Errors StoreEntry::new() might return
|
||||||
|
///
|
||||||
pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
|
pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
|
||||||
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
||||||
let entries = match self.entries.write() {
|
let entries = match self.entries.write() {
|
||||||
|
@ -574,6 +698,25 @@ impl Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete an entry
|
/// Delete an entry
|
||||||
|
///
|
||||||
|
/// # Executed Hooks
|
||||||
|
///
|
||||||
|
/// - Pre delete aspects, if the id can be used
|
||||||
|
/// - Post delete aspects, if the operation succeeded
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success: ()
|
||||||
|
///
|
||||||
|
/// On error:
|
||||||
|
/// - DeleteCallError(HookExecutionError(PreHookExecuteError(_)))
|
||||||
|
/// of the first failing pre hook.
|
||||||
|
/// - DeleteCallError(HookExecutionError(PostHookExecuteError(_)))
|
||||||
|
/// of the first failing post hook.
|
||||||
|
/// - DeleteCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
|
||||||
|
/// - DeleteCallError(FileNotFound()) if the StoreId refers to a non-existing entry.
|
||||||
|
/// - DeleteCallError(FileError()) if the internals failed to remove the file.
|
||||||
|
///
|
||||||
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
|
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
|
||||||
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
let id = try!(id.into_storeid()).with_base(self.path().clone());
|
||||||
if let Err(e) = self.execute_hooks_for_id(self.pre_delete_aspects.clone(), &id) {
|
if let Err(e) = self.execute_hooks_for_id(self.pre_delete_aspects.clone(), &id) {
|
||||||
|
@ -617,6 +760,8 @@ impl Store {
|
||||||
|
|
||||||
/// Save a copy of the Entry in another place
|
/// Save a copy of the Entry in another place
|
||||||
/// Executes the post_move_aspects for the new id
|
/// Executes the post_move_aspects for the new id
|
||||||
|
///
|
||||||
|
/// TODO: Introduce new aspect for `save_to()`.
|
||||||
pub fn save_to(&self, entry: &FileLockEntry, new_id: StoreId) -> Result<()> {
|
pub fn save_to(&self, entry: &FileLockEntry, new_id: StoreId) -> Result<()> {
|
||||||
self.save_to_other_location(entry, new_id, false)
|
self.save_to_other_location(entry, new_id, false)
|
||||||
}
|
}
|
||||||
|
@ -624,6 +769,8 @@ impl Store {
|
||||||
/// Save an Entry in another place
|
/// Save an Entry in another place
|
||||||
/// Removes the original entry
|
/// Removes the original entry
|
||||||
/// Executes the post_move_aspects for the new id
|
/// Executes the post_move_aspects for the new id
|
||||||
|
///
|
||||||
|
/// TODO: Introduce new aspect for `save_as()`.
|
||||||
pub fn save_as(&self, entry: FileLockEntry, new_id: StoreId) -> Result<()> {
|
pub fn save_as(&self, entry: FileLockEntry, new_id: StoreId) -> Result<()> {
|
||||||
self.save_to_other_location(&entry, new_id, true)
|
self.save_to_other_location(&entry, new_id, true)
|
||||||
}
|
}
|
||||||
|
@ -758,6 +905,21 @@ impl Store {
|
||||||
&self.location
|
&self.location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a hook in the store.
|
||||||
|
///
|
||||||
|
/// A hook is registered by a position (when should the hook be executed) and an aspect name.
|
||||||
|
/// The aspect name must be in the configuration file, so the configuration for the hook can be
|
||||||
|
/// passed to the `Hook` object.
|
||||||
|
///
|
||||||
|
/// # Available Hook positions
|
||||||
|
///
|
||||||
|
/// The hook positions are described in the type description of `HookPosition`.
|
||||||
|
///
|
||||||
|
/// # Aspect names
|
||||||
|
///
|
||||||
|
/// Aspect names are arbitrary, though sane things like "debug" or "vcs" are encouraged.
|
||||||
|
/// Refer to the documentation for more information.
|
||||||
|
///
|
||||||
pub fn register_hook(&mut self,
|
pub fn register_hook(&mut self,
|
||||||
position: HookPosition,
|
position: HookPosition,
|
||||||
aspect_name: &str,
|
aspect_name: &str,
|
||||||
|
@ -800,6 +962,7 @@ impl Store {
|
||||||
Err(SEK::HookRegisterError.into_error_with_cause(Box::new(annfe)))
|
Err(SEK::HookRegisterError.into_error_with_cause(Box::new(annfe)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the configuration for a hook by the name of the hook, from the configuration file.
|
||||||
fn get_config_for_hook(&self, name: &str) -> Option<&Value> {
|
fn get_config_for_hook(&self, name: &str) -> Option<&Value> {
|
||||||
match self.configuration {
|
match self.configuration {
|
||||||
Some(Value::Table(ref tabl)) => {
|
Some(Value::Table(ref tabl)) => {
|
||||||
|
@ -819,6 +982,13 @@ impl Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute all hooks from all aspects for a Store Id object.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// - () on success
|
||||||
|
/// - Error on the first failing hook.
|
||||||
|
///
|
||||||
fn execute_hooks_for_id(&self,
|
fn execute_hooks_for_id(&self,
|
||||||
aspects: Arc<Mutex<Vec<Aspect>>>,
|
aspects: Arc<Mutex<Vec<Aspect>>>,
|
||||||
id: &StoreId)
|
id: &StoreId)
|
||||||
|
@ -834,6 +1004,13 @@ impl Store {
|
||||||
.map_err(|e| HookErrorKind::HookExecutionError.into_error_with_cause(e))
|
.map_err(|e| HookErrorKind::HookExecutionError.into_error_with_cause(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute all hooks from all aspects for a mutable `FileLockEntry` object.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// - () on success
|
||||||
|
/// - Error on the first failing hook.
|
||||||
|
///
|
||||||
fn execute_hooks_for_mut_file(&self,
|
fn execute_hooks_for_mut_file(&self,
|
||||||
aspects: Arc<Mutex<Vec<Aspect>>>,
|
aspects: Arc<Mutex<Vec<Aspect>>>,
|
||||||
fle: &mut FileLockEntry)
|
fle: &mut FileLockEntry)
|
||||||
|
@ -853,6 +1030,7 @@ impl Store {
|
||||||
|
|
||||||
impl Debug for Store {
|
impl Debug for Store {
|
||||||
|
|
||||||
|
/// TODO: Make pretty.
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FMTError> {
|
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FMTError> {
|
||||||
try!(write!(fmt, " --- Store ---\n"));
|
try!(write!(fmt, " --- Store ---\n"));
|
||||||
try!(write!(fmt, "\n"));
|
try!(write!(fmt, "\n"));
|
||||||
|
@ -877,11 +1055,12 @@ impl Debug for Store {
|
||||||
|
|
||||||
impl Drop for Store {
|
impl Drop for Store {
|
||||||
|
|
||||||
/**
|
///
|
||||||
* Unlock all files on drop
|
/// Unlock all files on drop
|
||||||
*
|
//
|
||||||
* TODO: Unlock them
|
/// TODO: Unlock them
|
||||||
*/
|
/// TODO: Resolve this dirty hack with the StoreId for the Store drop hooks.
|
||||||
|
///
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match StoreId::new(Some(self.location.clone()), PathBuf::from(".")) {
|
match StoreId::new(Some(self.location.clone()), PathBuf::from(".")) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -909,6 +1088,10 @@ pub struct FileLockEntry<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FileLockEntry<'a, > {
|
impl<'a> FileLockEntry<'a, > {
|
||||||
|
|
||||||
|
/// Create a new FileLockEntry based on a `Entry` object.
|
||||||
|
///
|
||||||
|
/// Only for internal use.
|
||||||
fn new(store: &'a Store, entry: Entry) -> FileLockEntry<'a> {
|
fn new(store: &'a Store, entry: Entry) -> FileLockEntry<'a> {
|
||||||
FileLockEntry {
|
FileLockEntry {
|
||||||
store: store,
|
store: store,
|
||||||
|
@ -940,7 +1123,11 @@ impl<'a> DerefMut for FileLockEntry<'a> {
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<'a> Drop for FileLockEntry<'a> {
|
impl<'a> Drop for FileLockEntry<'a> {
|
||||||
|
|
||||||
/// This will silently ignore errors, use `Store::update` if you want to catch the errors
|
/// This will silently ignore errors, use `Store::update` if you want to catch the errors
|
||||||
|
///
|
||||||
|
/// This might panic if the store was compiled with the early-panic feature (which is not
|
||||||
|
/// intended for production use, though).
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
use libimagerror::trace::trace_error_dbg;
|
use libimagerror::trace::trace_error_dbg;
|
||||||
|
|
||||||
|
@ -956,21 +1143,21 @@ impl<'a> Drop for FileLockEntry<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl<'a> Drop for FileLockEntry<'a> {
|
impl<'a> Drop for FileLockEntry<'a> {
|
||||||
|
|
||||||
/// This will not silently ignore errors but prints the result of the _update() call for testing
|
/// This will not silently ignore errors but prints the result of the _update() call for testing
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.store._update(self, true).map_err(|e| trace_error(&e));
|
let _ = self.store._update(self, true).map_err(|e| trace_error(&e));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// `EntryContent` type
|
/// `EntryContent` type
|
||||||
pub type EntryContent = String;
|
pub type EntryContent = String;
|
||||||
|
|
||||||
/**
|
/// An Entry of the store
|
||||||
* An Entry of the store
|
//
|
||||||
*
|
/// Contains location, header and content part.
|
||||||
* Contains location, header and content part.
|
|
||||||
*/
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
location: StoreId,
|
location: StoreId,
|
||||||
|
@ -980,6 +1167,10 @@ pub struct Entry {
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
|
|
||||||
|
/// Create a new store entry with its location at `loc`.
|
||||||
|
///
|
||||||
|
/// This creates the entry with the default header from `Entry::default_header()` and an empty
|
||||||
|
/// content.
|
||||||
pub fn new(loc: StoreId) -> Entry {
|
pub fn new(loc: StoreId) -> Entry {
|
||||||
Entry {
|
Entry {
|
||||||
location: loc,
|
location: loc,
|
||||||
|
@ -988,10 +1179,16 @@ impl Entry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the default Header for an Entry.
|
||||||
|
///
|
||||||
|
/// This function should be used to get a new Header, as the default header may change. Via
|
||||||
|
/// this function, compatibility is ensured.
|
||||||
pub fn default_header() -> Value { // BTreeMap<String, Value>
|
pub fn default_header() -> Value { // BTreeMap<String, Value>
|
||||||
Value::default_header()
|
Value::default_header()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See `Entry::from_str()`, as this function is used internally. This is just a wrapper for
|
||||||
|
/// convenience.
|
||||||
pub fn from_reader<S: IntoStoreId>(loc: S, file: &mut Read) -> Result<Entry> {
|
pub fn from_reader<S: IntoStoreId>(loc: S, file: &mut Read) -> Result<Entry> {
|
||||||
let text = {
|
let text = {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
@ -1001,6 +1198,18 @@ impl Entry {
|
||||||
Self::from_str(loc, &text[..])
|
Self::from_str(loc, &text[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new Entry, with contents from the string passed.
|
||||||
|
///
|
||||||
|
/// The passed string _must_ be a complete valid store entry, including header. So this is
|
||||||
|
/// probably not what end-users want to call.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// This errors if
|
||||||
|
///
|
||||||
|
/// - String cannot be matched on regex to find header and content
|
||||||
|
/// - Header cannot be parsed into a TOML object
|
||||||
|
///
|
||||||
pub fn from_str<S: IntoStoreId>(loc: S, s: &str) -> Result<Entry> {
|
pub fn from_str<S: IntoStoreId>(loc: S, s: &str) -> Result<Entry> {
|
||||||
debug!("Building entry from string");
|
debug!("Building entry from string");
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -1032,32 +1241,44 @@ impl Entry {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the string representation of this entry
|
||||||
|
///
|
||||||
|
/// This means not only the content of the entry, but the complete entry (from memory, not from
|
||||||
|
/// disk).
|
||||||
pub fn to_str(&self) -> String {
|
pub fn to_str(&self) -> String {
|
||||||
format!("---\n{header}---\n{content}",
|
format!("---\n{header}---\n{content}",
|
||||||
header = ::toml::encode_str(&self.header),
|
header = ::toml::encode_str(&self.header),
|
||||||
content = self.content)
|
content = self.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the location of the Entry
|
||||||
pub fn get_location(&self) -> &StoreId {
|
pub fn get_location(&self) -> &StoreId {
|
||||||
&self.location
|
&self.location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the header of the Entry
|
||||||
pub fn get_header(&self) -> &Value {
|
pub fn get_header(&self) -> &Value {
|
||||||
&self.header
|
&self.header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the header mutably of the Entry
|
||||||
pub fn get_header_mut(&mut self) -> &mut Value {
|
pub fn get_header_mut(&mut self) -> &mut Value {
|
||||||
&mut self.header
|
&mut self.header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the content of the Entry
|
||||||
pub fn get_content(&self) -> &EntryContent {
|
pub fn get_content(&self) -> &EntryContent {
|
||||||
&self.content
|
&self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the content mutably of the Entry
|
||||||
pub fn get_content_mut(&mut self) -> &mut EntryContent {
|
pub fn get_content_mut(&mut self) -> &mut EntryContent {
|
||||||
&mut self.content
|
&mut self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify the entry.
|
||||||
|
///
|
||||||
|
/// Currently, this only verifies the header. This might change in the future.
|
||||||
pub fn verify(&self) -> Result<()> {
|
pub fn verify(&self) -> Result<()> {
|
||||||
self.header.verify()
|
self.header.verify()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue