summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-07-25 20:23:51 +0200
committerMatthias Beyer <mail@beyermatthias.de>2019-07-25 20:32:33 +0200
commit6ac6db57d11eeb2393fe0771db630899e9ea326c (patch)
tree274329e4e3d37955ff22c1f1801685945c9e8074
parentd5fd773da813832f93ee8bec59427b7b248d7373 (diff)
Add imag-timetrack shell
This patch adds a subcommand to imag-timetrack which allows a user to start a $SHELL and start a timetracking with it and as soon as the shell exits, the timetracking is stopped. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--bin/domain/imag-timetrack/src/main.rs3
-rw-r--r--bin/domain/imag-timetrack/src/shell.rs110
-rw-r--r--bin/domain/imag-timetrack/src/stop.rs2
-rw-r--r--bin/domain/imag-timetrack/src/ui.rs27
4 files changed, 141 insertions, 1 deletions
diff --git a/bin/domain/imag-timetrack/src/main.rs b/bin/domain/imag-timetrack/src/main.rs
index 2862b6d7..1c06e845 100644
--- a/bin/domain/imag-timetrack/src/main.rs
+++ b/bin/domain/imag-timetrack/src/main.rs
@@ -55,6 +55,7 @@ mod cont;
mod day;
mod list;
mod month;
+mod shell;
mod start;
mod stop;
mod track;
@@ -66,6 +67,7 @@ use crate::cont::cont;
use crate::day::day;
use crate::list::{list, list_impl};
use crate::month::month;
+use crate::shell::shell;
use crate::start::start;
use crate::stop::stop;
use crate::track::track;
@@ -91,6 +93,7 @@ fn main() {
"day" => day(&rt),
"list" => list(&rt),
"month" => month(&rt),
+ "shell" => shell(&rt),
"start" => start(&rt),
"stop" => stop(&rt),
"track" => track(&rt),
diff --git a/bin/domain/imag-timetrack/src/shell.rs b/bin/domain/imag-timetrack/src/shell.rs
new file mode 100644
index 00000000..97d659a8
--- /dev/null
+++ b/bin/domain/imag-timetrack/src/shell.rs
@@ -0,0 +1,110 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and 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::env;
+use std::process::Command;
+
+use filters::filter::Filter;
+
+use libimagerror::exit::ExitUnwrap;
+use libimagerror::iter::TraceIterator;
+use libimagerror::trace::MapErrTrace;
+use libimagerror::trace::trace_error;
+use libimagrt::runtime::Runtime;
+use libimagtimetrack::iter::filter::has_one_of_tags;
+use libimagtimetrack::store::TimeTrackStore;
+use libimagtimetrack::tag::TimeTrackingTag;
+use libimagtimetrack::timetracking::TimeTracking;
+use libimagutil::warn_result::*;
+
+pub fn shell(rt: &Runtime) -> i32 {
+ let (_, cmd) = rt.cli().subcommand();
+ let cmd = cmd.unwrap(); // checked in main()
+
+ let start = ::chrono::offset::Local::now().naive_local();
+ let tags = cmd.values_of("tags")
+ .unwrap() // enforced by clap
+ .map(String::from)
+ .map(TimeTrackingTag::from)
+ .collect::<Vec<_>>();
+
+ let mut shellcmd = {
+ let mkshell = |s: String| {
+ let mut cmd = Command::new(s);
+ cmd.stdin(::std::process::Stdio::inherit());
+ cmd.stdout(::std::process::Stdio::inherit());
+ cmd.stderr(::std::process::Stdio::inherit());
+ cmd
+ };
+
+ if let Some(s) = cmd.value_of("shell") {
+ mkshell(s.to_owned())
+ } else {
+ env::var("SHELL")
+ .map(|s| mkshell(s))
+ .map_err(|e| match e {
+ env::VarError::NotPresent => {
+ error!("No $SHELL variable in environment, cannot work!");
+ ::std::process::exit(1)
+ },
+ env::VarError::NotUnicode(_) => {
+ error!("$SHELL variable is not unicode, cannot work!");
+ ::std::process::exit(1)
+ }
+ })
+ .unwrap()
+ }
+ };
+
+ for tag in tags.iter() {
+ match rt.store().create_timetracking_at(&start, tag) {
+ Err(e) => trace_error(&e),
+ Ok(entry) => {
+ let _ = rt.report_touched(entry.get_location()).unwrap_or_exit();
+ }
+ }
+ }
+
+ let exit_code = match shellcmd.status() {
+ Ok(estat) => estat.code().unwrap_or(0),
+ Err(e) => {
+ error!("Error starting shell: {:?}", e);
+ ::std::process::exit(2)
+ },
+ };
+
+ let stop = ::chrono::offset::Local::now().naive_local();
+ let filter = has_one_of_tags(&tags);
+ rt.store()
+ .get_timetrackings()
+ .map_warn_err_str("Getting timetrackings failed")
+ .map_err_trace_exit_unwrap()
+ .trace_unwrap()
+ .filter(|e| filter.filter(e))
+ .for_each(|mut elem| if let Err(e) = elem.set_end_datetime(stop.clone()) {
+ trace_error(&e)
+ } else {
+ debug!("Setting end time worked: {:?}", elem);
+ let _ = rt.report_touched(elem.get_location()).unwrap_or_exit();
+ });
+
+ ::std::process::exit(exit_code)
+}
+
+
diff --git a/bin/domain/imag-timetrack/src/stop.rs b/bin/domain/imag-timetrack/src/stop.rs
index f5df726c..8bcd344b 100644
--- a/bin/domain/imag-timetrack/src/stop.rs
+++ b/bin/domain/imag-timetrack/src/stop.rs
@@ -98,7 +98,7 @@ pub fn stop(rt: &Runtime) -> i32 {
1
}
Ok(_) => {
- format!("Setting end time worked: {:?}", elem);
+ debug!("Setting end time worked: {:?}", elem);
let _ = rt.report_touched(elem.get_location()).unwrap_or_exit();
acc
}
diff --git a/bin/domain/imag-timetrack/src/ui.rs b/bin/domain/imag-timetrack/src/ui.rs
index a654a819..2803ec9b 100644
--- a/bin/domain/imag-timetrack/src/ui.rs
+++ b/bin/domain/imag-timetrack/src/ui.rs
@@ -183,4 +183,31 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.help("Limit to certain tags"))
)
+ .subcommand(SubCommand::with_name("shell")
+ .about("Start a shell and start timetracking, stop when shell exits")
+ .version("0.1")
+ .long_about(r#"
+ Tries to find the current shell via $SHELL. If none is found, this aborts operation and returns 1.
+ If a shell is found in the environment variables, the time tracking is created and the shell started.
+ As soon as the shell exits (no matter what exit code), the timetracking is stopped.
+ The command exits with the exit code of the shell it started. If there is no exit code, this exits with 0.
+ If there was a failure during setting the end-time, the command exits with the exit code of the shell anyways, but prints error information.
+ If the command for the shell could not be executed, this fails with 2.
+ "#)
+
+ .arg(Arg::with_name("shell")
+ .long("shell")
+ .short("s")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .help("Shell to start, defaults to $SHELL"))
+
+ .arg(Arg::with_name("tags")
+ .index(1)
+ .required(true)
+ .multiple(true)
+ .help("Tags to start"))
+ )
+
}