Merge pull request #667 from matthiasbeyer/rewrite-storeid-type

Rewrite storeid type
This commit is contained in:
Matthias Beyer 2016-09-05 16:10:47 +02:00 committed by GitHub
commit 737aab80dc
48 changed files with 482 additions and 470 deletions

View file

@ -1,4 +1,3 @@
use std::path::PathBuf;
use std::process::exit; use std::process::exit;
use libimagdiary::diary::Diary; use libimagdiary::diary::Diary;
@ -8,7 +7,6 @@ use libimagentrylist::listers::core::CoreLister;
use libimagentrylist::lister::Lister; use libimagentrylist::lister::Lister;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use util::get_diary_name; use util::get_diary_name;
@ -21,11 +19,11 @@ pub fn list(rt: &Runtime) {
} }
let diaryname = diaryname.unwrap(); let diaryname = diaryname.unwrap();
fn location_to_listing_string(id: &StoreId, base: &PathBuf) -> String { fn entry_to_location_listing_string(e: &Entry) -> String {
id.strip_prefix(base) e.get_location().clone()
.without_base()
.to_str()
.map_err(|e| trace_error(&e)) .map_err(|e| trace_error(&e))
.ok()
.and_then(|p| p.to_str().map(String::from))
.unwrap_or(String::from("<<Path Parsing Error>>")) .unwrap_or(String::from("<<Path Parsing Error>>"))
} }
@ -40,9 +38,7 @@ pub fn list(rt: &Runtime) {
a.ok() a.ok()
}).map(|e| e.into()); }).map(|e| e.into());
let base = rt.store().path(); CoreLister::new(&entry_to_location_listing_string)
CoreLister::new(&move |e: &Entry| location_to_listing_string(e.get_location(), base))
.list(es) // TODO: Do not ignore non-ok()s .list(es) // TODO: Do not ignore non-ok()s
.map_err(|e| DE::new(DEK::IOError, Some(Box::new(e)))) .map_err(|e| DE::new(DEK::IOError, Some(Box::new(e))))
}) })

View file

@ -23,3 +23,6 @@ path = "../libimagentrylink"
[dependencies.libimagerror] [dependencies.libimagerror]
path = "../libimagerror" path = "../libimagerror"
[dependencies.libimagutil]
path = "../libimagutil"

View file

@ -24,6 +24,7 @@ extern crate libimagentrylink;
extern crate libimagrt; extern crate libimagrt;
extern crate libimagstore; extern crate libimagstore;
extern crate libimagerror; extern crate libimagerror;
extern crate libimagutil;
use std::process::exit; use std::process::exit;
use std::ops::Deref; use std::ops::Deref;
@ -36,6 +37,7 @@ use libimagstore::store::FileLockEntry;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagerror::trace::{trace_error, trace_error_exit}; use libimagerror::trace::{trace_error, trace_error_exit};
use libimagentrylink::external::ExternalLinker; use libimagentrylink::external::ExternalLinker;
use libimagutil::warn_result::*;
use clap::ArgMatches; use clap::ArgMatches;
use url::Url; use url::Url;
@ -74,10 +76,19 @@ fn handle_internal_linking(rt: &Runtime) {
for entry in cmd.value_of("list").unwrap().split(',') { for entry in cmd.value_of("list").unwrap().split(',') {
debug!("Listing for '{}'", entry); debug!("Listing for '{}'", entry);
match get_entry_by_name(rt, entry) { match get_entry_by_name(rt, entry) {
Ok(e) => { Ok(Some(e)) => {
e.get_internal_links() e.get_internal_links()
.map(|links| { .map(|links| {
for (i, link) in links.iter().map(|l| l.to_str()).filter_map(|x| x).enumerate() { let i = links
.iter()
.filter_map(|l| {
l.to_str()
.map_warn_err(|e| format!("Failed to convert StoreId to string: {:?}", e))
.ok()
})
.enumerate();
for (i, link) in i {
println!("{: <3}: {}", i, link); println!("{: <3}: {}", i, link);
} }
}) })
@ -85,6 +96,11 @@ fn handle_internal_linking(rt: &Runtime) {
.ok(); .ok();
}, },
Ok(None) => {
warn!("Entry not found: {:?}", entry);
break;
}
Err(e) => { Err(e) => {
trace_error(&e); trace_error(&e);
break; break;
@ -148,7 +164,8 @@ fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
debug!("We couldn't get the entry from name: '{:?}'", from_name); debug!("We couldn't get the entry from name: '{:?}'", from_name);
trace_error(&e); None trace_error(&e); None
}, },
Ok(e) => Some(e), Ok(Some(e)) => Some(e),
Ok(None) => None,
} }
}) })
@ -166,17 +183,20 @@ fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
for entry in values.map(|v| get_entry_by_name(rt, v)) { for entry in values.map(|v| get_entry_by_name(rt, v)) {
match entry { match entry {
Err(e) => trace_error(&e), Err(e) => trace_error(&e),
Ok(e) => v.push(e), Ok(Some(e)) => v.push(e),
Ok(None) => warn!("Entry not found: {:?}", v),
} }
} }
v v
}) })
} }
fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<FileLockEntry<'a>, StoreError> { fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> {
use libimagstore::storeid::build_entry_path; use std::path::PathBuf;
build_entry_path(rt.store(), name) use libimagstore::storeid::StoreId;
.and_then(|path| rt.store().retrieve(path))
StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
.and_then(|id| rt.store().get(id))
} }
fn handle_external_linking(rt: &Runtime) { fn handle_external_linking(rt: &Runtime) {
@ -186,6 +206,11 @@ fn handle_external_linking(rt: &Runtime) {
if entry.is_err() { if entry.is_err() {
trace_error_exit(&entry.unwrap_err(), 1); trace_error_exit(&entry.unwrap_err(), 1);
} }
let entry = entry.unwrap();
if entry.is_none() {
warn!("Entry not found: {:?}", entry_name);
return;
}
let mut entry = entry.unwrap(); let mut entry = entry.unwrap();
if scmd.is_present("add") { if scmd.is_present("add") {

View file

@ -13,8 +13,9 @@ use clap::ArgMatches;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagstore::store::EntryHeader; use libimagstore::store::EntryHeader;
use libimagstore::storeid::build_entry_path; use libimagstore::storeid::StoreId;
use libimagerror::trace::trace_error_exit; use libimagerror::trace::trace_error_exit;
use libimagutil::debug_result::*;
use error::StoreError; use error::StoreError;
use error::StoreErrorKind; use error::StoreErrorKind;
@ -36,13 +37,15 @@ pub fn create(rt: &Runtime) {
exit(1); exit(1);
} }
let path = match build_entry_path(rt.store(), path.unwrap()) { let store_path = rt.store().path().clone();
let path = match StoreId::new(Some(store_path), PathBuf::from(path.unwrap())) {
Err(e) => trace_error_exit(&e, 1), Err(e) => trace_error_exit(&e, 1),
Ok(p) => p, Ok(o) => o,
}; };
debug!("path = {:?}", path); debug!("path = {:?}", path);
if scmd.subcommand_matches("entry").is_some() { if scmd.subcommand_matches("entry").is_some() {
debug!("Creating entry from CLI specification");
create_from_cli_spec(rt, scmd, &path) create_from_cli_spec(rt, scmd, &path)
.or_else(|_| create_from_source(rt, scmd, &path)) .or_else(|_| create_from_source(rt, scmd, &path))
.or_else(|_| create_with_content_and_header(rt, .or_else(|_| create_with_content_and_header(rt,
@ -50,13 +53,17 @@ pub fn create(rt: &Runtime) {
String::new(), String::new(),
EntryHeader::new())) EntryHeader::new()))
} else { } else {
debug!("Creating entry");
create_with_content_and_header(rt, &path, String::new(), EntryHeader::new()) create_with_content_and_header(rt, &path, String::new(), EntryHeader::new())
} }
.unwrap_or_else(|e| debug!("Error building Entry: {:?}", e)) .unwrap_or_else(|e| {
error!("Error building Entry");
trace_error_exit(&e, 1);
})
}); });
} }
fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Result<()> { fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
let content = matches.subcommand_matches("entry") let content = matches.subcommand_matches("entry")
.map_or_else(|| { .map_or_else(|| {
debug!("Didn't find entry subcommand, getting raw content"); debug!("Didn't find entry subcommand, getting raw content");
@ -80,7 +87,7 @@ fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> R
create_with_content_and_header(rt, path, content, header) create_with_content_and_header(rt, path, content, header)
} }
fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Result<()> { fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
let content = matches let content = matches
.value_of("from-raw") .value_of("from-raw")
.ok_or(StoreError::new(StoreErrorKind::NoCommandlineCall, None)) .ok_or(StoreError::new(StoreErrorKind::NoCommandlineCall, None))
@ -93,9 +100,11 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Res
debug!("Content with len = {}", content.len()); debug!("Content with len = {}", content.len());
Entry::from_str(path.clone(), &content[..]) Entry::from_str(path.clone(), &content[..])
.map_dbg_err(|e| format!("Error building entry: {:?}", e))
.and_then(|new_e| { .and_then(|new_e| {
let r = rt.store() let r = rt.store()
.create(path.clone()) .create(path.clone())
.map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
.map(|mut old_e| { .map(|mut old_e| {
*old_e.deref_mut() = new_e; *old_e.deref_mut() = new_e;
}); });
@ -103,17 +112,19 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Res
debug!("Entry build"); debug!("Entry build");
r r
}) })
.map_dbg_err(|e| format!("Error storing entry: {:?}", e))
.map_err(|serr| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(serr)))) .map_err(|serr| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(serr))))
} }
fn create_with_content_and_header(rt: &Runtime, fn create_with_content_and_header(rt: &Runtime,
path: &PathBuf, path: &StoreId,
content: String, content: String,
header: EntryHeader) -> Result<()> header: EntryHeader) -> Result<()>
{ {
debug!("Creating entry with content"); debug!("Creating entry with content at {:?}", path);
rt.store() rt.store()
.create(PathBuf::from(path)) .create(path.clone())
.map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
.map(|mut element| { .map(|mut element| {
{ {
let mut e_content = element.get_content_mut(); let mut e_content = element.get_content_mut();

View file

@ -1,6 +1,8 @@
use libimagstore::storeid::build_entry_path; use std::path::PathBuf;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error_exit; use libimagerror::trace::trace_error_exit;
use libimagstore::storeid::StoreId;
pub fn delete(rt: &Runtime) { pub fn delete(rt: &Runtime) {
use std::process::exit; use std::process::exit;
@ -10,7 +12,8 @@ pub fn delete(rt: &Runtime) {
.map(|sub| { .map(|sub| {
sub.value_of("id") sub.value_of("id")
.map(|id| { .map(|id| {
let path = try!(build_entry_path(rt.store(), id) let path = PathBuf::from(id);
let path = try!(StoreId::new(Some(rt.store().path().clone()), path)
.map_err(|e| trace_error_exit(&e, 1))); .map_err(|e| trace_error_exit(&e, 1)));
debug!("Deleting file at {:?}", id); debug!("Deleting file at {:?}", id);

View file

@ -1,6 +1,8 @@
use libimagstore::storeid::build_entry_path; use std::path::PathBuf;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::{trace_error, trace_error_exit}; use libimagerror::trace::{trace_error, trace_error_exit};
use libimagstore::storeid::StoreId;
use retrieve::print_entry; use retrieve::print_entry;
@ -10,7 +12,8 @@ pub fn get(rt: &Runtime) {
.map(|scmd| { .map(|scmd| {
scmd.value_of("id") scmd.value_of("id")
.map(|id| { .map(|id| {
let path = match build_entry_path(rt.store(), id) { let path = PathBuf::from(id);
let path = match StoreId::new(Some(rt.store().path().clone()), path) {
Err(e) => trace_error_exit(&e, 1), Err(e) => trace_error_exit(&e, 1),
Ok(p) => p, Ok(p) => p,
}; };

View file

@ -1,8 +1,10 @@
use std::path::PathBuf;
use clap::ArgMatches; use clap::ArgMatches;
use toml::Value; use toml::Value;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagstore::storeid::build_entry_path; use libimagstore::storeid::StoreId;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::{trace_error, trace_error_exit}; use libimagerror::trace::{trace_error, trace_error_exit};
@ -12,7 +14,8 @@ pub fn retrieve(rt: &Runtime) {
.map(|scmd| { .map(|scmd| {
scmd.value_of("id") scmd.value_of("id")
.map(|id| { .map(|id| {
let path = try!(build_entry_path(rt.store(), id) let path = PathBuf::from(id);
let path = try!(StoreId::new(Some(rt.store().path().clone()), path)
.map_err(|e| trace_error_exit(&e, 1))); .map_err(|e| trace_error_exit(&e, 1)));
debug!("path = {:?}", path); debug!("path = {:?}", path);

View file

@ -1,8 +1,9 @@
use std::ops::DerefMut; use std::ops::DerefMut;
use std::path::PathBuf;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagstore::storeid::build_entry_path;
use libimagerror::trace::trace_error_exit; use libimagerror::trace::trace_error_exit;
use libimagstore::storeid::StoreId;
use util::build_toml_header; use util::build_toml_header;
@ -12,7 +13,8 @@ pub fn update(rt: &Runtime) {
.map(|scmd| { .map(|scmd| {
scmd.value_of("id") scmd.value_of("id")
.map(|id| { .map(|id| {
let path = match build_entry_path(rt.store(), id) { let path = PathBuf::from(id);
let path = match StoreId::new(Some(rt.store().path().clone()), path) {
Err(e) => trace_error_exit(&e, 1), Err(e) => trace_error_exit(&e, 1),
Ok(p) => p, Ok(p) => p,
}; };

View file

@ -4,7 +4,7 @@ source $(dirname ${BASH_SOURCE[0]})/../../tests/utils.sh
source $(dirname ${BASH_SOURCE[0]})/utils.sh source $(dirname ${BASH_SOURCE[0]})/utils.sh
test_call() { test_call() {
imag-store create -p /test-call~0.2.0 imag-store create -p test-call
if [[ ! $? -eq 0 ]]; then if [[ ! $? -eq 0 ]]; then
err "Return value should be zero, was non-zero" err "Return value should be zero, was non-zero"
return 1; return 1;
@ -12,7 +12,7 @@ test_call() {
} }
test_call_id() { test_call_id() {
imag-store create -i /test-call~0.2.0 imag-store create -i test-call
if [[ ! $? -eq 0 ]]; then if [[ ! $? -eq 0 ]]; then
err "Return value should be zero, was non-zero" err "Return value should be zero, was non-zero"
return 1; return 1;
@ -28,7 +28,7 @@ test_call_no_id() {
} }
test_mkstore() { test_mkstore() {
imag-store create -p /test-mkstore~0.2.0 || { err "Calling imag failed"; return 1; } imag-store create -p test-mkstore || { err "Calling imag failed"; return 1; }
if [[ -d ${STORE} ]]; then if [[ -d ${STORE} ]]; then
out "Store exists." out "Store exists."
else else
@ -48,12 +48,12 @@ version = "0.2.0"
EOS EOS
) )
imag-store create -p /test-std-header~0.2.0 imag-store create -p test-std-header
local result=$(cat ${STORE}/test-std-header~0.2.0) local result=$(cat ${STORE}/test-std-header)
if [[ "$expected" == "$result" ]]; then if [[ "$expected" == "$result" ]]; then
out "Expected store entry == result" out "Expected store entry == result"
else else
err "${STORE}/test-std-header~0.2.0 differs from expected" err "${STORE}/test-std-header differs from expected"
return 1 return 1
fi fi
} }
@ -72,8 +72,8 @@ zzz = "z"
EOS EOS
) )
imag-store create -p /test-std-header-plus-custom~0.2.0 entry -h zzz.zzz=z imag-store create -p test-std-header-plus-custom entry -h zzz.zzz=z
local result=$(cat ${STORE}/test-std-header-plus-custom~0.2.0) local result=$(cat ${STORE}/test-std-header-plus-custom)
if [[ "$expected" == "$result" ]]; then if [[ "$expected" == "$result" ]]; then
out "Expected store entry == result" out "Expected store entry == result"
else else
@ -99,8 +99,8 @@ zzz = "z"
EOS EOS
) )
local filename="test-std-header-plus-custom-multiheader~0.2.0" local filename="test-std-header-plus-custom-multiheader"
imag-store create -p /$filename entry -h zzz.zzz=z foo.bar=baz imag-store create -p $filename entry -h zzz.zzz=z foo.bar=baz
local result=$(cat ${STORE}/$filename) local result=$(cat ${STORE}/$filename)
if [[ "$expected" == "$result" ]]; then if [[ "$expected" == "$result" ]]; then
out "Expected store entry == result" out "Expected store entry == result"
@ -126,8 +126,8 @@ zzz = "z"
EOS EOS
) )
local filename="test-std-header-plus-custom-mutliheader-same-section~0.2.0" local filename="test-std-header-plus-custom-mutliheader-same-section"
imag-store create -p /$filename entry -h zzz.zzz=z zzz.bar=baz imag-store create -p $filename entry -h zzz.zzz=z zzz.bar=baz
local result=$(cat ${STORE}/$filename) local result=$(cat ${STORE}/$filename)
if [[ "$expected" == "$result" ]]; then if [[ "$expected" == "$result" ]]; then
out "Expected store entry == result" out "Expected store entry == result"
@ -151,8 +151,8 @@ content
EOS EOS
) )
local name="test-std-header-plus-custom-and-content~0.2.0" local name="test-std-header-plus-custom-and-content"
imag-store create -p /$name entry -h zzz.zzz=z -c content imag-store create -p $name entry -h zzz.zzz=z -c content
local result=$(cat ${STORE}/$name) local result=$(cat ${STORE}/$name)
if [[ "$expected" == "$result" ]]; then if [[ "$expected" == "$result" ]]; then
out "Expected store entry == result" out "Expected store entry == result"

View file

@ -18,9 +18,9 @@ retrieve() {
} }
test_retrieve_nothing() { test_retrieve_nothing() {
local id="test-retrieve_nothing~0.2.0" local id="test-retrieve_nothing"
imag-store create -p /${id} || { err "create failed"; return 1; } imag-store create -p ${id} || { err "create failed"; return 1; }
out "Going to test the retrieve functionality now" out "Going to test the retrieve functionality now"
local zero_out="$(retrieve --id /${id})" local zero_out="$(retrieve --id /${id})"
@ -33,9 +33,9 @@ test_retrieve_nothing() {
} }
test_retrieve_content() { test_retrieve_content() {
local id="test-retrieve_simple~0.2.0" local id="test-retrieve_simple"
imag-store create -p /${id} || { err "create failed"; return 1; } imag-store create -p ${id} || { err "create failed"; return 1; }
out "Going to test the retrieve functionality now" out "Going to test the retrieve functionality now"
@ -49,12 +49,12 @@ test_retrieve_content() {
} }
test_retrieve_header() { test_retrieve_header() {
local id="test-retrieve_simple~0.2.0" local id="test-retrieve_simple"
imag-store create -p /${id} || { err "create failed"; return 1; } imag-store create -p ${id} || { err "create failed"; return 1; }
out "Going to test the retrieve functionality now" out "Going to test the retrieve functionality now"
local header_out="$(retrieve --id /${id} --header)" local header_out="$(retrieve --id ${id} --header)"
out "Retrieving for header_out finished" out "Retrieving for header_out finished"
if [[ ! "$header_out" != "$(std_header)" ]]; then if [[ ! "$header_out" != "$(std_header)" ]]; then
@ -64,12 +64,12 @@ test_retrieve_header() {
} }
test_retrieve_raw() { test_retrieve_raw() {
local id="test-retrieve_simple~0.2.0" local id="test-retrieve_simple"
imag-store create -p /${id} || { err "create failed"; return 1; } imag-store create -p ${id} || { err "create failed"; return 1; }
out "Going to test the retrieve functionality now" out "Going to test the retrieve functionality now"
local both_out="$(retrieve --id /${id} --raw)" local both_out="$(retrieve --id ${id} --raw)"
out "Retrieving for both_out finished" out "Retrieving for both_out finished"
if [[ "$both_out" != "$(std_header)" ]]; then if [[ "$both_out" != "$(std_header)" ]]; then

View file

@ -12,10 +12,10 @@ delete() {
} }
test_delete_simple() { test_delete_simple() {
local name="test~0.2.0" local name="test"
create -p /$name create -p $name
delete --id /$name delete --id $name
local n=$($(find ${STORE}/ -type f | wc -l)) local n=$($(find ${STORE}/ -type f | wc -l))
if [[ $n -eq 0 ]]; then if [[ $n -eq 0 ]]; then

View file

@ -10,14 +10,15 @@ extern crate libimagentrytag;
extern crate libimagerror; extern crate libimagerror;
use std::process::exit; use std::process::exit;
use std::path::PathBuf;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagentrytag::tagable::Tagable; use libimagentrytag::tagable::Tagable;
use libimagentrytag::tag::Tag; use libimagentrytag::tag::Tag;
use libimagstore::storeid::build_entry_path;
use libimagerror::trace::{trace_error, trace_error_exit}; use libimagerror::trace::{trace_error, trace_error_exit};
use libimagentrytag::ui::{get_add_tags, get_remove_tags}; use libimagentrytag::ui::{get_add_tags, get_remove_tags};
use libimagstore::storeid::StoreId;
mod ui; mod ui;
@ -34,11 +35,13 @@ fn main() {
.subcommand_name() .subcommand_name()
.map_or_else( .map_or_else(
|| { || {
let id = PathBuf::from(id);
let add = get_add_tags(rt.cli()); let add = get_add_tags(rt.cli());
let rem = get_remove_tags(rt.cli()); let rem = get_remove_tags(rt.cli());
alter(&rt, id, add, rem); alter(&rt, id, add, rem);
}, },
|name| { |name| {
let id = PathBuf::from(id);
debug!("Call: {}", name); debug!("Call: {}", name);
match name { match name {
"list" => list(id, &rt), "list" => list(id, &rt),
@ -50,9 +53,9 @@ fn main() {
}); });
} }
fn alter(rt: &Runtime, id: &str, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) { fn alter(rt: &Runtime, id: PathBuf, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) {
let path = { let path = {
match build_entry_path(rt.store(), id) { match StoreId::new(Some(rt.store().path().clone()), id) {
Err(e) => trace_error_exit(&e, 1), Err(e) => trace_error_exit(&e, 1),
Ok(s) => s, Ok(s) => s,
} }
@ -91,12 +94,10 @@ fn alter(rt: &Runtime, id: &str, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) {
} }
} }
fn list(id: &str, rt: &Runtime) { fn list(id: PathBuf, rt: &Runtime) {
let path = { let path = match StoreId::new(Some(rt.store().path().clone()), id) {
match build_entry_path(rt.store(), id) {
Err(e) => trace_error_exit(&e, 1), Err(e) => trace_error_exit(&e, 1),
Ok(s) => s, Ok(s) => s,
}
}; };
debug!("path = {:?}", path); debug!("path = {:?}", path);
@ -108,8 +109,7 @@ fn list(id: &str, rt: &Runtime) {
}, },
Err(e) => { Err(e) => {
debug!("Could not get '{:?}' => {:?}", id, path); warn!("Could not get entry '{:?}'", path);
warn!("Could not get entry '{}'", id);
trace_error_exit(&e, 1); trace_error_exit(&e, 1);
}, },
}; };

View file

@ -30,7 +30,6 @@ use std::path::PathBuf;
use libimagrt::setup::generate_runtime_setup; use libimagrt::setup::generate_runtime_setup;
use libimagerror::trace::trace_error_exit; use libimagerror::trace::trace_error_exit;
use libimagentryview::builtin::stdout::StdoutViewer; use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::builtin::versions::VersionsViewer;
use libimagentryview::viewer::Viewer; use libimagentryview::viewer::Viewer;
mod ui; mod ui;
@ -68,9 +67,7 @@ fn main() {
} }
}; };
let res = if rt.cli().is_present("versions") { let res = {
VersionsViewer::new(rt.store()).view_entry(&entry)
} else {
if scmd.is_present("view-in-stdout") { if scmd.is_present("view-in-stdout") {
} else if scmd.is_present("view-in-ui") { } else if scmd.is_present("view-in-ui") {
warn!("Viewing in UI is currently not supported, switch to stdout"); warn!("Viewing in UI is currently not supported, switch to stdout");

View file

@ -10,12 +10,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.help("View this entry at this store path") .help("View this entry at this store path")
.value_name("ID")) .value_name("ID"))
.arg(Arg::with_name("versions")
.long("versions")
.takes_value(false)
.required(false)
.help("Only print available versions for this file"))
.arg(Arg::with_name("view-header") .arg(Arg::with_name("view-header")
.long("header") .long("header")
.short("h") .short("h")

View file

@ -51,8 +51,9 @@ impl<'a> DerefMut for BookmarkCollection<'a> {
impl<'a> BookmarkCollection<'a> { impl<'a> BookmarkCollection<'a> {
pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> { pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
let id = ModuleEntryPath::new(name).into_storeid(); ModuleEntryPath::new(name)
store.create(id) .into_storeid()
.and_then(|id| store.create(id))
.map(|fle| { .map(|fle| {
BookmarkCollection { BookmarkCollection {
fle: fle, fle: fle,
@ -63,8 +64,9 @@ impl<'a> BookmarkCollection<'a> {
} }
pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> { pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
let id = ModuleEntryPath::new(name).into_storeid(); ModuleEntryPath::new(name)
store.get(id) .into_storeid()
.and_then(|id| store.get(id))
.map_err_into(BEK::StoreReadError) .map_err_into(BEK::StoreReadError)
.and_then(|fle| { .and_then(|fle| {
match fle { match fle {
@ -78,7 +80,10 @@ impl<'a> BookmarkCollection<'a> {
} }
pub fn delete(store: &Store, name: &str) -> Result<()> { pub fn delete(store: &Store, name: &str) -> Result<()> {
store.delete(ModuleEntryPath::new(name).into_storeid()).map_err_into(BEK::StoreReadError) ModuleEntryPath::new(name)
.into_storeid()
.and_then(|id| store.delete(id))
.map_err_into(BEK::StoreReadError)
} }
pub fn links(&self) -> Result<Vec<Url>> { pub fn links(&self) -> Result<Vec<Url>> {

View file

@ -21,7 +21,7 @@ extern crate regex;
#[macro_use] extern crate libimagerror; #[macro_use] extern crate libimagerror;
extern crate libimagentrylink; extern crate libimagentrylink;
module_entry_path_mod!("bookmark", "0.1.0"); module_entry_path_mod!("bookmark");
pub mod collection; pub mod collection;
pub mod error; pub mod error;

View file

@ -48,8 +48,10 @@ impl<'a> Counter<'a> {
debug!("Creating new counter: '{}' with value: {}", name, init); debug!("Creating new counter: '{}' with value: {}", name, init);
let fle = { let fle = {
let mut lockentry = try!(store.create(ModuleEntryPath::new(name.clone()).into_storeid()) let id = try!(ModuleEntryPath::new(name.clone())
.into_storeid()
.map_err_into(CEK::StoreWriteError)); .map_err_into(CEK::StoreWriteError));
let mut lockentry = try!(store.create(id).map_err_into(CEK::StoreWriteError));
{ {
let mut entry = lockentry.deref_mut(); let mut entry = lockentry.deref_mut();
@ -161,14 +163,18 @@ impl<'a> Counter<'a> {
pub fn load(name: CounterName, store: &Store) -> Result<Counter> { pub fn load(name: CounterName, store: &Store) -> Result<Counter> {
debug!("Loading counter: '{}'", name); debug!("Loading counter: '{}'", name);
let id = ModuleEntryPath::new(name).into_storeid(); let id = try!(ModuleEntryPath::new(name)
.into_storeid()
.map_err_into(CEK::StoreWriteError));
Counter::from_storeid(store, id) Counter::from_storeid(store, id)
} }
pub fn delete(name: CounterName, store: &Store) -> Result<()> { pub fn delete(name: CounterName, store: &Store) -> Result<()> {
debug!("Deleting counter: '{}'", name); debug!("Deleting counter: '{}'", name);
store.delete(ModuleEntryPath::new(name).into_storeid()) let id = try!(ModuleEntryPath::new(name)
.map_err_into(CEK::StoreWriteError) .into_storeid()
.map_err_into(CEK::StoreWriteError));
store.delete(id).map_err_into(CEK::StoreWriteError)
} }
pub fn all_counters(store: &Store) -> Result<CounterIterator> { pub fn all_counters(store: &Store) -> Result<CounterIterator> {

View file

@ -1,5 +1,6 @@
generate_error_module!( generate_error_module!(
generate_error_types!(CounterError, CounterErrorKind, generate_error_types!(CounterError, CounterErrorKind,
StoreIdError => "StoreId error",
StoreReadError => "Store read error", StoreReadError => "Store read error",
StoreWriteError => "Store write error", StoreWriteError => "Store write error",
HeaderTypeError => "Header type error", HeaderTypeError => "Header type error",

View file

@ -19,7 +19,7 @@ extern crate toml;
#[macro_use] extern crate libimagstore; #[macro_use] extern crate libimagstore;
#[macro_use] extern crate libimagerror; #[macro_use] extern crate libimagerror;
module_entry_path_mod!("counter", "0.2.0"); module_entry_path_mod!("counter");
pub mod counter; pub mod counter;
pub mod error; pub mod error;

View file

@ -45,8 +45,8 @@ impl<'a> Diary<'a> {
} }
pub fn retrieve(&self, id: DiaryId) -> Result<Entry> { pub fn retrieve(&self, id: DiaryId) -> Result<Entry> {
self.store id.into_storeid()
.retrieve(id.into_storeid()) .and_then(|id| self.store.retrieve(id))
.map(|fle| Entry::new(fle)) .map(|fle| Entry::new(fle))
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e)))) .map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
} }

View file

@ -9,6 +9,7 @@ use chrono::Timelike;
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId; use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Result as StoreResult;
use module_path::ModuleEntryPath; use module_path::ModuleEntryPath;
@ -118,7 +119,7 @@ impl Default for DiaryId {
impl IntoStoreId for DiaryId { impl IntoStoreId for DiaryId {
fn into_storeid(self) -> StoreId { fn into_storeid(self) -> StoreResult<StoreId> {
let s : String = self.into(); let s : String = self.into();
ModuleEntryPath::new(s).into_storeid() ModuleEntryPath::new(s).into_storeid()
} }

View file

@ -1,6 +1,5 @@
use std::path::PathBuf;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;
pub trait IsInDiary { pub trait IsInDiary {
@ -11,15 +10,15 @@ pub trait IsInDiary {
impl IsInDiary for Entry { impl IsInDiary for Entry {
fn is_in_diary(&self, name: &str) -> bool { fn is_in_diary(&self, name: &str) -> bool {
self.get_location().is_in_diary(name) self.get_location().clone().is_in_diary(name)
} }
} }
impl IsInDiary for PathBuf { impl IsInDiary for StoreId {
fn is_in_diary(&self, name: &str) -> bool { fn is_in_diary(&self, name: &str) -> bool {
self.to_str().map(|s| s.contains(name)).unwrap_or(false) self.local().starts_with(format!("diary/{}", name))
} }
} }

View file

@ -28,7 +28,7 @@ extern crate itertools;
extern crate libimagentryedit; extern crate libimagentryedit;
extern crate libimagrt; extern crate libimagrt;
module_entry_path_mod!("diary", "0.2.0"); module_entry_path_mod!("diary");
pub mod config; pub mod config;
pub mod error; pub mod error;

View file

@ -7,7 +7,8 @@ generate_error_module!(
InternalConversionError => "Error while converting values internally", InternalConversionError => "Error while converting values internally",
InvalidUri => "URI is not valid", InvalidUri => "URI is not valid",
StoreReadError => "Store read error", StoreReadError => "Store read error",
StoreWriteError => "Store write error" StoreWriteError => "Store write error",
StoreIdError => "StoreId handling error"
); );
); );

View file

@ -91,8 +91,8 @@ pub trait ExternalLinker : InternalLinker {
/// Check whether the StoreId starts with `/link/external/` /// Check whether the StoreId starts with `/link/external/`
pub fn is_external_link_storeid(id: &StoreId) -> bool { pub fn is_external_link_storeid(id: &StoreId) -> bool {
debug!("Checking whether this is a /link/external/*: '{:?}'", id); debug!("Checking whether this is a link/external/*: '{:?}'", id);
id.parent().map(|par| par.ends_with("/link/external")).unwrap_or(false) id.local().starts_with("link/external")
} }
fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> { fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
@ -144,7 +144,13 @@ impl ExternalLinker for Entry {
s.input_str(&link.as_str()[..]); s.input_str(&link.as_str()[..]);
s.result_str() s.result_str()
}; };
let file_id = ModuleEntryPath::new(format!("external/{}", hash)).into_storeid(); let file_id = try!(
ModuleEntryPath::new(format!("external/{}", hash)).into_storeid()
.map_err_into(LEK::StoreWriteError)
.map_dbg_err(|_| {
format!("Failed to build StoreId for this hash '{:?}'", hash)
})
);
debug!("Link = '{:?}'", link); debug!("Link = '{:?}'", link);
debug!("Hash = '{:?}'", hash); debug!("Hash = '{:?}'", hash);

View file

@ -7,6 +7,7 @@ use libimagstore::store::Result as StoreResult;
use libimagerror::into::IntoError; use libimagerror::into::IntoError;
use error::LinkErrorKind as LEK; use error::LinkErrorKind as LEK;
use error::MapErrInto;
use result::Result; use result::Result;
use toml::Value; use toml::Value;
@ -53,13 +54,11 @@ impl InternalLinker for Entry {
.into_iter() .into_iter()
.fold(Ok(vec![]), |acc, elem| { .fold(Ok(vec![]), |acc, elem| {
acc.and_then(move |mut v| { acc.and_then(move |mut v| {
match elem { elem.map_err_into(LEK::InternalConversionError)
None => Err(LEK::InternalConversionError.into()), .map(|e| {
Some(e) => {
v.push(e); v.push(e);
Ok(v) v
}, })
}
}) })
})); }));
process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links))) process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
@ -98,16 +97,16 @@ impl InternalLinker for Entry {
} }
fn links_into_values(links: Vec<StoreId>) -> Vec<Option<Value>> { fn links_into_values(links: Vec<StoreId>) -> Vec<Result<Value>> {
links links
.into_iter() .into_iter()
.map(|s| s.to_str().map(String::from))
.unique() .unique()
.map(|s| s.without_base().to_str().map_err_into(LEK::InternalConversionError))
.map(|elem| elem.map(Value::String)) .map(|elem| elem.map(Value::String))
.sorted_by(|a, b| { .sorted_by(|a, b| {
match (a, b) { match (a, b) {
(&Some(Value::String(ref a)), &Some(Value::String(ref b))) => Ord::cmp(a, b), (&Ok(Value::String(ref a)), &Ok(Value::String(ref b))) => Ord::cmp(a, b),
(&None, _) | (_, &None) => Ordering::Equal, (&Err(_), _) | (_, &Err(_)) => Ordering::Equal,
_ => unreachable!() _ => unreachable!()
} }
}) })
@ -118,13 +117,11 @@ fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
.into_iter() .into_iter()
.fold(Ok(vec![]), |acc, elem| { .fold(Ok(vec![]), |acc, elem| {
acc.and_then(move |mut v| { acc.and_then(move |mut v| {
match elem { elem.map_err_into(LEK::InternalConversionError)
None => Err(LEK::InternalConversionError.into()), .map(|e| {
Some(e) => {
v.push(e); v.push(e);
Ok(v) v
}, })
}
}) })
})); }));
@ -142,13 +139,11 @@ fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
.into_iter() .into_iter()
.fold(Ok(vec![]), |acc, elem| { .fold(Ok(vec![]), |acc, elem| {
acc.and_then(move |mut v| { acc.and_then(move |mut v| {
match elem { elem.map_err_into(LEK::InternalConversionError)
None => Err(LEK::InternalConversionError.into()), .map(|e| {
Some(e) => {
v.push(e); v.push(e);
Ok(v) v
}, })
}
}) })
})); }));
process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links))) process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
@ -157,6 +152,8 @@ fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
} }
fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> { fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
use std::path::PathBuf;
let links = match links { let links = match links {
Err(e) => { Err(e) => {
debug!("RW action on store failed. Generating LinkError"); debug!("RW action on store failed. Generating LinkError");
@ -179,14 +176,15 @@ fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
return Err(LEK::ExistingLinkTypeWrong.into()); return Err(LEK::ExistingLinkTypeWrong.into());
} }
let links : Vec<Link> = links.into_iter() let links : Vec<Link> = try!(links.into_iter()
.map(|link| { .map(|link| {
match link { match link {
Value::String(s) => StoreId::from(s), Value::String(s) => StoreId::new_baseless(PathBuf::from(s))
.map_err_into(LEK::StoreIdError),
_ => unreachable!(), _ => unreachable!(),
} }
}) })
.collect(); .collect());
debug!("Ok, the RW action was successful, returning link vector now!"); debug!("Ok, the RW action was successful, returning link vector now!");
Ok(links) Ok(links)

View file

@ -23,7 +23,7 @@ extern crate crypto;
#[macro_use] extern crate libimagerror; #[macro_use] extern crate libimagerror;
#[macro_use] extern crate libimagutil; #[macro_use] extern crate libimagutil;
module_entry_path_mod!("links", "0.2.0"); module_entry_path_mod!("links");
pub mod error; pub mod error;
pub mod external; pub mod external;

View file

@ -28,8 +28,8 @@ impl<'a> Lister for LineLister<'a> {
use error::ListErrorKind as LEK; use error::ListErrorKind as LEK;
entries.fold_defresult(|entry| { entries.fold_defresult(|entry| {
write!(stdout(), "{:?}\n", entry.get_location().to_str().unwrap_or(self.unknown_output)) let s = entry.get_location().to_str().unwrap_or(String::from(self.unknown_output));
.map_err(|e| LE::new(LEK::FormatError, Some(Box::new(e)))) write!(stdout(), "{:?}\n", s).map_err(|e| LE::new(LEK::FormatError, Some(Box::new(e))))
}) })
} }

View file

@ -26,10 +26,12 @@ impl Lister for PathLister {
fn list<'a, I: Iterator<Item = FileLockEntry<'a>>>(&self, entries: I) -> Result<()> { fn list<'a, I: Iterator<Item = FileLockEntry<'a>>>(&self, entries: I) -> Result<()> {
use error::ListError as LE; use error::ListError as LE;
use error::ListErrorKind as LEK; use error::ListErrorKind as LEK;
use std::path::PathBuf;
entries.fold_defresult(|entry| { entries.fold_defresult(|entry| {
Ok(entry.get_location().clone()) Ok(entry.get_location().clone())
.and_then(|pb| { .and_then(|pb| {
let pb : PathBuf = pb.into();
if self.absolute { if self.absolute {
pb.canonicalize().map_err(|e| LE::new(LEK::FormatError, Some(Box::new(e)))) pb.canonicalize().map_err(|e| LE::new(LEK::FormatError, Some(Box::new(e))))
} else { } else {

View file

@ -0,0 +1,13 @@
generate_error_module!(
generate_error_types!(EntrySelectError, EntrySelectErrorKind,
CLIError => "Error on commandline",
IdMissingError => "Commandline: ID missing",
StoreIdParsingError => "Error while parsing StoreId",
IdSelectingError => "Error while selecting id"
);
);
pub use self::error::EntrySelectError;
pub use self::error::EntrySelectErrorKind;
pub use self::error::MapErrInto;

View file

@ -17,7 +17,10 @@ extern crate log;
extern crate interactor; extern crate interactor;
extern crate libimagstore; extern crate libimagstore;
#[macro_use]
extern crate libimagerror; extern crate libimagerror;
pub mod error;
pub mod result;
pub mod ui; pub mod ui;

View file

@ -0,0 +1,6 @@
use std::result::Result as RResult;
use error::EntrySelectError;
pub type Result<T> = RResult<T, EntrySelectError>;

View file

@ -3,7 +3,11 @@ use std::path::PathBuf;
use clap::{Arg, ArgMatches}; use clap::{Arg, ArgMatches};
use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreId;
use libimagerror::trace::trace_error; use libimagerror::into::IntoError;
use result::Result;
use error::MapErrInto;
use error::EntrySelectErrorKind as ESEK;
pub fn id_argument<'a, 'b>() -> Arg<'a, 'b> { pub fn id_argument<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(id_argument_name()) Arg::with_name(id_argument_name())
@ -26,28 +30,35 @@ pub fn id_argument_long() -> &'static str {
"id" "id"
} }
pub fn get_id(matches: &ArgMatches) -> Option<Vec<StoreId>> { pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> {
matches.values_of(id_argument_name()) matches
.map(|vals| { .values_of(id_argument_name())
.ok_or(ESEK::IdMissingError.into_error())
.map_err_into(ESEK::CLIError)
.and_then(|vals| {
vals.into_iter() vals.into_iter()
.map(String::from) .fold(Ok(vec![]), |acc, elem| {
.map(StoreId::from) acc.and_then(|mut v| {
.collect() let elem = StoreId::new_baseless(PathBuf::from(String::from(elem)));
let elem = try!(elem.map_err_into(ESEK::StoreIdParsingError));
v.push(elem);
Ok(v)
})
})
}) })
} }
pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Option<Vec<StoreId>> { pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Vec<StoreId>> {
use interactor::{pick_file, default_menu_cmd}; use interactor::{pick_file, default_menu_cmd};
get_id(matches).or_else(|| { match get_id(matches).map_err_into(ESEK::IdSelectingError) {
match pick_file(default_menu_cmd, store_path.clone()) { Ok(v) => Ok(v),
Err(e) => { Err(_) => {
trace_error(&e); let path = store_path.clone();
None let p = try!(pick_file(default_menu_cmd, path).map_err_into(ESEK::IdSelectingError));
let id = try!(StoreId::new_baseless(p).map_err_into(ESEK::StoreIdParsingError));
Ok(vec![id])
}, },
Ok(p) => Some(vec![StoreId::from(p)]),
} }
})
} }

View file

@ -1,4 +1,3 @@
pub mod editor; pub mod editor;
pub mod plain; pub mod plain;
pub mod stdout; pub mod stdout;
pub mod versions;

View file

@ -1,54 +0,0 @@
use libimagstore::store::Entry;
use libimagstore::store::Store;
use libimagerror::into::IntoError;
use viewer::Viewer;
use result::Result;
use error::ViewErrorKind as VEK;
pub struct VersionsViewer<'a> {
store: &'a Store,
}
impl<'a> VersionsViewer<'a> {
pub fn new(store: &'a Store) -> VersionsViewer<'a> {
VersionsViewer {
store: store,
}
}
}
impl<'a> Viewer for VersionsViewer<'a> {
fn view_entry(&self, entr: &Entry) -> Result<()> {
use glob::glob;
entr.get_location()
.clone()
.storified(self.store)
.to_str()
.and_then(|s| s.split("~").next())
.map(|component| {
glob(&format!("{}~*", component)[..])
.map_err(|_| VEK::PatternError.into_error())
.and_then(|paths| {
for entry in paths {
let p = match entry {
Err(_) => return Err(VEK::GlobError.into_error()),
Ok(p) => p,
};
let p = p.file_name()
.and_then(|s| s.to_str())
.unwrap(); // TODO
println!("{}", p);
};
Ok(())
})
})
.unwrap_or(Err(VEK::PatternBuildingError.into_error()))
}
}

View file

@ -9,4 +9,5 @@ generate_error_module!(
pub use self::error::NoteError; pub use self::error::NoteError;
pub use self::error::NoteErrorKind; pub use self::error::NoteErrorKind;
pub use self::error::MapErrInto;

View file

@ -24,7 +24,7 @@ extern crate libimagrt;
extern crate libimagentryedit; extern crate libimagentryedit;
extern crate libimagentrytag; extern crate libimagentrytag;
module_entry_path_mod!("notes", "0.2.0"); module_entry_path_mod!("notes");
pub mod error; pub mod error;
pub mod note; pub mod note;

View file

@ -19,6 +19,7 @@ use module_path::ModuleEntryPath;
use result::Result; use result::Result;
use error::NoteError as NE; use error::NoteError as NE;
use error::NoteErrorKind as NEK; use error::NoteErrorKind as NEK;
use error::MapErrInto;
#[derive(Debug)] #[derive(Debug)]
pub struct Note<'a> { pub struct Note<'a> {
@ -32,11 +33,10 @@ impl<'a> Note<'a> {
debug!("Creating new Note: '{}'", name); debug!("Creating new Note: '{}'", name);
let fle = { let fle = {
let lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid()); let mut lockentry = try!(ModuleEntryPath::new(name.clone())
if lockentry.is_err() { .into_storeid()
return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.unwrap_err())))); .and_then(|id| store.create(id))
} .map_err_into(NEK::StoreWriteError));
let mut lockentry = lockentry.unwrap();
{ {
let mut entry = lockentry.deref_mut(); let mut entry = lockentry.deref_mut();
@ -93,24 +93,26 @@ impl<'a> Note<'a> {
} }
pub fn delete(store: &Store, name: String) -> Result<()> { pub fn delete(store: &Store, name: String) -> Result<()> {
store.delete(ModuleEntryPath::new(name).into_storeid()) ModuleEntryPath::new(name)
.map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e)))) .into_storeid()
.and_then(|id| store.delete(id))
.map_err_into(NEK::StoreWriteError)
} }
pub fn retrieve(store: &Store, name: String) -> Result<Note> { pub fn retrieve(store: &Store, name: String) -> Result<Note> {
store.retrieve(ModuleEntryPath::new(name).into_storeid()) ModuleEntryPath::new(name)
.map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e)))) .into_storeid()
.and_then(|id| store.retrieve(id))
.map_err_into(NEK::StoreWriteError)
.map(|entry| Note { entry: entry }) .map(|entry| Note { entry: entry })
} }
pub fn get(store: &Store, name: String) -> Result<Option<Note>> { pub fn get(store: &Store, name: String) -> Result<Option<Note>> {
use libimagerror::into::IntoError; ModuleEntryPath::new(name)
.into_storeid()
match store.get(ModuleEntryPath::new(name).into_storeid()) { .and_then(|id| store.get(id))
Ok(Some(entry)) => Ok(Some(Note { entry: entry })), .map_err_into(NEK::StoreWriteError)
Ok(None) => Ok(None), .map(|o| o.map(|entry| Note { entry: entry }))
Err(e) => Err(NEK::StoreWriteError.into_error_with_cause(Box::new(e))),
}
} }
pub fn all_notes(store: &Store) -> Result<NoteIterator> { pub fn all_notes(store: &Store) -> Result<NoteIterator> {

View file

@ -25,7 +25,7 @@ extern crate walkdir;
#[macro_use] extern crate libimagutil; #[macro_use] extern crate libimagutil;
extern crate libimagentrylist; extern crate libimagentrylist;
module_entry_path_mod!("ref", "0.2.0"); module_entry_path_mod!("ref");
pub mod error; pub mod error;
pub mod flags; pub mod flags;

View file

@ -19,6 +19,7 @@ use libimagerror::into::IntoError;
use toml::Value; use toml::Value;
use error::RefErrorKind as REK; use error::RefErrorKind as REK;
use error::MapErrInto;
use flags::RefFlags; use flags::RefFlags;
use result::Result; use result::Result;
use hasher::*; use hasher::*;
@ -47,8 +48,9 @@ impl<'a> Ref<'a> {
/// ///
/// Returns None if the hash cannot be found. /// Returns None if the hash cannot be found.
pub fn get_by_hash(store: &'a Store, hash: String) -> Result<Option<Ref<'a>>> { pub fn get_by_hash(store: &'a Store, hash: String) -> Result<Option<Ref<'a>>> {
store ModuleEntryPath::new(hash)
.get(ModuleEntryPath::new(hash).into_storeid()) .into_storeid()
.and_then(|id| store.get(id))
.map(|opt_fle| opt_fle.map(|fle| Ref(fle))) .map(|opt_fle| opt_fle.map(|fle| Ref(fle)))
.map_err(Box::new) .map_err(Box::new)
.map_err(|e| REK::StoreReadError.into_error_with_cause(e)) .map_err(|e| REK::StoreReadError.into_error_with_cause(e))
@ -58,8 +60,9 @@ impl<'a> Ref<'a> {
/// ///
/// If the returned Result contains an error, the ref might not be deleted. /// If the returned Result contains an error, the ref might not be deleted.
pub fn delete_by_hash(store: &'a Store, hash: String) -> Result<()> { pub fn delete_by_hash(store: &'a Store, hash: String) -> Result<()> {
store ModuleEntryPath::new(hash)
.delete(ModuleEntryPath::new(hash).into_storeid()) .into_storeid()
.and_then(|id| store.delete(id))
.map_err(Box::new) .map_err(Box::new)
.map_err(|e| REK::StoreWriteError.into_error_with_cause(e)) .map_err(|e| REK::StoreWriteError.into_error_with_cause(e))
} }
@ -223,10 +226,8 @@ impl<'a> Ref<'a> {
/// Get the hash from the path of the ref /// Get the hash from the path of the ref
pub fn get_path_hash(&self) -> Option<String> { pub fn get_path_hash(&self) -> Option<String> {
self.0 let pb : PathBuf = self.0.get_location().clone().into();
.get_location() pb.file_name()
.as_path()
.file_name()
.and_then(|osstr| osstr.to_str()) .and_then(|osstr| osstr.to_str())
.and_then(|s| s.split("~").next()) .and_then(|s| s.split("~").next())
.map(String::from) .map(String::from)
@ -398,13 +399,9 @@ impl<'a> Ref<'a> {
// manually here. If you can come up with a better version of this, feel free to // manually here. If you can come up with a better version of this, feel free to
// take this note as a todo. // take this note as a todo.
for r in possible_refs { for r in possible_refs {
let contains_hash = match r.to_str() { let contains_hash = try!(r.to_str()
None => { // couldn't parse StoreId -> PathBuf -> &str .map_err_into(REK::TypeConversionError)
// TODO: How to report this? .map(|s| s.contains(&hash[..])));
return Err(REK::TypeConversionError.into_error());
},
Some(s) => s.contains(&hash[..]),
};
if !contains_hash { if !contains_hash {
continue; continue;

View file

@ -42,6 +42,7 @@ generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
StorePathError => "Store Path error", StorePathError => "Store Path error",
EntryRenameError => "Entry rename error", EntryRenameError => "Entry rename error",
StoreIdHandlingError => "StoreId handling error", StoreIdHandlingError => "StoreId handling error",
StoreIdLocalPartAbsoluteError => "StoreId 'id' part is absolute (starts with '/') which is not allowed",
CreateCallError => "Error when calling create()", CreateCallError => "Error when calling create()",
RetrieveCallError => "Error when calling retrieve()", RetrieveCallError => "Error when calling retrieve()",

View file

@ -36,6 +36,7 @@ use hook::position::HookPosition;
use hook::Hook; use hook::Hook;
use libimagerror::into::IntoError; use libimagerror::into::IntoError;
use libimagerror::trace::trace_error;
use libimagutil::iter::FoldResult; use libimagutil::iter::FoldResult;
use self::glob_store_iter::*; use self::glob_store_iter::*;
@ -65,14 +66,17 @@ pub enum StoreObject {
} }
pub struct Walk { pub struct Walk {
store_path: PathBuf,
dirwalker: WalkDirIter, dirwalker: WalkDirIter,
} }
impl Walk { impl Walk {
fn new(mut store_path: PathBuf, mod_name: &str) -> Walk { fn new(mut store_path: PathBuf, mod_name: &str) -> Walk {
let pb = store_path.clone();
store_path.push(mod_name); store_path.push(mod_name);
Walk { Walk {
store_path: pb,
dirwalker: WalkDir::new(store_path).into_iter(), dirwalker: WalkDir::new(store_path).into_iter(),
} }
} }
@ -95,7 +99,15 @@ impl Iterator for Walk {
Ok(next) => if next.file_type().is_dir() { Ok(next) => if next.file_type().is_dir() {
return Some(StoreObject::Collection(next.path().to_path_buf())) return Some(StoreObject::Collection(next.path().to_path_buf()))
} else if next.file_type().is_file() { } else if next.file_type().is_file() {
return Some(StoreObject::Id(next.path().to_path_buf().into())) let n = next.path().to_path_buf();
let sid = match StoreId::new(Some(self.store_path.clone()), n) {
Err(e) => {
trace_error(&e);
continue;
},
Ok(o) => o,
};
return Some(StoreObject::Id(sid))
}, },
Err(e) => { Err(e) => {
warn!("Error in Walker"); warn!("Error in Walker");
@ -376,7 +388,7 @@ impl Store {
/// Creates the Entry at the given location (inside the entry) /// Creates the Entry at the given location (inside the entry)
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 = id.into_storeid().storified(self); 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) {
return Err(e) return Err(e)
.map_err_into(SEK::PreHookExecuteError) .map_err_into(SEK::PreHookExecuteError)
@ -414,7 +426,7 @@ 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`.
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 = id.into_storeid().storified(self); 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) {
return Err(e) return Err(e)
.map_err_into(SEK::PreHookExecuteError) .map_err_into(SEK::PreHookExecuteError)
@ -447,57 +459,14 @@ impl Store {
/// ///
/// This executes the {pre,post}_retrieve_aspects hooks. /// This executes the {pre,post}_retrieve_aspects hooks.
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>>> {
if !id.clone().into_storeid().storified(self).exists() { let id_copy = try!(id.clone().into_storeid()).with_base(self.path().clone());
debug!("Does not exist: {:?}", id.clone().into_storeid()); if !id_copy.exists() {
debug!("Does not exist: {:?}", id_copy);
return Ok(None); return Ok(None);
} }
self.retrieve(id).map(Some).map_err_into(SEK::GetCallError) self.retrieve(id).map(Some).map_err_into(SEK::GetCallError)
} }
/// Same as `Store::get()` but also tries older versions of the entry, returning an iterator
/// over all versions of the entry.
pub fn get_all_versions<'a, S: IntoStoreId>(&'a self, id: S) -> Result<StoreIdIterator>
{
// get PathBuf component from storeid, but not version component
fn path_component<S: IntoStoreId>(id: S) -> Result<PathBuf> {
let p : PathBuf = id.into_storeid().into();
match p.to_str() {
Some(s) => {
let mut split = s.split("~");
let path_element = match split.next() {
Some(s) => s,
None => return Err(SE::new(SEK::StorePathError, None))
.map_err_into(SEK::GetAllVersionsCallError),
};
Ok(PathBuf::from(path_element))
},
None => Err(SE::new(SEK::StorePathError, None))
.map_err_into(SEK::GetAllVersionsCallError),
}
}
fn build_glob_pattern(mut pb: PathBuf) -> Option<String> {
pb.push("~*.*.*");
pb.to_str().map(String::from)
}
match path_component(id).map(build_glob_pattern) {
Err(e) => Err(SEK::StorePathError.into_error_with_cause(Box::new(e)))
.map_err_into(SEK::GetAllVersionsCallError),
Ok(None) => Err(SE::new(SEK::StorePathError, None))
.map_err_into(SEK::GetAllVersionsCallError),
Ok(Some(pattern)) => {
glob(&pattern[..])
.map(|paths| GlobStoreIdIterator::new(paths).into())
.map_err_into(SEK::GlobError)
.map_err_into(SEK::GetAllVersionsCallError)
}
}
}
/// Iterate over all StoreIds for one module name /// Iterate over all StoreIds for one module name
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();
@ -510,7 +479,7 @@ impl Store {
debug!("glob()ing with '{}'", path); debug!("glob()ing with '{}'", path);
glob(&path[..]).map_err_into(SEK::GlobError) glob(&path[..]).map_err_into(SEK::GlobError)
}) })
.map(|paths| GlobStoreIdIterator::new(paths).into()) .map(|paths| GlobStoreIdIterator::new(paths, self.path().clone()).into())
.map_err_into(SEK::GlobError) .map_err_into(SEK::GlobError)
.map_err_into(SEK::RetrieveForModuleCallError) .map_err_into(SEK::RetrieveForModuleCallError)
} }
@ -567,7 +536,7 @@ 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
pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> { pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
let id = id.into_storeid().storified(self); let id = try!(id.into_storeid()).with_base(self.path().clone());
let entries = match self.entries.write() { let entries = match self.entries.write() {
Err(_) => { Err(_) => {
return Err(SE::new(SEK::LockPoisoned, None)) return Err(SE::new(SEK::LockPoisoned, None))
@ -586,7 +555,7 @@ impl Store {
/// Delete an entry /// Delete an entry
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> { pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
let id = id.into_storeid().storified(self); 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) {
return Err(e) return Err(e)
.map_err_into(SEK::PreHookExecuteError) .map_err_into(SEK::PreHookExecuteError)
@ -609,7 +578,7 @@ impl Store {
// remove the entry first, then the file // remove the entry first, then the file
entries.remove(&id); entries.remove(&id);
if let Err(e) = FileAbstraction::remove_file(&id) { if let Err(e) = FileAbstraction::remove_file(&id.clone().into()) {
return Err(SEK::FileError.into_error_with_cause(Box::new(e))) return Err(SEK::FileError.into_error_with_cause(Box::new(e)))
.map_err_into(SEK::DeleteCallError); .map_err_into(SEK::DeleteCallError);
} }
@ -637,7 +606,7 @@ impl Store {
fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool) fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool)
-> Result<()> -> Result<()>
{ {
let new_id = new_id.storified(self); let new_id = new_id.with_base(self.path().clone());
let hsmap = self.entries.write(); let hsmap = self.entries.write();
if hsmap.is_err() { if hsmap.is_err() {
return Err(SE::new(SEK::LockPoisoned, None)).map_err_into(SEK::MoveCallError) return Err(SE::new(SEK::LockPoisoned, None)).map_err_into(SEK::MoveCallError)
@ -666,8 +635,8 @@ impl Store {
/// Move an entry without loading /// Move an entry without loading
pub fn move_by_id(&self, old_id: StoreId, new_id: StoreId) -> Result<()> { pub fn move_by_id(&self, old_id: StoreId, new_id: StoreId) -> Result<()> {
let new_id = new_id.storified(self); let new_id = new_id.with_base(self.path().clone());
let old_id = old_id.storified(self); let old_id = old_id.with_base(self.path().clone());
if let Err(e) = self.execute_hooks_for_id(self.pre_move_aspects.clone(), &old_id) { if let Err(e) = self.execute_hooks_for_id(self.pre_move_aspects.clone(), &old_id) {
return Err(e) return Err(e)
@ -677,15 +646,17 @@ impl Store {
} }
{ {
let hsmap = self.entries.write(); let hsmap = match self.entries.write() {
if hsmap.is_err() { Err(_) => return Err(SE::new(SEK::LockPoisoned, None)),
return Err(SE::new(SEK::LockPoisoned, None)) Ok(m) => m,
} };
let hsmap = hsmap.unwrap();
if hsmap.contains_key(&old_id) { if hsmap.contains_key(&old_id) {
return Err(SE::new(SEK::EntryAlreadyBorrowed, None)); return Err(SE::new(SEK::EntryAlreadyBorrowed, None));
} else { } else {
match FileAbstraction::rename(&old_id.clone(), &new_id) { let old_id_pb = old_id.clone().into();
let new_id_pb = new_id.clone().into();
match FileAbstraction::rename(&old_id_pb, &new_id_pb) {
Err(e) => return Err(SEK::EntryRenameError.into_error_with_cause(Box::new(e))), Err(e) => return Err(SEK::EntryRenameError.into_error_with_cause(Box::new(e))),
Ok(_) => { Ok(_) => {
debug!("Rename worked"); debug!("Rename worked");
@ -831,11 +802,19 @@ impl Drop for Store {
* TODO: Unlock them * TODO: Unlock them
*/ */
fn drop(&mut self) { fn drop(&mut self) {
let store_id = StoreId::from(self.location.clone()); match StoreId::new(Some(self.location.clone()), PathBuf::from(".")) {
Err(e) => {
trace_error(&e);
warn!("Cannot construct StoreId for Store to execute hooks!");
warn!("Will close Store without executing hooks!");
},
Ok(store_id) => {
if let Err(e) = self.execute_hooks_for_id(self.store_unload_aspects.clone(), &store_id) { if let Err(e) = self.execute_hooks_for_id(self.store_unload_aspects.clone(), &store_id) {
debug!("Store-load hooks execution failed. Cannot create store object."); debug!("Store-load hooks execution failed. Cannot create store object.");
warn!("Store Unload Hook error: {:?}", e); warn!("Store Unload Hook error: {:?}", e);
} }
},
};
debug!("Dropping store"); debug!("Dropping store");
} }
@ -1449,7 +1428,7 @@ impl Entry {
debug!("Header and content found. Yay! Building Entry object now"); debug!("Header and content found. Yay! Building Entry object now");
Ok(Entry { Ok(Entry {
location: loc.into_storeid(), location: try!(loc.into_storeid()),
header: try!(EntryHeader::parse(header)), header: try!(EntryHeader::parse(header)),
content: content.into(), content: content.into(),
}) })
@ -1490,11 +1469,18 @@ impl Entry {
mod glob_store_iter { mod glob_store_iter {
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::fmt::Error as FmtError; use std::fmt::Error as FmtError;
use std::path::PathBuf;
use glob::Paths; use glob::Paths;
use storeid::StoreId; use storeid::StoreId;
use storeid::StoreIdIterator; use storeid::StoreIdIterator;
use error::StoreErrorKind as SEK;
use error::MapErrInto;
use libimagerror::trace::trace_error;
pub struct GlobStoreIdIterator { pub struct GlobStoreIdIterator {
store_path: PathBuf,
paths: Paths, paths: Paths,
} }
@ -1516,8 +1502,9 @@ mod glob_store_iter {
impl GlobStoreIdIterator { impl GlobStoreIdIterator {
pub fn new(paths: Paths) -> GlobStoreIdIterator { pub fn new(paths: Paths, store_path: PathBuf) -> GlobStoreIdIterator {
GlobStoreIdIterator { GlobStoreIdIterator {
store_path: store_path,
paths: paths, paths: paths,
} }
} }
@ -1528,15 +1515,16 @@ mod glob_store_iter {
type Item = StoreId; type Item = StoreId;
fn next(&mut self) -> Option<StoreId> { fn next(&mut self) -> Option<StoreId> {
self.paths.next().and_then(|o| { self.paths
match o { .next()
Ok(o) => Some(o), .and_then(|o| {
Err(e) => { o.map_err_into(SEK::StoreIdHandlingError)
.and_then(|p| StoreId::new(Some(self.store_path.clone()), p))
.map_err(|e| {
debug!("GlobStoreIdIterator error: {:?}", e); debug!("GlobStoreIdIterator error: {:?}", e);
None trace_error(&e);
}, }).ok()
} })
}).map(|p| StoreId::from(p))
} }
} }
@ -1551,6 +1539,7 @@ mod test {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use super::EntryHeader; use super::EntryHeader;
use super::Token; use super::Token;
use storeid::StoreId;
use toml::Value; use toml::Value;
@ -1681,7 +1670,7 @@ Hai";
use super::Entry; use super::Entry;
use std::path::PathBuf; use std::path::PathBuf;
println!("{}", TEST_ENTRY); println!("{}", TEST_ENTRY);
let entry = Entry::from_str(PathBuf::from("/test/foo~1.3"), let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
TEST_ENTRY).unwrap(); TEST_ENTRY).unwrap();
assert_eq!(entry.content, "Hai"); assert_eq!(entry.content, "Hai");
@ -1692,7 +1681,7 @@ Hai";
use super::Entry; use super::Entry;
use std::path::PathBuf; use std::path::PathBuf;
println!("{}", TEST_ENTRY); println!("{}", TEST_ENTRY);
let entry = Entry::from_str(PathBuf::from("/test/foo~1.3"), let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
TEST_ENTRY).unwrap(); TEST_ENTRY).unwrap();
let string = entry.to_str(); let string = entry.to_str();

View file

@ -1,12 +1,11 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;
use semver::Version;
use std::fmt::{Display, Debug, Formatter}; use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError; use std::fmt::Error as FmtError;
use std::result::Result as RResult; use std::result::Result as RResult;
use std::path::Components;
use libimagerror::into::IntoError;
use error::StoreErrorKind as SEK; use error::StoreErrorKind as SEK;
use store::Result; use store::Result;
@ -14,21 +13,82 @@ use store::Store;
/// The Index into the Store /// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId(PathBuf); pub struct StoreId {
base: Option<PathBuf>,
id: PathBuf,
}
impl StoreId { impl StoreId {
pub fn storified(self, store: &Store) -> StoreId { pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
if self.starts_with(store.path()) { StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
debug!("Not storifying {:?}, because it is already.", self);
self
} else {
debug!("Create new store id out of: {:?} and {:?}", store.path(), self);
let mut new_id = store.path().clone();
new_id.push(self);
debug!("Created: '{:?}'", new_id);
StoreId::from(new_id)
} }
pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
if id.is_absolute() {
Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
} else {
Ok(StoreId {
base: None,
id: id
})
}
}
pub fn without_base(mut self) -> StoreId {
self.base = None;
self
}
pub fn with_base(mut self, base: PathBuf) -> Self {
self.base = Some(base);
self
}
pub fn storified(self, store: &Store) -> StoreId {
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
}
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())
}
/// Returns the components of the `id` part of the StoreId object.
///
/// Can be used to check whether a StoreId points to an entry in a specific collection of
/// StoreIds.
pub fn components(&self) -> Components {
self.id.components()
}
/// Get the _local_ part of a StoreId object, as in "the part from the store root to the entry".
pub fn local(&self) -> &PathBuf {
&self.id
} }
} }
@ -36,7 +96,9 @@ impl StoreId {
impl Into<PathBuf> for StoreId { impl Into<PathBuf> for StoreId {
fn into(self) -> PathBuf { fn into(self) -> PathBuf {
self.0 let mut base = self.base.unwrap_or(PathBuf::from("/"));
base.push(self.id);
base
} }
} }
@ -44,97 +106,35 @@ impl Into<PathBuf> for StoreId {
impl Display for StoreId { impl Display for StoreId {
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> { fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
match self.0.to_str() { match self.id.to_str() {
Some(s) => write!(fmt, "{}", s), Some(s) => write!(fmt, "{}", s),
None => write!(fmt, "{}", self.0.to_string_lossy()), None => write!(fmt, "{}", self.id.to_string_lossy()),
} }
} }
} }
impl Deref for StoreId {
type Target = PathBuf;
fn deref(&self) -> &PathBuf {
&self.0
}
}
impl From<PathBuf> for StoreId {
fn from(pb: PathBuf) -> StoreId {
StoreId(pb)
}
}
impl From<String> for StoreId {
fn from(string: String) -> StoreId {
StoreId(string.into())
}
}
impl AsRef<Path> for StoreId {
fn as_ref(&self) -> &Path {
self.0.as_ref()
}
}
impl Borrow<Path> for StoreId {
fn borrow(&self) -> &Path {
self.0.borrow()
}
}
/// This Trait allows you to convert various representations to a single one /// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store /// suitable for usage in the Store
pub trait IntoStoreId { pub trait IntoStoreId {
fn into_storeid(self) -> StoreId; fn into_storeid(self) -> Result<StoreId>;
}
impl IntoStoreId for PathBuf {
fn into_storeid(self) -> StoreId {
StoreId(self)
}
} }
impl IntoStoreId for StoreId { impl IntoStoreId for StoreId {
fn into_storeid(self) -> StoreId { fn into_storeid(self) -> Result<StoreId> {
self Ok(self)
} }
} }
pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> { impl IntoStoreId for PathBuf {
debug!("Checking path element for version"); fn into_storeid(self) -> Result<StoreId> {
if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) { StoreId::new_baseless(self)
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_export]
macro_rules! module_entry_path_mod { macro_rules! module_entry_path_mod {
($name:expr, $version:expr) => ( ($name:expr) => (
#[deny(missing_docs, #[deny(missing_docs,
missing_copy_implementations, missing_copy_implementations,
trivial_casts, trivial_numeric_casts, trivial_casts, trivial_numeric_casts,
@ -144,12 +144,12 @@ macro_rules! module_entry_path_mod {
unused_imports)] unused_imports)]
/// A helper module to create valid module entry paths /// A helper module to create valid module entry paths
pub mod module_path { pub mod module_path {
use semver::Version;
use std::convert::AsRef; use std::convert::AsRef;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use $crate::storeid::StoreId; use $crate::storeid::StoreId;
use $crate::store::Result;
/// A Struct giving you the ability to choose store entries assigned /// A Struct giving you the ability to choose store entries assigned
/// to it. /// to it.
@ -163,19 +163,16 @@ macro_rules! module_entry_path_mod {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
path.push(format!("{}", $name)); path.push(format!("{}", $name));
path.push(pa.as_ref().clone()); path.push(pa.as_ref().clone());
let version = Version::parse($version).unwrap();
let name = pa.as_ref().file_name().unwrap() let name = pa.as_ref().file_name().unwrap()
.to_str().unwrap(); .to_str().unwrap();
path.set_file_name(format!("{}~{}", path.set_file_name(name);
name,
version));
ModuleEntryPath(path) ModuleEntryPath(path)
} }
} }
impl $crate::storeid::IntoStoreId for ModuleEntryPath { impl $crate::storeid::IntoStoreId for ModuleEntryPath {
fn into_storeid(self) -> $crate::storeid::StoreId { fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
StoreId::from(self.0) StoreId::new(None, self.0)
} }
} }
} }
@ -218,13 +215,13 @@ mod test {
use storeid::IntoStoreId; use storeid::IntoStoreId;
module_entry_path_mod!("test", "0.2.0-alpha+leet1337"); module_entry_path_mod!("test");
#[test] #[test]
fn correct_path() { fn correct_path() {
let p = module_path::ModuleEntryPath::new("test"); let p = module_path::ModuleEntryPath::new("test");
assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337"); assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
} }
} }

View file

@ -18,27 +18,23 @@ use libimagstore::store::FileLockEntry;
use libimagstore::store::Entry; use libimagstore::store::Entry;
trait EntryFlock { trait EntryFlock {
fn lock(&self, store_location: &PathBuf) -> IoResult<()>; fn lock(&self) -> IoResult<()>;
fn unlock(&self, store_location: &PathBuf) -> IoResult<()>; fn unlock(&self) -> IoResult<()>;
} }
impl EntryFlock for Entry { impl EntryFlock for Entry {
fn lock(&self, store_location: &PathBuf) -> IoResult<()> { fn lock(&self) -> IoResult<()> {
use std::fs::File; use std::fs::File;
let mut location = store_location.clone(); let location : PathBuf = self.get_location().clone().into();
location.push(self.get_location());
File::open(location).and_then(|file| file.lock_exclusive()) File::open(location).and_then(|file| file.lock_exclusive())
} }
fn unlock(&self, store_location: &PathBuf) -> IoResult<()> { fn unlock(&self) -> IoResult<()> {
use std::fs::File; use std::fs::File;
let mut location = store_location.clone(); let location : PathBuf = self.get_location().clone().into();
location.push(self.get_location());
File::open(location).and_then(|file| file.unlock()) File::open(location).and_then(|file| file.unlock())
} }
@ -60,15 +56,13 @@ fn action_to_str(a: &Action) -> &'static str {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FlockUpdateHook { pub struct FlockUpdateHook {
action: Action, action: Action,
store_location: PathBuf,
} }
impl FlockUpdateHook { impl FlockUpdateHook {
pub fn new(action: Action, store_location: PathBuf) -> FlockUpdateHook { pub fn new(action: Action) -> FlockUpdateHook {
FlockUpdateHook { FlockUpdateHook {
action: action, action: action,
store_location: store_location,
} }
} }
@ -107,7 +101,7 @@ impl MutableHookDataAccessor for FlockUpdateHook {
fn access_mut(&self, fle: &mut FileLockEntry) -> HookResult<()> { fn access_mut(&self, fle: &mut FileLockEntry) -> HookResult<()> {
debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), fle.get_location()); debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), fle.get_location());
fle.lock(&self.store_location) fle.lock()
.map_err(|e| HookError::new(HookErrorKind::HookExecutionError, Some(Box::new(e)))) .map_err(|e| HookError::new(HookErrorKind::HookExecutionError, Some(Box::new(e))))
.map(|_| ()) .map(|_| ())
} }
@ -118,7 +112,7 @@ impl NonMutableHookDataAccessor for FlockUpdateHook {
fn access(&self, fle: &FileLockEntry) -> HookResult<()> { fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), fle.get_location()); debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), fle.get_location());
fle.unlock(&self.store_location) fle.unlock()
.map_err(|e| HookError::new(HookErrorKind::HookExecutionError, Some(Box::new(e)))) .map_err(|e| HookError::new(HookErrorKind::HookExecutionError, Some(Box::new(e))))
.map(|_| ()) .map(|_| ())
} }

View file

@ -53,12 +53,10 @@ impl NonMutableHookDataAccessor for LinkedEntriesExistHook {
let _ = fle.get_internal_links() let _ = fle.get_internal_links()
.map(|links| { .map(|links| {
for link in links { for link in links {
let mut path = self.store_location.clone(); if !link.exists() {
path.push(link); warn!("File link does not exist: {:?} -> {:?}", fle.get_location(), link);
if !path.exists() { } else if !link.is_file() {
warn!("File link does not exist: {:?} -> {:?}", fle.get_location(), path); warn!("File link is not a file: {:?} -> {:?}", fle.get_location(), link);
} else if !path.is_file() {
warn!("File link is not a file: {:?} -> {:?}", fle.get_location(), path);
} }
} }
}) })

View file

@ -2,6 +2,7 @@ generate_error_module!(
generate_error_types!(TodoError, TodoErrorKind, generate_error_types!(TodoError, TodoErrorKind,
ConversionError => "Conversion Error", ConversionError => "Conversion Error",
StoreError => "Store Error", StoreError => "Store Error",
StoreIdError => "Store Id handling error",
ImportError => "Error importing" ImportError => "Error importing"
); );
); );

View file

@ -22,7 +22,7 @@ extern crate serde_json;
#[macro_use] extern crate libimagerror; #[macro_use] extern crate libimagerror;
extern crate task_hookrs; extern crate task_hookrs;
module_entry_path_mod!("todo", "0.1.0"); module_entry_path_mod!("todo");
pub mod error; pub mod error;
pub mod result; pub mod result;

View file

@ -73,9 +73,9 @@ impl<'a> Task<'a> {
/// ///
/// If there is no task with this UUID, this returns `Ok(None)`. /// If there is no task with this UUID, this returns `Ok(None)`.
pub fn get_from_uuid(store: &'a Store, uuid: Uuid) -> Result<Option<Task<'a>>> { pub fn get_from_uuid(store: &'a Store, uuid: Uuid) -> Result<Option<Task<'a>>> {
let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid(); ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
.into_storeid()
store.get(store_id) .and_then(|store_id| store.get(store_id))
.map(|o| o.map(Task::new)) .map(|o| o.map(Task::new))
.map_err_into(TodoErrorKind::StoreError) .map_err_into(TodoErrorKind::StoreError)
} }
@ -138,7 +138,9 @@ impl<'a> Task<'a> {
} }
pub fn delete_by_uuid(store: &Store, uuid: Uuid) -> Result<()> { pub fn delete_by_uuid(store: &Store, uuid: Uuid) -> Result<()> {
store.delete(ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid()) ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
.into_storeid()
.and_then(|id| store.delete(id))
.map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))) .map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
} }
@ -196,34 +198,30 @@ impl<'a> IntoTask<'a> for TTask {
fn into_task(self, store : &'a Store) -> Result<Task<'a>> { fn into_task(self, store : &'a Store) -> Result<Task<'a>> {
let uuid = self.uuid(); let uuid = self.uuid();
let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid(); ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
.into_storeid()
match store.retrieve(store_id) { .map_err_into(TodoErrorKind::StoreIdError)
Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))), .and_then(|id| {
Ok(mut fle) => { store.retrieve(id)
.map_err_into(TodoErrorKind::StoreError)
.and_then(|mut fle| {
{ {
let mut header = fle.get_header_mut(); let mut hdr = fle.get_header_mut();
match header.read("todo") { let read = hdr.read("todo").map_err_into(TodoErrorKind::StoreError);
Ok(None) => { if try!(read).is_none() {
if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) { try!(hdr
return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))) .set("todo", Value::Table(BTreeMap::new()))
} .map_err_into(TodoErrorKind::StoreError));
}
Ok(Some(_)) => { }
Err(e) => {
return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
}
} }
if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) { try!(hdr.set("todo.uuid", Value::String(format!("{}",uuid)))
return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))) .map_err_into(TodoErrorKind::StoreError));
}
} }
// If none of the errors above have returned the function, everything is fine // If none of the errors above have returned the function, everything is fine
Ok(Task::new(fle)) Ok(Task::new(fle))
} })
} })
} }
} }