From 940cb3c000e01a1d5564a20e0fd3feecb624c28b Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Sat, 1 Apr 2023 20:50:57 +0100 Subject: [PATCH] Have the output Marker and markTidyer. --- .../RemoteProcess/RunRemoteProcess.php | 27 +++--- app/Actions/RemoteProcess/TidyOutput.php | 90 +++++++++++++++++++ tests/Feature/DockerCommandsTest.php | 12 ++- tests/Feature/RemoteProcessTest.php | 36 ++++++++ tests/Unit/ExampleTest.php | 5 -- 5 files changed, 152 insertions(+), 18 deletions(-) create mode 100644 app/Actions/RemoteProcess/TidyOutput.php create mode 100644 tests/Feature/RemoteProcessTest.php delete mode 100644 tests/Unit/ExampleTest.php diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index d13c6113c..53e0beb10 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -7,7 +7,6 @@ use Illuminate\Process\ProcessResult; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Process; -use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Models\Activity; class RunRemoteProcess @@ -26,9 +25,12 @@ class RunRemoteProcess protected $throttleIntervalMS = 500; - protected string $stdOutIncremental = ''; + protected int $counter = 1; - protected string $stdErrIncremental = ''; + public const MARK_START = "|--"; + public const MARK_END = "--|"; + public const SEPARATOR = '|'; + public const MARK_REGEX = "/(\|--\d+\|\d+\|(?:out|err)--\|)/"; /** * Create a new job instance. @@ -88,15 +90,10 @@ protected function handleOutput(string $type, string $output) if ($this->hideFromOutput) { return; } + $this->currentTime = $this->elapsedTime(); - if ($type === 'out') { - $this->stdOutIncremental .= $output; - } else { - $this->stdErrIncremental .= $output; - } - - $this->activity->description .= $output; + $this->activity->description .= $this->encodeOutput($type, $output); if ($this->isAfterLastThrottle()) { // Let's write to database. @@ -107,6 +104,16 @@ protected function handleOutput(string $type, string $output) } } + public function encodeOutput($type, $output) + { + return + static::MARK_START . $this->counter++ . + static::SEPARATOR . $this->elapsedTime() . + static::SEPARATOR . $type . + static::MARK_END . + $output; + } + /** * Determines if it's time to write again to database. * diff --git a/app/Actions/RemoteProcess/TidyOutput.php b/app/Actions/RemoteProcess/TidyOutput.php new file mode 100644 index 000000000..e2bd02f69 --- /dev/null +++ b/app/Actions/RemoteProcess/TidyOutput.php @@ -0,0 +1,90 @@ +activity->description, + flags: PREG_SPLIT_DELIM_CAPTURE + ); + + $tidyRows = $this + ->joinMarksWithFollowingItem($chunks) + ->reject(fn($i) => $i === '') + ->map(function ($i) { + if (!preg_match('/\|--(\d+)\|(\d+)\|(out|err)--\|(.*)/', $i, $matches)) { + return $i; + } + [$wholeLine, $sequence, $elapsedTime, $type, $output] = $matches; + return [ + 'sequence' => $sequence, + 'time' => $elapsedTime, + 'type' => $type, + 'output' => $output, + ]; + }); + + return $tidyRows + ->sortBy(fn($i) => $i['sequence']) + ->map(fn($i) => $i['output']) + ->implode("\n"); + } + + /** + * Function to join the defined mark, with the output + * that is the following element in the array. + * + * Turns this: + * [ + * "|--1|149|out--|", + * "/root\n", + * "|--2|251|out--|", + * "Welcome 1 times 1\n", + * "|--3|366|out--|", + * "Welcome 2 times 2\n", + * "|--4|466|out--|", + * "Welcome 3 times 3\n", + * ] + * + * into this: + * + * [ + * "|--1|149|out--|/root\n", + * "|--2|251|out--|Welcome 1 times 1\n", + * "|--3|366|out--|Welcome 2 times 2\n", + * "|--4|466|out--|Welcome 3 times 3\n", + * ] + */ + public function joinMarksWithFollowingItem($chunks): Collection + { + return collect($chunks)->reduce(function ($carry, $item) { + $last = $carry->last(); + if (preg_match(RunRemoteProcess::MARK_REGEX, $last) && !preg_match(RunRemoteProcess::MARK_REGEX, $item)) { + // If the last element is a delimiter and the current element is not, + // join them together and replace the last element with the joined string + $carry->pop(); + $joined = $last . $item; + $carry->push($joined); + } else { + // Otherwise, just add the current element to the result array + $carry->push($item); + } + return $carry; + }, collect()); + } +} diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index 322ca734c..5e40fe85d 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -1,9 +1,9 @@ format('Ymd_his'); $host = Server::where('name', 'testing-local-docker-container')->first(); + remoteProcess([ + "docker rm -f $(docker ps --filter='name={$coolifyNamePrefix}*' -aq)" + ], $host); + // Assert there's no containers start with coolify_test_* $activity = remoteProcess([$areThereCoolifyTestContainers], $host); - $containers = formatDockerCmdOutputToJson($activity->description); + $tidyOutput = (new TidyOutput($activity))(); + $containers = formatDockerCmdOutputToJson($tidyOutput); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName @@ -43,7 +48,8 @@ // docker ps name = $container $activity = remoteProcess([$areThereCoolifyTestContainers], $host); - $containers = formatDockerCmdOutputToJson($activity->description); + $tidyOutput = (new TidyOutput($activity))(); + $containers = formatDockerCmdOutputToJson($tidyOutput); expect($containers->where('Names', $containerName)->count())->toBe(1); // Stop testing containers diff --git a/tests/Feature/RemoteProcessTest.php b/tests/Feature/RemoteProcessTest.php new file mode 100644 index 000000000..aeca27edc --- /dev/null +++ b/tests/Feature/RemoteProcessTest.php @@ -0,0 +1,36 @@ +seed(DatabaseSeeder::class); +}); + +it('outputs correctly', function () { + + $host = Server::where('name', 'testing-local-docker-container')->first(); + + $activity = remoteProcess([ + 'pwd', + 'x=1; while [ $x -le 3 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', + ], $host); + + + preg_match(RunRemoteProcess::MARK_REGEX, $activity->description, $matchesInRawContent); + $out = (new TidyOutput($activity))(); + preg_match(RunRemoteProcess::MARK_REGEX, $out, $matchesInTidyOutput); + + expect($matchesInRawContent) + ->not()->toBeEmpty() + ->and($matchesInTidyOutput) + ->toBeEmpty(); + +}); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php deleted file mode 100644 index 44a4f337a..000000000 --- a/tests/Unit/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -});