317 lines
11 KiB
Rust
317 lines
11 KiB
Rust
|
|
#![ allow( warnings ) ]
|
|
|
|
use std::env;
|
|
use clap::{ArgAction, ArgMatches};
|
|
use clap::{Arg, crate_version, Command};
|
|
use log::Level;
|
|
use log::LevelFilter;
|
|
use env_logger::Builder;
|
|
use std::io::Write;
|
|
use colored::Colorize;
|
|
use log::{trace, debug, info, warn, error};
|
|
use std::ffi::{c_char, CStr};
|
|
|
|
mod error;
|
|
mod utils;
|
|
mod victor;
|
|
mod eval;
|
|
|
|
mod commands {
|
|
pub mod info;
|
|
pub mod stat;
|
|
pub mod run;
|
|
pub mod build;
|
|
pub mod list;
|
|
pub mod gui;
|
|
pub mod env;
|
|
pub mod snix_testing;
|
|
}
|
|
|
|
static APPNAME: &str = "vic";
|
|
static DEFAULT_LOG_LEVEL: LevelFilter = LevelFilter::Warn;
|
|
|
|
fn main() {
|
|
|
|
let cli_matches = cli_matches();
|
|
|
|
//init_logger(&cli_matches);
|
|
|
|
// log a message of every level, to test loging
|
|
// test_logger();
|
|
|
|
// match the subcommands
|
|
let result = match cli_matches.subcommand() {
|
|
Some(("info", sub_matches)) => commands::info::main(&sub_matches),
|
|
Some(("stat", sub_matches)) => commands::stat::main(&sub_matches),
|
|
Some(("run", sub_matches)) => commands::run::main(&sub_matches),
|
|
Some(("build", sub_matches)) => commands::build::main(&sub_matches),
|
|
Some(("list", sub_matches)) => commands::list::main(&sub_matches),
|
|
Some(("gui", sub_matches)) => commands::gui::main(&sub_matches),
|
|
|
|
Some(("env", sub_matches)) => commands::env::main(&sub_matches),
|
|
Some(("env-get", sub_matches)) => commands::env::get(&sub_matches),
|
|
|
|
Some(("snix-mount", sub_matches)) => commands::snix_testing::run_mount_blocking(&sub_matches),
|
|
Some(("snix-test", sub_matches)) => commands::snix_testing::run_snix_test(&sub_matches),
|
|
Some(("snix-build", sub_matches)) => commands::snix_testing::run_build(&sub_matches),
|
|
|
|
None => { println!("Hi, this is victorinix (also known as victor or vic). \nrun 'vic help' for a list of subcommands."); Ok(())},
|
|
Some((unknown_subcommand, _)) => { println!("The subcommand '{}' is not known to victorinix", unknown_subcommand); Ok(()) },
|
|
};
|
|
|
|
if let Err(vic_err) = result {
|
|
vic_err.log();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn test() {
|
|
let c_buf: *const c_char = unsafe { libelf::raw::elf_errmsg(-1) };
|
|
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
|
|
let str_slice: &str = c_str.to_str().unwrap();
|
|
println!("ERROR: {}", str_slice);
|
|
|
|
}
|
|
|
|
fn init_logger(cli_matches: &ArgMatches) {
|
|
|
|
// to save log messages, before the logger is setup
|
|
let mut log_messages: Vec<(Level, String)> = Vec::new();
|
|
|
|
log_messages.push((Level::Trace, "Starting victorinix".to_owned()));
|
|
|
|
// builder with DEFAULT_LOG_LEVEL
|
|
let mut builder = Builder::new();
|
|
builder.format_indent(Some(8));
|
|
|
|
|
|
|
|
// set loglevel
|
|
let mut log_level = DEFAULT_LOG_LEVEL;
|
|
log_messages.push((Level::Trace, format!("set log level to {} as specified by DEFAULT_LOG_LEVEL in the src/main.rs", DEFAULT_LOG_LEVEL)));
|
|
|
|
// check env RUST_LOG
|
|
let mut val_rust_log = level_from_env("RUST_LOG", log_level);
|
|
log_level = if let Some(level_rust_log) = val_rust_log.0 {
|
|
log_messages.push((Level::Trace, format!("set log level from the Variable RUST_LOG to {}", level_rust_log)));
|
|
level_rust_log
|
|
} else {log_level};
|
|
log_messages.append(&mut val_rust_log.1);
|
|
|
|
// check env VICTORINIX_LOG
|
|
let mut val_victorinix_log = level_from_env("VICTORINIX_LOG", log_level);
|
|
log_level = if let Some(level_victorinix_log) = val_victorinix_log.0 {
|
|
log_messages.push((Level::Trace, format!("set log level from the Variable VICTORINIX_LOG to {}", level_victorinix_log)));
|
|
level_victorinix_log
|
|
} else {log_level};
|
|
log_messages.append(&mut val_victorinix_log.1);
|
|
|
|
|
|
// check -vvvvv flags
|
|
let v_flag_count = cli_matches.get_count("verbose");
|
|
let old_log_level_as_num = match log_level {
|
|
LevelFilter::Off => 0,
|
|
LevelFilter::Error => 1,
|
|
LevelFilter::Warn => 2,
|
|
LevelFilter::Info => 3,
|
|
LevelFilter::Debug => 4,
|
|
LevelFilter::Trace => 5,
|
|
};
|
|
let new_log_level_num = old_log_level_as_num + v_flag_count;
|
|
|
|
log_level = match new_log_level_num {
|
|
0 => LevelFilter::Off,
|
|
1 => LevelFilter::Error,
|
|
2 => LevelFilter::Warn,
|
|
3 => LevelFilter::Info,
|
|
4 => LevelFilter::Debug,
|
|
5 => LevelFilter::Trace,
|
|
_ => {
|
|
log_messages.push((Level::Trace, format!("the number of verbose (-v) flags passed ({}) exeeds the maximumg log_level", v_flag_count)));
|
|
LevelFilter::Trace
|
|
},
|
|
};
|
|
log_messages.push((Level::Trace, format!("set log level from the verbose flags to {}", log_level)));
|
|
|
|
|
|
// check --log-level arg
|
|
if let Some(log_level_arg_string) = cli_matches.get_one::<String>("log-level") {
|
|
let log_level_from_arg = match log_level_arg_string.to_lowercase().as_str() {
|
|
"none" => LevelFilter::Off,
|
|
"trace" => LevelFilter::Trace,
|
|
"all" => LevelFilter::Trace,
|
|
"debug" => LevelFilter::Debug,
|
|
"info" => LevelFilter::Info,
|
|
"warn" => LevelFilter::Warn,
|
|
"error" => LevelFilter::Error,
|
|
_ => {
|
|
log_messages.push((Level::Warn, format!(
|
|
"The argument to --log-level \"{}\" is not a valid log-level. loglevel stays at: {}"
|
|
, log_level_arg_string
|
|
, log_level
|
|
)));
|
|
log_level
|
|
}
|
|
};
|
|
log_level = log_level_from_arg;
|
|
log_messages.push((Level::Trace, format!("set log level from the --log-level arg to {}", log_level_from_arg)));
|
|
}
|
|
|
|
// check --silent flag
|
|
if cli_matches.get_flag("silent") {
|
|
if log_level != DEFAULT_LOG_LEVEL {
|
|
log_messages.push((Level::Warn, format!(
|
|
"The loglevel was set by some method (it's not the DEFAULT_LOG_LEVEL) and is now overwritten by the --siltne to be OFF"
|
|
)))
|
|
}
|
|
log_level = LevelFilter::Off;
|
|
}
|
|
|
|
// actually set the log_level on the builder
|
|
builder.filter_level(log_level);
|
|
log_messages.push((Level::Info, format!("loglevel is now {}", log_level)));
|
|
|
|
|
|
// set format
|
|
builder.format(|buf, record| {
|
|
match record.level() {
|
|
Level::Trace => writeln!(buf, "[ {} ] {}", format!("{}", record.level()).yellow(), record.args()),
|
|
Level::Debug => writeln!(buf, "[ {} ] {}", format!("{}", record.level()).green(), record.args()),
|
|
Level::Info => writeln!(buf, "[ {} ] {}", format!("{}", record.level()).blue(), record.args()),
|
|
Level::Warn => writeln!(buf, "[ {} ] {}", format!("{}", record.level()).truecolor(245, 164, 66), record.args()),
|
|
Level::Error => writeln!(buf, "[ {} ] {}", format!("{}", record.level()).red(), record.args()),
|
|
}
|
|
});
|
|
|
|
builder.init();
|
|
|
|
|
|
// write out all log messages from log_messages
|
|
for (level, msg) in log_messages {
|
|
match level {
|
|
Level::Error => error!("{}", msg),
|
|
Level::Warn => warn!("{}", msg),
|
|
Level::Info => info!("{}", msg),
|
|
Level::Debug => debug!("{}", msg),
|
|
Level::Trace => trace!("{}", msg),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn test_logger() {
|
|
error!("hi from error");
|
|
warn!("hi from warn");
|
|
info!("hi from info");
|
|
debug!("hi from debug");
|
|
trace!("hi from trace");
|
|
}
|
|
|
|
fn level_from_env(var_name: &str, log_level: LevelFilter) -> (Option<log::LevelFilter>, Vec<(Level, String)>) {
|
|
let mut log_messages: Vec<(Level, String)> = Vec::new();
|
|
let var_value = env::var(var_name);
|
|
match var_value {
|
|
Ok(val) => {
|
|
// set loglevel acording to RUST_LOG
|
|
let level = match val.to_lowercase().as_str() {
|
|
"none" => LevelFilter::Off,
|
|
"trace" => LevelFilter::Trace,
|
|
"debug" => LevelFilter::Debug,
|
|
"info" => LevelFilter::Info,
|
|
"warn" => LevelFilter::Warn,
|
|
"error" => LevelFilter::Error,
|
|
_ => {
|
|
log_messages.push((Level::Warn, format!(
|
|
"The value of Environment Variable {}: \"{}\" is not a valid log-level. loglevel stays at: {}"
|
|
, var_name
|
|
, val
|
|
, log_level
|
|
)));
|
|
log_level
|
|
}
|
|
};
|
|
return (Some(level), log_messages)
|
|
},
|
|
Err(env::VarError::NotPresent) => {},
|
|
Err(env::VarError::NotUnicode(os_string)) => {
|
|
|
|
let os_string_as_hex : String = os_string.clone().into_encoded_bytes().iter()
|
|
.map(|b| format!("{:02x}", b).to_string())
|
|
.collect::<Vec<String>>()
|
|
.join("");
|
|
log_messages.push((Level::Debug, format!(
|
|
"value of Environment Variable {} was not a unicode valid string. Therefore ignoring it.
|
|
\n value with replacement char U+FFFD: {}
|
|
\n the WTF-8 raw bytes as hex: {}"
|
|
, var_name
|
|
, os_string.to_string_lossy(), os_string_as_hex
|
|
)));
|
|
},
|
|
};
|
|
return (None, log_messages);
|
|
}
|
|
|
|
fn cli_matches() -> clap::ArgMatches {
|
|
|
|
let main = Command::new(APPNAME)
|
|
.version(crate_version!())
|
|
.author("Sebastian Moser (c2vi)")
|
|
.about("Victorinix: Friendly and usefull box of portable computer tools. Powered by Nix and MiZe")
|
|
.arg_required_else_help(true)
|
|
.arg(Arg::new("verbose")
|
|
.long("verbose")
|
|
.short('v')
|
|
.action(ArgAction::Count)
|
|
)
|
|
.arg(Arg::new("log-level")
|
|
.long("log-level")
|
|
.value_name("LOGLEVEL")
|
|
.help("set the log-level to one of OFF, ERROR, WARN, INFO, DEBUG, TRACE")
|
|
)
|
|
.arg(Arg::new("silent")
|
|
.long("silent")
|
|
.action(ArgAction::SetTrue)
|
|
.help("set the log-level to OFF")
|
|
)
|
|
.subcommand(Command::new("info")
|
|
)
|
|
.subcommand(Command::new("stat")
|
|
)
|
|
.subcommand(Command::new("run")
|
|
.arg(Arg::new("runnable")
|
|
.help("The item to be run")
|
|
.action(clap::ArgAction::Append)
|
|
.trailing_var_arg(true)
|
|
)
|
|
//.arg(Arg::new("rest")
|
|
//.help("args to pass down to the runnable command")
|
|
//)
|
|
)
|
|
.subcommand(Command::new("build")
|
|
)
|
|
.subcommand(Command::new("list")
|
|
)
|
|
.subcommand(Command::new("gui")
|
|
)
|
|
|
|
.subcommand(Command::new("env")
|
|
)
|
|
.subcommand(Command::new("env-get")
|
|
.alias("eg")
|
|
)
|
|
|
|
.subcommand(Command::new("snix-mount")
|
|
.alias("sm")
|
|
)
|
|
.subcommand(Command::new("snix-test")
|
|
.alias("st")
|
|
)
|
|
.subcommand(Command::new("snix-build")
|
|
.alias("sb")
|
|
)
|
|
;
|
|
|
|
return main.get_matches();
|
|
}
|