izb/
base.rs

1use std::io::Write;
2use std::fs::OpenOptions;
3use chrono::Local;
4use std::path::PathBuf;
5use std::process::Command;
6use std::thread;
7use std::time::Duration;
8
9pub fn write_logfile(message: &str) {
10    let now = Local::now();
11    let timestamp = now.format("%Y-%m-%d %H:%M:%S").to_string();
12    let date = now.format("%Y-%m-%d").to_string();
13    
14    let log_entry = format!("[{}] {}\n", timestamp, message);
15    
16    let log_dir = PathBuf::from("/opt/builder/log");
17    let log_file = log_dir.join(format!("{}.log", date));
18    
19    match OpenOptions::new()
20        .create(true)
21        .append(true)
22        .open(&log_file)
23    {
24        Ok(mut file) => {
25            match file.write_all(log_entry.as_bytes()) {
26                Ok(_) => {}
27                Err(e) => {
28                    eprintln!("ERROR: could not write to log file: {:?}: {}", log_file, e);
29                    std::process::exit(1);
30                }
31            }
32        }
33        Err(e) => {
34            eprintln!("ERROR: could not open log file: {:?}: {}", log_file, e);
35            std::process::exit(1);
36        }
37    }
38}
39
40pub fn log(message: &str) {
41    println!("{}", message);
42    write_logfile(message);
43}
44
45pub fn halt(message: &str) -> ! {
46    let error_message = &format!("ERROR: {}", message);
47    eprintln!("{}", error_message);
48    write_logfile(error_message);
49    std::process::exit(1)
50}
51
52pub fn perform( description: &str, mut check: Command, mut operation: Command ){
53    match check.output() {
54        Ok(output) => {
55            if output.status.success() {
56                log(&format!("{} was already done, skipping.", description));
57                return
58            } 
59        },
60        Err(e) => {
61            halt(&format!("Check command '{}' failed: {}", check.cmdline(), e));
62        }
63    }
64
65    match operation.output() {
66        Ok(output) => {
67            if output.status.success() {
68                log(&format!("{} succeeded.", description));
69            } else {
70                let stdout = String::from_utf8_lossy(&output.stdout);
71                let stderr = String::from_utf8_lossy(&output.stderr);
72                halt(&format!("Command '{}' failed:\nSTDOUT: {}\nSTDERR: {}", operation.cmdline(), stdout, stderr));
73            }
74        },
75        Err(e) => {
76            halt(&format!("Command '{}' failed: {}", operation.cmdline(), e));
77        }
78    }
79
80}
81
82
83trait CommandExt {
84    fn cmdline(&self) -> String;
85}
86
87impl CommandExt for Command {
88    fn cmdline(&self) -> String {
89        format!("{} {}",
90            self.get_program().to_str().unwrap_or(""),
91            self.get_args().map(|s| s.to_str().unwrap_or("")).collect::<Vec<_>>().join(" ")
92        )
93    }
94}
95
96
97pub fn wait(mut command: Command, sleep: u64) {
98    loop {
99        match command.output() {
100            Ok(output) => {
101                if output.status.success() {
102                    return;
103                } else {
104                    thread::sleep(Duration::from_secs(sleep));
105                }
106            },
107            Err(e) => {
108                halt(&format!("Command '{}' failed: {}", command.cmdline(), e));
109            }
110        }
111    }
112}