chore: auto-commit (6 archivos)
- CMakeLists.txt - main.cpp - data_collectors.cpp - data_collectors.h - runner.cpp - runner.h Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+124
@@ -0,0 +1,124 @@
|
||||
#include "runner.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace odr {
|
||||
|
||||
namespace {
|
||||
|
||||
long long now_ms() {
|
||||
using namespace std::chrono;
|
||||
return duration_cast<milliseconds>(
|
||||
system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
std::string make_uid() {
|
||||
static std::atomic<int> ctr{0};
|
||||
long long ts = now_ms();
|
||||
int n = ctr.fetch_add(1, std::memory_order_relaxed);
|
||||
char buf[64];
|
||||
std::snprintf(buf, sizeof(buf), "%lld_%05d", ts, n);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool write_file(const fs::path& p, const std::string& bytes) {
|
||||
std::ofstream f(p, std::ios::binary | std::ios::trunc);
|
||||
if (!f.is_open()) return false;
|
||||
f.write(bytes.data(), (std::streamsize)bytes.size());
|
||||
return f.good();
|
||||
}
|
||||
|
||||
std::string read_file(const fs::path& p) {
|
||||
std::ifstream f(p, std::ios::binary);
|
||||
if (!f.is_open()) return "";
|
||||
std::ostringstream ss;
|
||||
ss << f.rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Quote para shell: encierra en comillas dobles, escapa los " internos.
|
||||
// Suficiente para paths del registry — no tocamos shell metacharacters
|
||||
// porque no hay input de usuario directo (paths controlados por la app).
|
||||
std::string sh_quote(const std::string& s) {
|
||||
std::string out;
|
||||
out.reserve(s.size() + 2);
|
||||
out.push_back('"');
|
||||
for (char c : s) {
|
||||
if (c == '"' || c == '\\' || c == '$' || c == '`') {
|
||||
out.push_back('\\');
|
||||
}
|
||||
out.push_back(c);
|
||||
}
|
||||
out.push_back('"');
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RunResult run_collector(const std::string& python_exe,
|
||||
const std::string& run_py,
|
||||
const std::string& tmp_dir,
|
||||
const std::string& ctx_json) {
|
||||
RunResult r;
|
||||
|
||||
std::error_code ec;
|
||||
fs::create_directories(tmp_dir, ec);
|
||||
if (ec) {
|
||||
r.stderr_str = "create_directories failed: " + ec.message();
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string uid = make_uid();
|
||||
fs::path ctx_path = fs::path(tmp_dir) / ("ctx_" + uid + ".json");
|
||||
fs::path out_path = fs::path(tmp_dir) / ("out_" + uid + ".json");
|
||||
fs::path err_path = fs::path(tmp_dir) / ("err_" + uid + ".log");
|
||||
|
||||
if (!write_file(ctx_path, ctx_json)) {
|
||||
r.stderr_str = "write ctx failed";
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string cmd =
|
||||
sh_quote(python_exe) + " " + sh_quote(run_py)
|
||||
+ " < " + sh_quote(ctx_path.string())
|
||||
+ " > " + sh_quote(out_path.string())
|
||||
+ " 2> " + sh_quote(err_path.string());
|
||||
|
||||
long long t0 = now_ms();
|
||||
int rc = std::system(cmd.c_str());
|
||||
r.duration_ms = now_ms() - t0;
|
||||
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
// POSIX: WEXITSTATUS para extraer exit code real.
|
||||
if (rc != -1 && WIFEXITED(rc)) {
|
||||
r.exit_code = WEXITSTATUS(rc);
|
||||
} else {
|
||||
r.exit_code = rc;
|
||||
}
|
||||
#else
|
||||
r.exit_code = rc;
|
||||
#endif
|
||||
|
||||
r.stdout_str = read_file(out_path);
|
||||
r.stderr_str = read_file(err_path);
|
||||
|
||||
// Cleanup salvo si fallo (dejar para debug).
|
||||
if (r.exit_code == 0) {
|
||||
std::error_code rmec;
|
||||
fs::remove(ctx_path, rmec);
|
||||
fs::remove(out_path, rmec);
|
||||
fs::remove(err_path, rmec);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace odr
|
||||
Reference in New Issue
Block a user