Skip to content

Commit

Permalink
chore: Start extraction of functions.php to dedicated class
Browse files Browse the repository at this point in the history
  • Loading branch information
lyrixx committed Apr 2, 2024
1 parent e45cc14 commit de3dc31
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 141 deletions.
74 changes: 74 additions & 0 deletions src/Helper/ParallelHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

namespace Castor\Helper;

use Castor\Console\Application;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;

/** @internal */
final class ParallelHelper
{
/**
* @return array<mixed>
*/
public static function parallel(Application $app, OutputInterface $output, callable ...$callbacks): array
{
/** @var \Fiber[] $fibers */
$fibers = [];
$exceptions = [];

foreach ($callbacks as $callback) {
$fiber = new \Fiber($callback);

try {
$fiber->start();
} catch (\Throwable $e) {
if ($output instanceof ConsoleOutput) {
$output = $output->getErrorOutput();
}

$app->renderThrowable($e, $output);

$exceptions[] = $e;
}

$fibers[] = $fiber;
}

$isRunning = true;

while ($isRunning) {
$isRunning = false;

foreach ($fibers as $fiber) {
$isRunning = $isRunning || !$fiber->isTerminated();

if (!$fiber->isTerminated() && $fiber->isSuspended()) {
try {
$fiber->resume();
} catch (\Throwable $e) {
if ($output instanceof ConsoleOutput) {
$output = $output->getErrorOutput();
}

$app->renderThrowable($e, $output);

$exceptions[] = $e;
}
}
}

if (\Fiber::getCurrent()) {
\Fiber::suspend();
usleep(1_000);
}
}

if ($exceptions) {
throw new \RuntimeException('One or more exceptions were thrown in parallel.');
}

return array_map(fn ($fiber) => $fiber->getReturn(), $fibers);
}
}
102 changes: 102 additions & 0 deletions src/Helper/WatchHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace Castor\Helper;

use Castor\Console\Application;
use Castor\Console\Output\SectionOutput;
use Castor\Context;
use JoliCode\PhpOsHelper\OsHelper;
use Symfony\Component\Process\Process;

use function Castor\run;

/** @internal */
final class WatchHelper
{
/**
* @param string|non-empty-array<string> $path
* @param (callable(string, string) : (false|void|null)) $function
*/
public static function watch(Application $app, SectionOutput $sectionOutput, string|array $path, callable $function, Context $context): void
{
$output = $sectionOutput->getConsoleOutput();

if (\is_array($path)) {
$parallelCallbacks = [];

foreach ($path as $p) {
$parallelCallbacks[] = fn () => self::watch($app, $sectionOutput, $p, $function, $context);
}

ParallelHelper::parallel($app, $output, ...$parallelCallbacks);

return;
}

$binary = match (true) {
OsHelper::isMacOS() => match (php_uname('m')) {
'arm64' => 'watcher-darwin-arm64',
default => 'watcher-darwin-amd64',
},
OsHelper::isWindows() => 'watcher-windows.exe',
default => match (php_uname('m')) {
'arm64' => 'watcher-linux-arm64',
default => 'watcher-linux-amd64',
},
};

$binaryPath = __DIR__ . '/../../tools/watcher/bin/' . $binary;

if (str_starts_with(__FILE__, 'phar:')) {
static $tmpPath;

if (null === $tmpPath) {
$tmpPath = sys_get_temp_dir() . '/' . $binary;
copy($binaryPath, $tmpPath);
chmod($tmpPath, 0o755);
}

$binaryPath = $tmpPath;
}

$watchContext = $context->withTty(false)->withPty(false)->withTimeout(null);

$command = [$binaryPath, $path];
$buffer = '';

run($command, callback: static function ($type, $bytes, $process) use ($function, $sectionOutput, &$buffer) {
if (Process::OUT === $type) {
$data = $buffer . $bytes;
$lines = explode("\n", $data);

while (!empty($lines)) {
$line = trim($lines[0]);

if ('' === $line) {
array_shift($lines);

continue;
}

try {
$eventLine = json_decode($line, true, 512, \JSON_THROW_ON_ERROR);
} catch (\JsonException) {
$buffer = implode("\n", $lines);

break;
}

$result = $function($eventLine['name'], $eventLine['operation']);

if (false === $result) {
$process->stop();
}

array_shift($lines);
}
} else {
$sectionOutput->writeProcessOutput($type, $bytes, $process);
}
}, context: $watchContext);
}
}
144 changes: 4 additions & 140 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use Castor\Exception\WaitFor\ExitedBeforeTimeoutException;
use Castor\Exception\WaitFor\TimeoutReachedException;
use Castor\Helper\HasherHelper;
use Castor\Helper\ParallelHelper;
use Castor\Helper\PathHelper;
use Castor\Helper\WatchHelper;
use Joli\JoliNotif\Notification;
use Joli\JoliNotif\NotifierFactory;
use JoliCode\PhpOsHelper\OsHelper;
Expand All @@ -19,7 +21,6 @@
use Spatie\Ssh\Ssh;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Dotenv\Dotenv;
Expand All @@ -42,68 +43,7 @@
*/
function parallel(callable ...$callbacks): array
{
/** @var \Fiber[] $fibers */
$fibers = [];
$exceptions = [];

foreach ($callbacks as $callback) {
$fiber = new \Fiber($callback);

try {
$fiber->start();
} catch (\Throwable $e) {
$app = app();
$output = output();

if ($output instanceof ConsoleOutput) {
$output = $output->getErrorOutput();
}

$app->renderThrowable($e, $output);

$exceptions[] = $e;
}

$fibers[] = $fiber;
}

$isRunning = true;

while ($isRunning) {
$isRunning = false;

foreach ($fibers as $fiber) {
$isRunning = $isRunning || !$fiber->isTerminated();

if (!$fiber->isTerminated() && $fiber->isSuspended()) {
try {
$fiber->resume();
} catch (\Throwable $e) {
$app = app();
$output = output();

if ($output instanceof ConsoleOutput) {
$output = $output->getErrorOutput();
}

$app->renderThrowable($e, $output);

$exceptions[] = $e;
}
}
}

if (\Fiber::getCurrent()) {
\Fiber::suspend();
usleep(1_000);
}
}

if ($exceptions) {
throw new \RuntimeException('One or more exceptions were thrown in parallel.');
}

return array_map(fn ($fiber) => $fiber->getReturn(), $fibers);
return ParallelHelper::parallel(GlobalHelper::getApplication(), GlobalHelper::getOutput(), ...$callbacks);
}

/**
Expand Down Expand Up @@ -528,85 +468,9 @@ function notify(string $message): void
*/
function watch(string|array $path, callable $function, ?Context $context = null): void
{
if (\is_array($path)) {
$parallelCallbacks = [];

foreach ($path as $p) {
$parallelCallbacks[] = fn () => watch($p, $function, $context);
}

parallel(...$parallelCallbacks);

return;
}

$context ??= GlobalHelper::getContext();

$binary = match (true) {
OsHelper::isMacOS() => match (php_uname('m')) {
'arm64' => 'watcher-darwin-arm64',
default => 'watcher-darwin-amd64',
},
OsHelper::isWindows() => 'watcher-windows.exe',
default => match (php_uname('m')) {
'arm64' => 'watcher-linux-arm64',
default => 'watcher-linux-amd64',
},
};

$binaryPath = __DIR__ . '/../tools/watcher/bin/' . $binary;

if (str_starts_with(__FILE__, 'phar:')) {
static $tmpPath;

if (null === $tmpPath) {
$tmpPath = sys_get_temp_dir() . '/' . $binary;
copy($binaryPath, $tmpPath);
chmod($tmpPath, 0o755);
}

$binaryPath = $tmpPath;
}

$watchContext = $context->withTty(false)->withPty(false)->withTimeout(null);

$command = [$binaryPath, $path];
$buffer = '';

run($command, callback: static function ($type, $bytes, $process) use ($function, &$buffer) {
if (Process::OUT === $type) {
$data = $buffer . $bytes;
$lines = explode("\n", $data);

while (!empty($lines)) {
$line = trim($lines[0]);

if ('' === $line) {
array_shift($lines);

continue;
}

try {
$eventLine = json_decode($line, true, 512, \JSON_THROW_ON_ERROR);
} catch (\JsonException) {
$buffer = implode("\n", $lines);

break;
}

$result = $function($eventLine['name'], $eventLine['operation']);

if (false === $result) {
$process->stop();
}

array_shift($lines);
}
} else {
GlobalHelper::getSectionOutput()->writeProcessOutput($type, $bytes, $process);
}
}, context: $watchContext);
WatchHelper::watch(GlobalHelper::getApplication(), GlobalHelper::getSectionOutput(), $path, $function, $context);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions tests/Examples/Generated/LayoutWithFolder.php.output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Options:
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
--no-remote Skip the import of all remote remote packages
--update-remotes Force the update of remote packages
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
Expand Down
2 changes: 2 additions & 0 deletions tests/Examples/Generated/LayoutWithOldFolder.php.output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Options:
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
--no-remote Skip the import of all remote remote packages
--update-remotes Force the update of remote packages
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
Expand Down
2 changes: 1 addition & 1 deletion tests/Examples/Generated/ParallelExceptionTest.php.err.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In parallel.php line 72:
parallel:exception


In functions.php line XXXX:
In ParallelHelper.php line XXXX:

One or more exceptions were thrown in parallel.

Expand Down
1 change: 1 addition & 0 deletions tests/Helper/OutputCleaner.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static function cleanOutput(string $string): string
$string = str_replace('castor.linux-amd64.phar', 'castor', $string);
$string = preg_replace('{In functions.php line \d+:}m', 'In functions.php line XXXX:', $string);
$string = preg_replace('{In FunctionFinder.php line \d+:}m', 'In FunctionFinder.php line XXXX:', $string);
$string = preg_replace('{In ParallelHelper.php line \d+:}m', 'In ParallelHelper.php line XXXX:', $string);
$string = preg_replace('{In Process.php line \d+:}m', 'In Process.php line XXXX:', $string);
$string = preg_replace('{In ContextRegistry.php line \d+:}m', 'In ContextRegistry.php line XXXX:', $string);
$string = preg_replace('{you are using v\d+.\d+.\d+.}m', 'you are using vX.Y.Z.', $string);
Expand Down

0 comments on commit de3dc31

Please sign in to comment.