Skip to content

Commit 8e71501

Browse files
committed
cli(build): fix CMake build after clean Vix uninstall
1 parent 16aa52e commit 8e71501

1 file changed

Lines changed: 105 additions & 34 deletions

File tree

src/cmake/CMakeBuild.cpp

Lines changed: 105 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <fcntl.h>
2727
#include <sys/wait.h>
2828
#include <unistd.h>
29+
#include <poll.h>
30+
#include <signal.h>
2931
#endif
3032

3133
#ifndef _WIN32
@@ -258,9 +260,11 @@ namespace vix::cli::build
258260
return r;
259261
}
260262

263+
// Fork
261264
pid_t pid = ::fork();
262265
if (pid == 0)
263266
{
267+
// Child: redirect stdout+stderr to pipe write end
264268
::dup2(pipefd[1], STDOUT_FILENO);
265269
::dup2(pipefd[1], STDERR_FILENO);
266270

@@ -280,6 +284,7 @@ namespace vix::cli::build
280284
_exit(127);
281285
}
282286

287+
// Parent
283288
::close(pipefd[1]);
284289

285290
std::string firstLine;
@@ -308,9 +313,7 @@ namespace vix::cli::build
308313
return false;
309314

310315
if (filterCMakeSummary)
311-
{
312316
return !is_cmake_configure_summary_line(line);
313-
}
314317

315318
if (!progressOnly)
316319
return true;
@@ -329,56 +332,118 @@ namespace vix::cli::build
329332

330333
std::string buf(16 * 1024, '\0');
331334

335+
// Heartbeat state
336+
const auto startTs = std::chrono::steady_clock::now();
337+
auto lastOutputTs = startTs;
338+
auto lastHeartbeatTs = startTs;
339+
340+
// poll loop
332341
while (true)
333342
{
334-
ssize_t n = ::read(pipefd[0], &buf[0], buf.size());
335-
if (n <= 0)
336-
break;
343+
struct pollfd pfd;
344+
pfd.fd = pipefd[0];
345+
pfd.events = POLLIN | POLLHUP | POLLERR;
346+
pfd.revents = 0;
337347

338-
r.producedOutput = true;
348+
// 250ms tick -> lets us print heartbeat & not look frozen
349+
const int pr = ::poll(&pfd, 1, 250);
339350

340-
write_all_fd(logfd, buf.data(), static_cast<std::size_t>(n));
351+
if (pr < 0)
352+
{
353+
if (errno == EINTR)
354+
continue;
355+
break;
356+
}
341357

342-
if (!gotFirstLine)
358+
// If data is ready, read it
359+
if (pr > 0 && (pfd.revents & POLLIN))
343360
{
344-
for (ssize_t i = 0; i < n; ++i)
361+
const ssize_t n = ::read(pipefd[0], &buf[0], buf.size());
362+
if (n <= 0)
363+
break;
364+
365+
r.producedOutput = true;
366+
lastOutputTs = std::chrono::steady_clock::now();
367+
368+
write_all_fd(logfd, buf.data(), static_cast<std::size_t>(n));
369+
370+
if (!gotFirstLine)
345371
{
346-
char c = buf[static_cast<std::size_t>(i)];
347-
if (c == '\n')
372+
for (ssize_t i = 0; i < n; ++i)
348373
{
349-
gotFirstLine = true;
350-
break;
374+
char c = buf[static_cast<std::size_t>(i)];
375+
if (c == '\n')
376+
{
377+
gotFirstLine = true;
378+
break;
379+
}
380+
if (firstLine.size() < 200)
381+
firstLine.push_back(c);
351382
}
352-
if (firstLine.size() < 200)
353-
firstLine.push_back(c);
354383
}
355-
}
356384

357-
if (quiet)
358-
continue;
385+
if (!quiet)
386+
{
387+
consoleBuf.append(buf.data(), static_cast<std::size_t>(n));
359388

360-
consoleBuf.append(buf.data(), static_cast<std::size_t>(n));
389+
std::size_t start = 0;
390+
while (true)
391+
{
392+
std::size_t nl = consoleBuf.find('\n', start);
393+
if (nl == std::string::npos)
394+
break;
395+
396+
std::string line = consoleBuf.substr(start, nl - start);
397+
if (should_echo_line(line))
398+
{
399+
line.push_back('\n');
400+
write_all_fd(STDOUT_FILENO, line.data(), line.size());
401+
}
402+
start = nl + 1;
403+
}
361404

362-
std::size_t start = 0;
363-
while (true)
364-
{
365-
std::size_t nl = consoleBuf.find('\n', start);
366-
if (nl == std::string::npos)
367-
break;
405+
if (start > 0)
406+
consoleBuf.erase(0, start);
407+
}
368408

369-
std::string line = consoleBuf.substr(start, nl - start);
409+
continue;
410+
}
370411

371-
if (should_echo_line(line))
412+
// EOF/HUP
413+
if (pr > 0 && (pfd.revents & (POLLHUP | POLLERR)))
414+
break;
415+
416+
// No output tick -> heartbeat (avoid "looks frozen")
417+
if (!quiet)
418+
{
419+
const auto now = std::chrono::steady_clock::now();
420+
const auto silenceMs =
421+
std::chrono::duration_cast<std::chrono::milliseconds>(now - lastOutputTs).count();
422+
const auto hbMs =
423+
std::chrono::duration_cast<std::chrono::milliseconds>(now - lastHeartbeatTs).count();
424+
425+
// print heartbeat every 5s of silence
426+
if (silenceMs >= 5000 && hbMs >= 5000)
372427
{
373-
line.push_back('\n');
374-
write_all_fd(STDOUT_FILENO, line.data(), line.size());
375-
}
428+
lastHeartbeatTs = now;
429+
const auto elapsedMs =
430+
std::chrono::duration_cast<std::chrono::milliseconds>(now - startTs).count();
376431

377-
start = nl + 1;
432+
std::string msg =
433+
"\r[building] still running… (" + util::format_seconds(elapsedMs) + ") ";
434+
write_all_fd(STDOUT_FILENO, msg.data(), msg.size());
435+
}
378436
}
437+
}
379438

380-
if (start > 0)
381-
consoleBuf.erase(0, start);
439+
// flush a possible last partial line when process ends
440+
if (!quiet && !consoleBuf.empty())
441+
{
442+
if (should_echo_line(consoleBuf))
443+
{
444+
std::string tail = consoleBuf + "\n";
445+
write_all_fd(STDOUT_FILENO, tail.data(), tail.size());
446+
}
382447
}
383448

384449
::close(pipefd[0]);
@@ -391,11 +456,17 @@ namespace vix::cli::build
391456
return r;
392457
}
393458

459+
if (!quiet)
460+
{
461+
// clear heartbeat line if any
462+
const std::string clear = "\r";
463+
write_all_fd(STDOUT_FILENO, clear.data(), clear.size());
464+
}
465+
394466
r.exitCode = process::normalize_exit_code(status);
395467
r.capturedFirstLine = util::trim(firstLine);
396468
return r;
397469
}
398-
399470
#else // _WIN32
400471

401472
process::ExecResult run_process_capture(

0 commit comments

Comments
 (0)