From 39107c529636d5f04d3eb7b2d9ab1f837633b33b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 17:10:45 +0100 Subject: [PATCH 01/22] Add result extension for translating io errors to exit codes --- lib/core/libimagerror/src/io.rs | 65 ++++++++++++++++++++++++++++++++ lib/core/libimagerror/src/lib.rs | 1 + 2 files changed, 66 insertions(+) create mode 100644 lib/core/libimagerror/src/io.rs diff --git a/lib/core/libimagerror/src/io.rs b/lib/core/libimagerror/src/io.rs new file mode 100644 index 00000000..3b9e74b9 --- /dev/null +++ b/lib/core/libimagerror/src/io.rs @@ -0,0 +1,65 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 the imag contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::io::ErrorKind; + +use trace::MapErrTrace; + +pub enum Settings { + Ignore(ErrorKind), + IgnoreAny(Vec), +} + +pub trait ToExitCode : MapErrTrace { + fn to_exit_code(self) -> i32; + fn to_exit_code_with(self, Settings) -> i32; +} + +impl ToExitCode for Result { + + /// Returns an exit code of 0 if the error was a broken pipe, else 1 + fn to_exit_code(self) -> { + self.to_exit_code_with(Settings::ErrorOn(ErrorKind::BrokenPipe)) + } + + /// Returns an exit code depending on the settings + /// + /// Via the settings, errors can be ignores (translates to exit code zero). All other errors + /// are translated into exit code 1 + /// + fn to_exit_code_with(self, settings: Settings) -> i32 { + if let Err(e) = self { + match settings { + Ignore(kind) => if e.kind() == kind { + 0 + } else { + 1 + }, + IgnoreAny(v) => if v.iter().any(|e| e == e.kind()) { + 0 + } else { + 1 + }, + } + } else { + 0 + } + } + +} diff --git a/lib/core/libimagerror/src/lib.rs b/lib/core/libimagerror/src/lib.rs index 204250ac..a09c347c 100644 --- a/lib/core/libimagerror/src/lib.rs +++ b/lib/core/libimagerror/src/lib.rs @@ -37,6 +37,7 @@ extern crate ansi_term; extern crate error_chain; +pub mod io; pub mod trace; pub mod iter; pub mod str; From 256bc47222df84a04895bce496d7edb588d992e0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 17:22:15 +0100 Subject: [PATCH 02/22] Refactor into two independent extensions --- lib/core/libimagerror/src/exit.rs | 29 ++++++++++++++++++++ lib/core/libimagerror/src/io.rs | 44 +++++++++++++------------------ lib/core/libimagerror/src/lib.rs | 1 + 3 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 lib/core/libimagerror/src/exit.rs diff --git a/lib/core/libimagerror/src/exit.rs b/lib/core/libimagerror/src/exit.rs new file mode 100644 index 00000000..6af8773d --- /dev/null +++ b/lib/core/libimagerror/src/exit.rs @@ -0,0 +1,29 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 the imag contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +pub trait ExitUnwrap { + fn unwrap_or_exit(self) -> T; +} + +impl ExitUnwrap for Result { + fn unwrap_or_exit(self) -> T { + self.unwrap_or_else(|e| ::std::process::exit(e)) + } +} + diff --git a/lib/core/libimagerror/src/io.rs b/lib/core/libimagerror/src/io.rs index 3b9e74b9..ac648427 100644 --- a/lib/core/libimagerror/src/io.rs +++ b/lib/core/libimagerror/src/io.rs @@ -19,23 +19,21 @@ use std::io::ErrorKind; -use trace::MapErrTrace; - pub enum Settings { Ignore(ErrorKind), IgnoreAny(Vec), } -pub trait ToExitCode : MapErrTrace { - fn to_exit_code(self) -> i32; - fn to_exit_code_with(self, Settings) -> i32; +pub trait ToExitCode { + fn to_exit_code(self) -> Result; + fn to_exit_code_with(self, Settings) -> Result; } -impl ToExitCode for Result { +impl ToExitCode for Result { /// Returns an exit code of 0 if the error was a broken pipe, else 1 - fn to_exit_code(self) -> { - self.to_exit_code_with(Settings::ErrorOn(ErrorKind::BrokenPipe)) + fn to_exit_code(self) -> Result { + self.to_exit_code_with(Settings::Ignore(ErrorKind::BrokenPipe)) } /// Returns an exit code depending on the settings @@ -43,23 +41,19 @@ impl ToExitCode for Result { /// Via the settings, errors can be ignores (translates to exit code zero). All other errors /// are translated into exit code 1 /// - fn to_exit_code_with(self, settings: Settings) -> i32 { - if let Err(e) = self { - match settings { - Ignore(kind) => if e.kind() == kind { - 0 - } else { - 1 - }, - IgnoreAny(v) => if v.iter().any(|e| e == e.kind()) { - 0 - } else { - 1 - }, - } - } else { - 0 - } + fn to_exit_code_with(self, settings: Settings) -> Result { + self.map_err(move |e| match settings { + Settings::Ignore(kind) => if e.kind() == kind { + 0 + } else { + 1 + }, + Settings::IgnoreAny(v) => if v.iter().any(|el| e.kind() == *el) { + 0 + } else { + 1 + }, + }) } } diff --git a/lib/core/libimagerror/src/lib.rs b/lib/core/libimagerror/src/lib.rs index a09c347c..a17aa21e 100644 --- a/lib/core/libimagerror/src/lib.rs +++ b/lib/core/libimagerror/src/lib.rs @@ -38,6 +38,7 @@ extern crate ansi_term; extern crate error_chain; pub mod io; +pub mod exit; pub mod trace; pub mod iter; pub mod str; From 88d21375b9bd10c3d4e4a3a9203ec697a0f398a5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 17:27:54 +0100 Subject: [PATCH 03/22] Refactor "imag store ids" command to not panic on broken pipe --- bin/core/imag-store/src/ids.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/core/imag-store/src/ids.rs b/bin/core/imag-store/src/ids.rs index 02b79602..d64659c8 100644 --- a/bin/core/imag-store/src/ids.rs +++ b/bin/core/imag-store/src/ids.rs @@ -17,14 +17,18 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::io::Write; + use libimagrt::runtime::Runtime; use libimagerror::trace::*; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; pub fn ids(rt: &Runtime) { let full = rt.cli().subcommand_matches("ids").unwrap() //secured by main .is_present("full"); let base = rt.store().path(); - let _ :Vec<_> = rt + let _ = rt .store() .entries() .map_err_trace_exit_unwrap(1) @@ -35,7 +39,9 @@ pub fn ids(rt: &Runtime) { }) .map(|i| i.to_str()) .map(|elem| elem.map_err_trace_exit_unwrap(1)) - .map(|i| println!("{}", i)) - .collect(); + .map(|i| writeln!(::std::io::stdout(), "{}", i)) + .collect::, ::std::io::Error>>() + .to_exit_code() + .unwrap_or_exit(); } From 013fc75d85f8e356fb7f76f659bf39ee19b9e949 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:00:34 +0100 Subject: [PATCH 04/22] Fix output for broken pipe errors --- bin/domain/imag-log/src/main.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/bin/domain/imag-log/src/main.rs b/bin/domain/imag-log/src/main.rs index 66a34add..c3f80017 100644 --- a/bin/domain/imag-log/src/main.rs +++ b/bin/domain/imag-log/src/main.rs @@ -43,9 +43,13 @@ extern crate libimaglog; extern crate libimagerror; extern crate libimagdiary; +use std::io::Write; + use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; use libimagdiary::diary::Diary; use libimaglog::log::Log; use libimaglog::error::LogError as LE; @@ -117,26 +121,28 @@ fn show(rt: &Runtime) { }; for iter in iters { - for element in iter { + let _ = iter.map(|element| { let e = element.map_err_trace_exit_unwrap(1); if !e.is_log().map_err_trace_exit_unwrap(1) { - continue; + return Ok(()); } let id = e.diary_id().map_err_trace_exit_unwrap(1); - println!("{dname: >10} - {y: >4}-{m:0>2}-{d:0>2}T{H:0>2}:{M:0>2} - {text}", + writeln!(::std::io::stdout(), + "{dname: >10} - {y: >4}-{m:0>2}-{d:0>2}T{H:0>2}:{M:0>2} - {text}", dname = id.diary_name(), y = id.year(), m = id.month(), d = id.day(), H = id.hour(), M = id.minute(), - text = e.get_content()); - } + text = e.get_content()) + .to_exit_code() + }) + .collect::>() + .unwrap_or_exit(); } - - info!("Ready."); } fn get_diary_name(rt: &Runtime) -> String { From eb2f6fbbe2ef0264a31e480eb5229192245af33a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:03:01 +0100 Subject: [PATCH 05/22] Fix for broken pipe errors --- bin/domain/imag-contact/src/main.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/domain/imag-contact/src/main.rs b/bin/domain/imag-contact/src/main.rs index 502b41b0..c2785901 100644 --- a/bin/domain/imag-contact/src/main.rs +++ b/bin/domain/imag-contact/src/main.rs @@ -52,6 +52,7 @@ extern crate libimagentryedit; use std::process::exit; use std::path::PathBuf; +use std::io::Write; use handlebars::Handlebars; use clap::ArgMatches; @@ -63,6 +64,8 @@ use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagerror::str::ErrFromStr; use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; use libimagcontact::store::ContactStore; use libimagcontact::error::ContactError as CE; use libimagcontact::contact::Contact; @@ -105,6 +108,7 @@ fn main() { fn list(rt: &Runtime) { let scmd = rt.cli().subcommand_matches("list").unwrap(); let list_format = get_contact_print_format("contact.list_format", rt, &scmd); + let mut out = ::std::io::stdout(); let _ = rt .store() @@ -138,7 +142,8 @@ fn list(rt: &Runtime) { .err_from_str() .map_err(CE::from) .map_err_trace_exit_unwrap(1); - println!("{}", s); + + writeln!(out, "{}", s).to_exit_code().unwrap_or_exit() }) .collect::>(); } @@ -206,7 +211,7 @@ fn show(rt: &Runtime) { .err_from_str() .map_err(CE::from) .map_err_trace_exit_unwrap(1); - println!("{}", s); + let _ = writeln!(::std::io::stdout(), "{}", s).to_exit_code().unwrap_or_exit(); } fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Handlebars { From 6a341d37238b7a0529f290fd2f7624ae470fedf4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:07:11 +0100 Subject: [PATCH 06/22] Abstract exit code as a type --- bin/domain/imag-log/src/main.rs | 2 +- lib/core/libimagerror/src/exit.rs | 12 ++++++++++-- lib/core/libimagerror/src/io.rs | 11 +++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/bin/domain/imag-log/src/main.rs b/bin/domain/imag-log/src/main.rs index c3f80017..b6744831 100644 --- a/bin/domain/imag-log/src/main.rs +++ b/bin/domain/imag-log/src/main.rs @@ -140,7 +140,7 @@ fn show(rt: &Runtime) { text = e.get_content()) .to_exit_code() }) - .collect::>() + .collect::, _>>() .unwrap_or_exit(); } } diff --git a/lib/core/libimagerror/src/exit.rs b/lib/core/libimagerror/src/exit.rs index 6af8773d..777fe684 100644 --- a/lib/core/libimagerror/src/exit.rs +++ b/lib/core/libimagerror/src/exit.rs @@ -17,13 +17,21 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +pub struct ExitCode(i32); + +impl From for ExitCode { + fn from(i: i32) -> ExitCode { + ExitCode(i) + } +} + pub trait ExitUnwrap { fn unwrap_or_exit(self) -> T; } -impl ExitUnwrap for Result { +impl> ExitUnwrap for Result { fn unwrap_or_exit(self) -> T { - self.unwrap_or_else(|e| ::std::process::exit(e)) + self.map_err(Into::into).unwrap_or_else(|e| ::std::process::exit(e.0)) } } diff --git a/lib/core/libimagerror/src/io.rs b/lib/core/libimagerror/src/io.rs index ac648427..fff73a61 100644 --- a/lib/core/libimagerror/src/io.rs +++ b/lib/core/libimagerror/src/io.rs @@ -19,20 +19,22 @@ use std::io::ErrorKind; +use exit::ExitCode; + pub enum Settings { Ignore(ErrorKind), IgnoreAny(Vec), } pub trait ToExitCode { - fn to_exit_code(self) -> Result; - fn to_exit_code_with(self, Settings) -> Result; + fn to_exit_code(self) -> Result; + fn to_exit_code_with(self, Settings) -> Result; } impl ToExitCode for Result { /// Returns an exit code of 0 if the error was a broken pipe, else 1 - fn to_exit_code(self) -> Result { + fn to_exit_code(self) -> Result { self.to_exit_code_with(Settings::Ignore(ErrorKind::BrokenPipe)) } @@ -41,7 +43,7 @@ impl ToExitCode for Result { /// Via the settings, errors can be ignores (translates to exit code zero). All other errors /// are translated into exit code 1 /// - fn to_exit_code_with(self, settings: Settings) -> Result { + fn to_exit_code_with(self, settings: Settings) -> Result { self.map_err(move |e| match settings { Settings::Ignore(kind) => if e.kind() == kind { 0 @@ -54,6 +56,7 @@ impl ToExitCode for Result { 1 }, }) + .map_err(ExitCode::from) } } From c2dfb2ef52c2bae3bca9a53dd74507e1620a5b70 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:21:00 +0100 Subject: [PATCH 07/22] Refactor timetrack subcommands output for broken pipe errors --- bin/domain/imag-timetrack/src/day.rs | 42 +++++++++++++------------ bin/domain/imag-timetrack/src/month.rs | 43 ++++++++++++++------------ bin/domain/imag-timetrack/src/week.rs | 42 +++++++++++++------------ bin/domain/imag-timetrack/src/year.rs | 42 +++++++++++++------------ lib/core/libimagerror/src/exit.rs | 6 ++++ 5 files changed, 99 insertions(+), 76 deletions(-) diff --git a/bin/domain/imag-timetrack/src/day.rs b/bin/domain/imag-timetrack/src/day.rs index 09f4882f..4bdbcda6 100644 --- a/bin/domain/imag-timetrack/src/day.rs +++ b/bin/domain/imag-timetrack/src/day.rs @@ -17,6 +17,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::io::Write; use std::str::FromStr; use filters::filter::Filter; @@ -25,6 +26,7 @@ use chrono::NaiveDateTime; use libimagerror::trace::trace_error; use libimagerror::trace::MapErrTrace; use libimagerror::iter::TraceIterator; +use libimagerror::io::ToExitCode; use libimagstore::store::FileLockEntry; use libimagtimetrack::error::TimeTrackError as TTE; use libimagtimetrack::timetrackingstore::TimeTrackStore; @@ -84,6 +86,7 @@ pub fn day(rt: &Runtime) -> i32 { tags_filter.and(start_time_filter).and(end_time_filter) }; + let mut out = ::std::io::stdout(); rt.store() .get_timetrackings() .map_err_trace_exit_unwrap(1) @@ -91,30 +94,31 @@ pub fn day(rt: &Runtime) -> i32 { .filter(Option::is_some) .map(Option::unwrap) .filter(|e| filter.filter(e)) - .fold(Ok(()), |acc: Result<(), ::libimagtimetrack::error::TimeTrackError>, e| { - acc.and_then(|_| { - debug!("Processing {:?}", e.get_location()); + .map(|e| -> Result<_, TTE> { + debug!("Processing {:?}", e.get_location()); - let tag = e.get_timetrack_tag()?; - debug!(" -> tag = {:?}", tag); + let tag = e.get_timetrack_tag()?; + debug!(" -> tag = {:?}", tag); - let start = e.get_start_datetime()?; - debug!(" -> start = {:?}", start); + let start = e.get_start_datetime()?; + debug!(" -> start = {:?}", start); - let end = e.get_end_datetime()?; - debug!(" -> end = {:?}", end); + let end = e.get_end_datetime()?; + debug!(" -> end = {:?}", end); - match (start, end) { - (None, _) => println!("{} has no start time.", tag), - (Some(s), None) => println!("{} | {} - ...", tag, s), - (Some(s), Some(e)) => println!("{} | {} - {}", tag, s, e), - } - - Ok(()) - }) + Ok((tag, start, end)) }) + .trace_unwrap_exit(1) + .map(|(tag, start, end)| { + match (start, end) { + (None, _) => writeln!(out, "{} has no start time.", tag), + (Some(s), None) => writeln!(out, "{} | {} - ...", tag, s), + (Some(s), Some(e)) => writeln!(out, "{} | {} - {}", tag, s, e), + } + .to_exit_code() + }) + .collect::, _>>() .map(|_| 0) - .map_err_trace() - .unwrap_or(1) + .unwrap_or_else(|e| e.code()) } diff --git a/bin/domain/imag-timetrack/src/month.rs b/bin/domain/imag-timetrack/src/month.rs index ac715500..90c38619 100644 --- a/bin/domain/imag-timetrack/src/month.rs +++ b/bin/domain/imag-timetrack/src/month.rs @@ -17,6 +17,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::io::Write; use std::str::FromStr; use filters::filter::Filter; @@ -24,6 +25,7 @@ use chrono::NaiveDateTime; use libimagerror::trace::trace_error; use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; use libimagerror::iter::TraceIterator; use libimagstore::store::FileLockEntry; use libimagtimetrack::error::TimeTrackError as TTE; @@ -99,6 +101,8 @@ pub fn month(rt: &Runtime) -> i32 { tags_filter.and(start_time_filter).and(end_time_filter) }; + let mut out = ::std::io::stdout(); + rt.store() .get_timetrackings() .map_err_trace_exit_unwrap(1) @@ -106,30 +110,31 @@ pub fn month(rt: &Runtime) -> i32 { .filter(Option::is_some) .map(Option::unwrap) .filter(|e| filter.filter(e)) - .fold(Ok(()), |acc: Result<(), ::libimagtimetrack::error::TimeTrackError>, e| { - acc.and_then(|_| { - debug!("Processing {:?}", e.get_location()); + .map(|e| -> Result<_, TTE> { + debug!("Processing {:?}", e.get_location()); - let tag = e.get_timetrack_tag()?; - debug!(" -> tag = {:?}", tag); + let tag = e.get_timetrack_tag()?; + debug!(" -> tag = {:?}", tag); - let start = e.get_start_datetime()?; - debug!(" -> start = {:?}", start); + let start = e.get_start_datetime()?; + debug!(" -> start = {:?}", start); - let end = e.get_end_datetime()?; - debug!(" -> end = {:?}", end); + let end = e.get_end_datetime()?; + debug!(" -> end = {:?}", end); - match (start, end) { - (None, _) => println!("{} has no start time.", tag), - (Some(s), None) => println!("{} | {} - ...", tag, s), - (Some(s), Some(e)) => println!("{} | {} - {}", tag, s, e), - } - - Ok(()) - }) + Ok((tag, start, end)) }) + .trace_unwrap_exit(1) + .map(|(tag, start, end)| { + match (start, end) { + (None, _) => writeln!(out, "{} has no start time.", tag), + (Some(s), None) => writeln!(out, "{} | {} - ...", tag, s), + (Some(s), Some(e)) => writeln!(out, "{} | {} - {}", tag, s, e), + } + .to_exit_code() + }) + .collect::, _>>() .map(|_| 0) - .map_err_trace() - .unwrap_or(1) + .unwrap_or_else(|e| e.code()) } diff --git a/bin/domain/imag-timetrack/src/week.rs b/bin/domain/imag-timetrack/src/week.rs index ba6953b8..a73657d8 100644 --- a/bin/domain/imag-timetrack/src/week.rs +++ b/bin/domain/imag-timetrack/src/week.rs @@ -17,6 +17,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::io::Write; use std::str::FromStr; use filters::filter::Filter; @@ -25,6 +26,7 @@ use chrono::NaiveDateTime; use libimagerror::trace::trace_error; use libimagerror::trace::MapErrTrace; use libimagerror::iter::TraceIterator; +use libimagerror::io::ToExitCode; use libimagstore::store::FileLockEntry; use libimagtimetrack::error::TimeTrackError as TTE; use libimagtimetrack::timetrackingstore::TimeTrackStore; @@ -97,6 +99,7 @@ pub fn week(rt: &Runtime) -> i32 { tags_filter.and(start_time_filter).and(end_time_filter) }; + let mut out = ::std::io::stdout(); rt.store() .get_timetrackings() .map_err_trace_exit_unwrap(1) @@ -104,30 +107,31 @@ pub fn week(rt: &Runtime) -> i32 { .filter(Option::is_some) .map(Option::unwrap) .filter(|e| filter.filter(e)) - .fold(Ok(()), |acc: Result<(), ::libimagtimetrack::error::TimeTrackError>, e| { - acc.and_then(|_| { - debug!("Processing {:?}", e.get_location()); + .map(|e| -> Result<_, TTE> { + debug!("Processing {:?}", e.get_location()); - let tag = e.get_timetrack_tag()?; - debug!(" -> tag = {:?}", tag); + let tag = e.get_timetrack_tag()?; + debug!(" -> tag = {:?}", tag); - let start = e.get_start_datetime()?; - debug!(" -> start = {:?}", start); + let start = e.get_start_datetime()?; + debug!(" -> start = {:?}", start); - let end = e.get_end_datetime()?; - debug!(" -> end = {:?}", end); + let end = e.get_end_datetime()?; + debug!(" -> end = {:?}", end); - match (start, end) { - (None, _) => println!("{} has no start time.", tag), - (Some(s), None) => println!("{} | {} - ...", tag, s), - (Some(s), Some(e)) => println!("{} | {} - {}", tag, s, e), - } - - Ok(()) - }) + Ok((tag, start, end)) }) + .trace_unwrap_exit(1) + .map(|(tag, start, end)| { + match (start, end) { + (None, _) => writeln!(out, "{} has no start time.", tag), + (Some(s), None) => writeln!(out, "{} | {} - ...", tag, s), + (Some(s), Some(e)) => writeln!(out, "{} | {} - {}", tag, s, e), + } + .to_exit_code() + }) + .collect::, _>>() .map(|_| 0) - .map_err_trace() - .unwrap_or(1) + .unwrap_or_else(|e| e.code()) } diff --git a/bin/domain/imag-timetrack/src/year.rs b/bin/domain/imag-timetrack/src/year.rs index 9e7d1aed..cddd21a1 100644 --- a/bin/domain/imag-timetrack/src/year.rs +++ b/bin/domain/imag-timetrack/src/year.rs @@ -17,6 +17,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::io::Write; use std::str::FromStr; use filters::filter::Filter; @@ -25,6 +26,7 @@ use chrono::NaiveDateTime; use libimagerror::trace::trace_error; use libimagerror::trace::MapErrTrace; use libimagerror::iter::TraceIterator; +use libimagerror::io::ToExitCode; use libimagstore::store::FileLockEntry; use libimagtimetrack::error::TimeTrackError as TTE; use libimagtimetrack::timetrackingstore::TimeTrackStore; @@ -96,6 +98,7 @@ pub fn year(rt: &Runtime) -> i32 { tags_filter.and(start_time_filter).and(end_time_filter) }; + let mut out = ::std::io::stdout(); rt.store() .get_timetrackings() .map_err_trace_exit_unwrap(1) @@ -103,30 +106,31 @@ pub fn year(rt: &Runtime) -> i32 { .filter(Option::is_some) .map(Option::unwrap) .filter(|e| filter.filter(e)) - .fold(Ok(()), |acc: Result<(), ::libimagtimetrack::error::TimeTrackError>, e| { - acc.and_then(|_| { - debug!("Processing {:?}", e.get_location()); + .map(|e| -> Result<_, TTE> { + debug!("Processing {:?}", e.get_location()); - let tag = e.get_timetrack_tag()?; - debug!(" -> tag = {:?}", tag); + let tag = e.get_timetrack_tag()?; + debug!(" -> tag = {:?}", tag); - let start = e.get_start_datetime()?; - debug!(" -> start = {:?}", start); + let start = e.get_start_datetime()?; + debug!(" -> start = {:?}", start); - let end = e.get_end_datetime()?; - debug!(" -> end = {:?}", end); + let end = e.get_end_datetime()?; + debug!(" -> end = {:?}", end); - match (start, end) { - (None, _) => println!("{} has no start time.", tag), - (Some(s), None) => println!("{} | {} - ...", tag, s), - (Some(s), Some(e)) => println!("{} | {} - {}", tag, s, e), - } - - Ok(()) - }) + Ok((tag, start, end)) }) + .trace_unwrap_exit(1) + .map(|(tag, start, end)| { + match (start, end) { + (None, _) => writeln!(out, "{} has no start time.", tag), + (Some(s), None) => writeln!(out, "{} | {} - ...", tag, s), + (Some(s), Some(e)) => writeln!(out, "{} | {} - {}", tag, s, e), + } + .to_exit_code() + }) + .collect::, _>>() .map(|_| 0) - .map_err_trace() - .unwrap_or(1) + .unwrap_or_else(|e| e.code()) } diff --git a/lib/core/libimagerror/src/exit.rs b/lib/core/libimagerror/src/exit.rs index 777fe684..30576b31 100644 --- a/lib/core/libimagerror/src/exit.rs +++ b/lib/core/libimagerror/src/exit.rs @@ -25,6 +25,12 @@ impl From for ExitCode { } } +impl ExitCode { + pub fn code(self) -> i32 { + self.0 + } +} + pub trait ExitUnwrap { fn unwrap_or_exit(self) -> T; } From 5e78a43242fe46f10213277ff3a7a7103a891183 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:29:46 +0100 Subject: [PATCH 08/22] Fix for broken pipe panics --- bin/domain/imag-habit/src/main.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/domain/imag-habit/src/main.rs b/bin/domain/imag-habit/src/main.rs index d9263dd2..bcce7459 100644 --- a/bin/domain/imag-habit/src/main.rs +++ b/bin/domain/imag-habit/src/main.rs @@ -47,11 +47,14 @@ extern crate libimagutil; extern crate libimagentrylist; extern crate libimaginteraction; +use std::io::Write; use std::process::exit; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimaghabit::store::HabitStore; use libimaghabit::habit::builder::HabitBuilder; use libimaghabit::habit::HabitTemplate; @@ -389,6 +392,7 @@ fn show(rt: &Runtime) { vec![date, comm] } + let mut out = ::std::io::stdout(); let _ = rt .store() @@ -403,12 +407,15 @@ fn show(rt: &Runtime) { let recur = habit.habit_recur_spec().map_err_trace_exit_unwrap(1); let comm = habit.habit_comment().map_err_trace_exit_unwrap(1); - println!("{i} - {name}\nBase : {b},\nRecurrence: {r}\nComment : {c}\n", + let _ = writeln!(out, + "{i} - {name}\nBase : {b},\nRecurrence: {r}\nComment : {c}\n", i = i, name = name, b = basedate, r = recur, - c = comm); + c = comm) + .to_exit_code() + .unwrap_or_exit(); let instances_iter = habit .linked_instances() From 876c1cb9af42b8fca1fa007a11d7658f4a242b7f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:33:28 +0100 Subject: [PATCH 09/22] Fix broken pipe panics --- bin/domain/imag-diary/src/main.rs | 7 +++++-- bin/domain/imag-mail/src/main.rs | 9 +++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bin/domain/imag-diary/src/main.rs b/bin/domain/imag-diary/src/main.rs index 1ed42666..ca13cf24 100644 --- a/bin/domain/imag-diary/src/main.rs +++ b/bin/domain/imag-diary/src/main.rs @@ -50,6 +50,8 @@ extern crate libimagutil; use std::process::exit; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; mod create; @@ -77,8 +79,9 @@ fn main() { if rt.is_ok() { rt.unwrap() } else { - println!("Could not set up Runtime"); - println!("{:?}", rt.err().unwrap()); + let mut out = ::std::io::stdout(); + let _ = writeln!(out, "Could not set up Runtime").to_exit_code().unwrap_or_exit(); + let _ = writeln!(out, "{:?}", rt.err().unwrap()).to_exit_code().unwrap_or_exit(); exit(1); } }; diff --git a/bin/domain/imag-mail/src/main.rs b/bin/domain/imag-mail/src/main.rs index 6a018f94..b822aeba 100644 --- a/bin/domain/imag-mail/src/main.rs +++ b/bin/domain/imag-mail/src/main.rs @@ -25,7 +25,11 @@ extern crate libimagmail; extern crate libimagerror; extern crate libimagutil; +use std::io::Write; + use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimagmail::mail::Mail; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; @@ -106,12 +110,13 @@ fn list(rt: &Runtime) { }, }; - println!("Mail: {id}\n\tFrom: {from}\n\tTo: {to}\n\t{subj}\n", + writeln!(::std::io::stdout(), + "Mail: {id}\n\tFrom: {from}\n\tTo: {to}\n\t{subj}\n", from = from, id = id, subj = subject, to = to - ); + ).to_exit_code().unwrap_or_exit() } let _ = rt.store() From 23e0f720e50f89fe25196f4b9adc84b719dd3975 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:38:43 +0100 Subject: [PATCH 10/22] Fix broken pipe errors --- bin/domain/imag-bookmark/src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/domain/imag-bookmark/src/main.rs b/bin/domain/imag-bookmark/src/main.rs index d630baca..9fbd75e0 100644 --- a/bin/domain/imag-bookmark/src/main.rs +++ b/bin/domain/imag-bookmark/src/main.rs @@ -42,6 +42,7 @@ extern crate libimagbookmark; extern crate libimagerror; extern crate libimagutil; +use std::io::Write; use std::process::exit; use toml_query::read::TomlValueReadTypeExt; @@ -53,6 +54,8 @@ use libimagbookmark::collection::BookmarkCollectionStore; use libimagbookmark::error::BookmarkError as BE; use libimagbookmark::link::Link as BookmarkLink; use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; mod ui; @@ -131,11 +134,12 @@ fn list(rt: &Runtime) { .ok_or(BE::from(format!("No BookmarkcollectionStore '{}' found", coll))) .map_err_trace_exit_unwrap(1); - let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1); + let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1); + let mut out = ::std::io::stdout(); debug!("Listing..."); for (i, link) in links.enumerate() { match link { - Ok(link) => println!("{: >3}: {}", i, link), + Ok(link) => writeln!(out, "{: >3}: {}", i, link).to_exit_code().unwrap_or_exit(), Err(e) => trace_error(&e) } }; From e501f66daceb0ad5a3218113a37e4a9b3c0580f6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:42:29 +0100 Subject: [PATCH 11/22] Fix broken pipe panics --- bin/domain/imag-diary/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/domain/imag-diary/src/main.rs b/bin/domain/imag-diary/src/main.rs index ca13cf24..0fcaf9d7 100644 --- a/bin/domain/imag-diary/src/main.rs +++ b/bin/domain/imag-diary/src/main.rs @@ -48,6 +48,7 @@ extern crate libimagstore; extern crate libimagtimeui; extern crate libimagutil; +use std::io::Write; use std::process::exit; use libimagerror::exit::ExitUnwrap; From 849229eec6d80641e9bbd908c2489748f88525fd Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:44:25 +0100 Subject: [PATCH 12/22] Fix broken pipe panics --- bin/domain/imag-todo/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/domain/imag-todo/src/main.rs b/bin/domain/imag-todo/src/main.rs index e7f53345..8fab4e46 100644 --- a/bin/domain/imag-todo/src/main.rs +++ b/bin/domain/imag-todo/src/main.rs @@ -29,11 +29,14 @@ extern crate libimagtodo; use std::process::{Command, Stdio}; use std::io::stdin; +use std::io::Write; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagtodo::taskstore::TaskStore; use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; mod ui; @@ -68,7 +71,10 @@ fn tw_hook(rt: &Runtime) { .import_task_from_reader(stdin) .map_err_trace_exit_unwrap(1); - println!("{}\nTask {} stored in imag", line, uuid); + let _ = writeln!(::std::io::stdout(), "{}\nTask {} stored in imag", line, uuid) + .to_exit_code() + .unwrap_or_exit(); + } else if subcmd.is_present("delete") { // The used hook is "on-modify". This hook gives two json-objects // per usage und wants one (the second one) back. @@ -142,7 +148,7 @@ fn list(rt: &Runtime) { }; // and then print that - println!("{}", outstring); + let _ = writeln!(::std::io::stdout(), "{}", outstring).to_exit_code().unwrap_or_exit(); }); res.map_err_trace().ok(); From 427ad89e55f83a49c3e888b5f2d4d969e511a9cb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 18:47:15 +0100 Subject: [PATCH 13/22] Fix broken pipe panics --- bin/domain/imag-notes/src/main.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/domain/imag-notes/src/main.rs b/bin/domain/imag-notes/src/main.rs index d15a211d..df1870e2 100644 --- a/bin/domain/imag-notes/src/main.rs +++ b/bin/domain/imag-notes/src/main.rs @@ -28,6 +28,7 @@ extern crate libimagerror; extern crate libimagutil; extern crate libimagstore; +use std::io::Write; use std::process::exit; use itertools::Itertools; @@ -39,6 +40,8 @@ use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagnotes::note::Note; use libimagnotes::notestore::*; use libimagerror::trace::MapErrTrace; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimagerror::iter::TraceIterator; use libimagutil::info_result::*; use libimagutil::warn_result::WarnResult; @@ -116,6 +119,8 @@ fn edit(rt: &Runtime) { fn list(rt: &Runtime) { use std::cmp::Ordering; + let mut out = ::std::io::stdout(); + let _ = rt .store() .all_notes() @@ -133,10 +138,10 @@ fn list(rt: &Runtime) { }) .iter() .for_each(|note| { - note.get_name() - .map(|name| println!("{}", name)) - .map_err_trace() - .ok(); + let name = note.get_name().map_err_trace_exit_unwrap(1); + writeln!(out, "{}", name) + .to_exit_code() + .unwrap_or_exit() }); } From 09da5cc21e8c600deac0a358e9027d4763cf8a78 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:30:09 +0100 Subject: [PATCH 14/22] Fix for broken pipe panic --- bin/core/imag-grep/src/main.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/bin/core/imag-grep/src/main.rs b/bin/core/imag-grep/src/main.rs index aba22190..64220f90 100644 --- a/bin/core/imag-grep/src/main.rs +++ b/bin/core/imag-grep/src/main.rs @@ -40,11 +40,15 @@ extern crate libimagstore; #[macro_use] extern crate libimagrt; extern crate libimagerror; +use std::io::Write; + use regex::Regex; use libimagrt::setup::generate_runtime_setup; use libimagstore::store::Entry; use libimagerror::trace::MapErrTrace; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; mod ui; @@ -87,32 +91,38 @@ fn main() { .map(|entry| show(&entry, &pattern, &opts, &mut count)) .count(); + let mut out = ::std::io::stdout(); + if opts.count { - println!("{}", count); + let _ = writeln!(out, "{}", count).to_exit_code().unwrap_or_exit(); } else if !opts.files_with_matches { - println!("Processed {} files, {} matches, {} nonmatches", + let _ = writeln!(out, "Processed {} files, {} matches, {} nonmatches", overall_count, count, - overall_count - count); + overall_count - count) + .to_exit_code() + .unwrap_or_exit(); } } fn show(e: &Entry, re: &Regex, opts: &Options, count: &mut usize) { + let mut out = ::std::io::stdout(); + if opts.files_with_matches { - println!("{}", e.get_location()); + let _ = writeln!(out, "{}", e.get_location()).to_exit_code().unwrap_or_exit(); } else if opts.count { *count += 1; } else { - println!("{}:", e.get_location()); + let _ = writeln!(out, "{}:", e.get_location()).to_exit_code().unwrap_or_exit(); for capture in re.captures_iter(e.get_content()) { for mtch in capture.iter() { if let Some(m) = mtch { - println!(" '{}'", m.as_str()); + let _ = writeln!(out, " '{}'", m.as_str()).to_exit_code().unwrap_or_exit(); } } } - println!(""); + let _ = writeln!(out, "").to_exit_code().unwrap_or_exit(); } } From 632d68e0e027406f4081492ff62e225865a194a3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:32:23 +0100 Subject: [PATCH 15/22] Fix broken pipe panic --- bin/core/imag-link/src/main.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/bin/core/imag-link/src/main.rs b/bin/core/imag-link/src/main.rs index 2266e06b..dbd62bae 100644 --- a/bin/core/imag-link/src/main.rs +++ b/bin/core/imag-link/src/main.rs @@ -50,6 +50,7 @@ extern crate libimagutil; #[cfg(not(test))] extern crate libimagutil; +use std::io::Write; use std::path::PathBuf; use libimagentrylink::external::ExternalLinker; @@ -57,6 +58,8 @@ use libimagentrylink::internal::InternalLinker; use libimagentrylink::internal::store_check::StoreLinkConsistentExt; use libimagentrylink::error::LinkError as LE; use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagstore::error::StoreError; @@ -226,7 +229,8 @@ fn list_linkings(rt: &Runtime) { .subcommand_matches("list") .unwrap(); // safed by clap - let list_externals = cmd.is_present("list-externals-too"); + let list_externals = cmd.is_present("list-externals-too"); + let mut out = ::std::io::stdout(); for entry in cmd.values_of("entries").unwrap() { // safed by clap match rt.store().get(PathBuf::from(entry)) { @@ -240,20 +244,27 @@ fn list_linkings(rt: &Runtime) { .ok(); if let Some(link) = link { - println!("{: <3}: {}", i, link); + let _ = writeln!(out, "{: <3}: {}", i, link) + .to_exit_code() + .unwrap_or_exit(); i += 1; } } if list_externals { - for link in entry.get_external_links(rt.store()).map_err_trace_exit_unwrap(1) { - let link = link - .map_err_trace_exit_unwrap(1) - .into_string(); + entry.get_external_links(rt.store()) + .map_err_trace_exit_unwrap(1) + .enumerate() + .for_each(|(i, link)| { + let link = link + .map_err_trace_exit_unwrap(1) + .into_string(); - println!("{: <3}: {}", i, link); - i += 1; - } + let _ = writeln!(out, "{: <3}: {}", i, link) + .to_exit_code() + .unwrap_or_exit(); + + }) } }, Ok(None) => warn!("Not found: {}", entry), From 872b300b9c2e14cab86a6efaf5200cb204c84a66 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:33:35 +0100 Subject: [PATCH 16/22] Fix broken pipe panics --- bin/core/imag-gps/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/core/imag-gps/src/main.rs b/bin/core/imag-gps/src/main.rs index 0a1dafa8..56423286 100644 --- a/bin/core/imag-gps/src/main.rs +++ b/bin/core/imag-gps/src/main.rs @@ -42,6 +42,7 @@ extern crate libimagutil; extern crate libimagerror; extern crate libimagstore; +use std::io::Write; use std::process::exit; use std::path::PathBuf; use std::str::FromStr; @@ -54,6 +55,8 @@ use libimagrt::setup::generate_runtime_setup; use libimagrt::runtime::Runtime; use libimagutil::warn_exit::warn_exit; use libimagerror::trace::MapErrTrace; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimagstore::storeid::IntoStoreId; mod ui; @@ -141,8 +144,10 @@ fn remove(rt: &Runtime) { }) .map_err_trace_exit_unwrap(1); // The parsing of the deleted values failed + let mut out = ::std::io::stdout(); + if scmd.is_present("print-removed") { - println!("{}", removed_value); + let _ = writeln!(out, "{}", removed_value).to_exit_code().unwrap_or_exit(); } } @@ -169,6 +174,7 @@ fn get(rt: &Runtime) { exit(1) }); - println!("{}", value); + let mut out = ::std::io::stdout(); + let _ = writeln!(out, "{}", value).to_exit_code().unwrap_or_exit(); } From fc0610b77f581c4f32c4af7ff29eee8dacb22a8c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:34:37 +0100 Subject: [PATCH 17/22] Fix broken pipe panic --- bin/core/imag-annotate/src/main.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/bin/core/imag-annotate/src/main.rs b/bin/core/imag-annotate/src/main.rs index 609deaef..cf758c4f 100644 --- a/bin/core/imag-annotate/src/main.rs +++ b/bin/core/imag-annotate/src/main.rs @@ -43,6 +43,7 @@ extern crate libimagerror; extern crate libimagstore; extern crate libimagutil; +use std::io::Write; use std::path::PathBuf; use libimagentryannotation::annotateable::*; @@ -50,6 +51,8 @@ use libimagentryannotation::annotation_fetcher::*; use libimagentryannotation::error::AnnotationError as AE; use libimagentryedit::edit::*; use libimagerror::trace::MapErrTrace; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagstore::store::FileLockEntry; @@ -132,6 +135,7 @@ fn remove(rt: &Runtime) { } fn list(rt: &Runtime) { + let mut out = ::std::io::stdout(); let scmd = rt.cli().subcommand_matches("list").unwrap(); // safed by clap let with_text = scmd.is_present("list-with-text"); match scmd.value_of("entry").map(PathBuf::from) { @@ -145,7 +149,9 @@ fn list(rt: &Runtime) { .annotations(rt.store()) .map_err_trace_exit_unwrap(1) .enumerate() - .map(|(i, a)| list_annotation(i, a.map_err_trace_exit_unwrap(1), with_text)) + .map(|(i, a)| { + list_annotation(&mut out, i, a.map_err_trace_exit_unwrap(1), with_text) + }) .collect::>(); } @@ -156,20 +162,25 @@ fn list(rt: &Runtime) { .all_annotations() .map_err_trace_exit_unwrap(1) .enumerate() - .map(|(i, a)| list_annotation(i, a.map_err_trace_exit_unwrap(1), with_text)) + .map(|(i, a)| { + list_annotation(&mut out, i, a.map_err_trace_exit_unwrap(1), with_text) + }) .collect::>(); } } } -fn list_annotation<'a>(i: usize, a: FileLockEntry<'a>, with_text: bool) { - if with_text { - println!("--- {i: >5} | {id}\n{text}\n\n", +fn list_annotation<'a>(out: &mut Write, i: usize, a: FileLockEntry<'a>, with_text: bool) { + let _ = if with_text { + writeln!(out, + "--- {i: >5} | {id}\n{text}\n\n", i = i, id = a.get_location(), - text = a.get_content()); + text = a.get_content()) } else { - println!("{: >5} | {}", i, a.get_location()); + writeln!(out, "{: >5} | {}", i, a.get_location()) } + .to_exit_code() + .unwrap_or_exit(); } From 125eebe1ce6080a191c04ae35aee2bb36c9a0a27 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:38:18 +0100 Subject: [PATCH 18/22] Fix broken pipe panic --- bin/core/imag-init/Cargo.toml | 1 + bin/core/imag-init/src/main.rs | 66 ++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/bin/core/imag-init/Cargo.toml b/bin/core/imag-init/Cargo.toml index 7eaf6f0b..7e9ff997 100644 --- a/bin/core/imag-init/Cargo.toml +++ b/bin/core/imag-init/Cargo.toml @@ -22,6 +22,7 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" } maintenance = { status = "actively-developed" } [dependencies] +libimagerror = { version = "0.7.0", path = "../../../lib/core/libimagerror" } [dependencies.clap] version = ">=2.29" diff --git a/bin/core/imag-init/src/main.rs b/bin/core/imag-init/src/main.rs index 79188534..8688481d 100644 --- a/bin/core/imag-init/src/main.rs +++ b/bin/core/imag-init/src/main.rs @@ -37,6 +37,8 @@ extern crate clap; #[cfg(test)] extern crate toml; +extern crate libimagerror; + mod ui; use std::fs::OpenOptions; @@ -45,6 +47,9 @@ use std::path::PathBuf; use std::path::Path; use std::process::Command; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; + const CONFIGURATION_STR : &'static str = include_str!("../imagrc.toml"); const GITIGNORE_STR : &'static str = r#" @@ -63,6 +68,7 @@ imagrc.toml fn main() { let app = ui::build_ui(); let matches = app.get_matches(); + let mut out = ::std::io::stdout(); let path = matches .value_of("path") @@ -73,8 +79,12 @@ fn main() { .map(PathBuf::from) .map(|mut p| { p.push(".imag"); p }) .map(|path| if path.exists() { - println!("Path '{:?}' already exists!", path); - println!("Cannot continue."); + let _ = writeln!(out, "Path '{:?}' already exists!", path) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "Cannot continue.") + .to_exit_code() + .unwrap_or_exit(); ::std::process::exit(1) } else { path @@ -109,7 +119,9 @@ fn main() { if find_command("git").is_some() && !matches.is_present("nogit") { // we initialize a git repository - println!("Going to initialize a git repository in the imag directory..."); + let _ = writeln!(out, "Going to initialize a git repository in the imag directory...") + .to_exit_code() + .unwrap_or_exit(); let gitignore_path = { let mut gitignore_path = path.clone(); @@ -138,10 +150,16 @@ fn main() { .expect("Calling 'git init' failed"); if output.status.success() { - println!("{}", String::from_utf8(output.stdout).expect("No UTF-8 output")); - println!("'git {} {} --no-pager init' succeeded", worktree, gitdir); + let _ = writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output")) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "'git {} {} --no-pager init' succeeded", worktree, gitdir) + .to_exit_code() + .unwrap_or_exit(); } else { - println!("{}", String::from_utf8(output.stderr).expect("No UTF-8 output")); + let _ = writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output")) + .to_exit_code() + .unwrap_or_exit(); ::std::process::exit(output.status.code().unwrap_or(1)); } } @@ -152,10 +170,16 @@ fn main() { .output() .expect("Calling 'git add' failed"); if output.status.success() { - println!("{}", String::from_utf8(output.stdout).expect("No UTF-8 output")); - println!("'git {} {} --no-pager add {}' succeeded", worktree, gitdir, gitignore_path); + let _ = writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output")) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "'git {} {} --no-pager add {}' succeeded", worktree, gitdir, gitignore_path) + .to_exit_code() + .unwrap_or_exit(); } else { - println!("{}", String::from_utf8(output.stderr).expect("No UTF-8 output")); + let _ = writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output")) + .to_exit_code() + .unwrap_or_exit(); ::std::process::exit(output.status.code().unwrap_or(1)); } } @@ -166,20 +190,32 @@ fn main() { .output() .expect("Calling 'git commit' failed"); if output.status.success() { - println!("{}", String::from_utf8(output.stdout).expect("No UTF-8 output")); - println!("'git {} {} --no-pager commit {} -m 'Initial import'' succeeded", worktree, gitdir, gitignore_path); + let _ = writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output")) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "'git {} {} --no-pager commit {} -m 'Initial import'' succeeded", worktree, gitdir, gitignore_path) + .to_exit_code() + .unwrap_or_exit(); } else { - println!("{}", String::from_utf8(output.stderr).expect("No UTF-8 output")); + let _ = writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output")) + .to_exit_code() + .unwrap_or_exit(); ::std::process::exit(output.status.code().unwrap_or(1)); } } - println!("git stuff finished!"); + let _ = writeln!(out, "git stuff finished!") + .to_exit_code() + .unwrap_or_exit(); } else { - println!("No git repository will be initialized"); + let _ = writeln!(out, "No git repository will be initialized") + .to_exit_code() + .unwrap_or_exit(); } - println!("Ready. Have fun with imag!"); + let _ = writeln!(out, "Ready. Have fun with imag!") + .to_exit_code() + .unwrap_or_exit(); } fn get_config() -> String { From 380aeccdc7483f349e491620fbe62b1bfac919ec Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:42:55 +0100 Subject: [PATCH 19/22] Fix broken pipe panics --- bin/core/imag/src/main.rs | 52 +++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/bin/core/imag/src/main.rs b/bin/core/imag/src/main.rs index 9addf820..18820c4d 100644 --- a/bin/core/imag/src/main.rs +++ b/bin/core/imag/src/main.rs @@ -31,6 +31,7 @@ use std::process::exit; use std::process::Command; use std::process::Stdio; use std::io::ErrorKind; +use std::io::{stdout, Stdout, Write}; use std::collections::BTreeMap; use walkdir::WalkDir; @@ -40,6 +41,8 @@ use toml_query::read::TomlValueReadExt; use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; /// Returns the helptext, putting the Strings in cmds as possible /// subcommands into it @@ -85,10 +88,12 @@ fn help_text(cmds: Vec) -> String { } /// Returns the list of imag-* executables found in $PATH -fn get_commands() -> Vec { +fn get_commands(out: &mut Stdout) -> Vec { let mut v = match env::var("PATH") { Err(e) => { - println!("PATH error: {:?}", e); + let _ = writeln!(out, "PATH error: {:?}", e) + .to_exit_code() + .unwrap_or_exit(); exit(1) }, @@ -122,7 +127,8 @@ fn main() { let appname = "imag"; let version = make_imag_version!(); let about = "imag - the PIM suite for the commandline"; - let commands = get_commands(); + let mut out = stdout(); + let commands = get_commands(&mut out); let helptext = help_text(commands.clone()); let mut app = Runtime::get_default_cli_builder(appname, &version, about) .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp]) @@ -152,14 +158,18 @@ fn main() { { let print_help = app.clone().get_matches().subcommand_name().map(|h| h == "help").unwrap_or(false); if print_help { - println!("{}", long_help); + let _ = writeln!(out, "{}", long_help) + .to_exit_code() + .unwrap_or_exit(); exit(0) } } let rt = Runtime::new(app) .unwrap_or_else(|e| { - println!("Runtime couldn't be setup. Exiting"); + let _ = writeln!(out, "Runtime couldn't be setup. Exiting") + .to_exit_code() + .unwrap_or_exit(); trace_error(&e); exit(1); }); @@ -171,7 +181,9 @@ fn main() { if matches.is_present("version") { debug!("Showing version"); - println!("imag {}", env!("CARGO_PKG_VERSION")); + let _ = writeln!(out, "imag {}", env!("CARGO_PKG_VERSION")) + .to_exit_code() + .unwrap_or_exit(); exit(0); } @@ -194,7 +206,9 @@ fn main() { }) .fold((), |_, line| { // The amount of newlines may differ depending on the subprocess - println!("{}", line.trim()); + let _ = writeln!(out, "{}", line.trim()) + .to_exit_code() + .unwrap_or_exit(); }); exit(0); @@ -203,9 +217,13 @@ fn main() { let aliases = match fetch_aliases(&rt) { Ok(aliases) => aliases, Err(e) => { - println!("Error while fetching aliases from configuration file"); + let _ = writeln!(out, "Error while fetching aliases from configuration file") + .to_exit_code() + .unwrap_or_exit(); debug!("Error = {:?}", e); - println!("Aborting"); + let _ = writeln!(out, "Aborting") + .to_exit_code() + .unwrap_or_exit(); exit(1); } }; @@ -250,16 +268,24 @@ fn main() { debug!("Error calling the subcommand"); match e.kind() { ErrorKind::NotFound => { - println!("No such command: 'imag-{}'", subcommand); - println!("See 'imag --help' for available subcommands"); + let _ = writeln!(out, "No such command: 'imag-{}'", subcommand) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "See 'imag --help' for available subcommands") + .to_exit_code() + .unwrap_or_exit(); exit(1); }, ErrorKind::PermissionDenied => { - println!("No permission to execute: 'imag-{}'", subcommand); + let _ = writeln!(out, "No permission to execute: 'imag-{}'", subcommand) + .to_exit_code() + .unwrap_or_exit(); exit(1); }, _ => { - println!("Error spawning: {:?}", e); + let _ = writeln!(out, "Error spawning: {:?}", e) + .to_exit_code() + .unwrap_or_exit(); exit(1); } } From 36e511d39bf3302331a7f0c7b2de0286c6c94848 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:45:28 +0100 Subject: [PATCH 20/22] Fix broken pipe panics --- bin/core/imag-store/src/retrieve.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/core/imag-store/src/retrieve.rs b/bin/core/imag-store/src/retrieve.rs index 1ebeeb7f..20dc100c 100644 --- a/bin/core/imag-store/src/retrieve.rs +++ b/bin/core/imag-store/src/retrieve.rs @@ -18,6 +18,7 @@ // use std::path::PathBuf; +use std::io::Write; use clap::ArgMatches; @@ -25,6 +26,8 @@ use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; use libimagrt::runtime::Runtime; use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; use libimagutil::debug_result::*; pub fn retrieve(rt: &Runtime) { @@ -48,9 +51,13 @@ pub fn retrieve(rt: &Runtime) { } pub fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) { + let mut out = ::std::io::stdout(); + if do_print_raw(scmd) { debug!("Printing raw content..."); - println!("{}", e.to_str()); + let _ = writeln!(out, "{}", e.to_str()) + .to_exit_code() + .unwrap_or_exit(); } else if do_filter(scmd) { debug!("Filtering..."); warn!("Filtering via header specs is currently now supported."); @@ -67,13 +74,17 @@ pub fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) { unimplemented!() } else { debug!("Printing header as TOML..."); - println!("{}", e.get_header()) + let _ = writeln!(out, "{}", e.get_header()) + .to_exit_code() + .unwrap_or_exit(); } } if do_print_content(scmd) { debug!("Printing content..."); - println!("{}", e.get_content()); + let _ = writeln!(out, "{}", e.get_content()) + .to_exit_code() + .unwrap_or_exit(); } } From e8f8969ded79ee7938ee2ba51b36196760084769 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:46:48 +0100 Subject: [PATCH 21/22] Fix broke pipe panics --- bin/core/imag-tag/src/main.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/core/imag-tag/src/main.rs b/bin/core/imag-tag/src/main.rs index 8c0fcc94..9fb21188 100644 --- a/bin/core/imag-tag/src/main.rs +++ b/bin/core/imag-tag/src/main.rs @@ -41,6 +41,7 @@ extern crate toml_query; extern crate env_logger; use std::path::PathBuf; +use std::io::Write; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; @@ -48,6 +49,8 @@ use libimagentrytag::tagable::Tagable; use libimagentrytag::tag::Tag; use libimagerror::trace::trace_error; use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; use libimagstore::storeid::StoreId; use libimagutil::warn_exit::warn_exit; @@ -161,19 +164,27 @@ fn list(id: PathBuf, rt: &Runtime) { unimplemented!() } + let mut out = ::std::io::stdout(); + if line_out { for tag in &tags { - println!("{}", tag); + let _ = writeln!(out, "{}", tag) + .to_exit_code() + .unwrap_or_exit(); } } if sepp_out { let sepp = scmd.value_of("sep").unwrap(); // we checked before - println!("{}", tags.join(sepp)); + let _ = writeln!(out, "{}", tags.join(sepp)) + .to_exit_code() + .unwrap_or_exit(); } if comm_out { - println!("{}", tags.join(", ")); + let _ = writeln!(out, "{}", tags.join(", ")) + .to_exit_code() + .unwrap_or_exit(); } } From b9d04730dbbd71275a240370e3ce55004d22fc69 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 14 Feb 2018 23:49:52 +0100 Subject: [PATCH 22/22] Fix for broken pipe panics --- bin/core/imag-diagnostics/src/main.rs | 71 +++++++++++++++++++-------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/bin/core/imag-diagnostics/src/main.rs b/bin/core/imag-diagnostics/src/main.rs index 24426e68..43172192 100644 --- a/bin/core/imag-diagnostics/src/main.rs +++ b/bin/core/imag-diagnostics/src/main.rs @@ -41,8 +41,12 @@ extern crate libimagerror; extern crate libimagentrylink; extern crate libimagstore; +use std::io::Write; + use libimagrt::setup::generate_runtime_setup; use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; use libimagstore::error::StoreError as Error; @@ -151,39 +155,66 @@ fn main() { let n = diags.len(); - println!("imag version {}", env!("CARGO_PKG_VERSION")); - println!(""); - println!("{} entries", n); + let mut out = ::std::io::stdout(); + + let _ = writeln!(out, "imag version {}", env!("CARGO_PKG_VERSION")) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "") + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "{} entries", n) + .to_exit_code() + .unwrap_or_exit(); for (k, v) in version_counts { - println!("{} entries with store version '{}'", v, k); + let _ = writeln!(out, "{} entries with store version '{}'", v, k) + .to_exit_code() + .unwrap_or_exit(); } if n != 0 { - println!("{} header sections in the average entry", sum_header_sections / n); - println!("{} average content bytecount", sum_bytecount_content / n); - println!("{} average overall bytecount", sum_overall_byte_size / n); + let _ = writeln!(out, "{} header sections in the average entry", sum_header_sections / n) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "{} average content bytecount", sum_bytecount_content / n) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "{} average overall bytecount", sum_overall_byte_size / n) + .to_exit_code() + .unwrap_or_exit(); if let Some((num, path)) = max_overall_byte_size { - println!("Largest Entry ({bytes} bytes): {path}", - bytes = num, - path = path - .into_pathbuf() - .map_err_trace_exit_unwrap(1) - .to_str() - .unwrap_or("Failed converting path to string") - ); + let _ = writeln!(out, + "Largest Entry ({bytes} bytes): {path}", + bytes = num, + path = path + .into_pathbuf() + .map_err_trace_exit_unwrap(1) + .to_str() + .unwrap_or("Failed converting path to string") + ) + .to_exit_code() + .unwrap_or_exit(); } - println!("{} average internal link count per entry", num_internal_links / n); + let _ = writeln!(out, "{} average internal link count per entry", num_internal_links / n) + .to_exit_code() + .unwrap_or_exit(); if let Some((num, path)) = max_internal_links { - println!("Entry with most internal links ({count}): {path}", + let _ = writeln!(out, "Entry with most internal links ({count}): {path}", count = num, path = path .into_pathbuf() .map_err_trace_exit_unwrap(1) .to_str() .unwrap_or("Failed converting path to string") - ); + ) + .to_exit_code() + .unwrap_or_exit(); } - println!("{} verified entries", verified_count); - println!("{} unverified entries", unverified_count); + let _ = writeln!(out, "{} verified entries", verified_count) + .to_exit_code() + .unwrap_or_exit(); + let _ = writeln!(out, "{} unverified entries", unverified_count) + .to_exit_code() + .unwrap_or_exit(); } }