1use anyhow::{Result, anyhow};
2use clap::{Parser, Subcommand};
3use futures::StreamExt;
4use std::path::PathBuf;
5
6use crate::cli::base_conversion::{BaseArgs, run_base_convert};
7use crate::cli::{StringInput, ToolResult, generate_help_bytes};
8use crate::utilities::{
9 fork, get_this_executable, upgrade_in_place,
10 wait_for_ctoolbox_exit_and_clean_up,
11};
12
13pub fn is_lightweight_command(command: String) -> bool {
15 matches!(
16 String::as_str(&command),
17 "base2base"
18 | "hex2dec"
19 | "dec2hex"
20 | "hexfmt"
21 | "gdb_instructions_generate"
22 | "help"
23 )
24}
25
26#[derive(Subcommand, Debug)]
27pub enum Command {
28 #[command(name = "waitshutdown")]
30 WaitShutdown {
31 #[arg(long)]
33 pid: u32,
34 },
35 #[command(name = "waitrestart")]
38 WaitRestart {
39 #[arg(long)]
41 pid: u32,
42 #[arg(long)]
44 port: u16,
45 },
46 #[command(name = "waitupgrade")]
50 WaitUpgrade {
51 #[arg(long)]
53 pid: u32,
54 #[arg(long)]
56 temp_path: PathBuf,
57 #[arg(long)]
59 target_path: PathBuf,
60 #[arg(long)]
62 port: u16,
63 },
64 #[command(name = "base2base")]
66 Base2Base {
67 #[arg(required = true)]
69 args: Vec<String>,
70 #[command(flatten)]
71 base_args: BaseArgs,
72 },
73 #[command(name = "hex2dec")]
75 Hex2Dec {
76 #[command(flatten)]
77 string_input: StringInput,
78 #[command(flatten)]
79 base_args: BaseArgs,
80 },
81 #[command(name = "dec2hex")]
83 Dec2Hex {
84 #[command(flatten)]
85 string_input: StringInput,
86 #[command(flatten)]
87 base_args: BaseArgs,
88 },
89 #[command(name = "hexfmt")]
91 Hexfmt {
92 #[command(flatten)]
93 string_input: StringInput,
94 #[command(flatten)]
95 base_args: BaseArgs,
96 },
97 #[command(name = "gdb_instructions_generate")]
99 GdbInstructionsGenerate {},
100 Help,
102 ShowNode {
104 #[arg(short, long)]
106 id: i128,
107 },
108}
109
110pub async fn run_lightweight_command(cmd: &Command) -> Result<ToolResult> {
115 match cmd {
116 Command::WaitShutdown { pid } => {
117 wait_for_ctoolbox_exit_and_clean_up(*pid);
118 Ok(ToolResult::immediate_ok(Vec::new()))
119 }
120 Command::WaitRestart { pid, port } => {
121 wait_for_ctoolbox_exit_and_clean_up(*pid);
122 fork(
123 &get_this_executable(),
124 vec!["--ctoolbox-ipc-port", &port.to_string().as_str()],
125 );
126 Ok(ToolResult::immediate_ok(Vec::new()))
127 }
128 Command::WaitUpgrade {
129 pid,
130 temp_path,
131 target_path,
132 port,
133 } => {
134 wait_for_ctoolbox_exit_and_clean_up(*pid);
135 upgrade_in_place(temp_path, target_path)?;
136 fork(
137 target_path,
138 vec!["--ctoolbox-ipc-port", &port.to_string().as_str()],
139 );
140 Ok(ToolResult::immediate_ok(Vec::new()))
141 }
142 Command::Base2Base { args, base_args } => {
143 let (input, from_base, to_base) = match args.len() {
144 1 => (&args[0], None, None),
145 3 => {
146 let from_base = Some(args[0].parse::<u8>()?);
147 let to_base = Some(args[1].parse::<u8>()?);
148 let input = &args[2];
149 (input, from_base, to_base)
150 }
151 _ => {
152 eprintln!(
153 "Invalid arguments! Usage: base2base [FROM_BASE TO_BASE INPUT] or [INPUT]"
154 );
155 std::process::exit(1);
156 }
157 };
158
159 run_base_convert(
160 &from_base,
161 &to_base,
162 &StringInput {
163 input: input.clone(),
164 },
165 base_args,
166 )
167 }
168 Command::Hex2Dec {
169 string_input,
170 base_args,
171 } => run_base_convert(&Some(16), &Some(10), string_input, base_args),
172 Command::Dec2Hex {
173 string_input,
174 base_args,
175 } => run_base_convert(&Some(10), &Some(16), string_input, base_args),
176 Command::Hexfmt {
177 string_input,
178 base_args,
179 } => run_base_convert(&Some(16), &Some(16), string_input, base_args),
180 Command::GdbInstructionsGenerate {} => {
181 crate::utilities::debug_tools::generate_gdb_instructions_streaming(
183 )?;
184 Ok(ToolResult::immediate_ok(Vec::new()))
185 }
186 Command::Help => Ok(ToolResult::immediate_ok(generate_help_bytes())),
187 Command::ShowNode { .. } => Err(anyhow!(
188 "ShowNode should not be run as lightweight command; it needs the full environment"
189 )),
190 }
191}