#include "workspace/CommandManager.h" #include #include "xml/tinyxml2.h" #include "common/SpdLogger.h" static QMap parseEnvAttr(const QString& envAttr) { QMap env; if (envAttr.isEmpty()) return env; const auto pairs = envAttr.split(';', Qt::SkipEmptyParts); for (const auto& p : pairs) { const auto kv = p.split('=', Qt::KeepEmptyParts); if (kv.size() >= 2) env.insert(kv[0].trimmed(), kv[1].trimmed()); } return env; } void CommandManager::Reload(WorkSpace* ws) { onCreate_.clear(); onLoad_.clear(); if (!ws) return; const QString cmdPath = QString("%1/%2").arg(ws->GetDir(), ws->GetCommondFilePath()); if (cmdPath.isEmpty()) { LOG_INFO("no command xml configured"); return; } QFileInfo fi(cmdPath); if (!fi.exists() || !fi.isFile()) { LOG_WARN("command xml not found: {}", cmdPath.toLocal8Bit().constData()); return; } tinyxml2::XMLDocument doc; auto rc = doc.LoadFile(cmdPath.toLocal8Bit().constData()); if (rc != tinyxml2::XML_SUCCESS) { LOG_WARN("load command xml failed: {} rc:{}", cmdPath.toLocal8Bit().constData(), static_cast(rc)); return; } auto* root = doc.RootElement(); if (!root) { LOG_WARN("command xml has no root: {}", cmdPath.toLocal8Bit().constData()); return; } for (auto* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) { const char* tag = node->Name(); if (!tag) continue; QString tagQ = QString::fromUtf8(tag).toLower(); if (tagQ != QLatin1String("commond") && tagQ != QLatin1String("command")) continue; Command cmd; if (const char* nameAttr = node->Attribute("name")) cmd.name = QString::fromUtf8(nameAttr); if (const char* exeAttr = node->Attribute("exe")) cmd.program = QString::fromUtf8(exeAttr); if (cmd.program.isEmpty()) { if (const char* programAttr = node->Attribute("program")) cmd.program = QString::fromUtf8(programAttr); } if (const char* pathAttr = node->Attribute("path")) cmd.path = QString::fromUtf8(pathAttr); if (cmd.path.isEmpty()) { if (const char* pathTypo = node->Attribute("paht")) cmd.path = QString::fromUtf8(pathTypo); } if (const char* argsAttr = node->Attribute("args")) cmd.rawArgs = QString::fromUtf8(argsAttr); if (const char* cwdAttr = node->Attribute("workingDir")) cmd.workingDir = QString::fromUtf8(cwdAttr); if (cmd.workingDir.isEmpty()) { if (const char* cwdAttr2 = node->Attribute("cwd")) cmd.workingDir = QString::fromUtf8(cwdAttr2); } if (const char* enabledAttr = node->Attribute("enabled")) { QString en = QString::fromUtf8(enabledAttr).toLower(); cmd.enabled = !(en == QLatin1String("false") || en == QLatin1String("0")); } if (const char* descAttr = node->Attribute("descript")) cmd.descript = QString::fromUtf8(descAttr); if (cmd.descript.isEmpty()) { if (const char* desc2 = node->Attribute("description")) cmd.descript = QString::fromUtf8(desc2); } if (const char* timeoutAttr = node->Attribute("timeoutSec")) { bool ok = false; int v = QString::fromUtf8(timeoutAttr).toInt(&ok); if (ok && v > 0) cmd.timeoutMs = v * 1000; } // env: either attribute env="KEY=VAL;K2=V2" or child elements if (const char* envAttr = node->Attribute("env")) { cmd.env = parseEnvAttr(QString::fromUtf8(envAttr)); } for (auto* envNode = node->FirstChildElement("env"); envNode; envNode = envNode->NextSiblingElement("env")) { const char* k = envNode->Attribute("key"); const char* v = envNode->Attribute("value"); if (k && v) cmd.env.insert(QString::fromUtf8(k), QString::fromUtf8(v)); } // Pre-build args list from rawArgs (actual insertion of path happens in executor) if (!cmd.rawArgs.isEmpty()) { for (const auto& part : cmd.rawArgs.split(' ', Qt::SkipEmptyParts)) { cmd.args << part; } } // when routing WorkSpace::CommandWhen target = WorkSpace::CommandWhen::OnCreate; // default if (const char* whenAttr = node->Attribute("when")) { QString wa = QString::fromUtf8(whenAttr).toLower(); if (wa == QLatin1String("onload")) target = WorkSpace::CommandWhen::OnLoad; } auto exec = std::make_unique(cmd); if (target == WorkSpace::CommandWhen::OnCreate) onCreate_.push_back(std::move(exec)); else onLoad_.push_back(std::move(exec)); } } void CommandManager::Execute(WorkSpace* ws, WorkSpace::CommandWhen when) { // Reload each time to reflect latest XML Reload(ws); auto& list = (when == WorkSpace::CommandWhen::OnCreate) ? onCreate_ : onLoad_; for (auto& exec : list) { exec->Execute(ws, when); } } std::vector CommandManager::ListCommands(WorkSpace* ws) { std::vector items; Reload(ws); for (auto& exec : onCreate_) { items.push_back(exec->Get()); } for (auto& exec : onLoad_) { items.push_back(exec->Get()); } return items; } bool CommandManager::ExecuteByName(WorkSpace* ws, const QString& name) { Reload(ws); auto matchAndRun = [&](std::vector>& list, WorkSpace::CommandWhen when) -> bool { for (auto& exec : list) { if (exec->Get().name == name) { exec->Execute(ws, when); return true; } } return false; }; if (matchAndRun(onCreate_, WorkSpace::CommandWhen::OnCreate)) return true; if (matchAndRun(onLoad_, WorkSpace::CommandWhen::OnLoad)) return true; return false; }