Added process

This commit is contained in:
2026-09-07 17:13:40 -06:00
parent 8f895f0757
commit 28f4c1ac94
7 changed files with 237 additions and 18 deletions
+35
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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);
+14
View File
@@ -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];
+17 -1
View File
@@ -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];
+30 -15
View File
@@ -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_;
}
}
+5 -1
View File
@@ -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();
};