add commond file
This commit is contained in:
parent
ddd69461dd
commit
51d84229da
@ -95,6 +95,8 @@ void WorkSpaceDlg::OnSure() {
|
||||
WorkSpace* workSpace = WorkSpaceManager::Get().GetOrCreate(workspacePath, name);
|
||||
workSpace->SetDescribe(ui->etDescribe->toPlainText());
|
||||
workSpace->SetCommondFilePath(commondPath_);
|
||||
// Execute commands configured for onCreate right after workspace is set up
|
||||
workSpace->ExecuteCommands(WorkSpace::CommandWhen::OnCreate);
|
||||
|
||||
WorkSpaceManager::Get().SetCurrent(workSpace);
|
||||
accept();
|
||||
@ -115,33 +117,17 @@ void WorkSpaceDlg::OnSelectSavePath() {
|
||||
|
||||
void WorkSpaceDlg::OnSelectCommondPath() {
|
||||
const QString workspacePath = Application::GetWorkSpacePath();
|
||||
const QString savePath = QFileDialog::getExistingDirectory(this,
|
||||
tr("select commond file directory"), workspacePath, QFileDialog::DontResolveSymlinks);
|
||||
if (savePath.isEmpty()) {
|
||||
LOG_WARN("save commond file is empty");
|
||||
const QString xmlPath = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr("select command xml file"),
|
||||
workspacePath,
|
||||
tr("XML files (*.xml);;All files (*.*)"));
|
||||
if (xmlPath.isEmpty()) {
|
||||
LOG_WARN("command xml file is empty");
|
||||
return;
|
||||
}
|
||||
commondPath_ = savePath;
|
||||
ui->leCommondPath->setText(QString("%1").arg(commondPath_));
|
||||
LOG_INFO("select path: {}", commondPath_.toLocal8Bit().constData());
|
||||
commondPath_ = xmlPath;
|
||||
ui->leCommondPath->setText(commondPath_);
|
||||
LOG_INFO("select command xml: {}", commondPath_.toLocal8Bit().constData());
|
||||
}
|
||||
//
|
||||
//void WorkSpaceDlg::InitFrame() {
|
||||
// FrameTitleBar* titleBar = new FrameTitleBar(this);
|
||||
// titleBar->SetMainWidget(this);
|
||||
//
|
||||
// titleBar->SetSysButton(FrameTitleBar::FTB_ICON | FrameTitleBar::FTB_CLOSE);
|
||||
//
|
||||
// QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
// layout->setContentsMargins(0, 0, 0, 0);
|
||||
// layout->setSpacing(0);
|
||||
//
|
||||
// layout->setStretch(0, 0);
|
||||
// layout->setStretch(1, 1);
|
||||
// layout->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
// SetTitleBar(titleBar);
|
||||
//
|
||||
// QWidget* mainDilag_ = new QWidget(this);
|
||||
// layout->addWidget(mainDilag_, 1);
|
||||
// ui->setupUi(mainDilag_);
|
||||
//}
|
||||
|
||||
|
||||
68
src/workspace/CommandExecutor.cpp
Normal file
68
src/workspace/CommandExecutor.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "workspace/CommandExecutor.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "common/SpdLogger.h"
|
||||
|
||||
void CommandExecutor::Execute(WorkSpace* ws, WorkSpace::CommandWhen when) {
|
||||
if (!ws) return;
|
||||
if (!cmd_.enabled) return;
|
||||
|
||||
const QString whenStr = (when == WorkSpace::CommandWhen::OnCreate) ? QStringLiteral("oncreate") : QStringLiteral("onload");
|
||||
|
||||
// Build final arguments (already prepared by manager but honor rawArgs if provided)
|
||||
QStringList argsList = cmd_.args;
|
||||
auto pushArgs = [&argsList](const QString& s) {
|
||||
if (!s.isEmpty()) {
|
||||
for (const auto& part : s.split(' ', Qt::SkipEmptyParts)) {
|
||||
argsList << part;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!cmd_.rawArgs.isEmpty()) {
|
||||
pushArgs(cmd_.rawArgs);
|
||||
}
|
||||
|
||||
const QString programLower = cmd_.program.toLower();
|
||||
if (!cmd_.path.isEmpty()) {
|
||||
if (programLower.endsWith("cmd.exe")) {
|
||||
argsList << "/c" << cmd_.path;
|
||||
} else if (programLower.endsWith("powershell.exe")) {
|
||||
argsList << "-NoProfile" << "-ExecutionPolicy" << "Bypass" << "-File" << cmd_.path;
|
||||
} else {
|
||||
argsList << cmd_.path;
|
||||
}
|
||||
}
|
||||
|
||||
QProcess proc;
|
||||
// Apply environment if provided
|
||||
if (!cmd_.env.empty()) {
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
for (auto it = cmd_.env.begin(); it != cmd_.env.end(); ++it) {
|
||||
env.insert(it.key(), it.value());
|
||||
}
|
||||
proc.setProcessEnvironment(env);
|
||||
}
|
||||
|
||||
proc.setProgram(cmd_.program);
|
||||
proc.setArguments(argsList);
|
||||
proc.setWorkingDirectory(cmd_.workingDir.isEmpty() ? ws->GetDir() : cmd_.workingDir);
|
||||
LOG_INFO("run command: name={} prog={} args={} cwd={} when={} desc={}",
|
||||
cmd_.name.toLocal8Bit().constData(),
|
||||
cmd_.program.toLocal8Bit().constData(),
|
||||
argsList.join(' ').toLocal8Bit().constData(),
|
||||
proc.workingDirectory().toLocal8Bit().constData(),
|
||||
whenStr.toLocal8Bit().constData(),
|
||||
cmd_.descript.toLocal8Bit().constData());
|
||||
proc.start();
|
||||
if (!proc.waitForStarted()) {
|
||||
LOG_WARN("command failed to start: {}", cmd_.program.toLocal8Bit().constData());
|
||||
return;
|
||||
}
|
||||
proc.waitForFinished(cmd_.timeoutMs);
|
||||
const QByteArray out = proc.readAllStandardOutput();
|
||||
const QByteArray err = proc.readAllStandardError();
|
||||
LOG_INFO("command '{}' exitCode={} stdout={} stderr={}", cmd_.name.toLocal8Bit().constData(), proc.exitCode(), out.constData(), err.constData());
|
||||
}
|
||||
32
src/workspace/CommandExecutor.h
Normal file
32
src/workspace/CommandExecutor.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
|
||||
#include "workspace/WorkSpace.h"
|
||||
|
||||
// Merge Command model into this header to reduce files
|
||||
struct Command {
|
||||
QString name;
|
||||
QString program;
|
||||
QStringList args; // final argument list to pass to QProcess
|
||||
QString rawArgs; // original args string from XML (optional)
|
||||
QString path; // script or executable path
|
||||
QString workingDir; // working directory
|
||||
bool enabled{true};
|
||||
QMap<QString, QString> env; // environment key/value pairs
|
||||
QString descript; // description
|
||||
int timeoutMs{30000}; // default 30s
|
||||
};
|
||||
|
||||
class CommandExecutor {
|
||||
public:
|
||||
explicit CommandExecutor(const Command& cmd) : cmd_(cmd) {}
|
||||
void Execute(WorkSpace* ws, WorkSpace::CommandWhen when);
|
||||
|
||||
const Command& Get() const { return cmd_; }
|
||||
|
||||
private:
|
||||
Command cmd_;
|
||||
};
|
||||
117
src/workspace/CommandManager.cpp
Normal file
117
src/workspace/CommandManager.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "workspace/CommandManager.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "xml/tinyxml2.h"
|
||||
#include "common/SpdLogger.h"
|
||||
|
||||
static QMap<QString, QString> parseEnvAttr(const QString& envAttr) {
|
||||
QMap<QString, QString> 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 = 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(), 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 <env key="" value=""/>
|
||||
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<CommandExecutor>(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);
|
||||
}
|
||||
}
|
||||
17
src/workspace/CommandManager.h
Normal file
17
src/workspace/CommandManager.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "workspace/WorkSpace.h"
|
||||
#include "workspace/CommandExecutor.h"
|
||||
|
||||
class CommandManager {
|
||||
public:
|
||||
void Reload(WorkSpace* ws);
|
||||
void Execute(WorkSpace* ws, WorkSpace::CommandWhen when);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<CommandExecutor>> onCreate_;
|
||||
std::vector<std::unique_ptr<CommandExecutor>> onLoad_;
|
||||
};
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#include "workspace/WorkSpaceXMLParse.h"
|
||||
#include "workspace/WorkSpaceXMLWrite.h"
|
||||
#include "workspace/CommandManager.h"
|
||||
|
||||
#include "workspace/WorkSpaceItem.h"
|
||||
#include "workspace/Timestep.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "common/SpdLogger.h"
|
||||
#include "entities/Entity.h"
|
||||
#include "utils/FileUtils.h"
|
||||
#include <QProcess>
|
||||
//#include "workspace/WorkSpaceItemGroup.h"
|
||||
//#include "workspace/WorkSpaceRiverGroup.h"
|
||||
//#include "workspace/WorkSpaceRiverNetGroup.h"
|
||||
@ -25,6 +27,7 @@ WorkSpace::WorkSpace(QObject* parent) noexcept
|
||||
: QObject(parent) {
|
||||
uuid_ = QUuid::createUuid().toString();
|
||||
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
|
||||
cmdMgr_ = std::make_unique<CommandManager>();
|
||||
}
|
||||
|
||||
WorkSpace::WorkSpace(const QString& path, QObject* parent)
|
||||
@ -32,6 +35,7 @@ WorkSpace::WorkSpace(const QString& path, QObject* parent)
|
||||
, path_(path){
|
||||
uuid_ = QUuid::createUuid().toString();
|
||||
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
|
||||
cmdMgr_ = std::make_unique<CommandManager>();
|
||||
}
|
||||
|
||||
const QString WorkSpace::GetDir() const {
|
||||
@ -379,4 +383,13 @@ void WorkSpace::OnLoaded() {
|
||||
if (nullptr != timestep_) {
|
||||
emit TimestepChanged(timestep_);
|
||||
}
|
||||
// Execute commands configured for onLoad
|
||||
ExecuteCommands(CommandWhen::OnLoad);
|
||||
}
|
||||
|
||||
void WorkSpace::ExecuteCommands(CommandWhen when) {
|
||||
if (!cmdMgr_) {
|
||||
cmdMgr_ = std::make_unique<CommandManager>();
|
||||
}
|
||||
cmdMgr_->Execute(this, when);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <QObject>
|
||||
|
||||
@ -15,6 +16,7 @@
|
||||
//#include "../ui/chartPlot/DYTChart.h"
|
||||
|
||||
class WorkSpaceItem;
|
||||
class CommandManager;
|
||||
|
||||
class WorkSpace : public QObject {
|
||||
Q_OBJECT
|
||||
@ -52,6 +54,10 @@ public:
|
||||
void SetCommondFilePath(const QString& path);
|
||||
const QString GetCommondFilePath() const;
|
||||
|
||||
// Execute command xml according to trigger
|
||||
enum class CommandWhen { OnCreate, OnLoad };
|
||||
void ExecuteCommands(CommandWhen when);
|
||||
|
||||
void SetSimMatlab(const QString& path);
|
||||
const QString GetSimMatlab() const;
|
||||
|
||||
@ -172,6 +178,8 @@ private:
|
||||
std::map<FileEntryType, std::vector<FileEntry>> files_;
|
||||
// Monotonic sequence for file entries changes, used to trigger UI refresh
|
||||
std::uint64_t filesSeq_{ 0 };
|
||||
// Executor for command XML actions
|
||||
std::unique_ptr<CommandManager> cmdMgr_;
|
||||
public:
|
||||
std::uint64_t GetFilesSeq() const { return filesSeq_; }
|
||||
friend class WorkSpaceXMLWrite;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user