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* workSpace = WorkSpaceManager::Get().GetOrCreate(workspacePath, name);
|
||||||
workSpace->SetDescribe(ui->etDescribe->toPlainText());
|
workSpace->SetDescribe(ui->etDescribe->toPlainText());
|
||||||
workSpace->SetCommondFilePath(commondPath_);
|
workSpace->SetCommondFilePath(commondPath_);
|
||||||
|
// Execute commands configured for onCreate right after workspace is set up
|
||||||
|
workSpace->ExecuteCommands(WorkSpace::CommandWhen::OnCreate);
|
||||||
|
|
||||||
WorkSpaceManager::Get().SetCurrent(workSpace);
|
WorkSpaceManager::Get().SetCurrent(workSpace);
|
||||||
accept();
|
accept();
|
||||||
@ -115,33 +117,17 @@ void WorkSpaceDlg::OnSelectSavePath() {
|
|||||||
|
|
||||||
void WorkSpaceDlg::OnSelectCommondPath() {
|
void WorkSpaceDlg::OnSelectCommondPath() {
|
||||||
const QString workspacePath = Application::GetWorkSpacePath();
|
const QString workspacePath = Application::GetWorkSpacePath();
|
||||||
const QString savePath = QFileDialog::getExistingDirectory(this,
|
const QString xmlPath = QFileDialog::getOpenFileName(
|
||||||
tr("select commond file directory"), workspacePath, QFileDialog::DontResolveSymlinks);
|
this,
|
||||||
if (savePath.isEmpty()) {
|
tr("select command xml file"),
|
||||||
LOG_WARN("save commond file is empty");
|
workspacePath,
|
||||||
|
tr("XML files (*.xml);;All files (*.*)"));
|
||||||
|
if (xmlPath.isEmpty()) {
|
||||||
|
LOG_WARN("command xml file is empty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
commondPath_ = savePath;
|
commondPath_ = xmlPath;
|
||||||
ui->leCommondPath->setText(QString("%1").arg(commondPath_));
|
ui->leCommondPath->setText(commondPath_);
|
||||||
LOG_INFO("select path: {}", commondPath_.toLocal8Bit().constData());
|
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/WorkSpaceXMLParse.h"
|
||||||
#include "workspace/WorkSpaceXMLWrite.h"
|
#include "workspace/WorkSpaceXMLWrite.h"
|
||||||
|
#include "workspace/CommandManager.h"
|
||||||
|
|
||||||
#include "workspace/WorkSpaceItem.h"
|
#include "workspace/WorkSpaceItem.h"
|
||||||
#include "workspace/Timestep.h"
|
#include "workspace/Timestep.h"
|
||||||
@ -15,6 +16,7 @@
|
|||||||
#include "common/SpdLogger.h"
|
#include "common/SpdLogger.h"
|
||||||
#include "entities/Entity.h"
|
#include "entities/Entity.h"
|
||||||
#include "utils/FileUtils.h"
|
#include "utils/FileUtils.h"
|
||||||
|
#include <QProcess>
|
||||||
//#include "workspace/WorkSpaceItemGroup.h"
|
//#include "workspace/WorkSpaceItemGroup.h"
|
||||||
//#include "workspace/WorkSpaceRiverGroup.h"
|
//#include "workspace/WorkSpaceRiverGroup.h"
|
||||||
//#include "workspace/WorkSpaceRiverNetGroup.h"
|
//#include "workspace/WorkSpaceRiverNetGroup.h"
|
||||||
@ -25,6 +27,7 @@ WorkSpace::WorkSpace(QObject* parent) noexcept
|
|||||||
: QObject(parent) {
|
: QObject(parent) {
|
||||||
uuid_ = QUuid::createUuid().toString();
|
uuid_ = QUuid::createUuid().toString();
|
||||||
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
|
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)
|
WorkSpace::WorkSpace(const QString& path, QObject* parent)
|
||||||
@ -32,6 +35,7 @@ WorkSpace::WorkSpace(const QString& path, QObject* parent)
|
|||||||
, path_(path){
|
, path_(path){
|
||||||
uuid_ = QUuid::createUuid().toString();
|
uuid_ = QUuid::createUuid().toString();
|
||||||
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
|
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 {
|
const QString WorkSpace::GetDir() const {
|
||||||
@ -379,4 +383,13 @@ void WorkSpace::OnLoaded() {
|
|||||||
if (nullptr != timestep_) {
|
if (nullptr != timestep_) {
|
||||||
emit TimestepChanged(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
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
@ -15,6 +16,7 @@
|
|||||||
//#include "../ui/chartPlot/DYTChart.h"
|
//#include "../ui/chartPlot/DYTChart.h"
|
||||||
|
|
||||||
class WorkSpaceItem;
|
class WorkSpaceItem;
|
||||||
|
class CommandManager;
|
||||||
|
|
||||||
class WorkSpace : public QObject {
|
class WorkSpace : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -52,6 +54,10 @@ public:
|
|||||||
void SetCommondFilePath(const QString& path);
|
void SetCommondFilePath(const QString& path);
|
||||||
const QString GetCommondFilePath() const;
|
const QString GetCommondFilePath() const;
|
||||||
|
|
||||||
|
// Execute command xml according to trigger
|
||||||
|
enum class CommandWhen { OnCreate, OnLoad };
|
||||||
|
void ExecuteCommands(CommandWhen when);
|
||||||
|
|
||||||
void SetSimMatlab(const QString& path);
|
void SetSimMatlab(const QString& path);
|
||||||
const QString GetSimMatlab() const;
|
const QString GetSimMatlab() const;
|
||||||
|
|
||||||
@ -172,6 +178,8 @@ private:
|
|||||||
std::map<FileEntryType, std::vector<FileEntry>> files_;
|
std::map<FileEntryType, std::vector<FileEntry>> files_;
|
||||||
// Monotonic sequence for file entries changes, used to trigger UI refresh
|
// Monotonic sequence for file entries changes, used to trigger UI refresh
|
||||||
std::uint64_t filesSeq_{ 0 };
|
std::uint64_t filesSeq_{ 0 };
|
||||||
|
// Executor for command XML actions
|
||||||
|
std::unique_ptr<CommandManager> cmdMgr_;
|
||||||
public:
|
public:
|
||||||
std::uint64_t GetFilesSeq() const { return filesSeq_; }
|
std::uint64_t GetFilesSeq() const { return filesSeq_; }
|
||||||
friend class WorkSpaceXMLWrite;
|
friend class WorkSpaceXMLWrite;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user