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
//! Miscellaneous convenience functions
//! 
//! These functions make some menial tasks a little easier to do,
//! like getting the executable's name, or running a command
use std::{
    env, fmt,
    path::Path,
    ffi::OsStr,
    process::{Child, Command}
};
use std::process::Stdio;

/// Data returned by utils::run_command()
///
/// This has the command's output, status code, and whether it was successful or not
pub struct CommandOutput {
    pub output: String,
    pub success: bool,
    pub code: u32
}

/// Run a command and return the output, status code, and whether the command succeeded or not
pub fn run_command<A: IntoIterator<Item = S> + Clone, S: AsRef<OsStr>>(prog: &str, superuser: bool, args: A) -> CommandOutput {
    let mut cmd = if superuser {
        let mut cmd_t = Command::new("sudo");
        cmd_t.arg(prog);
        cmd_t
    }
    else { Command::new(prog) };

    cmd.args(args);
    let output = match cmd.output() {
        Ok(o) => o,
        Err(why) => {
            return CommandOutput {
                output: why.to_string(),
                success: false,
                code: 666
            };
        }
    };
    let success = output.status.success();
    let mut o_fmt = if success { String::from_utf8(output.stdout).unwrap() } else { String::from_utf8(output.stderr).unwrap() };
    o_fmt.pop();

    CommandOutput {
        output: o_fmt,
        success,
        code: output.status.code().unwrap_or(1) as u32
    }
}

/// Spawn a detached process
pub fn spawn_process<A: IntoIterator<Item = S> + Clone, S: AsRef<OsStr>>(prog: &str, superuser: bool, shout_output: bool, args: A) -> Child {
    let mut cmd = if superuser {
        let mut cmd_t = Command::new("sudo");
        cmd_t.arg(prog);
        cmd_t
    }
    else {
        Command::new(prog)
    };
    if !shout_output {
        cmd.stdout(Stdio::null());
        cmd.stderr(Stdio::null());
    }

    cmd.args(args);
    cmd.spawn().unwrap()
}

/// Alphabetizes a vector of strings
pub fn alphabetize<L: fmt::Display>(list: &[L]) -> Vec<String> {
    // extract the strings from the generic value
    let mut string_list: Vec<String> = list.iter().map(|s| s.to_string()).collect();
    string_list.sort_unstable_by_key(|a| a.to_lowercase());
    string_list
}

/// Get the name of the file/directory from a file path
pub fn get_filename<D: Into<String>>(dir: D) -> String {
    let dir_t = dir.into();
    let dir_vec = dir_t.split('/');
    dir_vec.last().unwrap().to_string()
}

/// Gets the parent directory from a file path
pub fn get_parent<D: Into<String>>(dir: D) -> String {
    let dir_t = dir.into();
    let mut dir_vec: Vec<&str> = dir_t.split('/').collect();
    dir_vec.pop();
    dir_vec.pop();
    let mut new_dir= String::from("");

    for (_, folder) in dir_vec.iter().enumerate(){
        for c in folder.chars(){
            new_dir.push(c);
        }
        new_dir.push('/');
    }
    new_dir
}

/// Capitalize the first letter in a string
pub fn capitalize<W: fmt::Display>(word: W) -> String {
    let s1 = word.to_string();
    let mut v: Vec<char> = s1.chars().collect();

    for item in &mut v {
        if item.is_ascii_alphanumeric() {
            *item = item.to_ascii_uppercase();
            break;
        }
    }

    let s2: String = v.into_iter().collect();
    s2
}

/// Get the name of the executable
pub fn get_execname() -> String {
    env::args().next()
        .as_ref()
        .map(Path::new)
        .and_then(Path::file_name)
        .and_then(OsStr::to_str)
        .map(String::from).unwrap()
}