#[cfg(feature = "cmd")]
use anstyle::{
AnsiColor::{BrightBlue, BrightCyan, BrightGreen, Green, Red},
Color::Ansi,
Style,
};
#[cfg(feature = "cmd")]
use chardet::detect;
#[cfg(feature = "cmd")]
use encoding_rs::{Encoding, GBK, UTF_8, WINDOWS_1252};
#[cfg(feature = "cmd")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "cmd")]
fn detect_encoding(buf: &[u8]) -> &'static Encoding {
let result = detect(buf);
let encoding_name = result.0.to_lowercase();
let encoding_label = encoding_name.as_bytes();
if let Some((bom_encoding, _)) = Encoding::for_bom(buf) {
return bom_encoding;
}
if let Some(encoding) = Encoding::for_label(encoding_label) {
return encoding;
}
let (_, _, utf8_had_errors) = UTF_8.decode(buf);
if !utf8_had_errors {
return UTF_8;
}
let (_, _, gbk_had_errors) = GBK.decode(buf);
if !gbk_had_errors {
return GBK;
}
WINDOWS_1252
}
#[cfg(feature = "cmd")]
pub fn clap_help_styles() -> clap::builder::Styles {
clap::builder::Styles::styled()
.usage(Style::new().fg_color(Some(Ansi(BrightBlue))))
.header(Style::new().fg_color(Some(Ansi(BrightBlue))))
.literal(Style::new().fg_color(Some(Ansi(BrightGreen))))
.invalid(Style::new().bold().fg_color(Some(Ansi(Red))))
.error(Style::new().bold().fg_color(Some(Ansi(Red))))
.valid(Style::new().fg_color(Some(Ansi(Green))))
.placeholder(Style::new().fg_color(Some(Ansi(BrightCyan))))
}
#[cfg(feature = "cmd")]
#[derive(Debug, Deserialize, Serialize)]
pub struct CmdResult {
pub code: i32,
pub stdout: String,
pub stderr: String,
}
#[cfg(feature = "cmd")]
pub fn exec(cmd: &str, args: Option<&Vec<&str>>) -> Result<CmdResult, std::io::Error> {
use std::process::Command;
let mut cmd = Command::new(cmd);
if args.is_some_and(|a| !a.is_empty()) {
cmd.args(args.unwrap());
}
let ret = cmd.output();
let Ok(ret) = ret else {
return Err(ret.unwrap_err());
};
let code = ret.status.code().unwrap_or(-1);
let coding = detect_encoding(&ret.stdout);
let stdout = coding.decode(&ret.stdout).0.to_string();
let coding = detect_encoding(&ret.stderr);
let stderr = coding.decode(&ret.stderr).0.to_string();
Ok(CmdResult {
code,
stdout,
stderr,
})
}
#[cfg(all(feature = "cmd", target_os = "windows"))]
pub fn exec_raw(cmd: &str, args: Option<&str>) -> Result<CmdResult, std::io::Error> {
use std::{os::windows::process::CommandExt, process::Command};
let mut cmd = Command::new(cmd);
if let Some(args) = args {
cmd.raw_arg(args);
};
let ret = cmd.output();
let Ok(ret) = ret else {
return Err(ret.unwrap_err());
};
let code = ret.status.code().unwrap_or(-1);
let coding = detect_encoding(&ret.stdout);
let stdout = coding.decode(&ret.stdout).0.to_string();
let coding = detect_encoding(&ret.stderr);
let stderr = coding.decode(&ret.stderr).0.to_string();
Ok(CmdResult {
code,
stdout,
stderr,
})
}
#[test]
#[cfg(feature = "cmd")]
fn test_exec() {
let ret = exec("cmd", Some(&vec!["dir"])).unwrap();
println!("{:?}", ret);
}