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 App\Enums\ProcessStatus; 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 @@ class RunRemoteProcess 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 @@ class RunRemoteProcess } } + 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/resources/views/livewire/poll-activity.blade.php b/resources/views/livewire/poll-activity.blade.php index bc939f7d4..a5152efc0 100644 --- a/resources/views/livewire/poll-activity.blade.php +++ b/resources/views/livewire/poll-activity.blade.php @@ -1,5 +1,7 @@
- {{ data_get($activity, 'description') }} + @isset($activity) + {{ (new App\Actions\RemoteProcess\TidyOutput($activity))() }} + @endisset