1#![forbid(unsafe_code)]
21
22#![deny(
23 non_camel_case_types,
24 non_snake_case,
25 path_statements,
26 trivial_numeric_casts,
27 unstable_features,
28 unused_allocation,
29 unused_import_braces,
30 unused_imports,
31 unused_must_use,
32 unused_mut,
33 unused_qualifications,
34 while_true,
35)]
36
37#[macro_use] extern crate log;
38#[macro_use] extern crate failure;
39extern crate resiter;
40extern crate clap;
41
42extern crate libimagrt;
43extern crate libimagstore;
44extern crate libimagerror;
45extern crate libimagentrylink;
46
47mod ui;
48
49use std::path::PathBuf;
50
51use libimagrt::runtime::Runtime;
52use libimagrt::application::ImagApplication;
53use libimagstore::storeid::StoreId;
54use libimagstore::store::Store;
55use libimagstore::store::FileLockEntry;
56use libimagentrylink::linkable::Linkable;
57use libimagstore::iter::get::StoreIdGetIteratorExtension;
58
59use failure::Fallible as Result;
60use failure::err_msg;
61use resiter::IterInnerOkOrElse;
62use clap::App;
63
64
65pub enum ImagMv {}
70impl ImagApplication for ImagMv {
71 fn run(rt: Runtime) -> Result<()> {
72 let sourcename = rt
73 .cli()
74 .value_of("source")
75 .map(PathBuf::from)
76 .map(StoreId::new)
77 .unwrap()?; let destname = rt
80 .cli()
81 .value_of("dest")
82 .map(PathBuf::from)
83 .map(StoreId::new)
84 .unwrap()?; let mut linked_entries = rt.store()
88 .get(sourcename.clone())?
89 .ok_or_else(|| format_err!("Entry does not exist: {}", sourcename))?
90 .links()?
91 .map(|link| link.get_store_id().clone())
92 .map(Ok)
93 .into_get_iter(rt.store())
94 .map_inner_ok_or_else(|| err_msg("Linked entry does not exist"))
95 .collect::<Result<Vec<_>>>()?;
96
97 { let mut entry = rt
99 .store()
100 .get(sourcename.clone())?
101 .ok_or_else(|| err_msg("Source Entry does not exist"))?;
102
103 for link in linked_entries.iter_mut() {
104 entry.remove_link(link)?;
105 }
106 }
107
108 if let Err(e) = rt.store().move_by_id(sourcename.clone(), destname.clone()) {
109 debug!("Re-adding links to source entry because moving failed");
110 relink(rt.store(), sourcename, &mut linked_entries)?;
111
112 return Err(e);
113 }
114
115 rt.report_touched(&destname)?;
116
117 relink(rt.store(), destname, &mut linked_entries)?;
119
120 info!("Ok.");
121 Ok(())
122 }
123
124 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
125 ui::build_ui(app)
126 }
127
128 fn name() -> &'static str {
129 env!("CARGO_PKG_NAME")
130 }
131
132 fn description() -> &'static str {
133 "Move things around in the store"
134 }
135
136 fn version() -> &'static str {
137 env!("CARGO_PKG_VERSION")
138 }
139}
140
141
142
143fn relink<'a>(store: &'a Store, target: StoreId, linked_entries: &mut Vec<FileLockEntry<'a>>) -> Result<()> {
144 let mut entry = store
145 .get(target)?
146 .ok_or_else(|| err_msg("Funny things happened: Entry moved to destination did not fail, but entry does not exist"))?;
147
148 linked_entries
149 .iter_mut()
150 .map(|mut link| entry.add_link(&mut link))
151 .collect::<Result<Vec<_>>>()
152 .map(|_| ())
153}
154