Skip to content

Commit f36e659

Browse files
committed
fix(cli): restore friendly compile errors in direct script runner
1 parent 08631a2 commit f36e659

7 files changed

Lines changed: 126 additions & 36 deletions

File tree

include/vix/cli/commands/run/RunDetail.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,8 @@ namespace vix::commands::RunCommand::detail
492492
const std::string &spinnerLabel,
493493
bool passthroughRuntime,
494494
int timeoutSec = 0,
495-
bool useSan = false);
496-
495+
bool useSan = false,
496+
bool captureOnly = false);
497497
/**
498498
* @brief Run a command and capture its output plus exit code.
499499
*/

src/ErrorHandler.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,15 @@ namespace vix::cli
206206
const std::string cleanedLog = ::trim_build_preamble(buildLog);
207207
auto errors = ClangGccParser::parse(cleanedLog);
208208

209+
std::cerr << "[DEBUG PARSER] errors.size()=" << errors.size() << "\n";
210+
for (const auto &e : errors)
211+
{
212+
std::cerr << "[DEBUG PARSER] file=" << e.file
213+
<< " line=" << e.line
214+
<< " col=" << e.column
215+
<< " msg=" << e.message << "\n";
216+
}
217+
209218
if (errors.empty())
210219
{
211220
if (handle_unrecognized_cli_option_as_script_runtime_args(cleanedLog))

src/commands/run/RunProcess.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ namespace vix::commands::RunCommand::detail
9595
const std::string &spinnerLabel,
9696
bool passthroughRuntime,
9797
int timeoutSec,
98-
bool useSan)
98+
bool useSan,
99+
bool captureOnly)
99100
{
100101
(void)spinnerLabel;
101102
(void)passthroughRuntime;
@@ -1092,7 +1093,8 @@ namespace vix::commands::RunCommand::detail
10921093
const std::string &spinnerLabel,
10931094
bool passthroughRuntime,
10941095
int timeoutSec,
1095-
bool useSan)
1096+
bool useSan,
1097+
bool captureOnly)
10961098
{
10971099
SigintGuard sigGuard;
10981100
LiveRunResult result;
@@ -1121,7 +1123,6 @@ namespace vix::commands::RunCommand::detail
11211123
close_safe(pty.slaveFd);
11221124
::setpgid(pid, pid);
11231125

1124-
const bool captureOnly = false;
11251126
const bool forwardStdin =
11261127
passthroughRuntime && (::isatty(STDIN_FILENO) != 0);
11271128

src/commands/run/RunScript.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -920,14 +920,26 @@ namespace vix::commands::RunCommand::detail
920920
"Compiling script...",
921921
false,
922922
0,
923-
o.enableSanitizers || o.enableUbsanOnly);
923+
o.enableSanitizers || o.enableUbsanOnly,
924+
true);
924925

925926
if (build.exitCode != 0)
926927
{
927-
if (!build.failureHandled)
928-
handle_runtime_exit_code(build.exitCode, "compile", false);
928+
bool handled = false;
929929

930-
return build.exitCode == 0 ? 1 : build.exitCode;
930+
if (!build.stdoutText.empty() || !build.stderrText.empty())
931+
{
932+
const std::string compileLog = build.stdoutText + build.stderrText;
933+
handled = vix::cli::ErrorHandler::printBuildErrors(
934+
compileLog,
935+
directPlan.scriptPath,
936+
"Script compile failed");
937+
}
938+
939+
if (!handled)
940+
error("Script compile failed.");
941+
942+
return build.exitCode != 0 ? build.exitCode : 1;
931943
}
932944

933945
// Do not rewrite legacy cache metadata here.

src/commands/run/detail/DirectScriptRunner.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -477,27 +477,40 @@ namespace vix::commands::RunCommand::detail
477477
"Compiling script...",
478478
false,
479479
0,
480-
opt.enableSanitizers || opt.enableUbsanOnly);
480+
opt.enableSanitizers || opt.enableUbsanOnly,
481+
true);
481482

482483
if (build.exitCode != 0)
483484
{
485+
std::cerr << "[DEBUG NEW VIX] direct compile failure path reached\n";
486+
std::cerr << "[DEBUG NEW VIX] exitCode=" << build.exitCode << "\n";
487+
std::cerr << "[DEBUG NEW VIX] stdout empty=" << std::boolalpha << build.stdoutText.empty() << "\n";
488+
std::cerr << "[DEBUG NEW VIX] stderr empty=" << std::boolalpha << build.stderrText.empty() << "\n";
489+
490+
bool handled = false;
491+
484492
if (!build.stdoutText.empty() || !build.stderrText.empty())
485493
{
486494
const std::string compileLog = build.stdoutText + build.stderrText;
487-
const bool handled = vix::cli::ErrorHandler::printBuildErrors(
495+
496+
std::cerr << "[DEBUG NEW VIX] compileLog size=" << compileLog.size() << "\n";
497+
std::cerr << "[DEBUG NEW VIX] calling printBuildErrors(...)\n";
498+
499+
handled = vix::cli::ErrorHandler::printBuildErrors(
488500
compileLog,
489501
plan.scriptPath,
490502
"Script compile failed");
491503

492-
if (!handled && !build.printed_live)
493-
handle_runtime_exit_code(build.exitCode, "compile", false);
504+
std::cerr << "[DEBUG NEW VIX] printBuildErrors handled=" << handled << "\n";
494505
}
495-
else if (!build.failureHandled && !build.printed_live)
506+
507+
if (!handled)
496508
{
497-
handle_runtime_exit_code(build.exitCode, "compile", false);
509+
std::cerr << "[DEBUG NEW VIX] fallback: error(\"Script compile failed.\")\n";
510+
error("Script compile failed.");
498511
}
499512

500-
return -build.exitCode;
513+
return build.exitCode != 0 ? build.exitCode : 1;
501514
}
502515

503516
const std::string meta = make_direct_cache_meta(plan.scriptPath, plan);

src/errors/ClangGccParser.cpp

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,61 @@
2525
#endif
2626

2727
#include <sstream>
28+
#include <string>
29+
#include <algorithm>
30+
#include <cctype>
2831

2932
namespace vix::cli::errors
3033
{
34+
namespace
35+
{
36+
std::string trim_copy(std::string s)
37+
{
38+
while (!s.empty() &&
39+
(s.back() == '\n' || s.back() == '\r' || s.back() == ' ' || s.back() == '\t'))
40+
{
41+
s.pop_back();
42+
}
43+
44+
std::size_t i = 0;
45+
while (i < s.size() &&
46+
(s[i] == '\n' || s[i] == '\r' || s[i] == ' ' || s[i] == '\t'))
47+
{
48+
++i;
49+
}
50+
51+
s.erase(0, i);
52+
return s;
53+
}
54+
55+
std::string strip_ansi(std::string s)
56+
{
57+
static const std::regex ansiRe(R"(\x1B\[[0-9;?]*[ -/]*[@-~])");
58+
return std::regex_replace(s, ansiRe, "");
59+
}
60+
}
61+
3162
std::vector<CompilerError> ClangGccParser::parse(const std::string &buildLog)
3263
{
3364
std::vector<CompilerError> out;
3465

35-
// Example:
66+
// GCC / Clang examples:
3667
// /path/main.cpp:3:5: error: use of undeclared identifier 'std'
3768
// /path/foo.hpp:1:10: fatal error: 'h.hpp' file not found
38-
std::regex re(R"((.+?):(\d+):(\d+):\s*(fatal error|error|warning):\s*(.+))");
69+
// /path/main.cpp:2:10: fatal error: huh.hpp: No such file or directory
70+
static const std::regex re(
71+
R"(^(.+?):([0-9]+):([0-9]+):\s*(fatal error|error|warning):\s*(.+)$)");
3972

4073
std::istringstream iss(buildLog);
4174
std::string line;
75+
4276
while (std::getline(iss, line))
4377
{
44-
// Ignore make/ninja noise
78+
line = strip_ansi(trim_copy(line));
79+
80+
if (line.empty())
81+
continue;
82+
4583
if (line.rfind("gmake", 0) == 0 ||
4684
line.rfind("make", 0) == 0 ||
4785
line.rfind("ninja", 0) == 0)
@@ -50,20 +88,21 @@ namespace vix::cli::errors
5088
}
5189

5290
std::smatch m;
53-
if (std::regex_match(line, m, re))
91+
if (std::regex_search(line, m, re))
5492
{
5593
CompilerError e;
56-
e.file = m[1].str();
94+
e.file = trim_copy(m[1].str());
5795
e.line = std::stoi(m[2].str());
5896
e.column = std::stoi(m[3].str());
59-
// m[4] = "fatal error" | "error" | "warning"
60-
e.message = m[5].str();
97+
98+
const std::string severity = m[4].str();
99+
const std::string message = trim_copy(m[5].str());
100+
101+
e.message = severity + ": " + message;
61102
e.raw = line;
62103

63-
if (m[4].str() == "error" || m[4].str() == "fatal error")
64-
{
104+
if (severity == "error" || severity == "fatal error")
65105
out.push_back(std::move(e));
66-
}
67106
}
68107
}
69108

src/errors/RawLogDetectors.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,8 @@ namespace vix::cli::errors
399399
const std::string &runtimeLog,
400400
const std::filesystem::path &sourceFile)
401401
{
402-
(void)runtimeLog;
403-
404402
std::cerr << RED
405-
<< "runtime error: program failed at runtime"
406-
<< RESET << "\n";
407-
408-
std::cerr << YELLOW
409-
<< "hint: no specialized runtime rule matched this failure"
403+
<< "runtime error: unclassified runtime failure"
410404
<< RESET << "\n";
411405

412406
if (!sourceFile.empty())
@@ -416,6 +410,14 @@ namespace vix::cli::errors
416410
<< RESET << "\n";
417411
}
418412

413+
if (!runtimeLog.empty())
414+
{
415+
std::cerr << "\n";
416+
std::cerr << runtimeLog;
417+
if (runtimeLog.back() != '\n')
418+
std::cerr << "\n";
419+
}
420+
419421
return true;
420422
}
421423

@@ -1297,12 +1299,26 @@ namespace vix::cli::errors
12971299
const std::filesystem::path &sourceFile,
12981300
[[maybe_unused]] const std::string &contextMessage)
12991301
{
1300-
if (handleRuntimeAnything(buildLog, sourceFile))
1301-
return true;
1302-
13031302
if (handleLinkerErrors(buildLog, sourceFile))
13041303
return true;
13051304

1305+
const bool looksRuntime =
1306+
icontains(buildLog, "AddressSanitizer") ||
1307+
icontains(buildLog, "UndefinedBehaviorSanitizer") ||
1308+
icontains(buildLog, "LeakSanitizer") ||
1309+
icontains(buildLog, "ThreadSanitizer") ||
1310+
icontains(buildLog, "MemorySanitizer") ||
1311+
icontains(buildLog, "runtime error:") ||
1312+
icontains(buildLog, "Segmentation fault") ||
1313+
icontains(buildLog, "SIGSEGV") ||
1314+
icontains(buildLog, "SIGABRT") ||
1315+
icontains(buildLog, "Aborted") ||
1316+
icontains(buildLog, "terminate called after") ||
1317+
icontains(buildLog, "what():");
1318+
1319+
if (looksRuntime)
1320+
return handleRuntimeAnything(buildLog, sourceFile);
1321+
13061322
return false;
13071323
}
13081324

0 commit comments

Comments
 (0)