Skip to content

Commit

Permalink
Added timeout option and dropped resolving relative paths
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelpetri committed Apr 6, 2023
1 parent abc42d4 commit 7605399
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 23 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"michaelpetri/php-generic-list": "^0.1.1",
"symfony/dependency-injection": "^6.2.7",
"symfony/framework-bundle": "^6.2.7",
"michaelpetri/php-git": "^0.2.0"
"michaelpetri/php-git": "^0.3.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.15.1",
Expand Down
16 changes: 8 additions & 8 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 31 additions & 9 deletions src/Infrastructure/Transport/Dsn.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@
namespace MichaelPetri\SymfonyFileWatcher\Infrastructure\Transport;

use MichaelPetri\Git\Value\Directory;
use MichaelPetri\Git\Value\Duration;

/** @psalm-immutable */
final class Dsn
{
private const DEFAULT_OPTIONS = [
'timeout' => 60000
];

private const ERROR = 'The given file watcher DSN "%s" is invalid: %s';
public const SCHEME = 'watch://';

public function __construct(
public readonly Directory $directory
public readonly Directory $directory,
public readonly Duration $timeout
) {
}

Expand All @@ -24,20 +30,36 @@ public static function fromString(string $dsn): self
throw new \InvalidArgumentException(\sprintf(self::ERROR, $dsn, 'Invalid scheme.'));
}

// Cut off scheme to get path.
$path = \substr($dsn, \strlen(self::SCHEME));
// File uri's don't require a host, so we just add one here to use php's internal parse url function.
$dsnWithFakeHost = \str_replace(self::SCHEME, self::SCHEME . 'localhost', $dsn);

if (false === $components = \parse_url($dsnWithFakeHost)) {
throw new \InvalidArgumentException(\sprintf(self::ERROR, $dsn, 'Malformed string.'));
}

// Use parsed path or current directory as fallback.
$path = $components['path'] ?? \realpath('.');

// Resolve absolute real path.
if ($realPath = \realpath($path)) {
$path = $realPath;
}

try {
return new self(
Directory::from($path)
);
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException(\sprintf(self::ERROR, $dsn, 'Invalid path.'), 0, $e);
$query = [];
if (isset($components['query'])) {
\parse_str($components['query'], $query);
}

// Use parsed timeout or default fallback.
$timeout = (int) ($query['timeout'] ?? self::DEFAULT_OPTIONS['timeout']);

if (0 >= $timeout) {
throw new \InvalidArgumentException(\sprintf(self::ERROR, $dsn, 'Timeout options must be positive int.'));
}

return new self(
Directory::from($path),
Duration::inMilliseconds($timeout)
);
}
}
5 changes: 4 additions & 1 deletion src/Infrastructure/Transport/FileWatcherFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ final class FileWatcherFactory implements TransportFactoryInterface
{
public function createTransport(string $dsn, array $options = [], ?SerializerInterface $serializer = null): TransportInterface
{
$dsn = Dsn::fromString($dsn);

return new EventReceiver(
new GitRepository(
Dsn::fromString($dsn)->directory
$dsn->directory,
$dsn->timeout
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use MichaelPetri\Git\GitRepositoryInterface;
use MichaelPetri\Git\Value\Change;
use MichaelPetri\Git\Value\Directory;
use MichaelPetri\Git\Value\Duration;
use MichaelPetri\Git\Value\File;
use MichaelPetri\Git\Value\Status;
use MichaelPetri\SymfonyFileWatcher\Domain\Event\FileChanged;
Expand Down Expand Up @@ -37,7 +38,7 @@ protected function setUp(): void
$p = new Process(['mkdir', '-p', $this->directory->path]);
$p->mustRun();

$this->repository = new GitRepository($this->directory);
$this->repository = new GitRepository($this->directory, Duration::inSeconds(60));
$this->receiver = new EventReceiver($this->repository);

$this->receiver->setup();
Expand Down
11 changes: 8 additions & 3 deletions tests/Unit/Infrastructure/Transport/DsnTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@
final class DsnTest extends TestCase
{
/** @dataProvider validDsnProvider */
public function testFromString(string $input, string $expectedPath): void
public function testFromString(string $input, string $expectedPath, int $expectedTimeoutInSeconds = 60): void
{
self::assertEquals($expectedPath, Dsn::fromString($input)->directory->path);
self::assertEquals($expectedTimeoutInSeconds, Dsn::fromString($input)->timeout->seconds);
}

public static function validDsnProvider(): iterable
{
yield 'no explicit path will use current directory' => ['watch://', \realpath('.')];
yield 'root path ' => ['watch:///', '/'];
yield 'relative path will be resolved to absolute path' => ['watch://src/Domain/..', \realpath('src')];
yield 'absolute path will be resolved to absolute path' => ['watch:///tmp/../tmp', '/tmp'];
yield 'with timeout option' => ['watch:///tmp?timeout=300000', '/tmp', 300];
}

/** @dataProvider invalidDsnProvider */
Expand All @@ -35,7 +36,11 @@ public static function invalidDsnProvider(): iterable
{
yield 'doctrine dsn' => [
'mysql://user:password@localhost:3306/database',
new \Exception('The given file watcher DSN "mysql://user:password@localhost:3306/database" is invalid: Invalid scheme.')
new \InvalidArgumentException('The given file watcher DSN "mysql://user:password@localhost:3306/database" is invalid: Invalid scheme.')
];
yield 'invalid timeout' => [
'watch:///tmp?timeout=0',
new \InvalidArgumentException('The given file watcher DSN "watch:///tmp?timeout=0" is invalid: Timeout options must be positive int.')
];
}
}

0 comments on commit 7605399

Please sign in to comment.