2026-06-18 19:22:29 -05:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <filesystem>
|
2026-06-18 21:16:23 -05:00
|
|
|
#include <memory>
|
|
|
|
|
#include <optional>
|
2026-06-18 19:22:29 -05:00
|
|
|
#include <string>
|
2026-06-18 21:16:23 -05:00
|
|
|
#include <string_view>
|
|
|
|
|
#include <utility>
|
2026-06-18 19:22:29 -05:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
namespace izo {
|
|
|
|
|
|
2026-06-18 19:39:40 -05:00
|
|
|
struct ProcessOptions {
|
2026-06-18 19:22:29 -05:00
|
|
|
std::filesystem::path executable;
|
|
|
|
|
std::vector<std::string> arguments;
|
2026-06-18 19:39:40 -05:00
|
|
|
std::filesystem::path workingDirectory;
|
2026-06-18 19:22:29 -05:00
|
|
|
bool detached = false;
|
2026-06-18 21:16:23 -05:00
|
|
|
bool captureOutput = false;
|
|
|
|
|
bool pipeStdin = false;
|
|
|
|
|
// Used by RunProcess. A negative value waits indefinitely.
|
|
|
|
|
std::int64_t timeoutMs = -1;
|
2026-06-18 19:22:29 -05:00
|
|
|
};
|
|
|
|
|
|
2026-06-18 19:39:40 -05:00
|
|
|
struct ProcessResult {
|
2026-06-18 19:22:29 -05:00
|
|
|
bool started = false;
|
2026-06-18 19:39:40 -05:00
|
|
|
std::uint32_t processId = 0;
|
|
|
|
|
std::string errorMessage;
|
2026-06-18 19:22:29 -05:00
|
|
|
explicit operator bool() const noexcept { return started; }
|
|
|
|
|
};
|
|
|
|
|
|
2026-06-18 19:39:40 -05:00
|
|
|
ProcessResult LaunchProcess(const ProcessOptions& options);
|
2026-06-18 19:22:29 -05:00
|
|
|
|
2026-06-18 21:16:23 -05:00
|
|
|
class Process {
|
|
|
|
|
public:
|
|
|
|
|
Process() = default;
|
|
|
|
|
~Process();
|
|
|
|
|
Process(Process&&) noexcept = default;
|
|
|
|
|
Process& operator=(Process&& other) noexcept;
|
|
|
|
|
Process(const Process&) = delete;
|
|
|
|
|
Process& operator=(const Process&) = delete;
|
|
|
|
|
|
|
|
|
|
explicit operator bool() const noexcept { return state_ != nullptr; }
|
|
|
|
|
std::uint32_t Id() const noexcept;
|
|
|
|
|
bool IsRunning() const;
|
|
|
|
|
// Returns false if the timeout expires or this Process is invalid.
|
|
|
|
|
bool Wait(std::int64_t timeoutMs = -1, std::string* errorMessage = nullptr);
|
|
|
|
|
// Forcefully terminates the child process.
|
|
|
|
|
bool Terminate(std::string* errorMessage = nullptr);
|
|
|
|
|
std::optional<int> ExitCode() const;
|
|
|
|
|
|
|
|
|
|
bool WriteStdin(std::string_view data, std::string* errorMessage = nullptr);
|
|
|
|
|
bool CloseStdin(std::string* errorMessage = nullptr);
|
|
|
|
|
// Captured output is complete after Wait succeeds.
|
|
|
|
|
std::string Stdout() const;
|
|
|
|
|
std::string Stderr() const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct State;
|
|
|
|
|
explicit Process(std::shared_ptr<State> state) : state_(std::move(state)) {}
|
|
|
|
|
std::shared_ptr<State> state_;
|
|
|
|
|
|
|
|
|
|
friend Process StartProcess(const ProcessOptions&, std::string*);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Process StartProcess(const ProcessOptions& options, std::string* errorMessage = nullptr);
|
|
|
|
|
|
|
|
|
|
struct RunProcessResult {
|
|
|
|
|
bool started = false;
|
|
|
|
|
bool timedOut = false;
|
|
|
|
|
int exitCode = -1;
|
|
|
|
|
std::string stdoutText;
|
|
|
|
|
std::string stderrText;
|
|
|
|
|
std::string errorMessage;
|
|
|
|
|
|
|
|
|
|
explicit operator bool() const noexcept { return started && !timedOut && exitCode == 0; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RunProcessResult RunProcess(const ProcessOptions& options);
|
|
|
|
|
|
|
|
|
|
bool IsProcessRunning(std::uint32_t processId) noexcept;
|
|
|
|
|
std::uint32_t GetCurrentProcessId() noexcept;
|
|
|
|
|
std::uint32_t GetParentProcessId() noexcept;
|
|
|
|
|
|
2026-06-18 19:22:29 -05:00
|
|
|
} // namespace izo
|