1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use regex::Regex;
use structopt::StructOpt;

use std::io;
use std::path::PathBuf;
use std::process;

pub mod exec;
pub mod filter;

/// run scripts or programs in a directory
#[derive(StructOpt, Debug)]
#[structopt()]
pub struct Opt {
    /// print the names of the scripts which would be run, but don't actually run them.
    #[structopt(long)]
    pub test: bool,

    /// print the names of the all matching files (not limited to executables), but don't
    /// actually run them. This option cannot be used with --test.
    #[structopt(long)]
    pub list: bool,

    /// print the name of each script to stderr before running.
    #[structopt(short, long)]
    pub verbose: bool,

    /// similar to --verbose, but only prints the name of scripts which produce output.
    /// The script's name is printed to whichever of stdout or stderr the script produces
    /// output on. The script's name is not printed to stderr if --verbose also specified.
    #[structopt(long)]
    pub report: bool,

    /// reverse the scripts' execution order.
    #[structopt(long)]
    pub reverse: bool,

    /// exit as soon as a script returns with a non-zero exit code.
    #[structopt(long)]
    pub exit_on_error: bool,

    /// sets the umask to umask before running the scripts. umask should be specified in
    /// octal. By default the umask is set to 022.
    #[structopt(long, default_value = "022")]
    pub umask: String,

    /// filename must be in one or more of either the LANANA-assigned namespace, the LSB
    /// namespaces - either hierarchical or reserved - or the Debian cron script namespace.
    #[structopt(long)]
    pub lsbsysinit: bool,

    /// validate filenames against custom extended regular expression REGEX.
    #[structopt(long)]
    pub regex: Option<Regex>,

    /// pass argument to the scripts.  Use --arg once for each argument you want passed.
    #[structopt(short = "a", long)]
    pub arg: Vec<String>,

    #[structopt(name = "DIRECTORY", parse(from_os_str))]
    pub dir: PathBuf,
}

impl Opt {
    pub fn usage_error(self: &Self, s: &str) {
        eprintln!("{}", s);
        eprintln!("");
        let app = Self::clap();
        let mut out = io::stderr();
        app.write_help(&mut out).expect("failed to write to stderr");
        eprintln!("");
        process::exit(exitcode::USAGE)
    }

    #[cfg(debug_assertions)]
    pub fn debug_options(self: &Self) {
        dbg!("{:#?}", &self);
    }

    #[cfg(not(debug_assertions))]
    pub fn debug_options(self: &Self) {}
}

#[derive(Default)]
pub struct Status {
    pub exit_code: exitcode::ExitCode,
}

impl Status {
    pub fn reset(&mut self) {
        self.exit_code = exitcode::OK;
    }
}

pub struct Report {
    report_string: String,
    report: bool,
    verbose: bool,
    used: bool,
}

impl Report {
    pub fn new(opt: &Opt, fp: &PathBuf) -> Report {
        Report {
            report_string: String::from(fp.to_str().expect("cannot get file path")),
            report: opt.report,
            verbose: opt.verbose,
            used: false,
        }
    }

    fn get_report(self: &mut Self, condition: bool) -> Option<&String> {
        if self.used {
            return None;
        }
        self.used = true;
        if condition {
            Some(&self.report_string)
        } else {
            None
        }
    }

    pub fn out_report(self: &mut Self) -> Option<&String> {
        self.get_report(self.report)
    }

    pub fn err_report(self: &mut Self) -> Option<&String> {
        self.get_report(self.report && !self.verbose)
    }
}