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;
38extern crate clap;
39#[macro_use] extern crate failure;
40
41extern crate libimagstore;
42extern crate libimagrt;
43extern crate libimagentryref;
44extern crate libimagerror;
45extern crate libimaginteraction;
46extern crate libimagutil;
47
48mod ui;
49
50use std::io::Write;
51
52use failure::Fallible as Result;
53use failure::Error;
54use failure::err_msg;
55use clap::App;
56
57use libimagrt::application::ImagApplication;
58use libimagrt::runtime::Runtime;
59use libimagentryref::reference::Ref;
60use libimagentryref::reference::RefFassade;
61use libimagentryref::hasher::default::DefaultHasher;
62use libimagentryref::util::get_ref_config;
63use libimagentryref::reference::MutRef;
64
65pub enum ImagRef {}
70impl ImagApplication for ImagRef {
71 fn run(rt: Runtime) -> Result<()> {
72 if let Some(name) = rt.cli().subcommand_name() {
73 debug!("Call: {}", name);
74 match name {
75 "deref" => deref(&rt),
76 "create" => create(&rt),
77 "remove" => remove(&rt),
78 "list-dead" => list_dead(&rt),
79 other => {
80 debug!("Unknown command");
81 if rt.handle_unknown_subcommand("imag-ref", other, rt.cli())?.success() {
82 Ok(())
83 } else {
84 Err(format_err!("Subcommand failed"))
85 }
86 },
87 }
88 } else {
89 Ok(())
90 }
91 }
92
93 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
94 ui::build_ui(app)
95 }
96
97 fn name() -> &'static str {
98 env!("CARGO_PKG_NAME")
99 }
100
101 fn description() -> &'static str {
102 "Reference files outside of the store"
103 }
104
105 fn version() -> &'static str {
106 env!("CARGO_PKG_VERSION")
107 }
108}
109
110fn deref(rt: &Runtime) -> Result<()> {
111 let cmd = rt.cli().subcommand_matches("deref").unwrap();
112 let basepath = cmd.value_of("override-basepath");
113 let cfg = get_ref_config(&rt, "imag-ref")?;
114 let out = rt.stdout();
115 let mut outlock = out.lock();
116
117 rt.ids::<::ui::PathProvider>()?
118 .ok_or_else(|| err_msg("No ids supplied"))?
119 .into_iter()
120 .map(|id| {
121 match rt.store().get(id.clone())? {
122 Some(entry) => {
123 let r_entry = entry.as_ref_with_hasher::<DefaultHasher>();
124
125 if let Some(alternative_basepath) = basepath {
126 r_entry.get_path_with_basepath_setting(&cfg, alternative_basepath)
127 } else {
128 r_entry.get_path(&cfg)
129 }?
130 .to_str()
131 .ok_or_else(|| Error::from(::libimagerror::errors::ErrorMsg::UTF8Error))
132 .and_then(|s| writeln!(outlock, "{}", s).map_err(Error::from))?;
133
134 rt.report_touched(&id)
135 },
136 None => Err(format_err!("No entry for id '{}' found", id))
137 }
138 })
139 .collect()
140}
141
142fn remove(rt: &Runtime) -> Result<()> {
143 use libimaginteraction::ask::ask_bool;
144
145 let cmd = rt.cli().subcommand_matches("remove").unwrap();
146 let yes = cmd.is_present("yes");
147 let mut input = rt.stdin().ok_or_else(|| err_msg("No input stream. Cannot ask for permission"))?;
148 let mut output = rt.stdout();
149
150 rt.ids::<::ui::PathProvider>()?
151 .ok_or_else(|| err_msg("No ids supplied"))?
152 .into_iter()
153 .map(|id| {
154 match rt.store().get(id.clone())? {
155 None => Err(format_err!("No entry for id '{}' found", id)),
156 Some(mut entry) => {
157 if yes || ask_bool(&format!("Delete ref from entry '{}'", id), None, &mut input, &mut output)? {
158 entry.as_ref_with_hasher_mut::<DefaultHasher>().remove_ref()
159 } else {
160 info!("Aborted");
161 Ok(())
162 }
163 },
164 }
165 })
166 .collect()
167}
168
169fn list_dead(rt: &Runtime) -> Result<()> {
170 let cfg = get_ref_config(&rt, "imag-ref")?;
171 let cmd = rt.cli().subcommand_matches("list-dead").unwrap(); let list_path = cmd.is_present("list-dead-pathes");
173 let list_id = cmd.is_present("list-dead-ids");
174 let mut output = rt.stdout();
175
176 rt.ids::<crate::ui::PathProvider>()?
177 .ok_or_else(|| err_msg("No ids supplied"))?
178 .into_iter()
179 .map(|id| {
180 match rt.store().get(id.clone())? {
181 Some(entry) => {
182 let entry_ref = entry.as_ref_with_hasher::<DefaultHasher>();
183
184 if entry_ref.is_ref()? { let entry_path = entry_ref.get_path(&cfg)?;
186
187 if !entry_path.exists() {
188 if list_id {
189 writeln!(output, "{}", entry.get_location().local().display())
190 } else if list_path {
191 writeln!(output, "{}", entry_path.display())
192 } else {
193 unimplemented!()
194 }?;
195
196 rt.report_touched(entry.get_location())
197 } else {
198 Ok(())
199 }
200 } else {
201 Ok(())
202 }
203 }
204
205 None => Err(format_err!("Does not exist: {}", id.local().display())),
206 }
207 })
208 .collect()
209}
210
211fn create(_rt: &Runtime) -> Result<()> {
212 unimplemented!()
213}
214