Skip to content

Commit ba95beb

Browse files
committed
fix(cli): record and replay single-file script runs
1 parent 153b606 commit ba95beb

3 files changed

Lines changed: 152 additions & 10 deletions

File tree

src/commands/replay/ReplayProcess.cpp

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*
1515
*/
1616
#include <vix/cli/commands/replay/ReplayProcess.hpp>
17+
#include <vix/cli/commands/run/RunDetail.hpp>
1718
#include <vix/cli/Style.hpp>
1819

1920
#include <cstdlib>
@@ -76,6 +77,29 @@ namespace vix::commands::replay
7677
return out;
7778
}
7879

80+
/**
81+
* @brief Print the replay command in a readable multi-line format.
82+
*
83+
* @param cwd Working directory used for replay.
84+
* @param command Command executed after changing directory.
85+
*/
86+
void print_replay_command_block(const fs::path &cwd, const std::string &command)
87+
{
88+
std::cout << PAD << GRAY << "replay" << RESET << "\n";
89+
90+
std::cout << PAD
91+
<< GRAY << "cwd" << RESET
92+
<< " "
93+
<< CYAN << BOLD << cwd.string() << RESET
94+
<< "\n";
95+
96+
std::cout << PAD
97+
<< GRAY << "cmd" << RESET
98+
<< " "
99+
<< CYAN << BOLD << command << RESET
100+
<< "\n";
101+
}
102+
79103
#ifdef _WIN32
80104
/**
81105
* @brief Build environment assignments for cmd.exe.
@@ -253,10 +277,7 @@ namespace vix::commands::replay
253277
#endif
254278

255279
if (options.print_command)
256-
{
257-
std::cout << PAD << GRAY << "replay" << RESET << "\n";
258-
std::cout << PAD << CYAN << BOLD << finalCmd << RESET << "\n";
259-
}
280+
print_replay_command_block(result.cwd, result.command);
260281

261282
if (options.dry_run)
262283
{
@@ -265,10 +286,24 @@ namespace vix::commands::replay
265286
return true;
266287
}
267288

268-
const int raw = std::system(finalCmd.c_str());
289+
const auto run =
290+
vix::commands::RunCommand::detail::run_cmd_live_filtered_capture(
291+
finalCmd,
292+
"",
293+
true,
294+
0,
295+
false,
296+
false);
269297

270-
result.raw_status = raw;
271-
result.exit_code = replay_normalize_exit_code(raw);
298+
result.raw_status = run.rawStatus;
299+
result.exit_code = run.exitCode;
300+
301+
if (result.exit_code == 130 ||
302+
(run.terminatedBySignal && run.termSignal == 2))
303+
{
304+
std::cout << " " << GRAY << "" << RESET
305+
<< " ℹ Program interrupted by user (SIGINT).\n";
306+
}
272307

273308
return true;
274309
}

src/commands/run/RunScript.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <vix/cli/commands/run/detail/DirectScriptRunner.hpp>
1818
#include <vix/cli/commands/run/detail/ScriptProbe.hpp>
1919
#include <vix/cli/commands/run/detail/ScriptCMake.hpp>
20+
#include <vix/cli/commands/replay/ReplayCapture.hpp>
21+
#include <vix/cli/commands/replay/ReplayRecorder.hpp>
2022
#include <vix/cli/errors/RawLogDetectors.hpp>
2123
#include <vix/cli/Style.hpp>
2224
#include <vix/utils/Env.hpp>
@@ -722,12 +724,64 @@ namespace vix::commands::RunCommand::detail
722724
cmdRun += join_quoted_args_local(opt.runArgs);
723725
cmdRun = wrap_with_cwd_if_needed(opt, cmdRun);
724726

727+
namespace replay = vix::commands::replay;
728+
729+
replay::ReplayRecorder recorder;
730+
replay::ReplayRecorderConfig replayConfig{};
731+
732+
replayConfig.base_dir = fs::current_path();
733+
replayConfig.cwd = fs::current_path();
734+
replayConfig.project_dir = fs::current_path();
735+
replayConfig.target_path = state.script;
736+
replayConfig.mode = opt.watch ? replay::ReplayMode::Dev : replay::ReplayMode::Run;
737+
replayConfig.target_kind = replay::ReplayTargetKind::SingleCpp;
738+
replayConfig.command = opt.watch
739+
? "vix dev " + state.script.string()
740+
: "vix run " + state.script.string();
741+
replayConfig.resolved_command = cmdRun;
742+
replayConfig.vix_args = opt.scriptFlags;
743+
replayConfig.app_args = opt.runArgs;
744+
replayConfig.watch = opt.watch;
745+
replayConfig.direct_script = false;
746+
replayConfig.cmake_fallback = true;
747+
replayConfig.replayable = true;
748+
749+
std::string replayErr;
750+
const bool replayEnabled = recorder.begin(replayConfig, replayErr);
751+
752+
replay::ReplayCapture replayCapture;
753+
if (replayEnabled)
754+
replayCapture.attach(&recorder);
755+
725756
LiveRunResult rr = run_cmd_live_filtered_capture(
726757
cmdRun,
727758
"",
728-
isInteractive, // ← corrigé
759+
isInteractive,
729760
effective_timeout_sec(opt),
730-
opt.enableSanitizers || opt.enableUbsanOnly);
761+
opt.enableSanitizers || opt.enableUbsanOnly,
762+
false,
763+
replayEnabled ? &replayCapture : nullptr);
764+
765+
if (replayEnabled)
766+
{
767+
replay::ReplayProcessResult process =
768+
replay::make_replay_process_result(
769+
rr.exitCode,
770+
rr.rawStatus,
771+
rr.terminatedBySignal,
772+
rr.termSignal);
773+
774+
replay::ReplayCapturedResult captured =
775+
replay::make_replay_captured_result(
776+
replayCapture.output(),
777+
process);
778+
779+
replay::ReplayRecorderFinish finish =
780+
replay::make_replay_finish_from_capture(captured);
781+
782+
std::string finishErr;
783+
(void)recorder.finish(finish, finishErr);
784+
}
731785

732786
int runCode = normalize_exit_code(rr.exitCode);
733787

src/commands/run/detail/DirectScriptRunner.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <vix/cli/commands/helpers/ProcessHelpers.hpp>
1616
#include <vix/cli/commands/helpers/TextHelpers.hpp>
1717
#include <vix/cli/commands/run/RunScriptHelpers.hpp>
18+
#include <vix/cli/commands/replay/ReplayCapture.hpp>
19+
#include <vix/cli/commands/replay/ReplayRecorder.hpp>
1820
#include <vix/cli/ErrorHandler.hpp>
1921
#include <vix/cli/Style.hpp>
2022
#include <vix/utils/Env.hpp>
@@ -766,13 +768,64 @@ namespace vix::commands::RunCommand::detail
766768
if (!plan.shouldRun)
767769
return 0;
768770

771+
namespace replay = vix::commands::replay;
772+
773+
replay::ReplayRecorder recorder;
774+
replay::ReplayRecorderConfig replayConfig{};
775+
776+
replayConfig.base_dir = fs::current_path();
777+
replayConfig.cwd = fs::current_path();
778+
replayConfig.project_dir = fs::current_path();
779+
replayConfig.target_path = plan.scriptPath;
780+
replayConfig.mode = opt.watch ? replay::ReplayMode::Dev : replay::ReplayMode::Run;
781+
replayConfig.target_kind = replay::ReplayTargetKind::SingleCpp;
782+
replayConfig.command = opt.watch
783+
? "vix dev " + plan.scriptPath.string()
784+
: "vix run " + plan.scriptPath.string();
785+
replayConfig.resolved_command = plan.runCmd;
786+
replayConfig.vix_args = opt.scriptFlags;
787+
replayConfig.app_args = opt.runArgs;
788+
replayConfig.watch = opt.watch;
789+
replayConfig.direct_script = true;
790+
replayConfig.cmake_fallback = false;
791+
replayConfig.replayable = true;
792+
793+
std::string replayErr;
794+
const bool replayEnabled = recorder.begin(replayConfig, replayErr);
795+
796+
replay::ReplayCapture replayCapture;
797+
if (replayEnabled)
798+
replayCapture.attach(&recorder);
799+
769800
const LiveRunResult run = run_cmd_live_filtered_capture(
770801
plan.runCmd,
771802
"Running script...",
772803
plan.passthroughRuntime,
773804
plan.effectiveTimeoutSec,
774805
opt.enableSanitizers || opt.enableUbsanOnly,
775-
false);
806+
false,
807+
replayEnabled ? &replayCapture : nullptr);
808+
809+
if (replayEnabled)
810+
{
811+
replay::ReplayProcessResult process =
812+
replay::make_replay_process_result(
813+
run.exitCode,
814+
run.rawStatus,
815+
run.terminatedBySignal,
816+
run.termSignal);
817+
818+
replay::ReplayCapturedResult captured =
819+
replay::make_replay_captured_result(
820+
replayCapture.output(),
821+
process);
822+
823+
replay::ReplayRecorderFinish finish =
824+
replay::make_replay_finish_from_capture(captured);
825+
826+
std::string finishErr;
827+
(void)recorder.finish(finish, finishErr);
828+
}
776829

777830
if (is_user_interrupt_result(run))
778831
{

0 commit comments

Comments
 (0)