Added process
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BOLD="\033[1m"
|
||||
RESET="\033[0m"
|
||||
|
||||
SUCCESS="\033[38;2;80;220;100m"
|
||||
FAIL="\033[38;2;255;90;90m"
|
||||
INFO="\033[38;2;100;200;255m"
|
||||
DIM="\033[2m"
|
||||
|
||||
LOG="./out/out.log"
|
||||
|
||||
# Start
|
||||
printf "${DIM}────────────────────────────────────────${RESET}\n"
|
||||
printf "${INFO}${BOLD}> Running...${RESET}\n"
|
||||
printf "${DIM}────────────────────────────────────────${RESET}\n\n"
|
||||
|
||||
# Send both stdout and stderr to the console and the log file.
|
||||
start=$(date +%s.%N)
|
||||
./out/out "$@" 2>&1 | tee "$LOG"
|
||||
status=${PIPESTATUS[0]}
|
||||
end=$(date +%s.%N)
|
||||
elapsed=$(awk "BEGIN { printf \"%.3f\", $end - $start }")
|
||||
|
||||
# Status!
|
||||
printf "\n${DIM}────────────────────────────────────────${RESET}\n"
|
||||
if (( status == 0 )); then
|
||||
printf "${SUCCESS}${BOLD}✓ Success${RESET} (exit %d)\n" "$status"
|
||||
else
|
||||
printf "${FAIL}${BOLD}✗ Failed${RESET} (exit %d)\n" "$status"
|
||||
fi
|
||||
printf "${INFO}${BOLD}> Time${RESET} ${elapsed}s\n"
|
||||
printf "${INFO}${BOLD}> Log${RESET} %s\n" "$LOG"
|
||||
printf "${DIM}────────────────────────────────────────${RESET}"
|
||||
exit "$status"
|
||||
+132
-1
@@ -2,12 +2,15 @@
|
||||
|
||||
#include <desktoplib/terminal/Terminal.hpp>
|
||||
#include <desktoplib/terminal/ui/Box.hpp>
|
||||
#include <desktoplib/proc/Process.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
int main() {
|
||||
/*
|
||||
// Original Terminal test - commented out
|
||||
int main_terminal() {
|
||||
using namespace ckitty::terminal;
|
||||
Terminal term;
|
||||
|
||||
@@ -111,5 +114,133 @@ int main() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
// Process test
|
||||
int main() {
|
||||
using namespace ckitty;
|
||||
|
||||
std::cout << "=== Process Test ===\n";
|
||||
|
||||
// Test 1: Simple command execution
|
||||
{
|
||||
std::cout << "\n--- Test 1: echo command ---\n";
|
||||
Process proc;
|
||||
#ifdef _WIN32
|
||||
proc.setExec("cmd.exe");
|
||||
proc.addParam("/c echo Hello from Process!");
|
||||
#else
|
||||
proc.setExec("echo");
|
||||
proc.addParam("Hello from Process!");
|
||||
#endif
|
||||
proc.run();
|
||||
|
||||
while (proc.isRunning()) {
|
||||
std::string_view out = proc.nextOutput();
|
||||
if (!out.empty()) {
|
||||
std::cout << "Output: " << out;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
std::cout << "Final output: " << proc.getOutput() << "\n";
|
||||
std::cout << "Exit code: " << proc.stopCode() << "\n";
|
||||
}
|
||||
|
||||
// Test 2: Command with input
|
||||
{
|
||||
std::cout << "\n--- Test 2: cat with input ---\n";
|
||||
Process proc;
|
||||
#ifdef _WIN32
|
||||
proc.setExec("cmd.exe");
|
||||
proc.addParam("/c findstr /r \"^\"");
|
||||
#else
|
||||
proc.setExec("cat");
|
||||
#endif
|
||||
proc.run();
|
||||
|
||||
std::string testInput = "Line 1\nLine 2\nLine 3\n";
|
||||
proc.addInput(testInput);
|
||||
proc.closeInput(); // Close stdin so cat gets EOF
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
while (proc.isRunning()) {
|
||||
std::string_view out = proc.nextOutput();
|
||||
if (!out.empty()) {
|
||||
std::cout << "Output: " << out;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
std::cout << "Final output: " << proc.getOutput() << "\n";
|
||||
std::cout << "Exit code: " << proc.stopCode() << "\n";
|
||||
}
|
||||
|
||||
// Test 3: Non-existent command (should fail)
|
||||
{
|
||||
std::cout << "\n--- Test 3: Non-existent command ---\n";
|
||||
Process proc;
|
||||
proc.setExec("this_command_does_not_exist_12345");
|
||||
proc.run();
|
||||
|
||||
while (proc.isRunning()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
std::cout << "Exit code: " << proc.stopCode() << "\n";
|
||||
}
|
||||
|
||||
// Test 4: Long running process with timeout
|
||||
{
|
||||
std::cout << "\n--- Test 4: Sleep command ---\n";
|
||||
Process proc;
|
||||
#ifdef _WIN32
|
||||
proc.setExec("cmd.exe");
|
||||
proc.addParam("/c timeout /t 5");
|
||||
#else
|
||||
proc.setExec("sleep");
|
||||
proc.addParam("5");
|
||||
#endif
|
||||
proc.run();
|
||||
|
||||
int polls = 0;
|
||||
while (proc.isRunning() && polls < 10) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
polls++;
|
||||
}
|
||||
|
||||
if (proc.isRunning()) {
|
||||
std::cout << "Process still running, terminating...\n";
|
||||
proc.terminate();
|
||||
}
|
||||
|
||||
while (proc.isRunning()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
std::cout << "failed(): " << (proc.failed() ? "true" : "false") << " (expected false)\n";
|
||||
std::cout << "Exit code: " << proc.stopCode() << "\n";
|
||||
}
|
||||
|
||||
// Test 5: Non-existent command
|
||||
{
|
||||
std::cout << "\n--- Test 5: Non-existent command ---\n";
|
||||
Process proc;
|
||||
proc.setExec("this_command_does_not_exist_12345");
|
||||
proc.run();
|
||||
|
||||
std::cout << "failed(): " << (proc.failed() ? "true" : "false") << " (expected true)\n";
|
||||
|
||||
while (proc.isRunning()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
std::cout << "Exit code: " << proc.stopCode() << " (expected 127 on Unix)\n";
|
||||
}
|
||||
|
||||
std::cout << "\n=== All Process Tests Complete ===\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,10 @@ namespace ckitty {
|
||||
|
||||
void writeInput(ProcessInfo* info, std::string_view data);
|
||||
|
||||
void closeInput(ProcessInfo* info);
|
||||
|
||||
void terminate(ProcessInfo* info);
|
||||
|
||||
std::string readOutput(ProcessInfo* info);
|
||||
|
||||
std::string readError(ProcessInfo* info);
|
||||
|
||||
@@ -125,6 +125,20 @@ namespace ckitty {
|
||||
write(info->stdin_fd, data.data(), data.size());
|
||||
}
|
||||
|
||||
void closeInput(ProcessInfo* info) {
|
||||
if (!info) return;
|
||||
if (info->stdin_fd != -1) {
|
||||
close(info->stdin_fd);
|
||||
info->stdin_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void terminate(ProcessInfo* info) {
|
||||
if (!info || !info->running) return;
|
||||
kill(info->pid, SIGKILL);
|
||||
info->running = false;
|
||||
}
|
||||
|
||||
std::string readOutput(ProcessInfo* info) {
|
||||
if (!info) return "";
|
||||
char buf[4096];
|
||||
|
||||
@@ -45,7 +45,9 @@ namespace ckitty {
|
||||
SetHandleInformation(hStderrRead, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation(hStdinWrite, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
|
||||
STARTUPINFOA si;
|
||||
ZeroMemory(&si, sizeof(STARTUPINFOA));
|
||||
si.cb = sizeof(STARTUPINFOA);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdOutput = hStdoutWrite;
|
||||
si.hStdError = hStderrWrite;
|
||||
@@ -130,6 +132,20 @@ namespace ckitty {
|
||||
WriteFile(info->hStdin, data.data(), static_cast<DWORD>(data.size()), &written, nullptr);
|
||||
}
|
||||
|
||||
void closeInput(ProcessInfo* info) {
|
||||
if (!info) return;
|
||||
if (info->hStdin) {
|
||||
CloseHandle(info->hStdin);
|
||||
info->hStdin = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void terminate(ProcessInfo* info) {
|
||||
if (!info || !info->running) return;
|
||||
TerminateProcess(info->pi.hProcess, 1);
|
||||
info->running = false;
|
||||
}
|
||||
|
||||
std::string readOutput(ProcessInfo* info) {
|
||||
if (!info) return "";
|
||||
char buf[4096];
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
namespace ckitty {
|
||||
|
||||
Process::~Process() {
|
||||
if (ProcessInfo) {
|
||||
ckitty::proc::os::destroyProcess(ProcessInfo);
|
||||
ProcessInfo = nullptr;
|
||||
if (info) {
|
||||
ckitty::proc::os::destroyProcess(info);
|
||||
info = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,29 +20,40 @@ namespace ckitty {
|
||||
}
|
||||
|
||||
void Process::run() {
|
||||
if (ProcessInfo) return;
|
||||
ProcessInfo = ckitty::proc::os::createProcess(exec_, args_);
|
||||
if (info) return;
|
||||
info = ckitty::proc::os::createProcess(exec_, args_);
|
||||
failed_ = (info == nullptr);
|
||||
}
|
||||
|
||||
bool Process::isRunning() {
|
||||
if (!ProcessInfo) return false;
|
||||
return ckitty::proc::os::isRunning(ProcessInfo);
|
||||
if (!info) return false;
|
||||
return ckitty::proc::os::isRunning(info);
|
||||
}
|
||||
|
||||
int Process::stopCode() {
|
||||
if (!ProcessInfo) return 0;
|
||||
return ckitty::proc::os::getExitCode(ProcessInfo);
|
||||
if (!info) return 0;
|
||||
return ckitty::proc::os::getExitCode(info);
|
||||
}
|
||||
|
||||
void Process::addInput(std::string_view view) {
|
||||
if (!ProcessInfo) return;
|
||||
ckitty::proc::os::writeInput(ProcessInfo, view);
|
||||
if (!info) return;
|
||||
ckitty::proc::os::writeInput(info, view);
|
||||
}
|
||||
|
||||
void Process::closeInput() {
|
||||
if (!info) return;
|
||||
ckitty::proc::os::closeInput(info);
|
||||
}
|
||||
|
||||
void Process::terminate() {
|
||||
if (!info) return;
|
||||
ckitty::proc::os::terminate(info);
|
||||
}
|
||||
|
||||
std::string_view Process::getOutput() {
|
||||
if (!ProcessInfo) return "";
|
||||
if (!info) return "";
|
||||
static std::string accumulated;
|
||||
std::string fresh = ckitty::proc::os::readOutput(ProcessInfo);
|
||||
std::string fresh = ckitty::proc::os::readOutput(info);
|
||||
if (!fresh.empty()) {
|
||||
accumulated += fresh;
|
||||
}
|
||||
@@ -50,10 +61,14 @@ namespace ckitty {
|
||||
}
|
||||
|
||||
std::string_view Process::nextOutput() {
|
||||
if (!ProcessInfo) return "";
|
||||
if (!info) return "";
|
||||
static std::string fresh;
|
||||
fresh = ckitty::proc::os::readOutput(ProcessInfo);
|
||||
fresh = ckitty::proc::os::readOutput(info);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
bool Process::failed() const {
|
||||
return failed_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,9 +10,10 @@ namespace ckitty {
|
||||
|
||||
class Process {
|
||||
private:
|
||||
ckitty::proc::os::ProcessInfo* ProcessInfo = nullptr;
|
||||
ckitty::proc::os::ProcessInfo* info = nullptr;
|
||||
std::string exec_;
|
||||
std::vector<std::string> args_;
|
||||
bool failed_ = false;
|
||||
|
||||
public:
|
||||
Process() = default;
|
||||
@@ -24,8 +25,11 @@ namespace ckitty {
|
||||
|
||||
bool isRunning();
|
||||
int stopCode();
|
||||
bool failed() const;
|
||||
|
||||
void addInput(std::string_view view);
|
||||
void closeInput();
|
||||
void terminate();
|
||||
std::string_view getOutput();
|
||||
std::string_view nextOutput();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user