Skip to content

Commit 12be466

Browse files
SteveL-MSFTSteve Lee (POWERSHELL HE/HIM) (from Dev Box)
andauthored
Update dsc.exe to have single process exit point (#1693)
* Change how dsc returns exit code using Result pattern * fix Windows build * address copilot feedback --------- Co-authored-by: Steve Lee (POWERSHELL HE/HIM) (from Dev Box) <slee@ntdev.microsoft.com>
1 parent 861df43 commit 12be466

4 files changed

Lines changed: 266 additions & 232 deletions

File tree

dsc/src/main.rs

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use clap_complete::generate;
77
use dsc_lib::{progress::ProgressFormat, util::DSC_IGNORE_SETTINGS_FILE};
88
use server::start_server;
99
use rust_i18n::{i18n, t};
10-
use std::{env::set_var, io, process::exit};
10+
use std::{env::set_var, io, process::ExitCode};
1111
use sysinfo::{Process, RefreshKind, System, get_current_pid, ProcessRefreshKind};
1212
use tracing::{error, info, warn, debug};
1313

14-
use crate::util::{EXIT_INVALID_INPUT, get_input};
14+
use crate::util::get_input;
1515

1616
#[cfg(debug_assertions)]
1717
use crossterm::event;
@@ -28,7 +28,7 @@ pub mod util;
2828

2929
i18n!("locales", fallback = "en-us");
3030

31-
fn main() {
31+
fn main() -> ExitCode {
3232
#[cfg(windows)]
3333
{
3434
let handle = match std::thread::Builder::new()
@@ -39,27 +39,38 @@ fn main() {
3939
Ok(handle) => handle,
4040
Err(err) => {
4141
error!("{}", t!("main.failedToSpawnMain", error = err));
42-
exit(util::EXIT_DSC_ERROR);
42+
return ExitCode::from(util::EXIT_DSC_ERROR);
4343
}
4444
};
4545

46-
if let Err(err) = handle.join() {
47-
error!("{}", t!("main.failedToJoinMain", error = err : {:?}));
48-
exit(util::EXIT_DSC_ERROR);
46+
match handle.join() {
47+
Ok(result) => {
48+
if let Err(code) = result {
49+
return code;
50+
}
51+
},
52+
Err(err) => {
53+
error!("{}", t!("main.failedToJoinMain", error = err : {:?}));
54+
return ExitCode::from(util::EXIT_DSC_ERROR);
55+
}
4956
}
57+
ExitCode::from(util::EXIT_SUCCESS)
5058
}
5159
#[cfg(not(windows))]
5260
{
53-
dsc_main();
61+
match dsc_main() {
62+
Ok(_) => ExitCode::from(util::EXIT_SUCCESS),
63+
Err(code) => code,
64+
}
5465
}
5566
}
5667

57-
fn dsc_main() {
68+
fn dsc_main() -> Result<(), ExitCode> {
5869
#[cfg(debug_assertions)]
5970
check_debug();
6071

6172
#[cfg(windows)]
62-
check_store();
73+
check_store()?;
6374

6475
if ctrlc::set_handler(ctrlc_handler).is_err() {
6576
error!("{}", t!("main.failedCtrlCHandler"));
@@ -87,7 +98,9 @@ fn dsc_main() {
8798
generate(shell, &mut cmd, "dsc", &mut io::stdout());
8899
},
89100
SubCommand::Config { subcommand, parameters, parameters_file, system_root, as_group, as_assert, as_include } => {
90-
let params = get_input(None, parameters_file.as_ref());
101+
let Ok(params) = get_input(None, parameters_file.as_ref()) else {
102+
return Err(ExitCode::from(util::EXIT_INVALID_INPUT));
103+
};
91104
let file_params = if params.is_empty() {
92105
None
93106
} else {
@@ -101,7 +114,7 @@ fn dsc_main() {
101114
Ok(merged) => Some(merged),
102115
Err(err) => {
103116
error!("{}: {err}", t!("main.failedMergingParameters"));
104-
exit(EXIT_INVALID_INPUT);
117+
return Err(ExitCode::from(util::EXIT_INVALID_INPUT)) ;
105118
}
106119
}
107120
},
@@ -110,58 +123,59 @@ fn dsc_main() {
110123
(None, None) => None,
111124
};
112125

113-
subcommand::config(&subcommand, &merged_parameters, system_root.as_ref(), &as_group, &as_assert, &as_include, progress_format);
126+
subcommand::config(&subcommand, &merged_parameters, system_root.as_ref(), &as_group, &as_assert, &as_include, progress_format)?;
114127
},
115128
SubCommand::Extension { subcommand } => {
116-
subcommand::extension(&subcommand, progress_format);
129+
subcommand::extension(&subcommand, progress_format)?;
117130
},
118131
SubCommand::Function { subcommand } => {
119-
subcommand::function(&subcommand);
132+
subcommand::function(&subcommand)?;
120133
},
121134
SubCommand::Server => {
122135
if let Err(err) = start_server() {
123136
error!("{}", t!("main.failedToStartServer", error = err));
124-
exit(util::EXIT_SERVER_FAILED);
137+
return Err(ExitCode::from(util::EXIT_SERVER_FAILED));
125138
}
126-
exit(util::EXIT_SUCCESS);
139+
return Ok(());
127140
}
128141
SubCommand::Resource { subcommand } => {
129-
subcommand::resource(&subcommand, progress_format);
142+
subcommand::resource(&subcommand, progress_format)?;
130143
},
131144
SubCommand::Schema { dsc_type , output_format } => {
132145
let schema = util::get_schema(dsc_type);
133146
let json = match serde_json::to_string(&schema) {
134147
Ok(json) => json,
135148
Err(err) => {
136149
error!("JSON: {err}");
137-
exit(util::EXIT_JSON_ERROR);
150+
return Err(ExitCode::from(util::EXIT_JSON_ERROR));
138151
}
139152
};
140-
util::write_object(&json, output_format.as_ref(), false);
153+
util::write_object(&json, output_format.as_ref(), false)?;
141154
},
142155
}
143156

144-
exit(util::EXIT_SUCCESS);
157+
Ok(())
145158
}
146159

147160
fn ctrlc_handler() {
161+
use std::process::exit;
148162
warn!("{}", t!("main.ctrlCReceived"));
149163

150164
// get process tree for current process and terminate all processes
151165
let sys = System::new_with_specifics(RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()));
152166
info!("{}: {}", t!("main.foundProcesses"), sys.processes().len());
153167
let Ok(current_pid) = get_current_pid() else {
154168
error!("{}", t!("main.failedToGetPid"));
155-
exit(util::EXIT_CTRL_C);
169+
exit(i32::from(util::EXIT_CTRL_C));
156170
};
157171
info!("{}: {}", t!("main.currentPid"), current_pid);
158172
let Some(current_process) = sys.process(current_pid) else {
159173
error!("{}", t!("main.failedToGetProcess"));
160-
exit(util::EXIT_CTRL_C);
174+
exit(i32::from(util::EXIT_CTRL_C));
161175
};
162176

163177
terminate_subprocesses(&sys, current_process);
164-
exit(util::EXIT_CTRL_C);
178+
exit(i32::from(util::EXIT_CTRL_C));
165179
}
166180

167181
fn terminate_subprocesses(sys: &System, process: &Process) {
@@ -200,32 +214,34 @@ fn check_debug() {
200214

201215
// Check if the dsc binary parent process is WinStore.App or Explorer.exe
202216
#[cfg(windows)]
203-
fn check_store() {
217+
fn check_store() -> Result<(), ExitCode> {
204218
use std::io::Read;
205219

206220
let sys = System::new_with_specifics(RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()));
207221
// get current process
208222
let Ok(current_pid) = get_current_pid() else {
209-
return;
223+
return Ok(());
210224
};
211225

212226
// get parent process
213227
let Some(current_process) = sys.process(current_pid) else {
214-
return;
228+
return Ok(());
215229
};
216230
let Some(parent_process_pid) = current_process.parent() else {
217-
return;
231+
return Ok(());
218232
};
219233
let Some(parent_process) = sys.process(parent_process_pid) else {
220-
return;
234+
return Ok(());
221235
};
222236

223237
// MS Store runs app using `sihost.exe`
224238
if parent_process.name().eq_ignore_ascii_case("sihost.exe") || parent_process.name().eq_ignore_ascii_case("explorer.exe") {
225239
eprintln!("{}", t!("main.storeMessage"));
226240
// wait for keypress
227241
let _ = io::stdin().read(&mut [0u8]).unwrap();
228-
exit(util::EXIT_INVALID_ARGS);
242+
return Err(ExitCode::from(util::EXIT_INVALID_ARGS));
229243
}
244+
245+
Ok(())
230246
}
231247

0 commit comments

Comments
 (0)