mirror of
https://github.com/johndoe6345789/GithubWorkflowTool.git
synced 2026-04-25 06:05:02 +00:00
148 lines
4.3 KiB
C++
148 lines
4.3 KiB
C++
#include "backends/ContainerBackend.h"
|
|
#include <QProcess>
|
|
#include <QDebug>
|
|
|
|
namespace gwt {
|
|
namespace backends {
|
|
|
|
ContainerBackend::ContainerBackend(QObject* parent)
|
|
: ExecutionBackend(parent)
|
|
{
|
|
detectRuntime();
|
|
}
|
|
|
|
ContainerBackend::~ContainerBackend() {
|
|
cleanup();
|
|
}
|
|
|
|
bool ContainerBackend::executeStep(const core::WorkflowStep& step,
|
|
const QVariantMap& context) {
|
|
if (m_containerId.isEmpty()) {
|
|
emit error("Container not prepared");
|
|
return false;
|
|
}
|
|
|
|
// Execute command in container
|
|
if (!step.run.isEmpty()) {
|
|
QProcess process;
|
|
QStringList args;
|
|
|
|
// Use specified shell or default to sh
|
|
// Common shells: bash, sh, dash, ash
|
|
QString shell = step.shell.isEmpty() ? "sh" : step.shell;
|
|
|
|
// Basic shell validation - prefer bash if available, fallback to sh
|
|
if (shell == "bash" || shell == "/bin/bash") {
|
|
// Try bash first, will fail if not available
|
|
shell = "bash";
|
|
} else if (shell == "sh" || shell == "/bin/sh") {
|
|
shell = "sh";
|
|
}
|
|
// For other shells, use as specified and let container fail if unavailable
|
|
|
|
args << "exec" << m_containerId << shell << "-c" << step.run;
|
|
|
|
process.start(m_containerRuntime, args);
|
|
|
|
if (!process.waitForFinished(STEP_TIMEOUT_MS)) {
|
|
emit error("Step execution timeout");
|
|
return false;
|
|
}
|
|
|
|
QString output = QString::fromUtf8(process.readAllStandardOutput());
|
|
emit this->output(output);
|
|
|
|
if (process.exitCode() != 0) {
|
|
QString errorMsg = QString::fromUtf8(process.readAllStandardError());
|
|
emit error("Step failed: " + errorMsg);
|
|
return false;
|
|
}
|
|
} else if (!step.uses.isEmpty()) {
|
|
// Handle actions like actions/checkout@v3
|
|
emit this->output("Action execution: " + step.uses + " (stub)");
|
|
// Would need more complex action resolution
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ContainerBackend::prepareEnvironment(const QString& runsOn) {
|
|
QString image = mapRunsOnToImage(runsOn);
|
|
|
|
QProcess process;
|
|
QStringList args;
|
|
args << "run" << "-d" << "-it" << image << "sh";
|
|
|
|
process.start(m_containerRuntime, args);
|
|
|
|
if (!process.waitForFinished(PREPARE_TIMEOUT_MS)) {
|
|
emit error("Container creation timeout");
|
|
return false;
|
|
}
|
|
|
|
if (process.exitCode() != 0) {
|
|
QString errorMsg = QString::fromUtf8(process.readAllStandardError());
|
|
emit error("Failed to create container: " + errorMsg);
|
|
return false;
|
|
}
|
|
|
|
m_containerId = QString::fromUtf8(process.readAllStandardOutput()).trimmed();
|
|
return !m_containerId.isEmpty();
|
|
}
|
|
|
|
void ContainerBackend::cleanup() {
|
|
if (!m_containerId.isEmpty()) {
|
|
QProcess process;
|
|
QStringList args;
|
|
args << "rm" << "-f" << m_containerId;
|
|
|
|
process.start(m_containerRuntime, args);
|
|
process.waitForFinished(CLEANUP_TIMEOUT_MS);
|
|
|
|
m_containerId.clear();
|
|
}
|
|
}
|
|
|
|
bool ContainerBackend::detectRuntime() {
|
|
// Try docker first
|
|
QProcess dockerCheck;
|
|
dockerCheck.start("docker", QStringList() << "--version");
|
|
|
|
if (dockerCheck.waitForFinished(5000) && dockerCheck.exitCode() == 0) {
|
|
m_containerRuntime = "docker";
|
|
return true;
|
|
}
|
|
|
|
// Try podman
|
|
QProcess podmanCheck;
|
|
podmanCheck.start("podman", QStringList() << "--version");
|
|
|
|
if (podmanCheck.waitForFinished(5000) && podmanCheck.exitCode() == 0) {
|
|
m_containerRuntime = "podman";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QString ContainerBackend::mapRunsOnToImage(const QString& runsOn) const {
|
|
// Map GitHub runner specs to container images
|
|
if (runsOn.contains("ubuntu-latest") || runsOn.contains("ubuntu-22.04")) {
|
|
return "ubuntu:22.04";
|
|
} else if (runsOn.contains("ubuntu-20.04")) {
|
|
return "ubuntu:20.04";
|
|
} else if (runsOn.contains("ubuntu")) {
|
|
return "ubuntu:latest";
|
|
} else if (runsOn.contains("debian")) {
|
|
return "debian:latest";
|
|
} else if (runsOn.contains("alpine")) {
|
|
return "alpine:latest";
|
|
}
|
|
|
|
// Default
|
|
return "ubuntu:22.04";
|
|
}
|
|
|
|
} // namespace backends
|
|
} // namespace gwt
|