evobench_tools/run/sub_command/
wd_log.rs

1use std::{
2    io::{BufWriter, Write, stderr, stdout},
3    os::unix::{ffi::OsStrExt, process::CommandExt},
4    process::Command,
5    time::Duration,
6};
7
8use anyhow::{Context, Result, anyhow, bail};
9
10use crate::run::working_directory_pool::{
11    WdAllowBareOpt, WorkingDirectoryIdOpt, WorkingDirectoryPool,
12};
13
14#[derive(Debug, clap::Args)]
15pub struct LogOrLogf {
16    /// Instead of opening the last log file, show a list of all
17    /// log files for the given working directory, sorted by run
18    /// start time (newest at the bottom)
19    #[clap(short, long)]
20    list: bool,
21
22    #[clap(flatten)]
23    allow_bare: WdAllowBareOpt,
24
25    /// The ID of the working direcory for which to show the (last)
26    /// log file(s)
27    id: WorkingDirectoryIdOpt,
28}
29
30impl LogOrLogf {
31    pub fn run(self, logf: bool, working_directory_pool: &WorkingDirectoryPool) -> Result<()> {
32        let Self {
33            list,
34            allow_bare,
35            id,
36        } = self;
37        let id = id.to_working_directory_id(allow_bare)?;
38
39        let working_directory_path =
40            if let Some(wd) = working_directory_pool.get_working_directory(id) {
41                wd.working_directory_path()
42            } else {
43                let mut out = BufWriter::new(stderr().lock());
44                writeln!(
45                    &mut out,
46                    "NOTE: working directory with id {id} does not exist. \
47                     Looking for log files anyway."
48                )?;
49                out.flush()?;
50                if !list {
51                    std::thread::sleep(Duration::from_millis(1400));
52                }
53                working_directory_pool.get_working_directory_path(id)
54            };
55
56        if list {
57            let mut out = BufWriter::new(stdout().lock());
58            for (standard_log_path, _run_id) in working_directory_path.standard_log_paths()? {
59                out.write_all(standard_log_path.as_os_str().as_bytes())?;
60                out.write_all(b"\n")?;
61            }
62            out.flush()?;
63        } else {
64            let (standard_log_path, _run_id) = working_directory_path
65                .last_standard_log_path()?
66                .ok_or_else(|| anyhow!("could not find a log file for working directory {id}"))?;
67
68            if logf {
69                let mut cmd = Command::new("tail");
70                cmd.arg("-F");
71                cmd.arg("--");
72                cmd.arg(standard_log_path);
73                return Err(cmd.exec()).with_context(|| anyhow!("executing {cmd:?}"));
74            } else {
75                let pager = match std::env::var("PAGER") {
76                    Ok(s) => s,
77                    Err(e) => match e {
78                        std::env::VarError::NotPresent => "less".into(),
79                        _ => bail!("can't decode PAGER env var: {e:#}"),
80                    },
81                };
82
83                let mut cmd = Command::new(&pager);
84                cmd.arg(standard_log_path);
85                return Err(cmd.exec()).with_context(|| anyhow!("executing pager {pager:?}"));
86            }
87        }
88        Ok(())
89    }
90}