use std::{
io::Write,
os::raw::c_int,
path::Path,
};
use futures::StreamExt;
use signal_hook_tokio::Signals;
use tokio::sync::mpsc::UnboundedReceiver;
use tracexec_core::{
cli::{
args::{
LogModeArgs,
TuiModeArgs,
},
options::ExportFormat,
},
event::TracerMessage,
export::{
Exporter,
ExporterMetadata,
},
proc::BaselineInfo,
pty::{
PtySize,
PtySystem,
UnixMasterPty,
native_pty_system,
},
tracer::TracerMode,
};
use tracexec_exporter_json::{
JsonExporter,
JsonStreamExporter,
};
use tracexec_exporter_perfetto::PerfettoExporter;
pub fn spawn_signal_handler(
watched_signals: impl IntoIterator<Item = c_int>,
mut handler: impl FnMut(c_int) + Send + 'static,
) -> color_eyre::Result<()> {
let mut signals = Signals::new(watched_signals)?;
tokio::spawn(async move {
while let Some(signal) = signals.next().await {
handler(signal);
}
});
Ok(())
}
pub fn initialize_tui(tui_args: &TuiModeArgs, executable_path: &Path) -> color_eyre::Result<()> {
tracexec_tui::theme::initialize(
tui_args.theme_file.as_ref().map(|path| path.as_deref()),
tui_args.theme.as_deref(),
executable_path,
tui_args
.theme_file
.as_ref()
.is_some_and(|path| path.is_from_cli()),
)?;
owo_colors::control::set_should_colorize(false);
Ok(())
}
pub fn setup_tui_io(
tty: bool,
tracee_env: Option<&[(std::ffi::OsString, std::ffi::OsString)]>,
) -> color_eyre::Result<(BaselineInfo, TracerMode, Option<UnixMasterPty>)> {
if !tty {
return Ok((
BaselineInfo::new_with_env(tracee_env)?,
TracerMode::Tui(None),
None,
));
}
let pair = native_pty_system().openpty(PtySize::default())?;
Ok((
BaselineInfo::with_pts_and_env(&pair.slave, tracee_env)?,
TracerMode::Tui(Some(pair.slave)),
Some(pair.master),
))
}
pub fn tui_log_args() -> LogModeArgs {
LogModeArgs {
show_cmdline: false, show_argv: true,
show_interpreter: true,
more_colors: false,
less_colors: false,
diff_env: true,
..Default::default()
}
}
pub fn collect_log_args(foreground: bool, no_foreground: bool) -> LogModeArgs {
LogModeArgs {
show_cmdline: false,
show_argv: true,
show_interpreter: true,
more_colors: false,
less_colors: false,
diff_env: false,
foreground,
no_foreground,
..Default::default()
}
}
pub async fn run_exporter(
format: ExportFormat,
output: Box<dyn Write + Send + Sync + 'static>,
metadata: ExporterMetadata,
events: UnboundedReceiver<TracerMessage>,
) -> color_eyre::Result<i32> {
match format {
ExportFormat::Json => JsonExporter::new(output, metadata, events)?.run().await,
ExportFormat::JsonStream => {
JsonStreamExporter::new(output, metadata, events)?
.run()
.await
}
ExportFormat::Perfetto => PerfettoExporter::new(output, metadata, events)?.run().await,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tui_log_args_enable_tui_rendering_inputs() {
let args = tui_log_args();
assert!(!args.show_cmdline);
assert!(args.show_argv);
assert!(args.show_interpreter);
assert!(args.diff_env);
assert!(!args.more_colors);
assert!(!args.less_colors);
}
#[test]
fn collect_log_args_preserve_foreground_choice() {
let args = collect_log_args(true, false);
assert!(args.show_argv);
assert!(args.show_interpreter);
assert!(!args.diff_env);
assert!(args.foreground);
assert!(!args.no_foreground);
}
}