Add minimal CLI debug utilities

This commit is contained in:
NGnius (Graham) 2024-02-01 21:02:59 -05:00
parent 32a36f8627
commit 23f5f607cc
7 changed files with 273 additions and 2 deletions

113
backend/Cargo.lock generated
View file

@ -92,6 +92,54 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anstream"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "async-recursion" name = "async-recursion"
version = "1.0.5" version = "1.0.5"
@ -280,6 +328,46 @@ dependencies = [
"libloading", "libloading",
] ]
[[package]]
name = "clap"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]] [[package]]
name = "cmake" name = "cmake"
version = "0.1.50" version = "0.1.50"
@ -289,6 +377,12 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]] [[package]]
name = "community_settings_core" name = "community_settings_core"
version = "0.1.0" version = "0.1.0"
@ -624,6 +718,12 @@ dependencies = [
"http", "http",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.3" version = "0.3.3"
@ -1072,6 +1172,7 @@ name = "powertools"
version = "1.5.0-ng1" version = "1.5.0-ng1"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"clap",
"community_settings_core", "community_settings_core",
"libc", "libc",
"libryzenadj", "libryzenadj",
@ -1364,6 +1465,12 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.4.1" version = "2.4.1"
@ -1691,6 +1798,12 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"

View file

@ -37,6 +37,8 @@ libryzenadj = { version = "0.13" }
# ureq's tls feature does not like musl targets # ureq's tls feature does not like musl targets
ureq = { version = "2", features = ["json", "gzip", "brotli", "charset"], default-features = false, optional = true } ureq = { version = "2", features = ["json", "gzip", "brotli", "charset"], default-features = false, optional = true }
clap = { version = "4.4", features = [ "derive" ] }
[features] [features]
default = ["online", "decky"] default = ["online", "decky"]
decky = ["usdpl-back/decky"] decky = ["usdpl-back/decky"]

42
backend/src/cli/args.rs Normal file
View file

@ -0,0 +1,42 @@
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
/// TCP port for front-end client connection
#[arg(long)]
pub port: Option<u16>,
/// Override log file location
#[arg(long)]
pub log: Option<std::path::PathBuf>,
/// Force verbose logging
#[arg(short, long)]
pub verbose: bool,
/// Specail operation to perform
#[command(subcommand)]
pub op: Option<Operation>,
}
impl Args {
pub fn load() -> Self {
Self::parse()
}
pub fn is_default(&self) -> bool {
self.port.is_none()
&& self.log.is_none()
&& !self.verbose
&& self.op.is_none()
}
}
#[derive(Subcommand, Debug)]
pub enum Operation {
/// Dump useful system information for adding new device support
DumpSys,
/// Remove all files created by PowerTools, not including $HOME/homebrew/plugins/PowerTools/
Clean,
}

21
backend/src/cli/clean.rs Normal file
View file

@ -0,0 +1,21 @@
pub fn clean_up() -> Result<(), ()> {
let dirs = vec![
crate::utility::settings_dir_old(),
crate::utility::settings_dir(),
];
if let Err(e) = clean_up_io(dirs.iter()) {
log::error!("Error removing directories: {}", e);
Err(())
} else {
Ok(())
}
}
fn clean_up_io(directories: impl Iterator<Item=impl AsRef<std::path::Path>>) -> std::io::Result<()> {
let results = directories.map(|dir| std::fs::remove_dir_all(dir));
for res in results {
res?;
}
Ok(())
}

View file

@ -0,0 +1,66 @@
use std::path::{Path, PathBuf};
use std::process::Command;
use std::thread::{self, JoinHandle};
use std::sync::mpsc::{channel, Sender};
use std::io::Write;
pub fn dump_sys_info() -> Result<(), ()> {
let (tx, rx) = channel();
let mut join_handles = Vec::new();
let useful_files = vec![
PathBuf::from("/proc/ioports"),
PathBuf::from("/proc/cpuinfo"),
PathBuf::from("/etc/os-release"),
];
for file in useful_files {
join_handles.push(read_file(file, tx.clone()));
}
let useful_commands = vec![
"dmidecode",
];
for cmd in useful_commands.into_iter() {
join_handles.push(execute_command(cmd, tx.clone()));
}
for join_handle in join_handles.into_iter() {
if let Err(e) = join_handle.join() {
log::error!("Thread failed to complete: {:?}", e);
}
}
let mut dump_file = std::fs::File::create("powertools_sys_dump.txt").expect("Failed to create dump file");
for response in rx.into_iter() {
dump_file.write(
&format!("{} v{} ###### {} ######\n{}\n",
crate::consts::PACKAGE_NAME,
crate::consts::PACKAGE_VERSION,
response.0,
response.1.unwrap_or("[None]".to_owned())
).into_bytes()
).expect("Failed to write to dump file");
}
Ok(())
}
fn read_file(file: impl AsRef<Path> + Send + 'static, tx: Sender<(String, Option<String>)>) -> JoinHandle<()> {
thread::spawn(move || {
let file = file.as_ref();
tx.send(
(file.display().to_string(),
std::fs::read_to_string(file).ok())
).expect("Failed to send file contents");
})
}
fn execute_command(command: &'static str, tx: Sender<(String, Option<String>)>) -> JoinHandle<()> {
thread::spawn(move || {
tx.send(
(command.to_owned(), Command::new(command)
.output()
.map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
.ok()
)).expect("Failed to send command output");
}
)
}

12
backend/src/cli/mod.rs Normal file
View file

@ -0,0 +1,12 @@
mod args;
mod clean;
mod dump_sys;
pub use args::{Args, Operation};
pub fn do_op(op: &Operation) -> Result<(), ()> {
match op {
Operation::DumpSys => dump_sys::dump_sys_info(),
Operation::Clean => clean::clean_up(),
}
}

View file

@ -1,4 +1,5 @@
mod api; mod api;
mod cli;
mod persist; mod persist;
mod settings; mod settings;
mod state; mod state;
@ -19,13 +20,18 @@ use usdpl_back::core::serdes::Primitive;
use usdpl_back::Instance; use usdpl_back::Instance;
fn main() -> Result<(), ()> { fn main() -> Result<(), ()> {
let args = cli::Args::load();
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let log_filepath = usdpl_back::api::dirs::home() let log_filepath = usdpl_back::api::dirs::home()
.unwrap_or_else(|| "/tmp/".into()) .unwrap_or_else(|| "/tmp/".into())
.join(PACKAGE_NAME.to_owned() + ".log"); .join(PACKAGE_NAME.to_owned() + ".log");
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
let log_filepath = std::path::Path::new("/tmp").join(format!("{}.log", PACKAGE_NAME)); let log_filepath = std::path::Path::new("/tmp").join(format!("{}.log", PACKAGE_NAME));
let log_filepath = args.log.clone().unwrap_or(log_filepath);
println!("Logging to: {:?}", log_filepath); println!("Logging to: {:?}", log_filepath);
if !args.is_default() {
println!("CLI arguments, as parsed: {:?}", &args);
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let old_log_filepath = usdpl_back::api::dirs::home() let old_log_filepath = usdpl_back::api::dirs::home()
.unwrap_or_else(|| "/tmp/".into()) .unwrap_or_else(|| "/tmp/".into())
@ -44,7 +50,7 @@ fn main() -> Result<(), ()> {
}, },
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
{ {
LevelFilter::Info if args.verbose { LevelFilter::Debug } else { LevelFilter::Info }
}, },
Default::default(), Default::default(),
std::fs::File::create(&log_filepath).expect("Failed to create log file"), std::fs::File::create(&log_filepath).expect("Failed to create log file"),
@ -52,6 +58,15 @@ fn main() -> Result<(), ()> {
) )
.unwrap(); .unwrap();
log::debug!("Logging to: {:?}.", log_filepath); log::debug!("Logging to: {:?}.", log_filepath);
log::info!("CLI arguments, as parsed: {:?}", &args);
// sepcial operation start-up
if let Some(op) = &args.op {
return cli::do_op(op);
// do not continue with regular startup
}
// regular start-up
log::info!("Starting back-end ({} v{})", PACKAGE_NAME, PACKAGE_VERSION); log::info!("Starting back-end ({} v{})", PACKAGE_NAME, PACKAGE_VERSION);
println!("Starting back-end ({} v{})", PACKAGE_NAME, PACKAGE_VERSION); println!("Starting back-end ({} v{})", PACKAGE_NAME, PACKAGE_VERSION);
log::info!( log::info!(
@ -125,7 +140,7 @@ fn main() -> Result<(), ()> {
let (message_getter, message_dismisser) = api::message::MessageHandler::new().to_callables(); let (message_getter, message_dismisser) = api::message::MessageHandler::new().to_callables();
let instance = Instance::new(PORT) let instance = Instance::new(args.port.unwrap_or(PORT))
.register("V_INFO", |_: Vec<Primitive>| { .register("V_INFO", |_: Vec<Primitive>| {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {