// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "../luaengine.h" #include "utils.h" #include #include using namespace Utils; using namespace std::string_view_literals; namespace Lua::Internal { void setupProcessModule() { registerProvider("Process", [](sol::state_view lua) -> sol::object { const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"sv); QObject *guard = pluginSpec->connectionGuard.get(); sol::table async = lua.script("return require('async')", "_process_").get(); sol::function wrap = async["wrap"]; sol::table process = lua.create_table(); process["runInTerminal_cb"] = [guard = pluginSpec->connectionGuard.get()](const QString &cmdline, const sol::function &cb) { Process *p = new Process; p->setTerminalMode(TerminalMode::Run); p->setCommand(CommandLine::fromUserInput((cmdline))); p->setEnvironment(Environment::systemEnvironment()); QObject::connect(p, &Process::done, guard, [p, cb]() { cb(p->exitCode()); }); }; process["commandOutput_cb"] = [guard = pluginSpec->connectionGuard.get()](const QString &cmdline, const sol::function &cb) { Process *p = new Process; p->setCommand(CommandLine::fromUserInput((cmdline))); p->setEnvironment(Environment::systemEnvironment()); QObject::connect(p, &Process::done, guard, [p, cb]() { cb(p->allOutput()); }); p->start(); }; process["runInTerminal"] = wrap(process["runInTerminal_cb"]); process["commandOutput"] = wrap(process["commandOutput_cb"]); process["create"] = [](const sol::table ¶meter) { const auto cmd = toFilePath(parameter.get>("command"sv)); const QStringList arguments = parameter.get_or("arguments", {}); const std::optional workingDirectory = parameter.get>( "workingDirectory"); const auto stdOut = parameter.get>("stdout"sv); const auto stdErr = parameter.get>("stderr"sv); const auto stdIn = parameter.get>("stdin"sv); const auto onFinished = parameter.get>("onFinished"sv); auto p = std::make_unique(); p->setCommand({cmd, arguments}); if (workingDirectory) p->setWorkingDirectory(*workingDirectory); if (stdIn) p->setWriteData(stdIn->toUtf8()); if (stdOut) { // clang-format off QObject::connect(p.get(), &Process::readyReadStandardOutput, p.get(), [p = p.get(), cb = *stdOut]() { void_safe_call(cb, p->readAllStandardOutput()); }); // clang-format on } if (stdErr) { // clang-format off QObject::connect(p.get(), &Process::readyReadStandardError, p.get(), [p = p.get(), cb = *stdErr]() { void_safe_call(cb, p->readAllStandardError()); }); // clang-format on } if (onFinished) { // clang-format off QObject::connect(p.get(), &Process::done, p.get(), [p = p.get(), cb = *onFinished]() { void_safe_call(cb); }); // clang-format on } return p; }; process.new_usertype( "Process", sol::no_constructor, "start_cb", [guard](Process *process, sol::function callback) { if (process->state() != QProcess::NotRunning) callback(false, "Process is already running"); struct Connections { QMetaObject::Connection startedConnection; QMetaObject::Connection doneConnection; }; std::shared_ptr connections = std::make_shared(); // clang-format off connections->startedConnection = QObject::connect(process, &Process::started, guard, [callback, process, connections]() { process->disconnect(connections->doneConnection); callback(true); }, Qt::SingleShotConnection); connections->doneConnection = QObject::connect(process, &Process::done, guard, [callback, process, connections]() { process->disconnect(connections->startedConnection); callback(false, process->errorString()); }, Qt::SingleShotConnection); // clang-format on process->start(); }, "stop_cb", [](Process *process, sol::function callback) { if (process->state() != QProcess::Running) callback(false, "Process is not running"); // clang-format off QObject::connect(process, &Process::done, process, [callback, process]() { callback(true); process->disconnect(); }, Qt::SingleShotConnection); // clang-format on process->stop(); }, "isRunning", &Process::isRunning); process["Process"]["start"] = wrap(process["Process"]["start_cb"]); process["Process"]["stop"] = wrap(process["Process"]["stop_cb"]); return process; }); } } // namespace Lua::Internal