fix: post-hook now runs when game binary does not exist
validate_launch() rejects missing executables in build_plan(), causing an early return via `?` before the post-hook block was ever reached. Fix by separating the dry-run path (still fails fast with `?`) from the real-launch path, where build_plan() result is captured without `?` and chained into execute_wait() via and_then(). The post-hook fires for both plan-validation failures and execute_wait() spawn failures. Also skips the pre-launch hook when the plan is invalid (no binary to set up for), and skips state recording in the same case. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
+23
-16
@@ -1421,16 +1421,10 @@ fn launch_command(
|
|||||||
let resolved = profile::resolve(config, &executable)?;
|
let resolved = profile::resolve(config, &executable)?;
|
||||||
let verbose = resolved.settings.verbose;
|
let verbose = resolved.settings.verbose;
|
||||||
let settings = resolved.settings.clone();
|
let settings = resolved.settings.clone();
|
||||||
let plan = launch::build_plan(command, settings.clone())?;
|
|
||||||
let log_path = settings.log_file.then(|| {
|
|
||||||
settings
|
|
||||||
.log_path
|
|
||||||
.as_deref()
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|| crate::log::default_log_path(&paths.state_dir))
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Dry-run: build the plan (fail-fast) and render it without launching.
|
||||||
if dry_run {
|
if dry_run {
|
||||||
|
let plan = launch::build_plan(command, settings.clone())?;
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
launch::render_plan(&plan, &resolved.profile_name, verbose)
|
launch::render_plan(&plan, &resolved.profile_name, verbose)
|
||||||
@@ -1459,6 +1453,16 @@ fn launch_command(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Real launch: capture plan errors so the post-hook can always run.
|
||||||
|
let plan_result = launch::build_plan(command, settings.clone());
|
||||||
|
let log_path = settings.log_file.then(|| {
|
||||||
|
settings
|
||||||
|
.log_path
|
||||||
|
.as_deref()
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.unwrap_or_else(|| crate::log::default_log_path(&paths.state_dir))
|
||||||
|
});
|
||||||
|
|
||||||
// Log the launch header.
|
// Log the launch header.
|
||||||
if let Some(log_path) = &log_path {
|
if let Some(log_path) = &log_path {
|
||||||
crate::log::append(
|
crate::log::append(
|
||||||
@@ -1467,13 +1471,15 @@ fn launch_command(
|
|||||||
"--- launch ---".to_string(),
|
"--- launch ---".to_string(),
|
||||||
format!("executable: {}", executable.basename),
|
format!("executable: {}", executable.basename),
|
||||||
format!("profile: {}", resolved.profile_name),
|
format!("profile: {}", resolved.profile_name),
|
||||||
format!("command: {}", format_command(&plan.command)),
|
format!("command: {}", format_command(command)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run pre-launch hook.
|
// Run pre-launch hook (only when the plan is valid; skip if binary not found).
|
||||||
if let Some(pre_cmd) = settings.pre_launch.as_deref() {
|
if plan_result.is_ok()
|
||||||
|
&& let Some(pre_cmd) = settings.pre_launch.as_deref()
|
||||||
|
{
|
||||||
let hook_result = run_hook(pre_cmd);
|
let hook_result = run_hook(pre_cmd);
|
||||||
let log_label = match &hook_result {
|
let log_label = match &hook_result {
|
||||||
Ok(status) => exit_status_label(*status),
|
Ok(status) => exit_status_label(*status),
|
||||||
@@ -1507,16 +1513,16 @@ fn launch_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the launch in state (Steam context only).
|
// Record the launch in state (Steam context only, when plan is valid).
|
||||||
if env::is_steam_context() {
|
if plan_result.is_ok() && env::is_steam_context() {
|
||||||
detect::record_launch(state, &executable, &resolved.profile_name);
|
detect::record_launch(state, &executable, &resolved.profile_name);
|
||||||
config::save_state(paths, state)?;
|
config::save_state(paths, state)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(post_cmd) = settings.post_launch.clone() {
|
if let Some(post_cmd) = settings.post_launch.clone() {
|
||||||
// Spawn the game and wait. Capture both success and failure so the
|
// Chain plan building with game execution so post-hook runs even when
|
||||||
// post-hook can always run once we've passed the pre-hook check.
|
// the binary doesn't exist or otherwise fails to spawn.
|
||||||
let game_result = launch::execute_wait(plan);
|
let game_result = plan_result.and_then(launch::execute_wait);
|
||||||
|
|
||||||
let (elapsed_secs, game_exit_label) = match &game_result {
|
let (elapsed_secs, game_exit_label) = match &game_result {
|
||||||
Ok((exit_status, elapsed)) => {
|
Ok((exit_status, elapsed)) => {
|
||||||
@@ -1579,6 +1585,7 @@ fn launch_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let plan = plan_result?;
|
||||||
launch::execute(plan)
|
launch::execute(plan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user