forked from qt-creator/qt-creator
Lua: Create Process bindings
Change-Id: I4b8cca8433df306acdb13e9651c08ab1e01ffa82 Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -10,10 +10,24 @@ using namespace Utils;
|
|||||||
|
|
||||||
namespace Lua::Internal {
|
namespace Lua::Internal {
|
||||||
|
|
||||||
|
FilePath toFilePath(std::variant<FilePath, QString> &&v)
|
||||||
|
{
|
||||||
|
return std::visit(
|
||||||
|
[](auto &&arg) -> FilePath {
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, QString>)
|
||||||
|
return FilePath::fromUserInput(arg);
|
||||||
|
else
|
||||||
|
return arg;
|
||||||
|
},
|
||||||
|
v);
|
||||||
|
}
|
||||||
|
|
||||||
void setupProcessModule()
|
void setupProcessModule()
|
||||||
{
|
{
|
||||||
registerProvider("Process", [](sol::state_view lua) -> sol::object {
|
registerProvider("Process", [](sol::state_view lua) -> sol::object {
|
||||||
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
|
||||||
|
QObject *guard = pluginSpec->connectionGuard.get();
|
||||||
|
|
||||||
sol::table async = lua.script("return require('async')", "_process_").get<sol::table>();
|
sol::table async = lua.script("return require('async')", "_process_").get<sol::table>();
|
||||||
sol::function wrap = async["wrap"];
|
sol::function wrap = async["wrap"];
|
||||||
@@ -46,6 +60,100 @@ void setupProcessModule()
|
|||||||
process["runInTerminal"] = wrap(process["runInTerminal_cb"]);
|
process["runInTerminal"] = wrap(process["runInTerminal_cb"]);
|
||||||
process["commandOutput"] = wrap(process["commandOutput_cb"]);
|
process["commandOutput"] = wrap(process["commandOutput_cb"]);
|
||||||
|
|
||||||
|
process["create"] = [](const sol::table ¶meter) {
|
||||||
|
const auto cmd = toFilePath(parameter.get<std::variant<FilePath, QString>>("command"));
|
||||||
|
|
||||||
|
const QStringList arguments
|
||||||
|
= parameter.get_or<QStringList, const char *, QStringList>("arguments", {});
|
||||||
|
const std::optional<FilePath> workingDirectory = parameter.get<std::optional<FilePath>>(
|
||||||
|
"workingDirectory");
|
||||||
|
|
||||||
|
const auto stdOut = parameter.get<std::optional<sol::function>>("stdout");
|
||||||
|
const auto stdErr = parameter.get<std::optional<sol::function>>("stderr");
|
||||||
|
const auto stdIn = parameter.get<sol::optional<QString>>("stdin");
|
||||||
|
|
||||||
|
auto p = std::make_unique<Process>();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
process.new_usertype<Process>(
|
||||||
|
"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> connections = std::make_shared<Connections>();
|
||||||
|
|
||||||
|
// 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;
|
return process;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -14,4 +14,38 @@ function process.runInTerminal(cmd) end
|
|||||||
---@return string output The output of the command.
|
---@return string output The output of the command.
|
||||||
function process.commandOutput(cmd) end
|
function process.commandOutput(cmd) end
|
||||||
|
|
||||||
|
---@class Process
|
||||||
|
process.Process = {}
|
||||||
|
|
||||||
|
---@class ProcessParameters
|
||||||
|
---@field command FilePath The command to run.
|
||||||
|
---@field arguments? string[] The arguments to pass to the command.
|
||||||
|
---@field workingDirectory? FilePath The working directory for the command.
|
||||||
|
---@field stdin? string The input to write to stdin.
|
||||||
|
---@field stdout? function The callback to call when the process writes to stdout.
|
||||||
|
---@field stderr? function The callback to call when the process writes to stderr.
|
||||||
|
process.ProcessParameters = {}
|
||||||
|
|
||||||
|
---Creates a new process object.
|
||||||
|
---@param parameters ProcessParameters
|
||||||
|
---@return Process
|
||||||
|
function process.create(parameters) end
|
||||||
|
|
||||||
|
---Start the process.
|
||||||
|
---@async
|
||||||
|
---@return boolean isRunning Whether the process was started successfully.
|
||||||
|
function process.Process:start() end
|
||||||
|
|
||||||
|
---Stop the process.
|
||||||
|
---@async
|
||||||
|
---@return boolean didStop Whether the process was stopped successfully.
|
||||||
|
---@return number exitCode The exit code of the process.
|
||||||
|
---@return string error The error message if the process could not be stopped.
|
||||||
|
function process.Process:stop() end
|
||||||
|
|
||||||
|
---Returns whether the process is running.
|
||||||
|
---@return boolean isRunning Whether the process is running.
|
||||||
|
function process.Process:isRunning() end
|
||||||
|
|
||||||
|
---
|
||||||
return process
|
return process
|
||||||
|
Reference in New Issue
Block a user