diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..58f82e00 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: CI + +on: + push: + pull_request: + +jobs: + PHPUnit: + name: PHPUnit (PHP ${{ matrix.php }} with ${{ matrix.extensions }} on ${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + php: + - "8.1" + - "8.0" + - "7.4" + extensions: + - "" + - "uv-amphp/ext-uv@master" + steps: + - uses: actions/checkout@v2 + - name: Install libuv + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install libuv1-dev + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: pcov + extensions: ${{ matrix.extensions }} + - run: composer install + - run: vendor/bin/phpunit --coverage-text --debug + PHPUnit-Docker: + name: PHPUnit (PHP ${{ matrix.php }} on Docker) + runs-on: ubuntu-latest + container: + image: wyrihaximusnet/php:${{ matrix.php }}-nts-alpine-slim-dev-root + strategy: + fail-fast: false + matrix: + php: + - "8.1" + - "8.0" + - "7.4" + steps: + - uses: actions/checkout@v2 + - run: composer install + - run: vendor/bin/phpunit --coverage-text diff --git a/.gitignore b/.gitignore index 22d0d82f..58be7c72 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ vendor +.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d1b6f65f..00000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: php - -cache: - directories: - - $HOME/.composer/cache/files - -php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - 7.2 - - nightly - -matrix: - allow_failures: - - php: 5.4 - - php: 7.1 - - php: nightly - -install: - - ./travis-init.sh - - composer install -n - -script: - - ./vendor/bin/phpunit --exclude-group permissions - - export phploc=~/.phpenv/versions/$(phpenv version-name)/bin/php - - sudo $phploc ./vendor/bin/phpunit --group permissions diff --git a/README.md b/README.md index f6782dad..6f80e0a0 100644 --- a/README.md +++ b/README.md @@ -1,147 +1,288 @@ -Filesystem -========== +# Filesystem Component + +[![CI status](https://github.com/reactphp/filesystem/workflows/CI/badge.svg)](https://github.com/reactphp/filesystem/actions) + +[ReactPHP](https://reactphp.org/)'s filesystem component that enables non-blocking filesystem operations. + +**Table of Contents** + +* [Quickstart example](#quickstart-example) +* [Usage](#usage) + * [Factory](#factory) + * [create()](#create) + * [Filesystem implementations](#filesystem-implementations) + * [ChildProcess](#childprocess) + * [Uv](#uv) + * [AdapterInterface](#adapterinterface) + * [detect()](#detect) + * [directory()](#directory) + * [file()](#file) + * [NodeInterface](#nodeinterface) + * [path()](#path) + * [name()](#name) + * [stat()](#stat) + * [DirectoryInterface](#directoryinterface) + * [ls](#ls) + * [FileInterface](#fileinterface) + * [getContents()](#getcontents) + * [putContents()](#putcontents) + * [NotExistInterface](#notexistinterface) + * [createDirectory()](#createdirectory) + * [createFile()](#createfile) +* [Install](#install) +* [Tests](#tests) +* [License](#license) + +## Quickstart example + +Here is a program that lists everything in the current directory. -[![Build Status](https://secure.travis-ci.org/reactphp/filesystem.png?branch=master)](http://travis-ci.org/reactphp/filesystem) [![Code Climate](https://codeclimate.com/github/reactphp/filesystem/badges/gpa.svg)](https://codeclimate.com/github/reactphp/filesystem) +```php +use React\Filesystem\Factory; +use React\Filesystem\Node\DirectoryInterface; +use React\Filesystem\Node\NodeInterface; + +Factory::create()->detect(__DIR__)->then(function (DirectoryInterface $directory) { + return $directory->ls(); +})->then(static function ($nodes) { + foreach ($nodes as $node) { + assert($node instanceof NodeInterface); + echo $node->name(), ': ', get_class($node), PHP_EOL; + } + echo '----------------------------', PHP_EOL, 'Done listing directory', PHP_EOL; +}, function (Throwable $throwable) { + echo $throwable; +}); +``` -[ReactPHP](https://reactphp.org/)'s evented asynchronous, non-blocking filesystem access library. +See also the [examples](examples). -Table of Contents ------------------ +## Usage -1. [Introduction](#introduction) -2. [Adapters](#adapters) -3. [Examples](#examples) - * [Creating filesystem object](#creating-filesystem-object) - * [File object](#file-object) - * [Reading files](#reading-files) - * [Writing files](#writing-files) - * [Directory object](#directory-object) - * [List contents](#list-contents) -4. [Install](#install) -5. [License](#license) +See [`Factory::create()`](#create). -Introduction ------------- +### Factory -`react/filesystem` is a package to power your application with asynchronous, non-blocking filesystem access. Asynchronous access is enabled by various adapters described below. +The `Factory` class exists as a convenient way to pick the best available +[filesystem implementation](#filesystem-implementations). -Adapters ------------- +#### create() -* ChildProcessAdapter - Adapter using child processes to perform IO actions (default adapter if no extensions are installed) +The `create(): AdapterInterface` method can be used to create a new filesystem instance: -Examples --------- +```php +$filesystem = \React\Filesystem\Factory::create(); +``` -`Adding examples here over time.` +This method always returns an instance implementing [`adapterinterface`](#adapterinterface), +the actual [Filesystem implementations](#filesystem-implementations) is an implementation detail. -Creating filesystem object --------------------------- +This method can be called at any time. However, certain scheduling mechanisms are used that will make the event loop +busier with every new instance of a filesystem adapter. To prevent that it is preferred you create it once and inject +it where required. -```php -file(__FILE__); // Returns a \React\Filesystem\Node\FileInterface compatible object -``` +The factory will determine the most performant filesystem for your environment. Any extension based filesystem are +preferred before falling back to less performant filesystems. When no extensions are detected it will fall back to +the [`ChildProcess`](#childprocess) on Linux/Mac machines, and to an internal fallback filesystem for windows that +uses blocking system calls. This blocking filesystem isn't documented and will be removed once +the [`ChildProcess`](#childprocess) filesystem works on Windows. It's merely mentioned here for reference until then. + +Advanced! If you explicitly need a certain filesystem implementation, you can +manually instantiate one of the following classes. +Note that you may have to install the required PHP extensions for the respective +event loop implementation first or they will throw a `BadMethodCallException` on creation. + +#### ChildProcess + +A [`child process`](https://reactphp.org/child-process/) based filesystem. + +This uses the blocking calls like the [`file_get_contents()`](https://www.php.net/manual/en/function.file-get-contents.php) +function to do filesystem calls and is the only implementation which works out of the box with PHP. + +Due to using child processes to handle filesystem calls, this filesystem the least performant is only used when no +extensions are found to create a more performant filesystem. + +#### Uv + +An `ext-uv` based filesystem. + +This filesystem uses the [`uv` PECL extension](https://pecl.php.net/package/uv), that +provides an interface to `libuv` library. + +This filesystem is known to work with PHP 7+. + +### AdapterInterface + +#### detect() + +The `detect(string $path): PromiseInterface` is the preferred way to get an object representing a node on the filesystem. + +When calling this method it will attempt to detect what kind of node the path is you've given it, and return an object +implementing [`NodeInterface`](#nodeinterface). If nothing exists at the given path, a [`NotExistInterface`](#notexistinterface) object will be +returned which you can use to create a file or directory. + +#### directory() + +The `directory(string $path): DirectoryInterface` creates an object representing a directory at the specified path. + +Keep in mind that unlike the `detect` method the `directory` method cannot guarantee the path you pass is actually a +directory on the filesystem and may result in unexpected behavior. + +#### file() + +The `file(string $path): DirectoryInterface` creates an object representing a file at the specified path. + +Keep in mind that unlike the `detect` method the `file` method cannot guarantee the path you pass is actually a +file on the filesystem and may result in unexpected behavior. + +### NodeInterface + +The `NodeInterface` is at the core of all other node interfaces such as `FileInterface` or `DirectoryInterface`. It +provides basic methods that are useful for all types of nodes. + +#### path() + +The `path(): string` method returns the path part of the node's location. So if the full path is `/path/to/file.ext` this method returns `/path/to/`. -Reading files -------------- +#### name() + +The `name(): string` method returns the name part of the node's location. So if the full path is `/path/to/file.ext` this method returns `file.ext`. + +#### stat() + +The `stat(): PromiseInterface` method stats the node and provides you with information such as its size, full path, create/update time. + +### DirectoryInterface + +#### ls + +The `ls(): PromiseInterface>` method list all contents of the given directory and will return an +array with nodes in it. It will do it's best to detect which type a node is itself, and otherwise fallback +to `FilesystemInterface::detect(string $path): PromiseInterface`. + +### FileInterface + +The `*Contents` methods on this interface are designed to behave the same as PHP's `file_(get|put)_contents` functions +as possible. Resulting in a very familiar API to read/stream from files, or write/append to a file. + +#### getContents + +For reading from files `getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface` provides two +arguments that control how much data it reads from the file. Without arguments, it will read everything: ```php -$filesystem->getContents('test.txt')->then(function($contents) { -}); +$file->getContents(); ``` -Which is a convenience method for: +The offset and maximum length let you 'select' a chunk of the file to be read. The following will skip the first `2048` +bytes and then read up to `1024` bytes from the file. However, if the file only contains `512` bytes after the `2048` +offset it will only return those `512` bytes. ```php -$filesystem->file('test.txt')->open('r')->then(function($stream) { - return \React\Stream\BufferedSink::createPromise($stream); -})->then(function($contents) { - // ... -}); +$file->getContents(2048, 1024); ``` -Which in it's turn is a convenience method for: +It is possible to tail files with, the following example uses a timer as trigger to check for updates: ```php -$filesystem->file('test.txt')->open('r')->then(function ($stream) use ($node) { - $buffer = ''; - $deferred = new \React\Promise\Deferred(); - $stream->on('data', function ($data) use (&$buffer) { - $buffer += $data; +$offset = 0; +Loop::addPeriodicTimer(1, function (TimerInterface $timer) use ($file, &$offset, $loop): void { + $file->getContents($offset)->then(function (string $contents) use (&$offset, $timer, $loop): void { + echo $contents; // Echo's the content for example purposes + $offset += strlen($contents); }); - $stream->on('end', function ($data) use ($stream, $deferred, &$buffer) { - $stream->close(); - $deferred->resolve(&$buffer); - }); - return $deferred->promise(); }); ``` -Writing files -------------- +#### putContents + +Writing to file's is `putContents(string $contents, int $flags = 0): PromiseInterface` specialty. By default, when +passing it contents, it will truncate the file when it exists or create a new one and then fill it with the contents +given. -Open a file for writing (`w` flag) and write `abcde` to `test.txt` and close it. Create it (`c` flag) when it doesn't exists and truncate it (`t` flag) when it does. ```php -$filesystem->file('test.txt')->open('cwt')->then(function ($stream) { - $stream->write('a'); - $stream->write('b'); - $stream->write('c'); - $stream->write('d'); - $stream->end('e'); -}); +$file->putContents('ReactPHP'); ``` -Directory object --------------------------- +Appending files is also supported, by using the `\FILE_APPEND` constant the file is appended when it exists. ```php -putContents(' is awesome!', \FILE_APPEND); +``` -$loop = \React\EventLoop\Factory::create(); -$filesystem = \React\Filesystem\Filesystem::create($loop); +### NotExistInterface -$dir = $filesystem->dir(__DIR__); // Returns a \React\Filesystem\Node\DirectoryInterface compatible object +Both creation methods will check if the parent directory exists and create it if it doesn't. Effectively making this +creation process recursively. + +#### createDirectory + +The following will create `lets/make/a/nested/directory` as a recursive directory structure. + +```php +$filesystem->directory( + __DIR__ . 'lets' . DIRECTORY_SEPARATOR . 'make' . DIRECTORY_SEPARATOR . 'a' . DIRECTORY_SEPARATOR . 'nested' . DIRECTORY_SEPARATOR . 'directory' +)->createDirectory(); ``` -List contents -------------- +#### createFile + +The following will create `with-a-file.txt` in `lets/make/a/nested/directory` and write `This is amazing!` into that file. ```php -$filesystem->dir(__DIR__)->ls()->then(function (array $list) { - foreach ($list as $node) { - echo $node->getPath(), PHP_EOL; - } +use React\Filesystem\Node\FileInterface;$filesystem->file( + __DIR__ . 'lets' . DIRECTORY_SEPARATOR . 'make' . DIRECTORY_SEPARATOR . 'a' . DIRECTORY_SEPARATOR . 'nested' . DIRECTORY_SEPARATOR . 'directory' . DIRECTORY_SEPARATOR . 'with-a-file.txt' +)->createFile()->then(function (FileInterface $file) { + return $file->putContents('This is amazing!') }); ``` -Install -------- +## Install + The recommended way to install this library is [through Composer](https://getcomposer.org). [New to Composer?](https://getcomposer.org/doc/00-intro.md) +This project follows [SemVer](https://semver.org/). This will install the latest supported version: ```bash -$ composer require react/filesystem:^0.1.1 +$ composer require react/filesystem:^0.2 +``` + +Installing any of the event loop extensions is suggested, but entirely optional. +See also [event loop implementations](#loop-implementations) for more details. + +## Tests + +To run the test suite, you first need to clone this repo and then install all +dependencies [through Composer](https://getcomposer.org): + +```bash +$ composer install +``` + +To run the test suite, go to the project root and run: + +```bash +$ php vendor/bin/phpunit ``` -License -------- +## License -React/Filesystem is released under the [MIT](https://github.com/reactphp/filesystem/blob/master/LICENSE) license. +MIT, see [LICENSE file](LICENSE). diff --git a/composer.json b/composer.json index f2c1004a..52f0de90 100644 --- a/composer.json +++ b/composer.json @@ -1,42 +1,49 @@ { - "name": "react/filesystem", - "description": "Asynchronous filesystem abstraction.", - "keywords": ["filesystem", "asynchronous"], - "license": "MIT", - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "require": { - "php": ">=5.4.0", - "evenement/evenement": "^3.0 || ^2.0", - "react/event-loop": "^1.0 || ^0.5 || ^0.4", - "react/promise": "~2.2", - "react/promise-stream": "^1.1", - "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4", - "wyrihaximus/react-child-process-pool": "^1.3" - }, - "require-dev": { - "clue/block-react": "^1.1", - "phpunit/phpunit": "^6.0 || ^5.0 || ^4.8" - }, - "autoload": { - "psr-4": { - "React\\Filesystem\\": "src/" + "name": "react/filesystem", + "description": "Asynchronous filesystem abstraction.", + "keywords": [ + "filesystem", + "asynchronous" + ], + "license": "MIT", + "authors": [ + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com" + } + ], + "require": { + "php": ">=7.4.0", + "react/event-loop": "^1.2", + "react/promise": "^2.8", + "react/promise-stream": "^1.2", + "react/stream": "^1.2", + "wyrihaximus/react-child-process-promise-closure": "^1.0" }, - "files": ["src/functions_include.php"] - }, - "autoload-dev": { - "psr-4": { - "React\\Tests\\Filesystem\\": "tests/" - } - }, - "config": { - "sort-packages": true, - "platform": { - "php": "5.4" + "require-dev": { + "clue/block-react": "^1.4", + "phpunit/phpunit": "^9.5" + }, + "autoload": { + "psr-4": { + "React\\Filesystem\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "React\\Tests\\Filesystem\\": "tests/" + } + }, + "suggest": { + "ext-uv": "* for better I/O performance" + }, + "config": { + "sort-packages": true, + "platform": { + "php": "7.4.7" + }, + "allow-plugins": { + "wyrihaximus/composer-update-bin-autoload-path": true + } } - } } diff --git a/composer.lock b/composer.lock index 04110066..b912387b 100644 --- a/composer.lock +++ b/composer.lock @@ -1,37 +1,98 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0301b26ae1ada823f6fbeb0b71fc57bb", + "content-hash": "f5ce03ce451f08ea50b1130047d65bfa", "packages": [ + { + "name": "cakephp/core", + "version": "4.3.5", + "source": { + "type": "git", + "url": "https://github.com/cakephp/core.git", + "reference": "58f3af964f3e33769153d743a204f6e97f23c157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/core/zipball/58f3af964f3e33769153d743a204f6e97f23c157", + "reference": "58f3af964f3e33769153d743a204f6e97f23c157", + "shasum": "" + }, + "require": { + "cakephp/utility": "^4.0", + "php": ">=7.2.0" + }, + "suggest": { + "cakephp/cache": "To use Configure::store() and restore().", + "cakephp/event": "To use PluginApplicationInterface or plugin applications.", + "league/container": "To use Container and ServiceProvider classes" + }, + "type": "library", + "autoload": { + "files": [ + "functions.php" + ], + "psr-4": { + "Cake\\Core\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/core/graphs/contributors" + } + ], + "description": "CakePHP Framework Core classes", + "homepage": "https://cakephp.org", + "keywords": [ + "cakephp", + "core", + "framework" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/cakephp/issues", + "source": "https://github.com/cakephp/core" + }, + "time": "2022-01-27T02:05:53+00:00" + }, { "name": "cakephp/utility", - "version": "3.4.7", + "version": "4.3.5", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "f194ce6c83f54d96ce8ae0020b5f58fa850a8ef4" + "reference": "3d352060ca3e49c81c3fd2bdb092ee345d8f4e38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/f194ce6c83f54d96ce8ae0020b5f58fa850a8ef4", - "reference": "f194ce6c83f54d96ce8ae0020b5f58fa850a8ef4", + "url": "https://api.github.com/repos/cakephp/utility/zipball/3d352060ca3e49c81c3fd2bdb092ee345d8f4e38", + "reference": "3d352060ca3e49c81c3fd2bdb092ee345d8f4e38", "shasum": "" }, + "require": { + "cakephp/core": "^4.0", + "php": ">=7.2.0" + }, "suggest": { "ext-intl": "To use Text::transliterate() or Text::slug()", "lib-ICU": "To use Text::transliterate() or Text::slug()" }, "type": "library", "autoload": { - "psr-4": { - "Cake\\Utility\\": "." - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Cake\\Utility\\": "." + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -40,41 +101,56 @@ "authors": [ { "name": "CakePHP Community", - "homepage": "https://cakephp.org" + "homepage": "https://github.com/cakephp/utility/graphs/contributors" } ], "description": "CakePHP Utility classes such as Inflector, String, Hash, and Security", - "time": "2017-04-18T04:05:20+00:00" + "homepage": "https://cakephp.org", + "keywords": [ + "cakephp", + "hash", + "inflector", + "security", + "string", + "utility" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/cakephp/issues", + "source": "https://github.com/cakephp/utility" + }, + "time": "2022-01-28T18:02:00+00:00" }, { "name": "doctrine/inflector", - "version": "v1.1.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" + "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", - "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", + "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "4.*" + "doctrine/coding-standard": "^8.2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "vimeo/psalm": "^4.10" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Inflector\\": "lib/" + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -82,6 +158,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -90,10 +170,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -103,46 +179,67 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", "keywords": [ "inflection", - "pluralize", - "singularize", - "string" + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } ], - "time": "2015-11-06T14:35:42+00:00" + "time": "2021-10-22T20:16:43+00:00" }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1 || ^8.0" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^8.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" @@ -156,43 +253,56 @@ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "homepage": "https://ocramius.github.io/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" }, { "name": "evenement/evenement", - "version": "v2.1.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/igorw/evenement.git", - "reference": "6ba9a777870ab49f417e703229d53931ed40fd7a" + "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/6ba9a777870ab49f417e703229d53931ed40fd7a", - "reference": "6ba9a777870ab49f417e703229d53931ed40fd7a", + "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7", + "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^6.0||^5.7||^4.8.35" + "phpunit/phpunit": "^6.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, "autoload": { "psr-0": { "Evenement": "src" @@ -213,7 +323,11 @@ "event-dispatcher", "event-emitter" ], - "time": "2017-07-17T17:39:19+00:00" + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/master" + }, + "time": "2017-07-23T21:35:13+00:00" }, { "name": "indigophp/hash-compat", @@ -264,37 +378,103 @@ "hash_equals", "hash_pbkdf2" ], + "support": { + "issues": "https://github.com/indigophp/hash-compat/issues", + "source": "https://github.com/indigophp/hash-compat/tree/master" + }, + "abandoned": true, "time": "2015-08-22T07:03:35+00:00" }, + { + "name": "opis/closure", + "version": "3.6.3", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/opis/closure/issues", + "source": "https://github.com/opis/closure/tree/3.6.3" + }, + "time": "2022-01-27T09:35:39+00:00" + }, { "name": "paragonie/random_compat", - "version": "v2.0.11", + "version": "v9.99.100", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", - "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", "shasum": "" }, "require": { - "php": ">=5.2.0" + "php": ">= 7" }, "require-dev": { - "phpunit/phpunit": "4.*|5.*" + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" }, "suggest": { "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." }, "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -309,31 +489,37 @@ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ "csprng", + "polyfill", "pseudorandom", "random" ], - "time": "2017-09-27T21:40:39+00:00" + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" }, { "name": "react/cache", - "version": "v0.4.2", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/reactphp/cache.git", - "reference": "75494f26b4ef089db9bf8c90b63c296246e099e8" + "reference": "4bf736a2cccec7298bdf745db77585966fc2ca7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/cache/zipball/75494f26b4ef089db9bf8c90b63c296246e099e8", - "reference": "75494f26b4ef089db9bf8c90b63c296246e099e8", + "url": "https://api.github.com/repos/reactphp/cache/zipball/4bf736a2cccec7298bdf745db77585966fc2ca7e", + "reference": "4bf736a2cccec7298bdf745db77585966fc2ca7e", "shasum": "" }, "require": { "php": ">=5.3.0", - "react/promise": "~2.0|~1.1" + "react/promise": "^3.0 || ^2.0 || ^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35" }, "type": "library", "autoload": { @@ -345,6 +531,28 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], "description": "Async, Promise-based cache interface for ReactPHP", "keywords": [ "cache", @@ -352,31 +560,46 @@ "promise", "reactphp" ], - "time": "2017-12-20T16:47:13+00:00" + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.1.1" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-02-02T06:47:52+00:00" }, { "name": "react/child-process", - "version": "v0.5.2", + "version": "v0.6.4", "source": { "type": "git", "url": "https://github.com/reactphp/child-process.git", - "reference": "aae49d7f1340bafb695b9af3ce4421ea41a39620" + "reference": "a778f3fb828d68caf8a9ab6567fd8342a86f12fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/aae49d7f1340bafb695b9af3ce4421ea41a39620", - "reference": "aae49d7f1340bafb695b9af3ce4421ea41a39620", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/a778f3fb828d68caf8a9ab6567fd8342a86f12fe", + "reference": "a778f3fb828d68caf8a9ab6567fd8342a86f12fe", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.0", - "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/stream": "^1.0 || ^0.7.6" + "react/event-loop": "^1.2", + "react/stream": "^1.2" }, "require-dev": { - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35", - "sebastian/environment": "^3.0 || ^2.0 || ^1.0" + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", + "react/socket": "^1.8", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" }, "type": "library", "autoload": { @@ -388,39 +611,74 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], "description": "Event-driven library for executing child processes with ReactPHP.", "keywords": [ "event-driven", "process", "reactphp" ], - "time": "2018-01-18T14:53:06+00:00" + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.4" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-10-12T10:37:07+00:00" }, { "name": "react/dns", - "version": "v0.4.13", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/reactphp/dns.git", - "reference": "7d1e08c300fd7de600810883386ee5e2a64898f4" + "reference": "6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/7d1e08c300fd7de600810883386ee5e2a64898f4", - "reference": "7d1e08c300fd7de600810883386ee5e2a64898f4", + "url": "https://api.github.com/repos/reactphp/dns/zipball/6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb", + "reference": "6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb", "shasum": "" }, "require": { "php": ">=5.3.0", - "react/cache": "~0.4.0|~0.3.0", - "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/promise": "^2.1 || ^1.2.1", - "react/promise-timer": "^1.2", - "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.5" + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.0 || ^2.7 || ^1.2.1", + "react/promise-timer": "^1.8" }, "require-dev": { "clue/block-react": "^1.2", - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + "phpunit/phpunit": "^9.3 || ^4.8.35" }, "type": "library", "autoload": { @@ -432,6 +690,28 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], "description": "Async DNS resolver for ReactPHP", "keywords": [ "async", @@ -439,31 +719,46 @@ "dns-resolver", "reactphp" ], - "time": "2018-02-27T12:51:22+00:00" + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.9.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-12-20T08:46:54+00:00" }, { "name": "react/event-loop", - "version": "v0.5.2", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/reactphp/event-loop.git", - "reference": "e94985d93c689c554265b01014f8c3064921ca27" + "reference": "be6dee480fc4692cec0504e65eb486e3be1aa6f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/e94985d93c689c554265b01014f8c3064921ca27", - "reference": "e94985d93c689c554265b01014f8c3064921ca27", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/be6dee480fc4692cec0504e65eb486e3be1aa6f2", + "reference": "be6dee480fc4692cec0504e65eb486e3be1aa6f2", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "~4.8.35 || ^5.7 || ^6.4" + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35" }, "suggest": { "ext-event": "~1.0 for ExtEventLoop", - "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + "ext-pcntl": "For signal handling support when using the StreamSelectLoop", + "ext-uv": "* for ExtUvLoop" }, "type": "library", "autoload": { @@ -475,41 +770,77 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", "keywords": [ "asynchronous", "event-loop" ], - "time": "2018-04-24T11:23:06+00:00" + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-07-11T12:31:24+00:00" }, { "name": "react/promise", - "version": "v2.5.1", + "version": "v2.8.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "62785ae604c8d69725d693eb370e1d67e94c4053" + "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/62785ae604c8d69725d693eb370e1d67e94c4053", - "reference": "62785ae604c8d69725d693eb370e1d67e94c4053", + "url": "https://api.github.com/repos/reactphp/promise/zipball/f3cff96a19736714524ca0dd1d4130de73dbbbc4", + "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4", "shasum": "" }, "require": { "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "^7.0 || ^6.5 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { - "psr-4": { - "React\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "React\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -526,30 +857,34 @@ "promise", "promises" ], - "time": "2017-03-25T12:08:31+00:00" + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v2.8.0" + }, + "time": "2020-05-12T15:16:56+00:00" }, { "name": "react/promise-stream", - "version": "v1.1.1", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise-stream.git", - "reference": "00e269d611e9c9a29356aef64c07f7e513e73dc9" + "reference": "3ebd94fe0d8edbf44937948af28d02d5437e9949" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise-stream/zipball/00e269d611e9c9a29356aef64c07f7e513e73dc9", - "reference": "00e269d611e9c9a29356aef64c07f7e513e73dc9", + "url": "https://api.github.com/repos/reactphp/promise-stream/zipball/3ebd94fe0d8edbf44937948af28d02d5437e9949", + "reference": "3ebd94fe0d8edbf44937948af28d02d5437e9949", "shasum": "" }, "require": { "php": ">=5.3", "react/promise": "^2.1 || ^1.2", - "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4 || ^0.3" + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6" }, "require-dev": { "clue/block-react": "^1.0", - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35", + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3", "react/promise-timer": "^1.0" }, @@ -569,7 +904,23 @@ "authors": [ { "name": "Christian Lück", - "email": "christian@lueck.tv" + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" } ], "description": "The missing link between Promise-land and Stream-land for ReactPHP", @@ -582,38 +933,52 @@ "stream", "unwrap" ], - "time": "2017-12-22T12:02:05+00:00" + "support": { + "issues": "https://github.com/reactphp/promise-stream/issues", + "source": "https://github.com/reactphp/promise-stream/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-10-18T10:47:09+00:00" }, { "name": "react/promise-timer", - "version": "v1.2.1", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise-timer.git", - "reference": "9b4cd9cbe7457e0d87fe8aa7ccceab8a2c830fbd" + "reference": "0bbbcc79589e5bfdddba68a287f1cb805581a479" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/9b4cd9cbe7457e0d87fe8aa7ccceab8a2c830fbd", - "reference": "9b4cd9cbe7457e0d87fe8aa7ccceab8a2c830fbd", + "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/0bbbcc79589e5bfdddba68a287f1cb805581a479", + "reference": "0bbbcc79589e5bfdddba68a287f1cb805581a479", "shasum": "" }, "require": { "php": ">=5.3", - "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/promise": "~2.1|~1.2" + "react/event-loop": "^1.2", + "react/promise": "^3.0 || ^2.7.0 || ^1.2.1" }, "require-dev": { - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35" }, "type": "library", "autoload": { + "files": [ + "src/functions_include.php" + ], "psr-4": { "React\\Promise\\Timer\\": "src/" - }, - "files": [ - "src/functions.php" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -622,11 +987,27 @@ "authors": [ { "name": "Christian Lück", - "email": "christian@lueck.tv" + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" } ], "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.", - "homepage": "https://github.com/react/promise-timer", + "homepage": "https://github.com/reactphp/promise-timer", "keywords": [ "async", "event-loop", @@ -635,34 +1016,49 @@ "timeout", "timer" ], - "time": "2017-12-22T15:41:41+00:00" + "support": { + "issues": "https://github.com/reactphp/promise-timer/issues", + "source": "https://github.com/reactphp/promise-timer/tree/v1.8.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-12-06T11:08:48+00:00" }, { "name": "react/socket", - "version": "v0.8.10", + "version": "v1.11.0", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "d3957313c92b539537fccc80170c05a27ec25796" + "reference": "f474156aaab4f09041144fa8b57c7d70aed32a1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/d3957313c92b539537fccc80170c05a27ec25796", - "reference": "d3957313c92b539537fccc80170c05a27ec25796", + "url": "https://api.github.com/repos/reactphp/socket/zipball/f474156aaab4f09041144fa8b57c7d70aed32a1c", + "reference": "f474156aaab4f09041144fa8b57c7d70aed32a1c", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.0", - "react/dns": "^0.4.13", - "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/promise": "^2.1 || ^1.2", - "react/promise-timer": "~1.0", - "react/stream": "^1.0 || ^0.7.1" + "react/dns": "^1.8", + "react/event-loop": "^1.2", + "react/promise": "^2.6.0 || ^1.2.1", + "react/promise-timer": "^1.8", + "react/stream": "^1.2" }, "require-dev": { - "clue/block-react": "^1.2", - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + "clue/block-react": "^1.5", + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", + "react/promise-stream": "^1.2" }, "type": "library", "autoload": { @@ -674,38 +1070,74 @@ "license": [ "MIT" ], - "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", - "keywords": [ - "Connection", - "Socket", - "async", - "reactphp", - "stream" - ], - "time": "2018-02-28T09:32:38+00:00" - }, - { + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.11.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-01-14T10:14:32+00:00" + }, + { "name": "react/stream", - "version": "v0.7.7", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/reactphp/stream.git", - "reference": "10100896018fd847a257cd81143b8e1b7be08e40" + "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/stream/zipball/10100896018fd847a257cd81143b8e1b7be08e40", - "reference": "10100896018fd847a257cd81143b8e1b7be08e40", + "url": "https://api.github.com/repos/reactphp/stream/zipball/7a423506ee1903e89f1e08ec5f0ed430ff784ae9", + "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.8", - "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5" + "react/event-loop": "^1.2" }, "require-dev": { "clue/stream-filter": "~1.2", - "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35" }, "type": "library", "autoload": { @@ -717,6 +1149,28 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", "keywords": [ "event-driven", @@ -728,7 +1182,160 @@ "stream", "writable" ], - "time": "2018-01-19T15:04:38+00:00" + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-07-11T12:37:55+00:00" + }, + { + "name": "thecodingmachine/safe", + "version": "v1.3.3", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^0.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "files": [ + "deprecated/apc.php", + "deprecated/libevent.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/ingres-ii.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/msql.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/mysqlndMs.php", + "generated/mysqlndQc.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/password.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pdf.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/simplexml.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "psr-4": { + "Safe\\": [ + "lib/", + "deprecated/", + "generated/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v1.3.3" + }, + "time": "2020-10-28T17:51:34+00:00" }, { "name": "tivie/php-os-detector", @@ -776,79 +1383,185 @@ "os", "os detection" ], + "support": { + "issues": "https://github.com/tivie/php-os-detector/issues", + "source": "https://github.com/tivie/php-os-detector/tree/master" + }, "time": "2017-10-21T03:33:59+00:00" }, { - "name": "wyrihaximus/cpu-core-detector", - "version": "1.0.1", + "name": "wyrihaximus/composer-update-bin-autoload-path", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/WyriHaximus/php-cpu-core-detector.git", - "reference": "459dbf380172f06de6bf1aaecb9b1a003f7937b1" + "url": "https://github.com/WyriHaximus/php-composer-update-bin-autoload-path.git", + "reference": "33413e3af4f4d7ab4de3653a706aed57f51e84af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-cpu-core-detector/zipball/459dbf380172f06de6bf1aaecb9b1a003f7937b1", - "reference": "459dbf380172f06de6bf1aaecb9b1a003f7937b1", + "url": "https://api.github.com/repos/WyriHaximus/php-composer-update-bin-autoload-path/zipball/33413e3af4f4d7ab4de3653a706aed57f51e84af", + "reference": "33413e3af4f4d7ab4de3653a706aed57f51e84af", "shasum": "" }, "require": { - "php": "^5.4||^7.0", - "react/child-process": "^0.5 || ^0.4", - "tivie/php-os-detector": "^1.0", - "wyrihaximus/react-child-process-promise": "^2.0", - "wyrihaximus/ticking-promise": "^1.5" + "composer-plugin-api": "^2", + "php": "^8 || ^7.4" }, "require-dev": { - "phake/phake": "~1.0.6", - "phpunit/phpunit": "^4.0||^5.0", - "squizlabs/php_codesniffer": "^1.5.6", - "vectorface/dunit": "~2.0" + "wyrihaximus/test-utilities": "^3" + }, + "type": "composer-plugin", + "extra": { + "class": "WyriHaximus\\Composer\\BinAutoloadPathUpdater", + "unused": [ + "php" + ] }, - "type": "library", "autoload": { "psr-4": { - "WyriHaximus\\CpuCoreDetector\\": "src/" - }, + "WyriHaximus\\Composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "🏰 Composer plugin that fills a bin file with the absolute composer autoload path", + "support": { + "issues": "https://github.com/WyriHaximus/php-composer-update-bin-autoload-path/issues", + "source": "https://github.com/WyriHaximus/php-composer-update-bin-autoload-path/tree/1.1.1" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2021-03-14T20:55:38+00:00" + }, + { + "name": "wyrihaximus/constants", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/WyriHaximus/php-constants.git", + "reference": "32ceffdd881593c7fa24d8fcbf9deb58687484cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WyriHaximus/php-constants/zipball/32ceffdd881593c7fa24d8fcbf9deb58687484cb", + "reference": "32ceffdd881593c7fa24d8fcbf9deb58687484cb", + "shasum": "" + }, + "require": { + "php": "^8 || ^7 || ^5.3" + }, + "type": "library", + "autoload": { "files": [ - "src/functions_include.php" + "src/Boolean/constants_include.php", + "src/ComposerAutoloader/constants_include.php", + "src/HTTPStatusCodes/constants_include.php", + "src/Numeric/constants_include.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], + "authors": [ + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com", + "homepage": "https://www.wyrihaximus.net/" + } + ], + "description": "Collection of constants for PHP", + "support": { + "issues": "https://github.com/WyriHaximus/php-constants/issues", + "source": "https://github.com/WyriHaximus/php-constants/tree/1.6.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2020-11-28T12:04:43+00:00" + }, + { + "name": "wyrihaximus/file-descriptors", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/WyriHaximus/php-file-descriptors.git", + "reference": "7e2a8330c6dfe535a597e8a317b31dddf3b49398" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WyriHaximus/php-file-descriptors/zipball/7e2a8330c6dfe535a597e8a317b31dddf3b49398", + "reference": "7e2a8330c6dfe535a597e8a317b31dddf3b49398", + "shasum": "" + }, + "require": { + "php": "^8 || ^7.4", + "tivie/php-os-detector": "^1.1" + }, + "require-dev": { + "wyrihaximus/iterator-or-array-to-array": "^1.1", + "wyrihaximus/test-utilities": "^3.3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "WyriHaximus\\FileDescriptors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], "authors": [ { "name": "Cees-Jan Kiewiet", "email": "ceesjank@gmail.com" } ], - "time": "2018-02-24T17:44:46+00:00" + "description": "List open file descriptors for the current process cross platform", + "support": { + "issues": "https://github.com/WyriHaximus/php-file-descriptors/issues", + "source": "https://github.com/WyriHaximus/php-file-descriptors/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2020-11-25T23:03:56+00:00" }, { "name": "wyrihaximus/json-throwable", - "version": "1.1.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/WyriHaximus/php-json-throwable.git", - "reference": "fc3588681dcccc3f1f2f94c8eca71687f0899340" + "reference": "d01d59a101d4d2639ec3be770646a7e6b168fafb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-json-throwable/zipball/fc3588681dcccc3f1f2f94c8eca71687f0899340", - "reference": "fc3588681dcccc3f1f2f94c8eca71687f0899340", + "url": "https://api.github.com/repos/WyriHaximus/php-json-throwable/zipball/d01d59a101d4d2639ec3be770646a7e6b168fafb", + "reference": "d01d59a101d4d2639ec3be770646a7e6b168fafb", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", - "php": "^7.0 || ^5.4" + "php": "^8 || ^7.4", + "thecodingmachine/safe": "^1.1", + "wyrihaximus/json-utilities": "^1.2" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2", - "jakub-onderka/php-console-highlighter": "^0.3.2", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0" + "wyrihaximus/test-utilities": "^3.3.1" }, "type": "library", "autoload": { @@ -869,49 +1582,48 @@ "email": "ceesjank@gmail.com" } ], - "description": "JSON encode and decode throwables and exceptions", - "time": "2018-03-12T21:39:58+00:00" + "description": "📠 JSON encode and decode throwables and exceptions", + "support": { + "issues": "https://github.com/WyriHaximus/php-json-throwable/issues", + "source": "https://github.com/WyriHaximus/php-json-throwable/tree/4.1.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2020-11-25T13:14:10+00:00" }, { - "name": "wyrihaximus/react-child-process-messenger", - "version": "2.8.1", + "name": "wyrihaximus/json-utilities", + "version": "1.3.0", "source": { "type": "git", - "url": "https://github.com/WyriHaximus/reactphp-child-process-messenger.git", - "reference": "afde926a729868f5d6f64f378836123c3b247dea" + "url": "https://github.com/WyriHaximus/php-json-utilities.git", + "reference": "dce46df18c70ab7e206fe7bda4f4c59506f17be6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-messenger/zipball/afde926a729868f5d6f64f378836123c3b247dea", - "reference": "afde926a729868f5d6f64f378836123c3b247dea", + "url": "https://api.github.com/repos/WyriHaximus/php-json-utilities/zipball/dce46df18c70ab7e206fe7bda4f4c59506f17be6", + "reference": "dce46df18c70ab7e206fe7bda4f4c59506f17be6", "shasum": "" }, "require": { - "cakephp/utility": "^3.4", - "doctrine/inflector": "^1.0", - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "indigophp/hash-compat": "^1.0", - "paragonie/random_compat": "^2.0", - "php": "^5.4||^7.0", - "react/child-process": "^0.5 || ^0.4", - "react/promise": "^2.2", - "react/promise-stream": "^1.1", - "react/socket": "^0.8.1", - "wyrihaximus/json-throwable": "^2.0 || ^1.1.1", - "wyrihaximus/ticking-promise": "^1.4" + "php": "^8 || ^7.4", + "thecodingmachine/safe": "^1.1" }, "require-dev": { - "clue/block-react": "^1.2", - "friendsofphp/php-cs-fixer": "^2.2", - "jakub-onderka/php-console-highlighter": "^0.3.2", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "phpunit/phpunit": "^4.8.35||^5.0||^6.0" + "wyrihaximus/test-utilities": "^3.3.1" }, "type": "library", "autoload": { "psr-4": { - "WyriHaximus\\React\\ChildProcess\\Messenger\\": "src/" - } + "WyriHaximus\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -920,52 +1632,51 @@ "authors": [ { "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com", - "homepage": "http://wyrihaximus.net/" + "email": "ceesjank@gmail.com" } ], - "description": "Messenger decorator for react/child-process", - "time": "2018-03-23T21:26:12+00:00" + "description": "Utilities for php-json-* packages", + "support": { + "issues": "https://github.com/WyriHaximus/php-json-utilities/issues", + "source": "https://github.com/WyriHaximus/php-json-utilities/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2020-11-25T11:27:40+00:00" }, { - "name": "wyrihaximus/react-child-process-pool", - "version": "1.4.2", + "name": "wyrihaximus/react-child-process-closure", + "version": "1.2.0", "source": { "type": "git", - "url": "https://github.com/WyriHaximus/reactphp-child-process-pool.git", - "reference": "232f2aef55ce6df816f837442e79ff2976ebc8ed" + "url": "https://github.com/WyriHaximus/reactphp-child-process-closure.git", + "reference": "6dfe8a535f86326315eaa545e20f5139e3b2d428" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-pool/zipball/232f2aef55ce6df816f837442e79ff2976ebc8ed", - "reference": "232f2aef55ce6df816f837442e79ff2976ebc8ed", + "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-closure/zipball/6dfe8a535f86326315eaa545e20f5139e3b2d428", + "reference": "6dfe8a535f86326315eaa545e20f5139e3b2d428", "shasum": "" }, "require": { - "evenement/evenement": "^3.0 || ^2.0", - "php": "^5.4||^7.0", - "wyrihaximus/cpu-core-detector": "^1.0.0", - "wyrihaximus/react-child-process-messenger": "^2.7.1", - "wyrihaximus/ticking-promise": "^1.5" + "opis/closure": "^3.5", + "php": "^8 || ^7.4", + "react/event-loop": "^1.2", + "react/promise": "^2.8", + "wyrihaximus/react-child-process-messenger": "^4.0" }, "require-dev": { - "clue/block-react": "^1.1", - "phake/phake": "^2.2.1", - "phpunit/phpunit": "^4.8.35||^5.0", - "squizlabs/php_codesniffer": "^1.5.6", - "vectorface/dunit": "~2.0" - }, - "suggest": { - "wyrihaximus/react-child-process-pool-redis-queue": "Redis RPC queue" + "wyrihaximus/async-test-utilities": "^4.0.4" }, "type": "library", "autoload": { "psr-4": { - "WyriHaximus\\React\\ChildProcess\\Pool\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] + "WyriHaximus\\React\\ChildProcess\\Closure\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -977,33 +1688,120 @@ "email": "ceesjank@gmail.com" } ], - "time": "2018-04-23T17:21:00+00:00" + "description": "Run closures in ReactPHP Child Processes", + "support": { + "issues": "https://github.com/WyriHaximus/reactphp-child-process-closure/issues", + "source": "https://github.com/WyriHaximus/reactphp-child-process-closure/tree/1.2.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2021-09-15T06:56:15+00:00" + }, + { + "name": "wyrihaximus/react-child-process-messenger", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/WyriHaximus/reactphp-child-process-messenger.git", + "reference": "a484664b3a6b4a8e16551d8a139017d03db2b6f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-messenger/zipball/a484664b3a6b4a8e16551d8a139017d03db2b6f9", + "reference": "a484664b3a6b4a8e16551d8a139017d03db2b6f9", + "shasum": "" + }, + "require": { + "cakephp/utility": "^4.2.4", + "doctrine/inflector": "^2.0.3", + "evenement/evenement": "^3.0.1", + "ext-hash": "^8 || ^7.4", + "ext-json": "^8 || ^7.4", + "indigophp/hash-compat": "^1.1", + "paragonie/random_compat": "^9.0 || ^2.0", + "php": "^8 || ^7.4", + "react/child-process": "^0.6.2", + "react/event-loop": "^1.1.1", + "react/promise": "^2.8", + "react/promise-stream": "^1.2", + "react/promise-timer": "^1.6", + "react/socket": "^1.6", + "thecodingmachine/safe": "^1.3.3", + "wyrihaximus/composer-update-bin-autoload-path": "^1.1.1", + "wyrihaximus/constants": "^1.6", + "wyrihaximus/file-descriptors": "^1.1", + "wyrihaximus/json-throwable": "^4.1", + "wyrihaximus/ticking-promise": "^2" + }, + "require-dev": { + "wyrihaximus/async-test-utilities": "^3.4.18" + }, + "type": "library", + "extra": { + "unused": [ + "php", + "react/promise-stream" + ], + "wyrihaximus": { + "bin-autoload-path-update": [ + "bin/child-process" + ] + } + }, + "autoload": { + "psr-4": { + "WyriHaximus\\React\\ChildProcess\\Messenger\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com", + "homepage": "http://wyrihaximus.net/" + } + ], + "description": "Messenger decorator for react/child-process", + "support": { + "issues": "https://github.com/WyriHaximus/reactphp-child-process-messenger/issues", + "source": "https://github.com/WyriHaximus/reactphp-child-process-messenger/tree/4.0.2" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2022-02-08T15:53:16+00:00" }, { - "name": "wyrihaximus/react-child-process-promise", - "version": "2.0.1", + "name": "wyrihaximus/react-child-process-promise-closure", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/WyriHaximus/reactphp-child-process-promise.git", - "reference": "9b6f1bace7af43afc79fa85b91c793cdb3ff199b" + "url": "https://github.com/WyriHaximus/reactphp-child-process-promise-closure.git", + "reference": "9d8f19feccc6b1b2d20334c916339e3816d9174f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-promise/zipball/9b6f1bace7af43afc79fa85b91c793cdb3ff199b", - "reference": "9b6f1bace7af43afc79fa85b91c793cdb3ff199b", + "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-promise-closure/zipball/9d8f19feccc6b1b2d20334c916339e3816d9174f", + "reference": "9d8f19feccc6b1b2d20334c916339e3816d9174f", "shasum": "" }, "require": { - "php": "^5.4||^7.0", - "react/child-process": "^0.5 || ^0.4", - "react/promise": "^2.2", - "wyrihaximus/ticking-promise": "^1.5.2" + "php": "^7.0", + "react/promise": "^2.5", + "wyrihaximus/react-child-process-closure": "^1.0" }, "require-dev": { - "phake/phake": "^2.1", - "phpunit/phpunit": "^4.4||^5.0", - "squizlabs/php_codesniffer": "^1.5.6", - "vectorface/dunit": "^2.0" + "api-clients/test-utilities": "^4.1" }, "type": "library", "autoload": { @@ -1021,36 +1819,36 @@ "authors": [ { "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com", - "homepage": "http://wyrihaximus.net/" + "email": "ceesjank@gmail.com" } ], - "description": "Wrapping ticks into a promise", - "time": "2017-10-17T11:37:15+00:00" + "support": { + "issues": "https://github.com/WyriHaximus/reactphp-child-process-promise-closure/issues", + "source": "https://github.com/WyriHaximus/reactphp-child-process-promise-closure/tree/master" + }, + "time": "2017-05-28T19:18:35+00:00" }, { "name": "wyrihaximus/ticking-promise", - "version": "1.6.3", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/WyriHaximus/TickingPromise.git", - "reference": "4bb99024402bb7526de8880f3dab0c1f0858def5" + "reference": "d3903d4bebe8e3c5b11464c0bb81802cdeeb3751" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/TickingPromise/zipball/4bb99024402bb7526de8880f3dab0c1f0858def5", - "reference": "4bb99024402bb7526de8880f3dab0c1f0858def5", + "url": "https://api.github.com/repos/WyriHaximus/TickingPromise/zipball/d3903d4bebe8e3c5b11464c0bb81802cdeeb3751", + "reference": "d3903d4bebe8e3c5b11464c0bb81802cdeeb3751", "shasum": "" }, "require": { - "php": "^7.0 || ^5.4", - "react/event-loop": "^1.0 || ^0.5 || ^0.4", - "react/promise": "~2.1" + "php": "^8 || ^7.4", + "react/event-loop": "^1.0", + "react/promise": "^2.8" }, "require-dev": { - "phpunit/phpunit": "~4.4", - "squizlabs/php_codesniffer": "^1.5.6", - "vectorface/dunit": "~1.4" + "wyrihaximus/async-test-utilities": "^3" }, "type": "library", "autoload": { @@ -1073,37 +1871,48 @@ } ], "description": "Wrapping ticks into a promise", - "time": "2018-04-05T12:36:50+00:00" + "support": { + "issues": "https://github.com/WyriHaximus/TickingPromise/issues", + "source": "https://github.com/WyriHaximus/TickingPromise/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + } + ], + "time": "2020-11-25T12:43:21+00:00" } ], "packages-dev": [ { "name": "clue/block-react", - "version": "v1.2.0", + "version": "v1.5.0", "source": { "type": "git", - "url": "https://github.com/clue/php-block-react.git", - "reference": "966c255580ec7a0259338798ddb89f77e121fe9e" + "url": "https://github.com/clue/reactphp-block.git", + "reference": "718b0571a94aa693c6fffc72182e87257ac900f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/clue/php-block-react/zipball/966c255580ec7a0259338798ddb89f77e121fe9e", - "reference": "966c255580ec7a0259338798ddb89f77e121fe9e", + "url": "https://api.github.com/repos/clue/reactphp-block/zipball/718b0571a94aa693c6fffc72182e87257ac900f3", + "reference": "718b0571a94aa693c6fffc72182e87257ac900f3", "shasum": "" }, "require": { "php": ">=5.3", - "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/promise": "~2.1|~1.2", - "react/promise-timer": "~1.0" + "react/event-loop": "^1.2", + "react/promise": "^3.0 || ^2.7 || ^1.2.1", + "react/promise-timer": "^1.5" }, "require-dev": { - "phpunit/phpunit": "^5.0 || ^4.8" + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", + "react/http": "^1.4" }, "type": "library", "autoload": { "files": [ - "src/functions.php" + "src/functions_include.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1113,104 +1922,453 @@ "authors": [ { "name": "Christian Lück", - "email": "christian@lueck.tv" + "email": "christian@clue.engineering" } ], - "description": "Integrate async React PHP components into your blocking environment", - "homepage": "https://github.com/clue/php-block-react", + "description": "Lightweight library that eases integrating async components built for ReactPHP in a traditional, blocking environment.", + "homepage": "https://github.com/clue/reactphp-block", "keywords": [ "async", + "await", "blocking", "event loop", "promise", "reactphp", + "sleep", "synchronous" ], - "time": "2017-08-03T13:14:15+00:00" + "support": { + "issues": "https://github.com/clue/reactphp-block/issues", + "source": "https://github.com/clue/reactphp-block/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2021-10-20T14:07:33+00:00" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.5", + "name": "myclabs/deep-copy", + "version": "1.10.2", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b", - "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "dflydev/markdown": "~1.0", - "erusev/parsedown": "~1.0" + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-11-13T09:40:50+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.13.2", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + }, + "time": "2021-11-30T19:35:32+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "15a90844ad40f127afd244c0cad228de2a80052a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/15a90844ad40f127afd244c0cad228de2a80052a", + "reference": "15a90844ad40f127afd244c0cad228de2a80052a", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.1.1" + }, + "time": "2022-02-07T21:56:48+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" } ], - "time": "2016-01-25T08:17:30+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" + }, + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpspec/prophecy", - "version": "1.7.5", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", - "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.2", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpspec/phpspec": "^6.0 || ^7.0", + "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -1238,43 +2396,52 @@ "spy", "stub" ], - "time": "2018-02-19T10:16:54+00:00" + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" + }, + "time": "2021-12-08T12:19:24+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "2.2.4", + "version": "9.2.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687", + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687", "shasum": "" }, "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.13.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" + "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" + "ext-pcov": "*", + "ext-xdebug": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -1289,7 +2456,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1300,29 +2467,42 @@ "testing", "xunit" ], - "time": "2015-10-06T15:47:00+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-05T09:12:13+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1337,7 +2517,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1347,26 +2527,48 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -1383,37 +2585,697 @@ "role": "lead" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "template" + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.5.13", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "597cb647654ede35e43b137926dfdfef0fb11743" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/597cb647654ede35e43b137926dfdfef0fb11743", + "reference": "597cb647654ede35e43b137926dfdfef0fb11743", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.7", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^2.3.4", + "sebastian/version": "^3.0.2" + }, + "require-dev": { + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0.1" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.13" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-01-24T07:33:35+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:49:45+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2020-09-28T05:52:38+00:00" }, { - "name": "phpunit/php-timer", - "version": "1.0.9", + "name": "sebastian/exporter", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1428,42 +3290,73 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ - "timer" + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { - "name": "phpunit/php-token-stream", - "version": "1.4.12", + "name": "sebastian/global-state", + "version": "5.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1481,58 +3374,48 @@ "email": "sebastian@phpunit.de" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ - "tokenizer" + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-12-04T08:55:13+00:00" + "time": "2021-06-11T13:31:12+00:00" }, { - "name": "phpunit/phpunit", - "version": "4.8.36", + "name": "sebastian/lines-of-code", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.2.2", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" + "nikic/php-parser": "^4.6", + "php": ">=7.3" }, - "suggest": { - "phpunit/php-invoker": "~1.1" + "require-dev": { + "phpunit/phpunit": "^9.3" }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8.x-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -1551,45 +3434,46 @@ "role": "lead" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-06-21T08:07:12+00:00" + "time": "2020-11-28T06:42:11+00:00" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", + "name": "sebastian/object-enumerator", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1604,44 +3488,47 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2015-10-02T06:51:40+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { - "name": "sebastian/comparator", - "version": "1.2.4", + "name": "sebastian/object-reflector", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1654,56 +3541,49 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { - "name": "sebastian/diff", - "version": "1.4.3", + "name": "sebastian/recursion-context", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1716,46 +3596,57 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2020-10-26T13:17:30+00:00" }, { - "name": "sebastian/environment", - "version": "1.3.8", + "name": "sebastian/resource-operations", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1773,41 +3664,44 @@ "email": "sebastian@phpunit.de" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2016-08-18T05:49:44+00:00" + "time": "2020-09-28T06:45:17+00:00" }, { - "name": "sebastian/exporter", - "version": "1.2.2", + "name": "sebastian/type", + "version": "2.3.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" + "php": ">=7.3" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -1820,62 +3714,47 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2016-06-17T09:04:28+00:00" + "time": "2021-06-15T12:49:02+00:00" }, { - "name": "sebastian/global-state", - "version": "1.1.1", + "name": "sebastian/version", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" + "php": ">=7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1890,83 +3769,126 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2020-09-28T06:39:44+00:00" }, { - "name": "sebastian/recursion-context", - "version": "1.0.5", + "name": "symfony/polyfill-ctype", + "version": "v1.24.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, - "require-dev": { - "phpunit/phpunit": "~4.4" + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-10-03T07:41:43+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { - "name": "sebastian/version", - "version": "1.0.6", + "name": "theseer/tokenizer", + "version": "1.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, "type": "library", "autoload": { "classmap": [ @@ -1979,45 +3901,59 @@ ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21T13:59:46+00:00" + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" }, { - "name": "symfony/yaml", - "version": "v2.8.36", + "name": "webmozart/assert", + "version": "1.10.0", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "be720fcfae4614df204190d57795351059946a77" + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/be720fcfae4614df204190d57795351059946a77", - "reference": "be720fcfae4614df204190d57795351059946a77", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "1.10-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Webmozart\\Assert\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2025,17 +3961,21 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2018-01-03T07:36:31+00:00" + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" } ], "aliases": [], @@ -2044,10 +3984,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.4.0" + "php": ">=7.4.0" }, "platform-dev": [], "platform-overrides": { - "php": "5.4" - } + "php": "7.4.7" + }, + "plugin-api-version": "2.2.0" } diff --git a/examples/directory_create_recursive.php b/examples/directory_create_recursive.php deleted file mode 100644 index 7077617c..00000000 --- a/examples/directory_create_recursive.php +++ /dev/null @@ -1,26 +0,0 @@ -getAdapter()), PHP_EOL; -$startDir = $filesystem->dir($start); -$dir = $filesystem->dir($dirName); -echo 'Creating directory: ' . $dirName, PHP_EOL; -$dir->createRecursive('rwxrwx---')->then(function () use ($startDir) { - return $startDir->lsRecursive(); -})->then(function (array $list) { - foreach ($list as $node) { - echo $node->getPath(), PHP_EOL; - } -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); - -echo 'Don\'t forget to clean up!', PHP_EOL; diff --git a/examples/directory_listing.php b/examples/directory_listing.php new file mode 100644 index 00000000..b2376517 --- /dev/null +++ b/examples/directory_listing.php @@ -0,0 +1,19 @@ +detect(__DIR__)->then(function (DirectoryInterface $directory) { + return $directory->ls(); +})->then(static function ($nodes) { + foreach ($nodes as $node) { + assert($node instanceof NodeInterface); + echo $node->name(), ': ', get_class($node), PHP_EOL; + } + echo '----------------------------', PHP_EOL, 'Done listing directory', PHP_EOL; +}, function (Throwable $throwable) { + echo $throwable; +}); diff --git a/examples/directory_ls.php b/examples/directory_ls.php deleted file mode 100644 index 593aa2dc..00000000 --- a/examples/directory_ls.php +++ /dev/null @@ -1,17 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->dir(__DIR__ . DIRECTORY_SEPARATOR . 'tmp')->ls()->then(function (array $list) { - foreach ($list as $node) { - echo get_class($node), ': ', $node->getPath(), PHP_EOL; - } -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_ls_recursive.php b/examples/directory_ls_recursive.php deleted file mode 100644 index c9ba1f36..00000000 --- a/examples/directory_ls_recursive.php +++ /dev/null @@ -1,17 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->dir(dirname(__DIR__))->lsRecursive()->then(function (array $list) { - foreach ($list as $node) { - echo $node->getPath(), PHP_EOL; - } -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_ls_recursive_regexp_interfaces.php b/examples/directory_ls_recursive_regexp_interfaces.php deleted file mode 100644 index 064ff704..00000000 --- a/examples/directory_ls_recursive_regexp_interfaces.php +++ /dev/null @@ -1,20 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->dir(dirname(__DIR__))->lsRecursive()->then(function (array $list) { - $iterator = new ArrayIterator($list); - $interfaces = new RegexIterator($iterator, '/.*?Interface.php$/'); - - foreach ($interfaces as $node) { - echo $node->getPath(), PHP_EOL; - } -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_ls_recursive_streaming.php b/examples/directory_ls_recursive_streaming.php deleted file mode 100644 index 64f6b77e..00000000 --- a/examples/directory_ls_recursive_streaming.php +++ /dev/null @@ -1,22 +0,0 @@ -getAdapter()), PHP_EOL; -$dir = $filesystem->dir(dirname(__DIR__)); -$stream = $dir->lsRecursiveStreaming(); -$stream->on('data', function (NodeInterface $node) use (&$i) { - echo $node->getPath(), PHP_EOL; - $i++; -}); -$stream->on('end', function () use (&$i) { - echo 'Found ', $i, ' nodes', PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_ls_recursive_streaming_strlen_file_get_contents.php b/examples/directory_ls_recursive_streaming_strlen_file_get_contents.php deleted file mode 100644 index eb3da3d3..00000000 --- a/examples/directory_ls_recursive_streaming_strlen_file_get_contents.php +++ /dev/null @@ -1,48 +0,0 @@ - 8, -]); -echo 'Using ', get_class($filesystem->getAdapter()), PHP_EOL; -$dir = $filesystem->dir(__DIR__); -$stream = $dir->lsRecursiveStreaming(); -$stream->on('data', function (NodeInterface $node) use (&$i) { - if ($node instanceof File) { - $node->getContents()->then(function ($contents) use ($node, &$i) { - echo $node->getPath(), ': ', formatBytes(strlen($contents)), PHP_EOL; - $i++; - }, function ($e) { - var_export($e->getMessage()); - }); - return; - } - - echo $node->getPath(), PHP_EOL; - $i++; -}); -$stream->on('end', function () use (&$i) { - echo 'Found ', $i, ' nodes', PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_ls_streaming.php b/examples/directory_ls_streaming.php deleted file mode 100644 index b50eb1d4..00000000 --- a/examples/directory_ls_streaming.php +++ /dev/null @@ -1,22 +0,0 @@ -getAdapter()), PHP_EOL; -$dir = $filesystem->dir(__DIR__); -$stream = $dir->lsStreaming(); -$stream->on('data', function (NodeInterface $node) use (&$i) { - echo $node->getPath(), PHP_EOL; - $i++; -}); -$stream->on('end', function () use (&$i) { - echo 'Found ', $i, ' nodes', PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_nested_listing.php b/examples/directory_nested_listing.php new file mode 100644 index 00000000..377de04d --- /dev/null +++ b/examples/directory_nested_listing.php @@ -0,0 +1,32 @@ +detect($dir)->then(function (DirectoryInterface $directory) { + return $directory->ls(); + })->then(static function (array $nodes) use (&$ls) { + foreach ($nodes as $node) { + assert($node instanceof NodeInterface); + echo $node->path() . $node->name(), ': ', get_class($node), PHP_EOL; + if ($node instanceof DirectoryInterface) { + $ls($node->path() . $node->name()); + } + } + })->then(null, function (Throwable $throwable) { + echo $throwable; + }); +}; + +$ls(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'src'); + +Loop::run(); + +echo '----------------------------', PHP_EOL, 'Done listing directory', PHP_EOL; diff --git a/examples/directory_rename.php b/examples/directory_rename.php deleted file mode 100644 index 9fd41948..00000000 --- a/examples/directory_rename.php +++ /dev/null @@ -1,15 +0,0 @@ -dir('new'); - -$dir->rename('new_name')->then(function(\React\Filesystem\Node\DirectoryInterface $newDir){ - echo 'Renamed to ' . $newDir->getPath() . PHP_EOL; -}, function(Exception $e) { - echo 'Error: ' . $e->getMessage() . PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_size.php b/examples/directory_size.php deleted file mode 100644 index bc00e244..00000000 --- a/examples/directory_size.php +++ /dev/null @@ -1,15 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->dir(dirname(__DIR__))->size()->then(function ($size) { - echo 'Directory "' . dirname(__DIR__) . '" contains ' . $size['directories'] . ' directories, ' . $size['files'] . ' files and is ' . $size['size'] . ' bytes in size', PHP_EOL; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_size_recursive.php b/examples/directory_size_recursive.php deleted file mode 100644 index bc5498a9..00000000 --- a/examples/directory_size_recursive.php +++ /dev/null @@ -1,24 +0,0 @@ -getAdapter()), PHP_EOL; -foreach ([ - 'examples', - 'src', - 'tests', - 'vendor', -] as $directory) { - $path = dirname(__DIR__) . '/' . $directory; - $filesystem->dir($path)->sizeRecursive()->then(function ($size) use ($path) { - echo 'Directory "' . $path . '" contains ' . $size['directories'] . ' directories, ' . $size['files'] . ' files and is ' . $size['size'] . ' bytes in size', PHP_EOL; - }, function ($e) { - echo $e->getMessage(), PHP_EOL, var_export($e->getArgs(), true), PHP_EOL; - }); - -} - -$loop->run(); diff --git a/examples/directory_stat.php b/examples/directory_stat.php deleted file mode 100644 index a9920e8f..00000000 --- a/examples/directory_stat.php +++ /dev/null @@ -1,17 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->dir(__DIR__)->stat()->then(function ($data) { - foreach ($data as $key => $value) { - echo $key, ': ', $value, PHP_EOL; - } -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/directory_to_directory_copy.php b/examples/directory_to_directory_copy.php deleted file mode 100644 index 2e45af05..00000000 --- a/examples/directory_to_directory_copy.php +++ /dev/null @@ -1,27 +0,0 @@ -getAdapter()), PHP_EOL; -$from = $filesystem->dir(dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'vendor'); -$to = $filesystem->dir(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'react_filesystem_file_to_file_copy' . DIRECTORY_SEPARATOR . uniqid()); -echo 'From: ', $from->getPath(), PHP_EOL; -echo 'To: ', $to->getPath(), PHP_EOL; -$to->createRecursive()->then(function () use ($from, $to) { - $i = 0; - $stream = $from->copyStreaming($to); - $stream->on('data', function (NodeInterface $node) use (&$i) { - echo $node->getPath(), PHP_EOL; - $i++; - }); - $stream->on('end', function () use (&$i) { - echo 'Copied ', $i, ' nodes', PHP_EOL; - }); -}); - -$loop->run(); diff --git a/examples/file_chown.php b/examples/file_chown.php deleted file mode 100644 index 2ca570d7..00000000 --- a/examples/file_chown.php +++ /dev/null @@ -1,16 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file('test.txt')->chown(1000, 1000)->then(function ($result) { - var_export($result); - echo PHP_EOL; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_create.php b/examples/file_create.php deleted file mode 100644 index 30265516..00000000 --- a/examples/file_create.php +++ /dev/null @@ -1,30 +0,0 @@ -getAdapter()), PHP_EOL; -$file = $filesystem->file($fileName); -$file->create() -->then(function () use ($file, $fileName) { - echo 'File "' . $fileName . '" created.', PHP_EOL; - return $file->stat(); -}) -->then(function ($data) use ($file) { - echo 'stat data: ', PHP_EOL; - foreach ($data as $key => $value) { - echo "\t", $key, ': ', $value, PHP_EOL; - } - return $file->remove(); -}) -->then(function () { - echo 'File removed', PHP_EOL; - echo 'Done!', PHP_EOL; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_create_new.php b/examples/file_create_new.php new file mode 100644 index 00000000..115f5162 --- /dev/null +++ b/examples/file_create_new.php @@ -0,0 +1,24 @@ +detect(sys_get_temp_dir() . __FILE__ . time() . time() . time() . time() . time() . time())->then(static function (NotExistInterface $node): PromiseInterface { + return $node->createFile(); +})->then(static function (FileInterface $file): PromiseInterface { + return $file->stat(); +})->then(static function (Stat $stat): void { + echo $stat->path(), ': ', get_class($stat), PHP_EOL; + echo 'Mode: ', $stat->mode(), PHP_EOL; + echo 'Uid: ', $stat->uid(), PHP_EOL; + echo 'Gid: ', $stat->gid(), PHP_EOL; + echo 'Size: ', $stat->size(), PHP_EOL; + echo 'Atime: ', $stat->atime()->format(DATE_ISO8601), PHP_EOL; + echo 'Mtime: ', $stat->mtime()->format(DATE_ISO8601), PHP_EOL; + echo 'Ctime: ', $stat->ctime()->format(DATE_ISO8601), PHP_EOL; +})->done(); diff --git a/examples/file_duplex_stream.php b/examples/file_duplex_stream.php deleted file mode 100644 index 89185441..00000000 --- a/examples/file_duplex_stream.php +++ /dev/null @@ -1,51 +0,0 @@ -getAdapter()), PHP_EOL; -$file = $filesystem->file($fileName); -$file->open('ct+') -->then(function (\React\Filesystem\Stream\DuplexStreamInterface $stream) use ($loop, $file, $fileName, $generatedFileContents, &$readedFileContents) { - $stream->on('end', function ($stream) use ($generatedFileContents, &$readedFileContents) { - if (strlen($generatedFileContents) != strlen($readedFileContents)) { - $stream->resume(); - } - }); - $stream->on('data', function ($data) use (&$readedFileContents) { - $readedFileContents .= $data; - }); - $stream->resume(); - $stream->write($generatedFileContents); -}); - -$loop->run(); -$file->remove(); -$loop->run(); - -if ($generatedFileContents == $readedFileContents) { - echo 'Contents read from disk match generated contents', PHP_EOL; -} else { - echo 'Contents read from disk DON\'T match generated contents', PHP_EOL; -} diff --git a/examples/file_exists.php b/examples/file_exists.php deleted file mode 100644 index 036f54cb..00000000 --- a/examples/file_exists.php +++ /dev/null @@ -1,24 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file(__FILE__)->exists()->then(function () use ($filesystem) { - echo 'File "' . __FILE__ . '" exists', PHP_EOL; - return new FulfilledPromise($filesystem); -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -})->then(function ($filesystem) { - $fakeFile = __FILE__ . time(); - $filesystem->file($fakeFile)->exists()->then(null, function () use($fakeFile) { - echo 'File "' . $fakeFile . '" doesn\'t exists', PHP_EOL; - }, function ($e) { - echo $e->getMessage(), PHP_EOL; - }); -}); -$loop->run(); diff --git a/examples/file_get_contents.php b/examples/file_get_contents.php deleted file mode 100644 index 18953121..00000000 --- a/examples/file_get_contents.php +++ /dev/null @@ -1,15 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file(__FILE__)->getContents()->then(function ($contents) { - echo $contents, PHP_EOL; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_parent.php b/examples/file_parent.php deleted file mode 100644 index 9be0e4cb..00000000 --- a/examples/file_parent.php +++ /dev/null @@ -1,14 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file(__FILE__); - -do { - echo $node->getName(), PHP_EOL; -} while ($node = $node->getParent()); diff --git a/examples/file_put_contents.php b/examples/file_put_contents.php deleted file mode 100644 index 65c76652..00000000 --- a/examples/file_put_contents.php +++ /dev/null @@ -1,19 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file($filename)->putContents($contents)->then(function ($contents) use ($filename) { - echo file_get_contents($filename), PHP_EOL; -}, function (Exception $e) { - echo $e->getMessage(), PHP_EOL; - echo $e->getTraceAsString(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_read.php b/examples/file_read.php new file mode 100644 index 00000000..1bc58f34 --- /dev/null +++ b/examples/file_read.php @@ -0,0 +1,12 @@ +detect(__FILE__)->then(function (FileInterface $file) { + return $file->getContents(); +})->then(static function (string $contents): void { + echo $contents; +})->done(); diff --git a/examples/file_size.php b/examples/file_size.php deleted file mode 100644 index 6c8e4c94..00000000 --- a/examples/file_size.php +++ /dev/null @@ -1,15 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file(__FILE__)->size()->then(function ($size) { - echo 'File "' . __FILE__ . '" is ' . $size . ' bytes', PHP_EOL; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_stat.php b/examples/file_stat.php index fb7b0aae..2b3c19ab 100644 --- a/examples/file_stat.php +++ b/examples/file_stat.php @@ -1,17 +1,20 @@ getAdapter()), PHP_EOL; -$filesystem->file(__FILE__)->stat()->then(function ($data) { - foreach ($data as $key => $value) { - echo $key, ': ', var_export($value, true), PHP_EOL; - } -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); +Factory::create()->detect(__FILE__)->then(function (FileInterface $file) { + return $file->stat(); +})->then(static function (Stat $stat): void { + echo $stat->path(), ': ', get_class($stat), PHP_EOL; + echo 'Mode: ', $stat->mode(), PHP_EOL; + echo 'Uid: ', $stat->uid(), PHP_EOL; + echo 'Gid: ', $stat->gid(), PHP_EOL; + echo 'Size: ', $stat->size(), PHP_EOL; + echo 'Atime: ', $stat->atime()->format(DATE_ISO8601), PHP_EOL; + echo 'Mtime: ', $stat->mtime()->format(DATE_ISO8601), PHP_EOL; + echo 'Ctime: ', $stat->ctime()->format(DATE_ISO8601), PHP_EOL; +})->done(); diff --git a/examples/file_tail.php b/examples/file_tail.php new file mode 100644 index 00000000..2d1b57f1 --- /dev/null +++ b/examples/file_tail.php @@ -0,0 +1,24 @@ +detect($filename)->then(function (FileInterface $file) { + Loop::addPeriodicTimer(1, function (TimerInterface $timer) use ($file, &$offset): void { + $file->getContents($offset)->then(function (string $contents) use (&$offset, $timer): void { + echo $contents; + $offset += strlen($contents); + if (trim($contents) === 'done') { + Loop::cancelTimer($timer); + } + }); + }); +})->done(); + +echo 'Append data to "', $filename, '" to see it appear beneath here, put "done" on a new line to stop watching it:', PHP_EOL; diff --git a/examples/file_time.php b/examples/file_time.php deleted file mode 100644 index 6c9e64bc..00000000 --- a/examples/file_time.php +++ /dev/null @@ -1,23 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->file(__FILE__)->time()->then(function ($times) { - $nextLine = "\r\n\t"; - echo 'File "' . __FILE__ . '":'; - echo $nextLine; - echo 'Access timestamp: ' . $times['atime']->format('r'); - echo $nextLine; - echo 'Creation timestamp: ' . $times['ctime']->format('r'); - echo $nextLine; - echo 'Modified timestamp: ' . $times['mtime']->format('r'); - echo "\r\n"; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_to_directory_copy.php b/examples/file_to_directory_copy.php deleted file mode 100644 index 7e657edb..00000000 --- a/examples/file_to_directory_copy.php +++ /dev/null @@ -1,26 +0,0 @@ -getAdapter()), PHP_EOL; -$from = $filesystem->file(__FILE__); -$to = $filesystem->dir(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'react_filesystem_file_to_file_copy' . DIRECTORY_SEPARATOR . uniqid()); -echo $to->getPath(), PHP_EOL; -$to->createRecursive()->then(function () use ($from, $to) { - return $from->copy($to); -})->then(function (FileInterface $file) { - echo $file->getPath(), PHP_EOL; - return $file->stat(); -})->then(function ($stats) { - var_export($stats); - echo PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_to_file_copy.php b/examples/file_to_file_copy.php deleted file mode 100644 index 7edbc140..00000000 --- a/examples/file_to_file_copy.php +++ /dev/null @@ -1,23 +0,0 @@ -getAdapter()), PHP_EOL; -$from = $filesystem->file(__FILE__); -$to = $filesystem->file(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'react_filesystem_file_to_file_copy_' . uniqid()); - -$from->copy($to)->then(function (FileInterface $file) { - echo $file->getPath(), PHP_EOL; - return $file->stat(); -})->then(function ($stats) { - var_export($stats); - echo PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_touch.php b/examples/file_touch.php deleted file mode 100644 index 38922063..00000000 --- a/examples/file_touch.php +++ /dev/null @@ -1,31 +0,0 @@ -getAdapter()), PHP_EOL; -$file = $filesystem->file(__FILE__); - -$file->time()->then($timesFunction)->then(function () use ($file) { - return $file->touch(); -})->then(function () use ($file) { - return $file->time(); -})->then($timesFunction)->then(null, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/file_unlink.php b/examples/file_unlink.php new file mode 100644 index 00000000..ad499eea --- /dev/null +++ b/examples/file_unlink.php @@ -0,0 +1,12 @@ +detect($filename)->then(function (FileInterface $file) use ($filename) { + return $file->unlink(); +})->done(); diff --git a/examples/file_write.php b/examples/file_write.php new file mode 100644 index 00000000..0c77a16a --- /dev/null +++ b/examples/file_write.php @@ -0,0 +1,12 @@ +detect(__FILE__ . '.copy')->then(static function (FileInterface $file) { + return $file->putContents(file_get_contents(__FILE__)); +})->then(static function ($result): void { + var_export([$result]); +})->done(); diff --git a/examples/link_get_contents.php b/examples/link_get_contents.php deleted file mode 120000 index 9a4eed64..00000000 --- a/examples/link_get_contents.php +++ /dev/null @@ -1 +0,0 @@ -file_get_contents.php \ No newline at end of file diff --git a/examples/link_readlink.php b/examples/link_readlink.php deleted file mode 100644 index ce45e705..00000000 --- a/examples/link_readlink.php +++ /dev/null @@ -1,15 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->getAdapter()->readlink('link_get_contents.php')->then(function ($contents) { - echo $contents, PHP_EOL; -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/link_symlink.php b/examples/link_symlink.php deleted file mode 100644 index da7db154..00000000 --- a/examples/link_symlink.php +++ /dev/null @@ -1,15 +0,0 @@ -getAdapter()), PHP_EOL; -$filesystem->getAdapter()->symlink('link_get_contents.php', 'symlink_' . time() . '.php')->then(function ($contents) { - var_export($contents); -}, function ($e) { - echo $e->getMessage(), PHP_EOL; -}); - -$loop->run(); diff --git a/examples/node_doesnt_exist.php b/examples/node_doesnt_exist.php new file mode 100644 index 00000000..6555b9bc --- /dev/null +++ b/examples/node_doesnt_exist.php @@ -0,0 +1,10 @@ +detect(__FILE__ . time() . time() . time() . time() . time() . time())->then(static function (NodeInterface $node): void { + echo get_class($node); +})->done(); diff --git a/examples/tail.php b/examples/tail.php deleted file mode 100644 index 09350111..00000000 --- a/examples/tail.php +++ /dev/null @@ -1,36 +0,0 @@ -getContents($path)->then(function ($content) use ($loop, $filesystem, $path) { - echo $content; - - $lastSize = strlen($content); - $adapter = $filesystem->getAdapter(); - - $adapter->open($path, 'r')->then(function ($fileDescriptor) use ($adapter, $filesystem, $loop, $path, &$lastSize) { - $file = $filesystem->file($path); - - $loop->addPeriodicTimer(1, function () use ($adapter, $fileDescriptor, $file, &$lastSize) { - $file->size()->then(function ($size) use ($adapter, $fileDescriptor, &$lastSize) { - if ($lastSize === $size) { - return; - } - - $adapter->read($fileDescriptor, $size - $lastSize, $lastSize)->then(function ($content) { - echo $content; - }); - - $lastSize = $size; - }); - }); - }); -}); - -$loop->run(); diff --git a/examples/test.txt b/examples/test.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/src/AdapterInterface.php b/src/AdapterInterface.php index e32bf893..0ebe94b8 100644 --- a/src/AdapterInterface.php +++ b/src/AdapterInterface.php @@ -2,246 +2,17 @@ namespace React\Filesystem; -use React\Filesystem\ObjectStream; -use React\EventLoop\LoopInterface; +use React\Filesystem\Node; use React\Promise\PromiseInterface; interface AdapterInterface { - const CREATION_MODE = 'rwxrw----'; - - /** - * Checks whether the current installation supports the adapter. - * - * @return bool - */ - public static function isSupported(); - - /** - * Return the loop associated with this adapter. - * - * @return LoopInterface - */ - public function getLoop(); - - /** - * Get the relevant filesystem for this adapter. - * - * @internal - * @return FilesystemInterface - */ - public function getFilesystem(); - - /** - * Set the relevant filesystem for this adapter. - * - * @internal - * @param FilesystemInterface $filesystem - * @return void - */ - public function setFilesystem(FilesystemInterface $filesystem); - - /** - * Call the underlying filesystem. - * - * @internal - * @param string $function - * @param array $args - * @param int $errorResultCode - * @return PromiseInterface - */ - public function callFilesystem($function, $args, $errorResultCode = -1); - - /** - * Create a directory at the given path with the given mode. - * - * @param string $path - * @param $mode - * @return PromiseInterface - */ - public function mkdir($path, $mode = self::CREATION_MODE); - - /** - * Remove the given directory, fails when it has contents. - * - * @param string $path - * @return PromiseInterface - */ - public function rmdir($path); - - /** - * Remove the given file. - * - * @param string $filename - * @return PromiseInterface - */ - public function unlink($filename); - - /** - * Change the mode of the given path. - * - * @param string $path - * @param int $mode - * @return PromiseInterface - */ - public function chmod($path, $mode); - /** - * Change the owner of the given path. - * - * @param string $path - * @param int $uid - * @param int $gid - * @return PromiseInterface + * @return PromiseInterface */ - public function chown($path, $uid, $gid); + public function detect(string $path): PromiseInterface; - /** - * Stat the node, returning information such as the file, c/m/a-time, mode, g/u-id, and more. - * - * @param string $filename - * @return PromiseInterface - */ - public function stat($filename); - - /** - * List contents of the given path. - * - * @param string $path - * @return PromiseInterface - */ - public function ls($path); - - /** - * List contents of the given path. - * - * @param string $path - * @return ObjectStream - */ - public function lsStream($path); + public function directory(string $path): Node\DirectoryInterface; - /** - * Touch the given path, either creating a file, or updating mtime on the file. - * - * @param string $path - * @param $mode - * @return PromiseInterface - */ - public function touch($path, $mode = self::CREATION_MODE); - - /** - * Open a file for reading or writing at the given path. This will return a file descriptor, - * which can be used to read or write to the file. And ultimately close the file descriptor. - * - * @param string $path - * @param string $flags - * @param $mode - * @return PromiseInterface - */ - public function open($path, $flags, $mode = self::CREATION_MODE); - - /** - * Read from the given file descriptor. - * - * @param mixed $fileDescriptor - * @param int $length - * @param int $offset - * @return PromiseInterface - */ - public function read($fileDescriptor, $length, $offset); - - /** - * Write to the given file descriptor. - * - * @param mixed $fileDescriptor - * @param string $data - * @param int $length - * @param int $offset - * @return PromiseInterface - */ - public function write($fileDescriptor, $data, $length, $offset); - - /** - * Close the given file descriptor. - * - * @param mixed $fd - * @return PromiseInterface - */ - public function close($fd); - - /** - * Reads the entire file. - * - * This is an optimization for adapters which can optimize - * the open -> (seek ->) read -> close sequence into one call. - * - * @param string $path - * @param int $offset - * @param int|null $length - * @return PromiseInterface - */ - public function getContents($path, $offset = 0, $length = null); - - /** - * Writes the given content to the specified file. - * If the file exists, the file is truncated. - * If the file does not exist, the file will be created. - * - * This is an optimization for adapters which can optimize - * the open -> write -> close sequence into one call. - * - * @param string $path - * @param string $content - * @return PromiseInterface - * @see AdapterInterface::appendContents() - */ - public function putContents($path, $content); - - /** - * Appends the given content to the specified file. - * If the file does not exist, the file will be created. - * - * This is an optimization for adapters which can optimize - * the open -> write -> close sequence into one call. - * - * @param string $path - * @param string $content - * @return PromiseInterface - * @see AdapterInterface::putContents() - */ - public function appendContents($path, $content); - - /** - * Rename a node. - * - * @param string $fromPath - * @param string $toPath - * @return PromiseInterface - */ - public function rename($fromPath, $toPath); - - /** - * Read link information from the given path (has to be a symlink). - * - * @param string $path - * @return PromiseInterface - */ - public function readlink($path); - - /** - * Create a symlink from $fromPath to $toPath. - * - * @param string $fromPath - * @param string $toPath - * @return PromiseInterface - */ - public function symlink($fromPath, $toPath); - - /** - * Detect the type of the given path. - * - * @param string $path - * @return PromiseInterface - */ - public function detectType($path); + public function file(string $path): Node\FileInterface; } diff --git a/src/ChildProcess/Adapter.php b/src/ChildProcess/Adapter.php index 0a58e090..3b0dcd8b 100644 --- a/src/ChildProcess/Adapter.php +++ b/src/ChildProcess/Adapter.php @@ -2,496 +2,51 @@ namespace React\Filesystem\ChildProcess; -use DateTime; -use Exception; -use Throwable; -use React\EventLoop\LoopInterface; -use React\Filesystem\ObjectStream; -use React\Filesystem\ObjectStreamSink; +use React\EventLoop\ExtUvLoop; use React\Filesystem\AdapterInterface; -use React\Filesystem\FilesystemInterface; -use React\Filesystem\MappedTypeDetector; use React\Filesystem\ModeTypeDetector; -use React\Filesystem\OpenFileLimiter; -use React\Filesystem\TypeDetectorInterface; -use React\Filesystem\PermissionFlagResolver; -use React\Filesystem\Node\NodeInterface; +use React\Filesystem\PollInterface; +use React\Filesystem\Stat; use React\Promise\PromiseInterface; -use WyriHaximus\React\ChildProcess\Messenger\Messages\Factory; -use WyriHaximus\React\ChildProcess\Messenger\Messages\Payload; -use WyriHaximus\React\ChildProcess\Messenger\Messenger; -use WyriHaximus\React\ChildProcess\Pool\Options; -use WyriHaximus\React\ChildProcess\Pool\PoolInterface; +use RuntimeException; +use React\EventLoop\LoopInterface; +use React\Filesystem\Node; -class Adapter implements AdapterInterface +/** + * @internal + */ +final class Adapter implements AdapterInterface { - const DEFAULT_POOL = 'WyriHaximus\React\ChildProcess\Pool\Factory\Flexible'; - const POOL_INTERFACE = 'WyriHaximus\React\ChildProcess\Pool\PoolFactoryInterface'; - const CHILD_CLASS_NAME = 'React\Filesystem\ChildProcess\Process'; - - /** - * @var LoopInterface - */ - protected $loop; - - /** - * @var FilesystemInterface - */ - protected $filesystem; - - /** - * @var PoolInterface - */ - protected $pool; - - /** - * @var OpenFileLimiter - */ - protected $openFileLimiter; - - /** - * @var array - */ - protected $fileDescriptors = []; - - /** - * @var TypeDetectorInterface[] - */ - protected $typeDetectors = []; - - /** - * @var PermissionFlagResolver - */ - protected $permissionFlagResolver; - - /** - * @var array - */ - protected $options = [ - 'lsFlags' => SCANDIR_SORT_NONE, - ]; - - /** - * Adapter constructor. - * @param LoopInterface $loop - * @param array $options - */ - public function __construct(LoopInterface $loop, array $options = []) - { - $this->loop = $loop; - - $this->openFileLimiter = new OpenFileLimiter(\React\Filesystem\getOpenFileLimit($options)); - $this->permissionFlagResolver = new PermissionFlagResolver(); - - $this->setUpPool($options); - - $this->options = array_merge_recursive($this->options, $options); - } - - protected function setUpPool($options) - { - $poolOptions = [ - Options::MIN_SIZE => 0, - Options::MAX_SIZE => 50, - Options::TTL => 3, - ]; - $poolClass = static::DEFAULT_POOL; - - if (isset($options['pool']['class']) && is_subclass_of($options['pool']['class'], static::POOL_INTERFACE)) { - $poolClass = $options['pool']['class']; - } - - call_user_func_array($poolClass . '::createFromClass', [ - self::CHILD_CLASS_NAME, - $this->loop, - $poolOptions, - ])->then(function (PoolInterface $pool) { - $this->pool = $pool; - }); - } - - /** - * @return bool - */ - public static function isSupported() - { - return substr(strtolower(PHP_OS), 0, 3) !== 'win' && function_exists('proc_open'); - } - - /** - * @return LoopInterface - */ - public function getLoop() - { - return $this->loop; - } + use StatTrait; - /** - * {@inheritDoc} - */ - public function getFilesystem() + public function detect(string $path): PromiseInterface { - return $this->filesystem; - } - - /** - * {@inheritDoc} - */ - public function setFilesystem(FilesystemInterface $filesystem) - { - $this->filesystem = $filesystem; - - $this->typeDetectors = [ - MappedTypeDetector::createDefault($this->filesystem), - new ModeTypeDetector($this->filesystem), - ]; - } - - /** - * @param string $function - * @param array $args - * @param int $errorResultCode - * @return PromiseInterface - */ - public function callFilesystem($function, $args, $errorResultCode = -1) - { - return $this->pool->rpc(Factory::rpc($function, $args))->then(function (Payload $payload) { - return \React\Promise\resolve($payload->getPayload()); - }, function ($payload) { - if ($payload instanceof Throwable) { - return \React\Promise\reject($payload); + return $this->internalStat($path)->then(function (?Stat $stat) use ($path) { + if ($stat === null) { + return new NotExist($this, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); } - return \React\Promise\reject(new Exception($payload['error']['message'])); - }); - } - - /** - * @param string $path - * @param int $mode - * @return PromiseInterface - */ - public function chmod($path, $mode) - { - return $this->callFilesystem('chmod', [ - 'path' => $path, - 'mode' => decoct($mode), - ]); - } - - /** - * @param string $path - * @param $mode - * @return PromiseInterface - */ - public function mkdir($path, $mode = self::CREATION_MODE) - { - return $this->callFilesystem('mkdir', [ - 'path' => $path, - 'mode' => decoct($this->permissionFlagResolver->resolve($mode)), - ]); - } - - /** - * @param string $path - * @param string $flags - * @param $mode - * @return PromiseInterface - */ - public function open($path, $flags, $mode = self::CREATION_MODE) - { - return \WyriHaximus\React\ChildProcess\Messenger\Factory::parentFromClass(self::CHILD_CLASS_NAME, $this->loop)->then(function (Messenger $messenger) use ($path, $flags, $mode) { - $this->fileDescriptors[] = $messenger; - \end($this->fileDescriptors); - $id = \key($this->fileDescriptors); - - return $this->fileDescriptors[$id]->rpc(Factory::rpc('open', [ - 'path' => $path, - 'flags' => $flags, - 'mode' => $mode, - ]))->then(function () use ($id) { - return $id; - }); - }); - } - - /** - * @param string $fileDescriptor - * @param int $length - * @param int $offset - * @return PromiseInterface - */ - public function read($fileDescriptor, $length, $offset) - { - return $this->fileDescriptors[$fileDescriptor]->rpc(Factory::rpc('read', [ - 'length' => $length, - 'offset' => $offset, - ]))->then(function ($payload) { - return \React\Promise\resolve(base64_decode($payload['chunk'])); - }); - } - - /** - * @param string $fileDescriptor - * @param string $data - * @param int $length - * @param int $offset - * @return PromiseInterface - */ - public function write($fileDescriptor, $data, $length, $offset) - { - return $this->fileDescriptors[$fileDescriptor]->rpc(Factory::rpc('write', [ - 'chunk' => base64_encode($data), - 'length' => $length, - 'offset' => $offset, - ])); - } - - /** - * @param string $fd - * @return PromiseInterface - */ - public function close($fd) - { - $fileDescriptor = $this->fileDescriptors[$fd]; - unset($this->fileDescriptors[$fd]); - return $fileDescriptor->rpc(Factory::rpc('close'))->then(function () use ($fileDescriptor) { - return $fileDescriptor->softTerminate(); - }, function () use ($fileDescriptor) { - return $fileDescriptor->softTerminate(); - }); - } - - /** - * Reads the entire file. - * - * This is an optimization for adapters which can optimize - * the open -> (seek ->) read -> close sequence into one call. - * - * @param string $path - * @param int $offset - * @param int|null $length - * @return PromiseInterface - */ - public function getContents($path, $offset = 0, $length = null) - { - return $this->callFilesystem('getContents', [ - 'path' => $path, - 'offset' => $offset, - 'maxlen' => $length, - ])->then(function ($payload) { - return \React\Promise\resolve(base64_decode($payload['chunk'])); - }); - } - - /** - * Writes the given content to the specified file. - * If the file exists, the file is truncated. - * If the file does not exist, the file will be created. - * - * This is an optimization for adapters which can optimize - * the open -> write -> close sequence into one call. - * - * @param string $path - * @param string $content - * @return PromiseInterface - * @see AdapterInterface::appendContents() - */ - public function putContents($path, $content) - { - return $this->callFilesystem('putContents', [ - 'path' => $path, - 'chunk' => base64_encode($content), - 'flags' => 0, - ])->then(function ($payload) { - return \React\Promise\resolve($payload['written']); - }); - } - - /** - * Appends the given content to the specified file. - * If the file does not exist, the file will be created. - * - * This is an optimization for adapters which can optimize - * the open -> write -> close sequence into one call. - * - * @param string $path - * @param string $content - * @return PromiseInterface - * @see AdapterInterface::putContents() - */ - public function appendContents($path, $content) - { - return $this->callFilesystem('putContents', [ - 'path' => $path, - 'chunk' => base64_encode($content), - 'flags' => FILE_APPEND, - ])->then(function ($payload) { - return \React\Promise\resolve($payload['written']); - }); - } - - /** - * @param string $path - * @return PromiseInterface - */ - public function rmdir($path) - { - return $this->callFilesystem('rmdir', [ - 'path' => $path, - ]); - } - - /** - * @param string $path - * @return PromiseInterface - */ - public function unlink($path) - { - return $this->callFilesystem('unlink', [ - 'path' => $path, - ]); - } - - /** - * @param string $path - * @param int $uid - * @param int $gid - * @return PromiseInterface - */ - public function chown($path, $uid, $gid) - { - return $this->callFilesystem('chown', [ - 'path' => $path, - 'uid' => $uid, - 'gid' => $gid, - ]); - } - - /** - * @param string $filename - * @return PromiseInterface - */ - public function stat($filename) - { - return $this->callFilesystem('stat', [ - 'path' => $filename, - ])->then(function ($stat) { - $stat['atime'] = new DateTime('@' . $stat['atime']); - $stat['mtime'] = new DateTime('@' . $stat['mtime']); - $stat['ctime'] = new DateTime('@' . $stat['ctime']); - return \React\Promise\resolve($stat); - }); - } - - /** - * @param string $path - * @return PromiseInterface - */ - public function ls($path) - { - return ObjectStreamSink::promise($this->lsStream($path)); - } - - /** - * @param string $path - * @return ObjectStream - */ - public function lsStream($path) - { - $stream = new ObjectStream(); - - $this->callFilesystem('readdir', [ - 'path' => $path, - 'flags' => $this->options['lsFlags'], - ])->then(function ($result) use ($path, $stream) { - $this->processLsContents($path, $result, $stream); - }); - - return $stream; - } - - protected function processLsContents($basePath, $result, ObjectStream $stream) - { - $promises = []; - - foreach ($result as $entry) { - $path = $basePath . DIRECTORY_SEPARATOR . $entry['name']; - $node = [ - 'path' => $path, - 'type' => $entry['type'], - ]; - $promises[] = \React\Filesystem\detectType($this->typeDetectors, $node)->then(function (NodeInterface $node) use ($stream) { - $stream->write($node); - }); - } - - \React\Promise\all($promises)->then(function () use ($stream) { - $stream->close(); - }); - } - - /** - * @param string $path - * @param $mode - * @return PromiseInterface - */ - public function touch($path, $mode = self::CREATION_MODE) - { - return $this->callFilesystem('touch', [ - 'path' => $path, - 'mode' => decoct($this->permissionFlagResolver->resolve($mode)), - ]); - } - - /** - * @param string $fromPath - * @param string $toPath - * @return PromiseInterface - */ - public function rename($fromPath, $toPath) - { - return $this->callFilesystem('rename', [ - 'from' => $fromPath, - 'to' => $toPath, - ]); - } - - /** - * @param string $path - * @return PromiseInterface - */ - public function readlink($path) - { - return $this->callFilesystem('readlink', [ - 'path' => $path, - ])->then(function ($result) { - return \React\Promise\resolve($result['path']); + switch (ModeTypeDetector::detect($stat->mode())) { + case Node\DirectoryInterface::class: + return $this->directory($stat->path()); + break; + case Node\FileInterface::class: + return $this->file($stat->path()); + break; + default: + return new Node\Unknown($stat->path(), $stat->path()); + break; + } }); } - /** - * @param string $fromPath - * @param string $toPath - * @return PromiseInterface - */ - public function symlink($fromPath, $toPath) + public function directory(string $path): Node\DirectoryInterface { - return $this->callFilesystem('symlink', [ - 'from' => $fromPath, - 'to' => $toPath, - ])->then(function ($result) { - return \React\Promise\resolve($result['result']); - }); + return new Directory($this,dirname($path) . DIRECTORY_SEPARATOR, basename($path)); } - /** - * @inheritDoc - */ - public function detectType($path) + public function file(string $path): Node\FileInterface { - return \React\Filesystem\detectType($this->typeDetectors, [ - 'path' => $path, - ]); + return new File(dirname($path) . DIRECTORY_SEPARATOR, basename($path)); } } diff --git a/src/ChildProcess/Directory.php b/src/ChildProcess/Directory.php new file mode 100644 index 00000000..df0f6100 --- /dev/null +++ b/src/ChildProcess/Directory.php @@ -0,0 +1,75 @@ +filesystem = $filesystem; + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function ls(): PromiseInterface + { + $path = $this->path . $this->name; + return childProcessPromiseClosure(Loop::get(), function () use ($path): array { + return scandir($path); + })->then( function (array $contents): PromiseInterface { + $promises = []; + foreach ($contents as $node) { + if (in_array($node, ['.', '..'])) { + continue; + } + + $promises[] = $this->filesystem->detect($this->path . $this->name . DIRECTORY_SEPARATOR . $node); + } + + return all($promises); + }); + } + + public function unlink(): PromiseInterface + { + $path = $this->path . $this->name; + return childProcessPromiseClosure(Loop::get(), function () use ($path): array { + if (count(scandir($path)) > 0) { + return ['unlinked' => false]; + } + + return ['unlinked' => rmdir($path)]; + })->then(static fn (array $data) => (bool)$data['unlinked']); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/ChildProcess/File.php b/src/ChildProcess/File.php new file mode 100644 index 00000000..dc3eabcd --- /dev/null +++ b/src/ChildProcess/File.php @@ -0,0 +1,71 @@ +path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface + { + $path = $this->path . $this->name; + return childProcessPromiseClosure(Loop::get(), function () use ($path, $offset, $maxlen): array { + return ['contents' => file_get_contents($path, false, null, $offset, $maxlen ?? (int)stat($path)['size'])]; + })->then(static fn (array $data): string => $data['contents']); + } + + public function putContents(string $contents, int $flags = 0): PromiseInterface + { + // Making sure we only pass in one flag for security reasons + if (($flags & \FILE_APPEND) == \FILE_APPEND) { + $flags = \FILE_APPEND; + } else { + $flags = 0; + } + + $path = $this->path . $this->name; + return childProcessPromiseClosure(Loop::get(), function () use ($path, $contents, $flags): array { + return ['size_written' => file_put_contents($path, $contents, $flags)]; + })->then(static fn (array $data) => (int)$data['size_written']); + } + + public function unlink(): PromiseInterface + { + $path = $this->path . $this->name; + return childProcessPromiseClosure(Loop::get(), function () use ($path): array { + return ['unlinked' => unlink($path)]; + })->then(static fn (array $data) => (bool)$data['unlinked']); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/ChildProcess/NotExist.php b/src/ChildProcess/NotExist.php new file mode 100644 index 00000000..1040b063 --- /dev/null +++ b/src/ChildProcess/NotExist.php @@ -0,0 +1,75 @@ +filesystem = $filesystem; + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function createDirectory(): PromiseInterface + { + $path = $this->path . $this->name; + return childProcessPromiseClosure(Loop::get(), function () use ($path): array { + return ['mkdir' => mkdir($path,0777, true)]; + })->then(fn (array $data): Node\DirectoryInterface => new Directory($this->filesystem, $this->path, $this->name)); + } + + public function createFile(): PromiseInterface + { + $file = new File($this->path, $this->name); + + return $this->filesystem->detect($this->path)->then(function (Node\NodeInterface $node): PromiseInterface { + if ($node instanceof Node\NotExistInterface) { + return $node->createDirectory(); + } + + return resolve($node); + })->then(function () use ($file): PromiseInterface { + return $file->putContents(''); + })->then(function () use ($file): Node\FileInterface { + return $file; + }); + } + + public function unlink(): PromiseInterface + { + // Essentially a No-OP since it doesn't exist anyway + return resolve(true); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/ChildProcess/Process.php b/src/ChildProcess/Process.php deleted file mode 100644 index 63afd4ed..00000000 --- a/src/ChildProcess/Process.php +++ /dev/null @@ -1,316 +0,0 @@ -registerRpc($method, $this->wrapper($method)); - } - } - - protected function wrapper($function) - { - return function (Payload $payload, Messenger $messenger) use ($function) { - return $this->$function($payload->getPayload()); - }; - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function mkdir(array $payload) - { - if ( - @mkdir( - $payload['path'], - octdec($payload['mode']) - ) - ) { - return \React\Promise\resolve([]); - } - - return \React\Promise\reject([ - 'error' => error_get_last(), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function rmdir(array $payload) - { - if (@rmdir($payload['path'])) { - return \React\Promise\resolve([]); - } - - return \React\Promise\reject([ - 'error' => error_get_last(), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function unlink(array $payload) - { - if (unlink($payload['path'])) { - return \React\Promise\resolve([]); - } - - return \React\Promise\reject([ - 'error' => error_get_last(), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function chmod(array $payload) - { - if (chmod($payload['path'], octdec($payload['mode']))) { - return \React\Promise\resolve([]); - } - - return \React\Promise\reject([ - 'error' => error_get_last(), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function chown(array $payload) - { - if (chown($payload['path'], $payload['uid']) && - chgrp($payload['path'], $payload['gid']) - ) { - return \React\Promise\resolve([]); - } - - return \React\Promise\reject([ - 'error' => error_get_last(), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function stat(array $payload) - { - if (!file_exists($payload['path'])) { - return \React\Promise\reject([ - 'error' => ['message' => 'Path doesn\'t exist'], - ]); - } - - $stat = lstat($payload['path']); - return \React\Promise\resolve([ - 'dev' => $stat['dev'], - 'ino' => $stat['ino'], - 'mode' => $stat['mode'], - 'nlink' => $stat['nlink'], - 'uid' => $stat['uid'], - 'size' => $stat['size'], - 'gid' => $stat['gid'], - 'rdev' => $stat['rdev'], - 'blksize' => $stat['blksize'], - 'blocks' => $stat['blocks'], - 'atime' => $stat['atime'], - 'mtime' => $stat['mtime'], - 'ctime' => $stat['ctime'], - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function readdir(array $payload) - { - $list = []; - foreach (scandir($payload['path'], $payload['flags']) as $node) { - $path = $payload['path'] . DIRECTORY_SEPARATOR . $node; - if ($node == '.' || $node == '..' || (!is_dir($path) && !is_file($path))) { - continue; - } - - $list[] = [ - 'type' => is_dir($path) ? 'dir' : 'file', - 'name' => $node, - ]; - } - return \React\Promise\resolve($list); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function open(array $payload) - { - $this->fd = @fopen($payload['path'], $payload['flags']); - return \React\Promise\resolve([ - 'result' => (string)$this->fd, - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function touch(array $payload) - { - return \React\Promise\resolve([ - touch($payload['path']) && chmod($payload['path'], octdec($payload['mode'])), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function read(array $payload) - { - fseek($this->fd, $payload['offset']); - return \React\Promise\resolve([ - 'chunk' => base64_encode(fread($this->fd, $payload['length'])), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function write(array $payload) - { - fseek($this->fd, $payload['offset']); - return \React\Promise\resolve([ - 'written' => fwrite($this->fd, base64_decode($payload['chunk']), $payload['length']), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function close(array $payload) - { - $closed = fclose($this->fd); - $this->fd = null; - return \React\Promise\resolve([ - $closed, - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function getContents(array $payload) - { - if ($payload['maxlen'] > 0) { - $chunk = file_get_contents($payload['path'], false, null, $payload['offset'], $payload['maxlen']); - } else { - $chunk = file_get_contents($payload['path'], false, null, $payload['offset']); - } - - return \React\Promise\resolve([ - 'chunk' => base64_encode($chunk), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function putContents(array $payload) - { - return \React\Promise\resolve([ - 'written' => file_put_contents($payload['path'], base64_decode($payload['chunk']), $payload['flags']), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function rename(array $payload) - { - if (rename($payload['from'], $payload['to'])) { - return \React\Promise\resolve([]); - } - - return \React\Promise\reject([ - 'error' => error_get_last(), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function readlink(array $payload) - { - return \React\Promise\resolve([ - 'path' => readlink($payload['path']), - ]); - } - - /** - * @param array $payload - * @return PromiseInterface - */ - public function symlink(array $payload) - { - return \React\Promise\resolve([ - 'result' => symlink($payload['from'], $payload['to']), - ]); - } -} diff --git a/src/ChildProcess/StatTrait.php b/src/ChildProcess/StatTrait.php new file mode 100644 index 00000000..287a197c --- /dev/null +++ b/src/ChildProcess/StatTrait.php @@ -0,0 +1,31 @@ +then(function (array $stat) use ($path): ?Stat { + if (count($stat) > 0) { + return new Stat($path, $stat); + } + + return null; + }); + } +} diff --git a/src/Factory.php b/src/Factory.php new file mode 100644 index 00000000..b204ec8f --- /dev/null +++ b/src/Factory.php @@ -0,0 +1,26 @@ +internalStat($path)->then(function (?Stat $stat) use ($path) { + if ($stat === null) { + return new NotExist($this, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); + } + + switch (ModeTypeDetector::detect($stat->mode())) { + case Node\DirectoryInterface::class: + return $this->directory($stat->path()); + break; + case Node\FileInterface::class: + return $this->file($stat->path()); + break; + default: + return new Node\Unknown($stat->path(), $stat->path()); + break; + } + }); + } + + public function directory(string $path): Node\DirectoryInterface + { + return new Directory($this, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); + } + + public function file(string $path): Node\FileInterface + { + return new File(dirname($path) . DIRECTORY_SEPARATOR, basename($path)); + } + + +} diff --git a/src/Fallback/Directory.php b/src/Fallback/Directory.php new file mode 100644 index 00000000..7efcdc54 --- /dev/null +++ b/src/Fallback/Directory.php @@ -0,0 +1,67 @@ +filesystem = $filesystem; + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function ls(): PromiseInterface + { + $path = $this->path . $this->name; + $promises = []; + foreach (scandir($path) as $node) { + if (in_array($node, ['.', '..'])) { + continue; + } + + $promises[] = $this->filesystem->detect($this->path . $this->name . DIRECTORY_SEPARATOR . $node); + } + + return all($promises); + } + + public function unlink(): PromiseInterface + { + $path = $this->path . $this->name; + if (count(scandir($path)) > 0) { + return resolve(false); + } + + return resolve(rmdir($path)); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/Fallback/File.php b/src/Fallback/File.php new file mode 100644 index 00000000..25c26e7c --- /dev/null +++ b/src/Fallback/File.php @@ -0,0 +1,63 @@ +path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface + { + $path = $this->path . $this->name; + return resolve(file_get_contents($path, false, null, $offset, $maxlen ?? (int)stat($path)['size'])); + } + + public function putContents(string $contents, int $flags = 0): PromiseInterface + { + // Making sure we only pass in one flag for security reasons + if (($flags & \FILE_APPEND) == \FILE_APPEND) { + $flags = \FILE_APPEND; + } else { + $flags = 0; + } + + $path = $this->path . $this->name; + return resolve(file_put_contents($path, $contents, $flags)); + } + + public function unlink(): PromiseInterface + { + $path = $this->path . $this->name; + return resolve(unlink($path)); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/Fallback/NotExist.php b/src/Fallback/NotExist.php new file mode 100644 index 00000000..66473b74 --- /dev/null +++ b/src/Fallback/NotExist.php @@ -0,0 +1,76 @@ +filesystem = $filesystem; + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function createDirectory(): PromiseInterface + { + $path = $this->path . $this->name; + mkdir($path,0777, true); + return resolve(new Directory($this->filesystem, $this->path, $this->name)); + } + + public function createFile(): PromiseInterface + { + $file = new File($this->path, $this->name); + + return $this->filesystem->detect($this->path)->then(function (Node\NodeInterface $node): PromiseInterface { + if ($node instanceof Node\NotExistInterface) { + return $node->createDirectory(); + } + + return resolve($node); + })->then(function () use ($file): PromiseInterface { + return $file->putContents(''); + })->then(function () use ($file): Node\FileInterface { + return $file; + }); + } + + public function unlink(): PromiseInterface + { + // Essentially a No-OP since it doesn't exist anyway + return resolve(true); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/Fallback/StatTrait.php b/src/Fallback/StatTrait.php new file mode 100644 index 00000000..47148aaf --- /dev/null +++ b/src/Fallback/StatTrait.php @@ -0,0 +1,27 @@ +getAdapter()->setFilesystem($filesystem); - return $filesystem; - } - - /** - * @return string[] - */ - public static function getSupportedAdapters() - { - $adapters = []; - - if (ChildProcess\Adapter::isSupported()) { - $adapters[] = 'ChildProcess'; - } - - return $adapters; - } - - /** - * Filesystem constructor. - * @param AdapterInterface $adapter - */ - private function __construct(AdapterInterface $adapter) - { - $this->adapter = $adapter; - } - - /** - * @return AdapterInterface - */ - public function getAdapter() - { - return $this->adapter; - } - - /** - * @param string $filename - * @return Node\FileInterface - */ - public function file($filename) - { - return new Node\File($filename, $this); - } - - /** - * @param string $path - * @return Node\DirectoryInterface - */ - public function dir($path) - { - return new Node\Directory($path, $this); - } - - /** - * @param string $path - * @param Node\NodeInterface $destination - * @return Node\LinkInterface - */ - public function link($path, Node\NodeInterface $destination) - { - return new Node\Link($path, $destination, $this); - } - - /** - * @param string $path - * @return \React\Promise\PromiseInterface - */ - public function constructLink($path) - { - return $this->adapter->readlink($path)->then(function ($linkPath) { - return $this->adapter->detectType($linkPath); - })->then(function (Node\NodeInterface $destination) use ($path) { - return \React\Promise\resolve($this->link($path, $destination)); - }); - } - - /** - * @param string $filename - * @return \React\Promise\PromiseInterface - */ - public function getContents($filename) - { - $file = $this->file($filename); - return $file->exists()->then(function () use ($file) { - return $file->getContents(); - }); - } -} diff --git a/src/FilesystemInterface.php b/src/FilesystemInterface.php deleted file mode 100644 index d92c0d45..00000000 --- a/src/FilesystemInterface.php +++ /dev/null @@ -1,65 +0,0 @@ - 'dir', - 'file' => 'file', - 'link' => 'constructLink', - ]; - - /** - * @var array - */ - protected $mapping = []; - - /** - * @var FilesystemInterface - */ - protected $filesystem; - - public static function createDefault(FilesystemInterface $filesystem) - { - return new static($filesystem, [ - 'mapping' => static::$defaultMapping, - ]); - } - - /** - * @param FilesystemInterface $filesystem - * @param array $options - */ - public function __construct(FilesystemInterface $filesystem, $options = []) - { - $this->filesystem = $filesystem; - - if (isset($options['mapping']) && is_array($options['mapping']) && count($options['mapping']) > 0) { - $this->mapping = $options['mapping']; - } - } - - /** - * @param array $node - * @return \React\Promise\PromiseInterface - */ - public function detect(array $node) - { - if (!isset($node['type']) || !isset($this->mapping[$node['type']])) { - return \React\Promise\reject(new Exception('Unknown type')); - } - - return \React\Promise\resolve([ - $this->filesystem, - $this->mapping[$node['type']], - ]); - } -} diff --git a/src/ModeTypeDetector.php b/src/ModeTypeDetector.php index de2f5594..23c32ab8 100644 --- a/src/ModeTypeDetector.php +++ b/src/ModeTypeDetector.php @@ -2,65 +2,28 @@ namespace React\Filesystem; -use Exception; -use React\Filesystem\FilesystemInterface; -use React\Filesystem\TypeDetectorInterface; +use React\EventLoop\ExtUvLoop; +use React\EventLoop\LoopInterface; +use React\Filesystem\Node\DirectoryInterface; +use React\Filesystem\Node\FileInterface; +use React\Filesystem\Node\Unknown; -class ModeTypeDetector implements TypeDetectorInterface +final class ModeTypeDetector { - /** - * @var array - */ - protected $mapping = [ - 0xa000 => 'constructLink', - 0x4000 => 'dir', - 0x8000 => 'file', - ]; + private const FILE = 0x8000; + private const DIRECTORY = 0x4000; + private const LINK = 0xa000; - /** - * @var FilesystemInterface - */ - protected $filesystem; - - /** - * @param FilesystemInterface $filesystem - */ - public function __construct(FilesystemInterface $filesystem) + public static function detect(int $mode): string { - $this->filesystem = $filesystem; - } - - /** - * @param array $node - * @return \React\Promise\PromiseInterface - */ - public function detect(array $node) - { - return $this->filesystem->getAdapter()->stat($node['path'])->then(function ($stat) { - return $this->walkMapping($stat); - }); - } - - protected function walkMapping($stat) - { - $promiseChain = \React\Promise\reject(new Exception('Unknown type')); - foreach ($this->mapping as $mappingMode => $method) { - $promiseChain = $promiseChain->otherwise(function () use ($stat, $mappingMode, $method) { - return $this->matchMapping($stat['mode'], $mappingMode, $method); - }); + if (($mode & self::FILE) == self::FILE) { + return FileInterface::class; } - return $promiseChain; - } - protected function matchMapping($mode, $mappingMode, $method) - { - if (($mode & $mappingMode) == $mappingMode) { - return \React\Promise\resolve([ - $this->filesystem, - $method, - ]); + if (($mode & self::DIRECTORY) == self::DIRECTORY) { + return DirectoryInterface::class; } - return \React\Promise\reject(new Exception('Unknown filesystem method for type')); + return Unknown::class; } } diff --git a/src/Node/Directory.php b/src/Node/Directory.php deleted file mode 100644 index 3556254a..00000000 --- a/src/Node/Directory.php +++ /dev/null @@ -1,362 +0,0 @@ -path . NodeInterface::DS; - } - - /** - * @return RecursiveInvoker - */ - protected function getRecursiveInvoker() - { - if ($this->recursiveInvoker instanceof RecursiveInvoker) { - return $this->recursiveInvoker; - } - - $this->recursiveInvoker = new RecursiveInvoker($this); - return $this->recursiveInvoker; - } - - /** - * @param $path - * @param FilesystemInterface $filesystem - * @param RecursiveInvoker $recursiveInvoker - */ - public function __construct($path, FilesystemInterface $filesystem, RecursiveInvoker $recursiveInvoker = null) - { - $this->filesystem = $filesystem; - $this->adapter = $filesystem->getAdapter(); - - $this->createNameNParentFromFilename($path); - $this->recursiveInvoker = $recursiveInvoker; - } - - /** - * {@inheritDoc} - */ - public function ls() - { - return $this->adapter->ls($this->path); - } - - /** - * {@inheritDoc} - */ - public function lsStreaming() - { - return $this->adapter->lsStream($this->path); - } - - /** - * {@inheritDoc} - */ - public function size($recursive = false) - { - return $this->ls()->then(function ($result) use ($recursive) { - return $this->processSizeContents($result, $recursive); - }); - } - - /** - * @param $nodes - * @param $recursive - * @return \React\Promise\Promise - */ - protected function processSizeContents($nodes, $recursive) - { - $numbers = [ - 'directories' => 0, - 'files' => 0, - 'size' => 0, - ]; - - $promises = []; - foreach ($nodes as $node) { - switch (true) { - case $node instanceof Directory: - $numbers['directories']++; - if ($recursive) { - $promises[] = $node->size()->then(function ($size) use (&$numbers) { - $numbers['directories'] += $size['directories']; - $numbers['files'] += $size['files']; - $numbers['size'] += $size['size']; - }); - } - break; - case $node instanceof File: - $numbers['files']++; - $promises[] = $node->size()->then(function ($size) use (&$numbers) { - $numbers['size'] += $size; - }); - break; - } - } - - return \React\Promise\all($promises)->then(function () use (&$numbers) { - return $numbers; - }); - } - - /** - * {@inheritDoc} - */ - public function create($mode = AdapterInterface::CREATION_MODE) - { - return $this->adapter->mkdir($this->path, $mode)->then(function () { - $deferred = new Deferred(); - - $check = function () use (&$check, $deferred) { - $this->stat()->then(function () use ($deferred) { - $deferred->resolve(); - }, function () use (&$check) { - $this->adapter->getLoop()->addTimer(0.1, $check); - }); - }; - - $check(); - - return $deferred->promise(); - }); - } - - /** - * {@inheritDoc} - */ - public function remove() - { - return $this->adapter->rmdir($this->path); - } - - - /** - * {@inheritdoc} - */ - public function rename($toDirectoryName) - { - return $this->adapter->rename($this->path, $toDirectoryName)->then(function () use ($toDirectoryName) { - return $this->filesystem->dir($toDirectoryName); - }); - } - - /** - * {@inheritDoc} - */ - public function createRecursive($mode = AdapterInterface::CREATION_MODE) - { - $parentPath = explode(DIRECTORY_SEPARATOR, $this->path); - array_pop($parentPath); - $parentPath = implode(DIRECTORY_SEPARATOR, $parentPath); - - $parentDirectory = $this->filesystem->dir($parentPath); - return $parentDirectory->stat()->then(null, function () use ($parentDirectory, $mode) { - return $parentDirectory->createRecursive($mode); - })->then(function () use ($mode) { - return $this->create($mode); - })->then(function () { - return null; - }); - } - - /** - * {@inheritDoc} - */ - public function chmodRecursive($mode) - { - return $this->getRecursiveInvoker()->execute('chmod', [$mode]); - } - - /** - * {@inheritDoc} - */ - public function chownRecursive($uid = -1, $gid = -1) - { - return $this->getRecursiveInvoker()->execute('chown', [$uid, $gid]); - } - - /** - * {@inheritDoc} - */ - public function removeRecursive() - { - return $this->getRecursiveInvoker()->execute('remove', []); - } - - /** - * {@inheritDoc} - */ - public function sizeRecursive() - { - return $this->size(true); - } - - /** - * {@inheritDoc} - */ - public function lsRecursive() - { - return ObjectStreamSink::promise($this->lsRecursiveStreaming()); - } - - /** - * {@inheritDoc} - */ - public function lsRecursiveStreaming() - { - return $this->processLsRecursiveContents($this->lsStreaming()); - } - - /** - * @param $sourceStream - * @return ObjectStream - */ - protected function processLsRecursiveContents($sourceStream) - { - $stream = new ObjectStream(); - $closeCount = 0; - $sourceStream->on('data', function (NodeInterface $node) use (&$closeCount, $stream) { - $stream->write($node); - if ($node instanceof Directory) { - $this->streamLsIntoStream($node, $stream, $closeCount); - } - }); - - $sourceStream->on('end', function () use (&$closeCount, $stream) { - $this->adapter->getLoop()->addPeriodicTimer(0.01, function ($timer) use (&$closeCount, $stream) { - if ($closeCount === 0) { - $this->adapter->getLoop()->cancelTimer($timer); - $stream->close(); - } - }); - }); - - return $stream; - } - - /** - * @param DirectoryInterface $node - * @param $stream - * @param $closeCount - */ - protected function streamLsIntoStream(DirectoryInterface $node, $stream, &$closeCount) - { - $closeCount++; - $nodeStream = $node->lsRecursiveStreaming(); - $nodeStream->on('end', function () use (&$closeCount) { - $closeCount--; - }); - $nodeStream->pipe($stream, [ - 'end' => false, - ]); - } - - /** - * @param NodeInterface $node - * @return \React\Promise\Promise - */ - public function copy(NodeInterface $node) - { - return ObjectStreamSink::promise($this->copyStreaming($node)); - } - - /** - * @param NodeInterface $node - * @return ObjectStream - */ - public function copyStreaming(NodeInterface $node) - { - if ($node instanceof DirectoryInterface) { - return $this->copyToDirectory($node); - } - - throw new \UnexpectedValueException('Unsupported node type'); - } - - /** - * @param DirectoryInterface $targetNode - * @return ObjectStream - */ - protected function copyToDirectory(DirectoryInterface $targetNode) - { - $promises = []; - $objectStream = new ObjectStream(); - - $stream = $this->lsStreaming(); - $stream->on('data', function (NodeInterface $node) use ($targetNode, &$promises, $objectStream) { - $deferred = new Deferred(); - $promises[] = $deferred->promise(); - - $stream = $this->handleStreamingCopyNode($node, $targetNode); - $stream->on('end', function () use ($deferred) { - $deferred->resolve(); - }); - $stream->pipe($objectStream , [ - 'end' => false, - ]); - }); - $stream->on('end', function () use ($objectStream, &$promises, $targetNode) { - \React\Promise\all($promises)->then(function () use ($objectStream, $targetNode) { - $objectStream->end(); - }); - }); - - return $objectStream; - } - - /** - * @param NodeInterface $node - * @param DirectoryInterface $targetNode - * @return ObjectStream - */ - protected function handleStreamingCopyNode(NodeInterface $node, DirectoryInterface $targetNode) - { - if ($node instanceof FileInterface) { - return $node->copyStreaming($targetNode); - } - - if ($node instanceof DirectoryInterface) { - $stream = new ObjectStream(); - $newDir = $targetNode->getFilesystem()->dir($targetNode->getPath() . $node->getName()); - - $newDir->stat()->then(null, function () use ($newDir) { - return $newDir->createRecursive(); - })->then(function () use ($node, $newDir, $stream) { - $node->copyStreaming($newDir)->pipe($stream); - }); - - return $stream; - } - } -} diff --git a/src/Node/DirectoryInterface.php b/src/Node/DirectoryInterface.php index fea6bc97..8796f367 100644 --- a/src/Node/DirectoryInterface.php +++ b/src/Node/DirectoryInterface.php @@ -4,77 +4,12 @@ use React\Filesystem\AdapterInterface; use React\Promise\PromiseInterface; +use Rx\Observable; interface DirectoryInterface extends NodeInterface { /** - * Create the directory, fails when directory already exists or when parent doesn't exist. - * - * @return PromiseInterface + * @return PromiseInterface> */ - public function create($mode = AdapterInterface::CREATION_MODE); - - /** - * Create the directory, creating any parent that doesn't exist. - * - * @return PromiseInterface - */ - public function createRecursive($mode = AdapterInterface::CREATION_MODE); - - /** - * Remove the directory, fails when it has contents. - * - * @return PromiseInterface - */ - public function remove(); - - /** - * Rename the directory and return the new directory through a promise - * - * @param string $toDirectoryName - * @return PromiseInterface - */ - public function rename($toDirectoryName); - - /** - * List contents of the directory. - * - * @return PromiseInterface - */ - public function ls(); - - /** - * List contents of the directory and any child directories recursively. - * - * @return PromiseInterface - */ - public function lsRecursive(); - - /** - * Change mode recursively. - * - * @param int $mode - * @return PromiseInterface - */ - public function chmodRecursive($mode); - - /** - * Change owner recursively. - * - * @return PromiseInterface - */ - public function chownRecursive(); - - /** - * Remove the directory and all its contents recursively. - * - * @return PromiseInterface - */ - public function removeRecursive(); - - /** - * @param DirectoryInterface $directory - * @return PromiseInterface - */ - //public function rsync(DirectoryInterface $directory); + public function ls(): PromiseInterface; } diff --git a/src/Node/File.php b/src/Node/File.php deleted file mode 100644 index 55a684c4..00000000 --- a/src/Node/File.php +++ /dev/null @@ -1,228 +0,0 @@ -filesystem = $filesystem; - $this->adapter = $filesystem->getAdapter(); - $this->createNameNParentFromFilename($filename); - } - - /** - * {@inheritDoc} - */ - public function exists() - { - return $this->stat()->then(function () { - return null; - }, function () { - throw new Exception('Not found'); - }); - } - - /** - * {@inheritDoc} - */ - public function size() - { - return $this->adapter->stat($this->path)->then(function ($result) { - return $result['size']; - }); - } - - /** - * {@inheritDoc} - */ - public function time() - { - return $this->adapter->stat($this->path)->then(function ($result) { - return [ - 'atime' => $result['atime'], - 'ctime' => $result['ctime'], - 'mtime' => $result['mtime'], - ]; - }); - } - - /** - * {@inheritDoc} - */ - public function rename($toFilename) - { - return $this->adapter->rename($this->path, $toFilename)->then(function () use ($toFilename) { - return $this->filesystem->file($toFilename); - }); - } - - /** - * {@inheritDoc} - */ - public function create($mode = AdapterInterface::CREATION_MODE, $time = null) - { - return $this->stat()->then(function () { - throw new \Exception('File exists already'); - }, function () use ($mode, $time) { - return $this->adapter->touch($this->path, $mode, $time); - }); - } - - /** - * {@inheritDoc} - */ - public function touch($mode = AdapterInterface::CREATION_MODE, $time = null) - { - return $this->adapter->touch($this->path, $mode, $time); - } - - /** - * {@inheritDoc} - */ - public function open($flags, $mode = AdapterInterface::CREATION_MODE) - { - if ($this->open === true) { - return \React\Promise\reject(new Exception('File is already open')); - } - - return $this->adapter->open($this->path, $flags, $mode)->then(function ($fd) use ($flags) { - $this->open = true; - $this->fileDescriptor = $fd; - return StreamFactory::create($this->path, $fd, $flags, $this->adapter); - }); - } - - /** - * {@inheritDoc} - */ - public function close() - { - if ($this->open === false) { - return \React\Promise\reject(new Exception('File is already closed')); - } - - return $this->adapter->close($this->fileDescriptor)->then(function () { - $this->open = false; - $this->fileDescriptor = null; - }); - } - - /** - * {@inheritDoc} - */ - public function getContents() - { - return $this->adapter->getContents($this->path); - } - - /** - * {@inheritDoc} - */ - public function putContents($contents) - { - return $this->adapter->putContents($this->path, $contents); - } - - /** - * {@inheritDoc} - */ - public function remove() - { - return $this->adapter->unlink($this->path); - } - - /** - * @param NodeInterface $node - * @return \React\Promise\PromiseInterface - */ - public function copy(NodeInterface $node) - { - return ObjectStreamSink::promise($this->copyStreaming($node)); - } - - /** - * @param NodeInterface $node - * @return ObjectStream - */ - public function copyStreaming(NodeInterface $node) - { - if ($node instanceof FileInterface) { - return $this->copyToFile($node); - } - - if ($node instanceof DirectoryInterface) { - return $this->copyToDirectory($node); - } - - throw new \UnexpectedValueException('Unsupported node type'); - } - - /** - * @param FileInterface $node - * @return ObjectStream - */ - protected function copyToFile(FileInterface $node) - { - $stream = new ObjectStream(); - - $this->open('r')->then(function (ReadableStreamInterface $readStream) use ($node) { - $readStream->pause(); - - return \React\Promise\all([ - 'read' => $readStream, - 'write' => $node->open('ctw'), - ]); - })->then(function (array $streams) use ($stream, $node) { - $streams['read']->pipe($streams['write']); - $streams['read']->on('close', function () use ($streams, $stream, $node) { - $streams['write']->close(); - $stream->end($node); - }); - $streams['read']->resume(); - })->done(); - - return $stream; - } - - /** - * @param DirectoryInterface $node - * @return ObjectStream - */ - protected function copyToDirectory(DirectoryInterface $node) - { - return $this->copyToFile($node->getFilesystem()->file($node->getPath() . $this->getName())); - } -} diff --git a/src/Node/FileInterface.php b/src/Node/FileInterface.php index 0deb1300..017ec23f 100644 --- a/src/Node/FileInterface.php +++ b/src/Node/FileInterface.php @@ -2,89 +2,22 @@ namespace React\Filesystem\Node; -use React\Filesystem\AdapterInterface; use React\Promise\PromiseInterface; interface FileInterface extends NodeInterface { - /** - * Returns true when the file exists - * - * @return PromiseInterface - */ - public function exists(); - - /** - * Remove the file - * - * @return PromiseInterface - */ - public function remove(); - - /** - * Open the file and return a promise resolve into a stream that can be read from or written to. - * - * @param $flags - * @param string $mode - * @return PromiseInterface - */ - public function open($flags, $mode = AdapterInterface::CREATION_MODE); - - /** - * Return the change time, access time, and modification time - * - * @return PromiseInterface - */ - public function time(); - - /** - * Rename the file and return the new file through a promise - * - * @param string $toFilename - * @return PromiseInterface - */ - public function rename($toFilename); - - /** - * Return the size of the file. - * - * @return PromiseInterface - */ - public function size(); - - /** - * Create the file - * - * @param string $mode - * @param null $time - * @return PromiseInterface - * - * @throws \Exception When the file already exists - */ - public function create($mode = AdapterInterface::CREATION_MODE, $time = null); - - /** - * Touch the file, modifying it's mtime when it exists, - * or creating the file when it doesn't it exists. - * - * @param string $mode - * @param null $time - * @return PromiseInterface - */ - public function touch($mode = AdapterInterface::CREATION_MODE, $time = null); - /** * Open the file and read all its contents returning those through a promise. * * @return PromiseInterface */ - public function getContents(); + public function getContents(int $offset = 0 , ?int $maxlen = null); /** * Write the given contents to the file, overwriting any existing contents or creating the file. * * @param string $contents - * @return PromiseInterface + * @return PromiseInterface */ - public function putContents($contents); + public function putContents(string $contents, int $flags = 0); } diff --git a/src/Node/GenericOperationInterface.php b/src/Node/GenericOperationInterface.php deleted file mode 100644 index 08d9f6df..00000000 --- a/src/Node/GenericOperationInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -path = $path; - - $path = rtrim($path, NodeInterface::DS); - - $pathBits = explode(NodeInterface::DS, $path); - $this->name = array_pop($pathBits); - - if (count($pathBits) > 0) { - $this->parent = $this->filesystem->dir(implode(NodeInterface::DS, $pathBits)); - $this->path = $this->parent->getPath() . $this->getName(); - } - } - - /** - * {@inheritDoc} - */ - public function getPath() - { - return $this->path; - } - - /** - * {@inheritDoc} - */ - public function getName() - { - return $this->name; - } - - /** - * {@inheritDoc} - */ - public function getParent() - { - return $this->parent; - } - - /** - * {@inheritDoc} - */ - public function __toString() - { - return $this->getPath(); - } - - /** - * {@inheritDoc} - */ - public function getFilesystem() - { - return $this->filesystem; - } - - /** - * {@inheritDoc} - */ - public function stat() - { - return $this->adapter->stat($this->getPath()); - } - - /** - * {@inheritDoc} - */ - public function chmod($mode) - { - return $this->adapter->chmod($this->getPath(), $mode); - } - - /** - * {@inheritDoc} - */ - public function chown($uid = -1, $gid = -1) - { - return $this->adapter->chown($this->getPath(), $uid, $gid); - } -} diff --git a/src/Node/Link.php b/src/Node/Link.php deleted file mode 100644 index fd86df52..00000000 --- a/src/Node/Link.php +++ /dev/null @@ -1,63 +0,0 @@ -node = $node; - $this->filesystem = $filesystem; - $this->adapter = $filesystem->getAdapter(); - $this->createNameNParentFromFilename($path); - } - - /** - * @inheritDoc - */ - public function getDestination() - { - return $this->node; - } - - /** - * @inheritDoc - */ - public function copy(NodeInterface $node) - { - return $this->node->copy($node); - } - - /** - * @inheritDoc - */ - public function copyStreaming(NodeInterface $node) - { - return $this->node->copyStreaming($node); - } - - /** - * @param string $name - * @param array $arguments - * @return mixed - */ - public function __call($name, $arguments) - { - return $this->node->$name(...$arguments); - } -} diff --git a/src/Node/LinkInterface.php b/src/Node/LinkInterface.php deleted file mode 100644 index ff5566b4..00000000 --- a/src/Node/LinkInterface.php +++ /dev/null @@ -1,13 +0,0 @@ - */ - public function copy(NodeInterface $node); + public function stat(): PromiseInterface; /** - * Copy this node to the given node streaming. The returned object is a stream, - * that emits events for each copy node during this operation. + * Remove the node from the filesystem, errors on non-empty directories * - * @param NodeInterface $node - * @return ObjectStream + * @return PromiseInterface */ - public function copyStreaming(NodeInterface $node); + public function unlink(): PromiseInterface; } diff --git a/src/Node/NotExistInterface.php b/src/Node/NotExistInterface.php new file mode 100644 index 00000000..ca19b5d8 --- /dev/null +++ b/src/Node/NotExistInterface.php @@ -0,0 +1,19 @@ + + */ + public function createDirectory(): PromiseInterface; + + /** + * @return PromiseInterface + */ + public function createFile(): PromiseInterface; +} diff --git a/src/Node/RecursiveInvoker.php b/src/Node/RecursiveInvoker.php deleted file mode 100644 index d6b1c6a5..00000000 --- a/src/Node/RecursiveInvoker.php +++ /dev/null @@ -1,54 +0,0 @@ -node = $node; - } - - /** - * @param string $method - * @param array $args - * @return \React\Promise\Promise - */ - public function execute($method, $args) - { - return $this->node->ls()->then(function ($list) use ($method, $args) { - return $this->iterateNode($list, $method, $args); - }); - } - - /** - * @param $list - * @param $method - * @param $args - * @return \React\Promise\PromiseInterface - */ - protected function iterateNode($list, $method, $args) - { - $promises = []; - - foreach ($list as $node) { - if ($node instanceof Directory) { - $promises[] = call_user_func_array([$node, $method . 'Recursive'], $args); - } else { - $promises[] = call_user_func_array([$node, $method], $args); - } - } - - return \React\Promise\all($promises)->then(function () use ($method, $args) { - return call_user_func_array([$this->node, $method], $args); - }); - } -} diff --git a/src/NodeNotFound.php b/src/NodeNotFound.php new file mode 100644 index 00000000..08f2b729 --- /dev/null +++ b/src/NodeNotFound.php @@ -0,0 +1,18 @@ +closed; - } - - public function pause() - { - } - - public function resume() - { - } - - public function pipe(WritableStreamInterface $dest, array $options = array()) - { - Util::pipe($this, $dest, $options); - - return $dest; - } - public function write($data) - { - $this->emit('data', array($data, $this)); - } - - public function end($data = null) - { - if (null !== $data) { - $this->write($data); - } - - $this->close(); - } - - public function isWritable() - { - return !$this->closed; - } - - public function close() - { - if ($this->closed) { - return; - } - - $this->closed = true; - $this->emit('end', array($this)); - $this->emit('close', array($this)); - $this->removeAllListeners(); - } -} diff --git a/src/ObjectStreamSink.php b/src/ObjectStreamSink.php deleted file mode 100644 index 74613639..00000000 --- a/src/ObjectStreamSink.php +++ /dev/null @@ -1,27 +0,0 @@ -on('data', function ($object) use (&$list) { - $list[] = $object; - }); - $stream->on('end', function () use ($deferred, &$list) { - $deferred->resolve($list); - }); - - return $deferred->promise(); - } -} diff --git a/src/OpenFileLimiter.php b/src/OpenFileLimiter.php deleted file mode 100644 index 0f52063a..00000000 --- a/src/OpenFileLimiter.php +++ /dev/null @@ -1,85 +0,0 @@ -limit = $limit; - $this->promises = new \SplQueue(); - } - - /** - * @return \React\Promise\PromiseInterface - */ - public function open() - { - if ($this->current < $this->limit) { - $this->current++; - return \React\Promise\resolve(); - } - - $deferred = new Deferred(); - $this->promises->enqueue($deferred); - return $deferred->promise(); - } - - public function close() - { - if (!$this->promises->isEmpty()) { - $this->promises->dequeue()->resolve(); - } else { - $this->current--; - } - } - - /** - * @return int - */ - public function getLimit() - { - return $this->limit; - } - - /** - * @return int - */ - public function getOutstanding() - { - return $this->current; - } - - /** - * @return int - */ - public function getQueueSize() - { - return $this->promises->count(); - } -} diff --git a/src/PermissionFlagResolver.php b/src/PermissionFlagResolver.php deleted file mode 100644 index 8cdaa9c0..00000000 --- a/src/PermissionFlagResolver.php +++ /dev/null @@ -1,66 +0,0 @@ - [ - 'w' => 128, - 'x' => 64, - 'r' => 256, - ], - 'group' => [ - 'w' => 16, - 'x' => 8, - 'r' => 32, - ], - 'universe' => [ - 'w' => 2, - 'x' => 1, - 'r' => 4, - ], - ]; - - /** - * {@inheritDoc} - */ - public function defaultFlags() - { - return static::DEFAULT_FLAG; - } - - /** - * {@inheritDoc} - */ - public function flagMapping() - { - return $this->flagMapping[$this->currentScope]; - } - - /** - * {@inheritDoc} - */ - public function resolve($flag, $flags = null, $mapping = null) - { - $resultFlags = 0; - $start = 0; - - foreach ([ - 'universe', - 'group', - 'user', - ] as $scope) { - $this->currentScope = $scope; - $start -= 3; - $chunk = substr($flag, $start, 3); - $resultFlags |= parent::resolve($chunk, $flags, $mapping); - } - - return $resultFlags; - } -} diff --git a/src/PollInterface.php b/src/PollInterface.php new file mode 100644 index 00000000..18f04241 --- /dev/null +++ b/src/PollInterface.php @@ -0,0 +1,12 @@ +deferred = $deferred; - $this->function = $function; - $this->args = $args; - $this->errorResultCode = $errorResultCode; - } - - /** - * @return Deferred - */ - public function getDeferred() - { - return $this->deferred; - } - - /** - * @return string - */ - public function getFunction() - { - return $this->function; - } - - /** - * @return array - */ - public function getArgs() - { - return $this->args; - } - - /** - * @return int - */ - public function getErrorResultCode() - { - return $this->errorResultCode; - } -} diff --git a/src/Stat.php b/src/Stat.php new file mode 100644 index 00000000..e834bae5 --- /dev/null +++ b/src/Stat.php @@ -0,0 +1,59 @@ + */ + private array $data; + + public function __construct(string $path, array $data) + { + $this->path = $path; + $this->data = $data; + } + + public function path(): string + { + return $this->path; + } + + public function mode(): ?int + { + return array_key_exists('mode', $this->data) ? $this->data['mode'] : null; + } + + public function uid(): ?int + { + return array_key_exists('uid', $this->data) ? $this->data['uid'] : null; + } + + public function gid(): ?int + { + return array_key_exists('gid', $this->data) ? $this->data['gid'] : null; + } + + public function size(): ?int + { + return array_key_exists('size', $this->data) ? $this->data['size'] : null; + } + + public function atime(): ?\DateTimeImmutable + { + return array_key_exists('atime', $this->data) ? new \DateTimeImmutable('@' . $this->data['atime']) : null; + } + + public function mtime(): ?\DateTimeImmutable + { + return array_key_exists('mtime', $this->data) ? new \DateTimeImmutable('@' . $this->data['mtime']) : null; + } + + public function ctime(): ?\DateTimeImmutable + { + return array_key_exists('ctime', $this->data) ? new \DateTimeImmutable('@' . $this->data['ctime']) : null; + } +} diff --git a/src/Stream/DuplexStream.php b/src/Stream/DuplexStream.php deleted file mode 100644 index 37aec595..00000000 --- a/src/Stream/DuplexStream.php +++ /dev/null @@ -1,48 +0,0 @@ -path = $path; - $this->setFilesystem($filesystem); - $this->fileDescriptor = $fileDescriptor; - } - - protected function readChunk() - { - if ($this->pause) { - return; - } - - $this->resolveSize()->then(function () { - $this->performRead($this->calculateChunkSize()); - }); - } - - protected function resolveSize() - { - if ($this->readCursor < $this->size) { - return \React\Promise\resolve(); - } - - return $this->getFilesystem()->stat($this->path)->then(function ($stat) { - $this->size = $stat['size']; - }); - } -} diff --git a/src/Stream/GenericStreamInterface.php b/src/Stream/GenericStreamInterface.php deleted file mode 100644 index 061fdbd8..00000000 --- a/src/Stream/GenericStreamInterface.php +++ /dev/null @@ -1,11 +0,0 @@ -path = $path; - $this->filesystem = $filesystem; - $this->fileDescriptor = $fileDescriptor; - } - - /** - * @return AdapterInterface - */ - public function getFilesystem() - { - return $this->filesystem; - } - - /** - * @param AdapterInterface $filesystem - */ - public function setFilesystem($filesystem) - { - $this->filesystem = $filesystem; - } - - /** - * {@inheritDoc} - */ - public function getFiledescriptor() - { - return $this->fileDescriptor; - } - - /** - * @return bool - */ - public function isClosed() - { - return $this->closed; - } - - /** - * @param bool $closed - */ - public function setClosed($closed) - { - $this->closed = $closed; - } - - /** - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * @param string $path - */ - public function setPath($path) - { - $this->path = $path; - } - - /** - * {@inheritDoc} - */ - public function close() - { - if ($this->closed) { - return; - } - - $this->closed = true; - - $this->filesystem->close($this->fileDescriptor)->then(function () { - $this->emit('close', [$this]); - $this->removeAllListeners(); - }); - } -} diff --git a/src/Stream/ReadableStream.php b/src/Stream/ReadableStream.php deleted file mode 100644 index cdb59867..00000000 --- a/src/Stream/ReadableStream.php +++ /dev/null @@ -1,27 +0,0 @@ -path = $path; - $this->filesystem = $filesystem; - $this->fileDescriptor = $fileDescriptor; - - $this->resume(); - } -} diff --git a/src/Stream/ReadableStreamTrait.php b/src/Stream/ReadableStreamTrait.php deleted file mode 100644 index 378a0644..00000000 --- a/src/Stream/ReadableStreamTrait.php +++ /dev/null @@ -1,108 +0,0 @@ -pause || $this->isReading) { - return; - } - - $this->pause = false; - - if ($this->size === null && $this->sizeLookupPromise === null) { - $this->sizeLookupPromise = $this->getFilesystem()->stat($this->getPath())->then(function ($info) { - if ($this->size !== null) { - throw new Exception('File was already stat-ed'); - } - - $this->size = $info['size']; - $this->readCursor = 0; - }); - } - - $this->sizeLookupPromise->then(function () { - $this->readChunk(); - }); - } - - public function pause() - { - $this->pause = true; - } - - public function pipe(WritableStreamInterface $dest, array $options = []) - { - if ($this === $dest) { - throw new \Exception('Can\'t pipe stream into itself!'); - } - - Util::pipe($this, $dest, $options); - - return $dest; - } - - public function isReadable() - { - return !$this->isClosed(); - } - - protected function readChunk() - { - if ($this->pause || $this->isReading) { - return; - } - - $this->performRead($this->calculateChunkSize()); - } - - protected function calculateChunkSize() - { - if ($this->readCursor + $this->chunkSize > $this->size) { - return $this->size - $this->readCursor; - } - - return $this->chunkSize; - } - - protected function performRead($chunkSize) - { - $this->isReading = true; - $this->getFilesystem()->read($this->getFileDescriptor(), $chunkSize, $this->readCursor)->then(function ($data) use ($chunkSize) { - $this->isReading = false; - if ($this->pause) { - return; - } - - // If chunk size can be set make sure to copy it before running this operation so - // that used can't change it mid operation and cause funkyness. - $this->readCursor += $chunkSize; - $this->emit('data', [ - $data, - $this, - ]); - - if ($this->readCursor < $this->size) { - $this->readChunk(); - } else { - $this->emit('end', [$this]); - $this->close(); - } - }); - } - - abstract function close(); -} diff --git a/src/Stream/StreamFactory.php b/src/Stream/StreamFactory.php deleted file mode 100644 index e2fe2e17..00000000 --- a/src/Stream/StreamFactory.php +++ /dev/null @@ -1,28 +0,0 @@ -path = $path; - $this->filesystem = $filesystem; - $this->fileDescriptor = $fileDescriptor; - } -} diff --git a/src/Stream/WritableStreamTrait.php b/src/Stream/WritableStreamTrait.php deleted file mode 100644 index 446dd47a..00000000 --- a/src/Stream/WritableStreamTrait.php +++ /dev/null @@ -1,42 +0,0 @@ -writeCursor; - $this->writeCursor += $length; - - return $this->getFilesystem()->write($this->getFileDescriptor(), $data, $length, $offset); - } - - /** - * {@inheritDoc} - */ - public function end($data = null) - { - if (null !== $data) { - $this->write($data); - } - - $this->close(); - } - - /** - * {@inheritDoc} - */ - public function isWritable() - { - return !$this->isClosed(); - } - - abstract function close(); -} diff --git a/src/TypeDetectorInterface.php b/src/TypeDetectorInterface.php index 16a73711..300af831 100644 --- a/src/TypeDetectorInterface.php +++ b/src/TypeDetectorInterface.php @@ -5,9 +5,9 @@ interface TypeDetectorInterface { /** - * @param FilesystemInterface $filesystem + * @param AdapterInterface $filesystem */ - public function __construct(FilesystemInterface $filesystem); + public function __construct(AdapterInterface $filesystem); /** * @param array $node diff --git a/src/Uv/Adapter.php b/src/Uv/Adapter.php new file mode 100644 index 00000000..e5e49e5b --- /dev/null +++ b/src/Uv/Adapter.php @@ -0,0 +1,79 @@ +loop = $loop; + $this->poll = new Poll($this->loop); + $this->uvLoop = $loop->getUvLoop(); + } + + public function detect(string $path): PromiseInterface + { + return $this->internalStat($path)->then(function (?Stat $stat) use ($path) { + if ($stat === null) { + return new NotExist($this->poll, $this, $this->loop, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); + } + + switch (ModeTypeDetector::detect($stat->mode())) { + case Node\DirectoryInterface::class: + return $this->directory($stat->path()); + break; + case Node\FileInterface::class: + return $this->file($stat->path()); + break; + default: + return new Node\Unknown($stat->path(), $stat->path()); + break; + } + }); + } + + public function directory(string $path): Node\DirectoryInterface + { + return new Directory($this->poll, $this, $this->loop, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); + } + + public function file(string $path): Node\FileInterface + { + return new File($this->poll, $this->loop, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); + } + + + protected function uvLoop() + { + return $this->uvLoop; + } + + protected function activate(): void + { + $this->poll->activate(); + } + + protected function deactivate(): void + { + $this->poll->deactivate(); + } +} diff --git a/src/Uv/Directory.php b/src/Uv/Directory.php new file mode 100644 index 00000000..5e66295b --- /dev/null +++ b/src/Uv/Directory.php @@ -0,0 +1,113 @@ +poll = $poll; + $this->filesystem = $filesystem; + $this->loop = $loop; + $this->uvLoop = $loop->getUvLoop(); + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function ls(): PromiseInterface + { + $this->activate(); + $deferred = new Deferred(); + uv_fs_scandir($this->uvLoop, $this->path . $this->name, function (array $contents) use ($deferred): void { + $promises = []; + foreach ($contents as $node) { + $promises[] = $this->filesystem->detect($this->path . $this->name . DIRECTORY_SEPARATOR . $node)->then(null, function (\Throwable $throwable) use ($deferred, &$promises) { + $deferred->reject($throwable); + foreach ($promises as $promise) { + if ($promise instanceof CancellablePromiseInterface) { + $promise->cancel(); + } + } + }); + } + + $deferred->resolve(all($promises)); + $this->deactivate(); + }); + + + return $deferred->promise(); + } + + public function unlink(): PromiseInterface + { + $this->activate(); + $deferred = new Deferred(); + uv_fs_scandir($this->uvLoop, $this->path . $this->name, function (array $contents) use ($deferred): void { + $this->deactivate(); + if (count($contents) > 0) { + $deferred->resolve(false); + + return; + } + + $this->activate(); + uv_fs_rmdir($this->uvLoop, $this->path . $this->name, function () use ($deferred): void { + $this->deactivate(); + $deferred->resolve(true); + }); + }); + + + return $deferred->promise(); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } + + protected function uvLoop() + { + return $this->uvLoop; + } + + protected function activate(): void + { + $this->poll->activate(); + } + + protected function deactivate(): void + { + $this->poll->deactivate(); + } +} diff --git a/src/Uv/File.php b/src/Uv/File.php new file mode 100644 index 00000000..f423ef9b --- /dev/null +++ b/src/Uv/File.php @@ -0,0 +1,109 @@ +poll = $poll; + $this->loop = $loop; + $this->uvLoop = $loop->getUvLoop(); + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface + { + $this->activate(); + return new Promise(function (callable $resolve) use ($offset, $maxlen): void { + uv_fs_open($this->uvLoop, $this->path . DIRECTORY_SEPARATOR . $this->name, UV::O_RDONLY, 0, function ($fileDescriptor) use ($resolve, $offset, $maxlen): void { + uv_fs_fstat($this->uvLoop, $fileDescriptor, function ($fileDescriptor, array $stat) use ($resolve, $offset, $maxlen): void { + uv_fs_read($this->uvLoop, $fileDescriptor, $offset, $maxlen ?? (int)$stat['size'], function ($fileDescriptor, string $buffer) use ($resolve): void { + $resolve($buffer); + uv_fs_close($this->uvLoop, $fileDescriptor, function () { + $this->deactivate(); + }); + }); + }); + }); + }); + } + + public function putContents(string $contents, int $flags = 0) + { + $this->activate(); + return new Promise(function (callable $resolve) use ($contents, $flags): void { + uv_fs_open( + $this->uvLoop, + $this->path . DIRECTORY_SEPARATOR . $this->name, + (($flags & \FILE_APPEND) == \FILE_APPEND) ? UV::O_RDWR | UV::O_CREAT | UV::O_APPEND : UV::O_RDWR | UV::O_CREAT, + 0644, + function ($fileDescriptor) use ($resolve, $contents, $flags): void { + uv_fs_write($this->uvLoop, $fileDescriptor, $contents, 0, function ($fileDescriptor, int $bytesWritten) use ($resolve): void { + $resolve($bytesWritten); + uv_fs_close($this->uvLoop, $fileDescriptor, function () { + $this->deactivate(); + }); + }); + } + ); + }); + } + + public function unlink(): PromiseInterface + { + $this->activate(); + return new Promise(function (callable $resolve): void { + uv_fs_unlink($this->uvLoop, $this->path . DIRECTORY_SEPARATOR . $this->name, function () use ($resolve): void { + $resolve(true); + $this->deactivate(); + }); + }); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } + + protected function uvLoop() + { + return $this->uvLoop; + } + + protected function activate(): void + { + $this->poll->activate(); + } + + protected function deactivate(): void + { + $this->poll->deactivate(); + } +} diff --git a/src/Uv/NotExist.php b/src/Uv/NotExist.php new file mode 100644 index 00000000..41c2561d --- /dev/null +++ b/src/Uv/NotExist.php @@ -0,0 +1,108 @@ +poll = $poll; + $this->filesystem = $filesystem; + $this->loop = $loop; + $this->uvLoop = $loop->getUvLoop(); + $this->path = $path; + $this->name = $name; + } + + public function stat(): PromiseInterface + { + return $this->internalStat($this->path . $this->name); + } + + public function createDirectory(): PromiseInterface + { + $this->activate(); + return $this->filesystem->detect($this->path)->then(function (Node\NodeInterface $node): PromiseInterface { + if ($node instanceof Node\NotExistInterface) { + return $node->createDirectory(); + } + + return resolve($node); + })->then(function (Node\DirectoryInterface $directory): PromiseInterface { + return new Promise(function (callable $resolve): void { + uv_fs_mkdir($this->uvLoop, $this->path . $this->name, 0777, function () use ($resolve): void { + $resolve(new Directory($this->poll, $this->filesystem, $this->loop, $this->path, $this->name)); + $this->deactivate(); + }); + }); + }); + } + + public function createFile(): PromiseInterface + { + $file = new File($this->poll, $this->loop, $this->path, $this->name); + + return $this->filesystem->detect($this->path . DIRECTORY_SEPARATOR)->then(function (Node\NodeInterface $node): PromiseInterface { + if ($node instanceof Node\NotExistInterface) { + return $node->createDirectory(); + } + + return resolve($node); + })->then(function () use ($file): PromiseInterface { + return $file->putContents(''); + })->then(function () use ($file): Node\FileInterface { + return $file; + }); + } + + public function unlink(): PromiseInterface + { + // Essentially a No-OP since it doesn't exist anyway + return resolve(true); + } + + public function path(): string + { + return $this->path; + } + + public function name(): string + { + return $this->name; + } + + protected function uvLoop() + { + return $this->uvLoop; + } + + protected function activate(): void + { + $this->poll->activate(); + } + + protected function deactivate(): void + { + $this->poll->deactivate(); + } +} diff --git a/src/Uv/Poll.php b/src/Uv/Poll.php new file mode 100644 index 00000000..f8a19c78 --- /dev/null +++ b/src/Uv/Poll.php @@ -0,0 +1,43 @@ +loop = $loop; + } + + public function activate(): void + { + if ($this->workInProgress++ === 0) { + $this->workInProgressTimer = $this->loop->addPeriodicTimer($this->workInterval, static function () {}); + } + } + + public function deactivate(): void + { + if (--$this->workInProgress <= 0) { + $this->loop->cancelTimer($this->workInProgressTimer); + } + } +} diff --git a/src/Uv/StatTrait.php b/src/Uv/StatTrait.php new file mode 100644 index 00000000..95b1a2ed --- /dev/null +++ b/src/Uv/StatTrait.php @@ -0,0 +1,36 @@ +activate(); + uv_fs_stat($this->uvLoop(), $path, function ($stat) use ($path, $resolve, $reject): void { + $this->deactivate(); + if (is_array($stat)) { + $resolve(new Stat($path, $stat)); + } else { + $resolve(null); + } + }); + }); + } + + abstract protected function uvLoop(); // phpcs:disabled + abstract protected function activate(): void; + abstract protected function deactivate(): void; +} diff --git a/src/functions.php b/src/functions.php deleted file mode 100644 index 741f70e2..00000000 --- a/src/functions.php +++ /dev/null @@ -1,37 +0,0 @@ -otherwise(function () use ($node, $detector) { - return $detector->detect($node); - }); - } - - return $promiseChain->then(function ($callable) use ($node) { - return \React\Promise\resolve($callable($node['path'])); - }); -} diff --git a/src/functions_include.php b/src/functions_include.php deleted file mode 100644 index 9152e111..00000000 --- a/src/functions_include.php +++ /dev/null @@ -1,7 +0,0 @@ -> + */ + final public function provideFilesystems(): iterable + { + $loop = EventLoop\Loop::get(); + + yield 'fallback' => [new Fallback\Adapter()]; + + if (DIRECTORY_SEPARATOR !== '\\') { + yield 'childprocess' => [new ChildProcess\Adapter()]; + } + + if (\function_exists('uv_loop_new') && $loop instanceof ExtUvLoop) { + yield 'uv' => [new Uv\Adapter()]; + } + + yield 'factory' => [Factory::create()]; + } + + public function await(PromiseInterface $promise) + { + return await($promise, EventLoop\Loop::get(), 30); + } +} diff --git a/tests/AbstractFlagResolverTest.php b/tests/AbstractFlagResolverTest.php deleted file mode 100644 index f60f38fd..00000000 --- a/tests/AbstractFlagResolverTest.php +++ /dev/null @@ -1,17 +0,0 @@ -assertInstanceOf('React\Filesystem\FlagResolver', $this->resolver); - $this->assertInstanceOf('React\Filesystem\FlagResolverInterface', $this->resolver); - } - - public function testFlagMappingType() - { - $this->assertInternalType('array', $this->resolver->flagMapping()); - } -} diff --git a/tests/Adapters/AbstractAdaptersTest.php b/tests/Adapters/AbstractAdaptersTest.php deleted file mode 100644 index 2846994c..00000000 --- a/tests/Adapters/AbstractAdaptersTest.php +++ /dev/null @@ -1,96 +0,0 @@ -adapterFactory($adapters, 'libevent', function () { - return new EventLoop\LibEventLoop(); - }); - } - - if (class_exists('libev\EventLoop', false)) - { - $this->adapterFactory($adapters, 'libev', function () { - return new EventLoop\LibEvLoop; - }); - } - - if (class_exists('EventBase', false)) - { - $this->adapterFactory($adapters, 'extevent', function () { - return new EventLoop\ExtEventLoop; - }); - } - - $this->adapterFactory($adapters, 'streamselect', function () { - return new EventLoop\StreamSelectLoop(); - }); - - $this->adapterFactory($adapters, 'factory', function () { - return EventLoop\Factory::create(); - }); - - return $adapters; - } - - protected function adapterFactory(&$adapters, $loopSlug, callable $loopFactory) - { - $adapters[$loopSlug . '-factory'] = $this->getFacoryProvider($loopFactory); - $adapters[$loopSlug . '-child-process'] = $this->getChildProcessProvider($loopFactory); - - if (extension_loaded('pthreads')) { - $adapters[$loopSlug . '-pthreads'] = $this->getPthreadsProvider($loopFactory); - } - } - - protected function getChildProcessProvider(callable $loopFactory) - { - $loop = $loopFactory(); - return [ - $loop, - new ChildProcess\Adapter($loop, [Options::TTL => 0.01,]), - ]; - } - - protected function getFacoryProvider(callable $loopFactory) - { - $loop = $loopFactory(); - return [ - $loop, - Filesystem::create($loop)->getAdapter(), - ]; - } - - public function filesystemProvider() - { - $filesystems = []; - - foreach ($this->adapterProvider() as $name => $adapter) { - $filesystems[$name] = [ - $adapter[0], - Filesystem::createFromAdapter($adapter[1]), - ]; - } - - return $filesystems; - } -} diff --git a/tests/Adapters/DirectoryTest.php b/tests/Adapters/DirectoryTest.php deleted file mode 100644 index c0bc5cc3..00000000 --- a/tests/Adapters/DirectoryTest.php +++ /dev/null @@ -1,218 +0,0 @@ -tmpDir . 'path'; - touch($path); - $listing = $this->await($filesystem->dir($this->tmpDir)->ls(), $loop); - $this->assertSame(1, count($listing)); - $this->assertSame($path, reset($listing)->getPath()); - } - - /** - * @dataProvider filesystemProvider - */ - public function testSize(LoopInterface $loop, FilesystemInterface $filesystem) - { - $contents = str_repeat('a', 100); - $path = $this->tmpDir . 'path'; - file_put_contents($path, $contents); - mkdir($this->tmpDir . 'subPath'); - file_put_contents($this->tmpDir . 'subPath/file', $contents); - $size = $this->await($filesystem->dir($this->tmpDir)->size(), $loop); - $this->assertSame([ - 'directories' => 1, - 'files' => 1, - 'size' => 100, - ], $size); - } - - /** - * @dataProvider filesystemProvider - */ - public function testSizeRecursive(LoopInterface $loop, FilesystemInterface $filesystem) - { - $contents = str_repeat('a', 100); - $path = $this->tmpDir . 'path'; - file_put_contents($path, $contents); - mkdir($this->tmpDir . 'subPath'); - file_put_contents($this->tmpDir . 'subPath/file', $contents); - $size = $this->await($filesystem->dir($this->tmpDir)->sizeRecursive(), $loop); - $this->assertSame([ - 'directories' => 1, - 'files' => 2, - 'size' => 200, - ], $size); - } - - /** - * @dataProvider filesystemProvider - */ - public function testCreate(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $this->await($filesystem->dir($dir)->createRecursive(), $loop); - $this->assertFileExists($dir); - $this->assertSame('0760', substr(sprintf('%o', fileperms($dir)), -4)); - } - - /** - * @dataProvider filesystemProvider - */ - public function testCreateRecursive(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'to' . DIRECTORY_SEPARATOR . 'reactphp' . DIRECTORY_SEPARATOR . 'filesystem'; - $this->await($filesystem->dir($dir)->createRecursive(), $loop); - $this->assertFileExists($dir); - } - - /** - * @dataProvider filesystemProvider - */ - public function testRemove(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - mkdir($dir); - $this->assertFileExists($dir); - $this->await($filesystem->dir($dir)->remove(), $loop); - $this->assertFileNotExists($dir); - } - - /** - * @dataProvider filesystemProvider - */ - public function testRemoveSubDir(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $subDir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'sub'; - mkdir($dir); - mkdir($subDir); - $this->assertFileExists($dir); - $this->assertFileExists($subDir); - $this->await($filesystem->dir($subDir)->remove(), $loop); - $this->assertFileExists($dir); - $this->assertFileNotExists($subDir); - } - - /** - * @dataProvider filesystemProvider - */ - public function testRemoveRecursive(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $subDir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'sub'; - mkdir($dir); - mkdir($subDir); - $this->assertFileExists($dir); - $this->assertFileExists($subDir); - $this->await($filesystem->dir($dir)->removeRecursive(), $loop); - $this->assertFileNotExists($subDir); - $this->assertFileNotExists($dir); - } - - /** - * @dataProvider filesystemProvider - * @group permissions - */ - public function testChmod(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $subDir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'sub'; - mkdir($dir); - mkdir($subDir); - chmod($dir, 0777); - chmod($subDir, 0777); - $this->assertFileExists($dir); - $this->assertFileExists($subDir); - $this->assertSame('0777', substr(sprintf('%o', fileperms($dir)), -4)); - $this->assertSame('0777', substr(sprintf('%o', fileperms($subDir)), -4)); - clearstatcache(); - $this->await($filesystem->dir($dir)->chmod(0555), $loop); - clearstatcache(); - $this->assertSame('0555', substr(sprintf('%o', fileperms($dir)), -4)); - $this->assertSame('0777', substr(sprintf('%o', fileperms($subDir)), -4)); - clearstatcache(); - } - - /** - * @dataProvider filesystemProvider - * @group permissions - */ - public function testChmodRecursive(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $subDir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'sub'; - mkdir($dir); - mkdir($subDir); - chmod($dir, 0777); - chmod($subDir, 0777); - $this->assertFileExists($dir); - $this->assertFileExists($subDir); - $this->assertSame('0777', substr(sprintf('%o', fileperms($dir)), -4)); - $this->assertSame('0777', substr(sprintf('%o', fileperms($subDir)), -4)); - clearstatcache(); - $this->await($filesystem->dir($dir)->chmodRecursive(0555), $loop); - clearstatcache(); - $this->assertSame('0555', substr(sprintf('%o', fileperms($dir)), -4)); - $this->assertSame('0555', substr(sprintf('%o', fileperms($subDir)), -4)); - clearstatcache(); - } - - /** - * @dataProvider filesystemProvider - * @group permissions - */ - public function testChown(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $subDir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'sub'; - mkdir($dir, 0777); - mkdir($subDir, 0777); - clearstatcache(); - $this->assertFileExists($dir); - $this->assertFileExists($subDir); - clearstatcache(); - $stat = stat($dir); - sleep(2); - $this->await($filesystem->dir($dir)->chown($stat['uid'], getmyuid()), $loop, 5); - clearstatcache(); - $this->assertNotSame($stat, stat($dir)); - clearstatcache(); - } - - /** - * @dataProvider filesystemProvider - * @group permissions - */ - public function testChownRecursive(LoopInterface $loop, FilesystemInterface $filesystem) - { - $dir = $this->tmpDir . 'path'; - $subDir = $this->tmpDir . 'path' . DIRECTORY_SEPARATOR . 'sub'; - mkdir($dir, 0777); - mkdir($subDir, 0777); - $this->assertFileExists($dir); - $this->assertFileExists($subDir); - clearstatcache(); - $stat = stat($dir); - $subStat = stat($subDir); - sleep(2); - $this->await($filesystem->dir($dir)->chownRecursive(-1, getmyuid()), $loop); - clearstatcache(); - $this->assertNotSame($stat, stat($dir)); - $this->assertNotSame($subStat, stat($subDir)); - clearstatcache(); - } -} diff --git a/tests/Adapters/FileTest.php b/tests/Adapters/FileTest.php deleted file mode 100644 index 754ee463..00000000 --- a/tests/Adapters/FileTest.php +++ /dev/null @@ -1,280 +0,0 @@ -await($filesystem->file(__FILE__)->stat(), $loop); - foreach ($actualStat as $key => $value) { - if (!is_string($key) || in_array($key, ['atime', 'mtime', 'ctime'])) { - continue; - } - - $this->assertSame($actualStat[$key], $result[$key]); - } - - $this->assertInstanceOf('DateTime', $result['atime']); - $this->assertEquals($actualStat['atime'], $result['atime']->format('U')); - $this->assertInstanceOf('DateTime', $result['mtime']); - $this->assertEquals($actualStat['mtime'], $result['mtime']->format('U')); - $this->assertInstanceOf('DateTime', $result['atime']); - $this->assertEquals($actualStat['ctime'], $result['ctime']->format('U')); - } - - /** - * @dataProvider filesystemProvider - */ - public function testTime(LoopInterface $loop, FilesystemInterface $filesystem) - { - $actualStat = lstat(__FILE__); - $result = $this->await($filesystem->file(__FILE__)->time(), $loop); - $this->assertCount(3, $result); - $this->assertInstanceOf('DateTime', $result['atime']); - $this->assertEquals($actualStat['atime'], $result['atime']->format('U')); - $this->assertInstanceOf('DateTime', $result['mtime']); - $this->assertEquals($actualStat['mtime'], $result['mtime']->format('U')); - $this->assertInstanceOf('DateTime', $result['atime']); - $this->assertEquals($actualStat['ctime'], $result['ctime']->format('U')); - } - - /** - * @dataProvider filesystemProvider - */ - public function testSize(LoopInterface $loop, FilesystemInterface $filesystem) - { - $actualStat = lstat(__FILE__); - $result = $this->await($filesystem->file(__FILE__)->size(), $loop); - $this->assertEquals($actualStat['size'], $result); - } - - /** - * @dataProvider filesystemProvider - */ - public function testExists(LoopInterface $loop, FilesystemInterface $filesystem) - { - $result = true; - try { - $this->await($filesystem->file(__FILE__)->exists(), $loop); - } catch (\Exception $e) { - $result = false; - } - $this->assertTrue($result); - } - - /** - * @dataProvider filesystemProvider - */ - public function testDoesntExist(LoopInterface $loop, FilesystemInterface $filesystem) - { - $this->setLoopTimeout($loop); - $rejectionReason = null; - - try { - $this->await($filesystem->file(__FILE__ . '.' . time())->stat(), $loop); - } catch (\Exception $e) { - $rejectionReason = $e->getMessage(); - } - - $this->assertTrue( - $rejectionReason === 'Path doesn\'t exist' || - $rejectionReason === 'No such file or directory' - ); - } - - /** - * @dataProvider filesystemProvider - */ - public function testRemove(LoopInterface $loop, FilesystemInterface $filesystem) - { - $tempFile = $this->tmpDir . uniqid('', true); - touch($tempFile); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFile)); - $this->await($filesystem->file($tempFile)->remove(), $loop); - $this->assertFileNotExists($tempFile); - } - - /** - * @dataProvider filesystemProvider - */ - public function testCreate(LoopInterface $loop, FilesystemInterface $filesystem) - { - $tempFile = $this->tmpDir . uniqid('', true); - $this->assertFileNotExists($tempFile); - $this->await($filesystem->file($tempFile)->create(), $loop); - $this->assertFileExists($tempFile); - $this->assertSame('0760', substr(sprintf('%o', fileperms($tempFile)), -4)); - } - - /** - * @dataProvider filesystemProvider - */ - public function testTouch(LoopInterface $loop, FilesystemInterface $filesystem) - { - $tempFile = $this->tmpDir . uniqid('', true); - $this->assertFileNotExists($tempFile); - $this->await($filesystem->file($tempFile)->touch(), $loop); - $this->assertFileExists($tempFile); - } - - /** - * @dataProvider filesystemProvider - */ - public function testGetContents(LoopInterface $loop, FilesystemInterface $filesystem) - { - $tempFile = $this->tmpDir . uniqid('', true); - $contents = str_pad('a', 1024*512); - file_put_contents($tempFile, $contents); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFile)); - $this->assertFileExists($tempFile); - $fileContents = $this->await($filesystem->file($tempFile)->getContents(), $loop); - $this->assertSame($contents, $fileContents); - } - - /** - * @dataProvider filesystemProvider - */ - public function testGetBinaryContents(LoopInterface $loop, FilesystemInterface $filesystem) - { - $file = __DIR__ . DIRECTORY_SEPARATOR . 'reactphp-logo.png'; - $this->assertFileExists($file); - $fileContents = $this->await($filesystem->file($file)->getContents(), $loop); - $this->assertSame(file_get_contents($file), $fileContents); - } - - /** - * @dataProvider filesystemProvider - */ - public function testCopy(LoopInterface $loop, FilesystemInterface $filesystem) - { - $tempFileSource = $this->tmpDir . uniqid('source', true); - $tempFileDestination = $this->tmpDir . uniqid('destination', true); - $contents = str_pad('a', 33, 'b'); - file_put_contents($tempFileSource, $contents); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFileSource)); - $this->assertFileExists($tempFileSource); - $this->assertSame($contents, file_get_contents($tempFileSource)); - $this->await($filesystem->file($tempFileSource)->copy($filesystem->file($tempFileDestination)), $loop); - $this->assertFileEquals($tempFileSource, $tempFileDestination); - } - - /** - * @dataProvider filesystemProvider - */ - public function testCopyToDirectory(LoopInterface $loop, FilesystemInterface $filesystem) - { - $filename = uniqid('source', true); - $tempFileSource = $this->tmpDir . $filename; - $tempFileDestination = $this->tmpDir . uniqid('destination', true) . DIRECTORY_SEPARATOR; - $contents = str_pad('a', 33, 'b'); - file_put_contents($tempFileSource, $contents); - mkdir($tempFileDestination); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFileSource) && !file_exists($tempFileDestination)); - $this->assertFileExists($tempFileSource); - $this->assertSame($contents, file_get_contents($tempFileSource)); - $this->await($filesystem->file($tempFileSource)->copy($filesystem->dir($tempFileDestination)), $loop); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFileDestination . $filename) || stat($tempFileDestination . $filename)['size'] == 0); - $this->assertFileEquals($tempFileSource, $tempFileDestination . $filename); - } - - /** - * @dataProvider filesystemProvider - * @group permissions - */ - public function testChmod(LoopInterface $loop, FilesystemInterface $filesystem) - { - $filename = uniqid('', true); - $tempFile = $this->tmpDir . $filename; - touch($tempFile); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFile)); - chmod($tempFile, 0777); - $this->await($filesystem->file($tempFile)->chmod(0666), $loop); - $this->assertSame('0666', substr(sprintf('%o', fileperms($tempFile)), -4)); - } - - /** - * @dataProvider filesystemProvider - * @group permissions - */ - public function testChownUid(LoopInterface $loop, FilesystemInterface $filesystem) - { - $filename = uniqid('', true); - $tempFile = $this->tmpDir . $filename; - touch($tempFile); - do { - usleep(500); - $this->checkIfTimedOut(); - } while (!file_exists($tempFile)); - $this->await($filesystem->file($tempFile)->chown(1000), $loop); - $this->assertSame(1000, fileowner($tempFile)); - } - - /** - * @dataProvider filesystemProvider - */ - public function testRename(LoopInterface $loop, FilesystemInterface $filesystem) - { - $filenameFrom = uniqid('', true); - $tempFileFrom = $this->tmpDir . $filenameFrom; - file_put_contents($tempFileFrom, $filenameFrom); - $filenameTo = uniqid('', true); - $tempFileTo = $this->tmpDir . $filenameTo; - $this->await($filesystem->file($tempFileFrom)->rename($tempFileTo), $loop); - $this->assertFileExists($tempFileTo); - $this->assertSame($filenameFrom, file_get_contents($tempFileTo)); - } - - /** - * @dataProvider filesystemProvider - */ - public function testPutContents(LoopInterface $loop, FilesystemInterface $filesystem) - { - $contents = str_repeat('abc', 1024 * 1024 * 5); - $filename = uniqid('', true); - $tempFile = $this->tmpDir . $filename; - $this->await($filesystem->file($tempFile)->putContents($contents), $loop); - $this->assertFileExists($tempFile); - $this->assertSame($contents, file_get_contents($tempFile)); - } - /** - * @dataProvider filesystemProvider - */ - public function testPutBinaryContents(LoopInterface $loop, FilesystemInterface $filesystem) - { - $contents = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'reactphp-logo.png'); - $filename = uniqid('', true); - $tempFile = $this->tmpDir . $filename; - $this->await($filesystem->file($tempFile)->putContents($contents), $loop); - $this->assertFileExists($tempFile); - $this->assertSame($contents, file_get_contents($tempFile)); - } -} diff --git a/tests/Adapters/InterfaceTest.php b/tests/Adapters/InterfaceTest.php deleted file mode 100644 index 04ac3ffb..00000000 --- a/tests/Adapters/InterfaceTest.php +++ /dev/null @@ -1,25 +0,0 @@ -assertInstanceOf('React\Filesystem\AdapterInterface', $adapter); - } - - /** - * @dataProvider adapterProvider - */ - public function testLoop(LoopInterface $loop, AdapterInterface $adapter) - { - $this->assertInstanceOf('React\EventLoop\LoopInterface', $adapter->getLoop()); - } -} diff --git a/tests/Adapters/reactphp-logo.png b/tests/Adapters/reactphp-logo.png deleted file mode 100644 index 001a8c8d..00000000 Binary files a/tests/Adapters/reactphp-logo.png and /dev/null differ diff --git a/tests/ChildProcess/AdapterTest.php b/tests/ChildProcess/AdapterTest.php deleted file mode 100644 index 98b4a498..00000000 --- a/tests/ChildProcess/AdapterTest.php +++ /dev/null @@ -1,374 +0,0 @@ -assertInstanceOf( - 'React\Filesystem\AdapterInterface', - new Adapter($this->getMock('React\EventLoop\LoopInterface'), [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ]) - ); - } - - public function testGetLoop() - { - $loop = $this->getMock('React\EventLoop\LoopInterface'); - $filesystem = new Adapter($loop, [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ]); - $this->assertSame($loop, $filesystem->getLoop()); - } - - public function testGetSetFilesystem() - { - $loop = $this->getMock('React\EventLoop\LoopInterface'); - $filesystem = new Adapter($loop, [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ]); - - $this->assertNull($filesystem->getFilesystem()); - $fs = \React\Filesystem\Filesystem::createFromAdapter($this->mockAdapter()); - $filesystem->setFilesystem($fs); - - $this->assertSame($fs, $filesystem->getFilesystem()); - } - - public function callFilesystemProvider() - { - return [ - [ - 'mkdir', - [ - 'foo.bar', - ], - [ - 'mkdir', - [ - 'path' => 'foo.bar', - 'mode' => '760', - ], - ], - ], - [ - 'mkdir', - [ - 'foo.bar', - 'rwxrwxrwx', - ], - [ - 'mkdir', - [ - 'path' => 'foo.bar', - 'mode' => '777', - ], - ], - ], - [ - 'rmdir', - [ - 'foo.bar', - ], - [ - 'rmdir', - [ - 'path' => 'foo.bar', - ], - ], - ], - [ - 'unlink', - [ - 'foo.bar', - ], - [ - 'unlink', - [ - 'path' => 'foo.bar', - ], - ], - ], - [ - 'touch', - [ - 'foo.bar', - ], - [ - 'touch', - [ - 'path' => 'foo.bar', - 'mode' => '760', - ], - ], - ], - [ - 'rename', - [ - 'foo.bar', - 'bar.foo', - ], - [ - 'rename', - [ - 'from' => 'foo.bar', - 'to' => 'bar.foo', - ], - ], - ], - [ - 'chown', - [ - 'foo.bar', - 0, - 2, - ], - [ - 'chown', - [ - 'path' => 'foo.bar', - 'uid' => 0, - 'gid' => 2, - ], - ], - ], - [ - 'chmod', - [ - 'foo.bar', - 0123, - ], - [ - 'chmod', - [ - 'path' => 'foo.bar', - 'mode' => '123', - ], - ], - ], - [ - 'readlink', - [ - 'foo.bar', - ], - [ - 'readlink', - [ - 'path' => 'foo.bar', - ], - ], - ], - [ - 'stat', - [ - 'foo.bar', - ], - [ - 'stat', - [ - 'path' => 'foo.bar', - ], - ], - ], - [ - 'symlink', - [ - 'foo.bar', - 'bar.foo', - ], - [ - 'symlink', - [ - 'from' => 'foo.bar', - 'to' => 'bar.foo', - ], - ], - ], - ]; - } - - /** - * @dataProvider callFilesystemProvider - */ - public function testCallFilesystem($method, $arguments, $mockArguments) - { - $loop = $this->getMock('React\EventLoop\LoopInterface'); - $filesystem = new Adapter($loop, [ - 'pool' => [ - 'class' => 'React\Tests\Filesystem\ChildProcess\SingletonPoolStub', - ], - ]); - - call_user_func_array([$filesystem, $method], $arguments); - - $calls = SingletonPoolStub::getCalls(); - self::assertCount(1, $calls); - /** @var array $call */ - $call = $calls[0][1][0]->jsonSerialize(); - self::assertSame($mockArguments[0], $call['target']); - self::assertSame($mockArguments[1], $call['payload']->getPayload()); - } - - public function testLs() - { - $loop = \React\EventLoop\Factory::create(); - $adapter = new Adapter($loop, [ - 'pool' => [ - 'class' => 'React\Tests\Filesystem\ChildProcess\SingletonPoolStub', - ], - ]); - - $deferred = new Deferred(); - SingletonPoolStub::setRpcResponse($deferred->promise()); - - $fs = Filesystem::createFromAdapter($adapter); - - $promise = $adapter->ls('foo.bar'); - $this->assertInstanceOf('React\Promise\PromiseInterface', $promise); - $deferred->resolve(new Payload([ - [ - 'type' => 'file', - 'name' => 'bar.foo', - ], - ])); - - $nodes = $this->await($promise, $loop); - - $calls = SingletonPoolStub::getCalls(); - self::assertCount(1, $calls); - /** @var array $call */ - $call = $calls[0][1][0]->jsonSerialize(); - self::assertSame('readdir', $call['target']); - self::assertSame([ - 'path' => 'foo.bar', - 'flags' => 2, - ], $call['payload']->getPayload()); - - $this->assertEquals(new File('foo.bar/bar.foo', $fs), reset($nodes)); - } - - public function testLsStream() - { - $loop = $this->getMock('React\EventLoop\LoopInterface'); - $adapter = new Adapter($loop, [ - 'pool' => [ - 'class' => 'React\Tests\Filesystem\ChildProcess\SingletonPoolStub', - ], - ]); - - $deferred = new Deferred(); - SingletonPoolStub::setRpcResponse($deferred->promise()); - - Filesystem::createFromAdapter($adapter); - - $stream = $adapter->lsStream('foo.bar'); - $this->assertInstanceOf('React\Filesystem\ObjectStream', $stream); - - $calledOnData = false; - $stream->on('data', function (NodeInterface $file) use (&$calledOnData) { - $this->assertInstanceOf('React\Filesystem\Node\File', $file); - $this->assertSame('foo.bar/bar.foo', $file->getPath()); - $calledOnData = true; - }); - - $deferred->resolve(new Payload([ - [ - 'type' => 'file', - 'name' => 'bar.foo', - ], - ])); - - $calls = SingletonPoolStub::getCalls(); - self::assertCount(1, $calls); - /** @var array $call */ - $call = $calls[0][1][0]->jsonSerialize(); - self::assertSame('readdir', $call['target']); - self::assertSame([ - 'path' => 'foo.bar', - 'flags' => 2, - ], $call['payload']->getPayload()); - - $this->assertTrue($calledOnData); - } - - public function testErrorFromPool() - { - $this->setExpectedException('\Exception', 'oops'); - - $loop = Factory::create(); - $adapter = new Adapter($loop, [ - 'pool' => [ - 'class' => 'React\Tests\Filesystem\ChildProcess\PoolRpcErrorMockFactory', - ], - ]); - $this->await($adapter->touch('foo.bar'), $loop, 1); - } - - public function testGetContents() - { - $loop = \React\EventLoop\Factory::create(); - $adapter = new Adapter($loop); - - $contents = $this->await($adapter->getContents(__FILE__), $loop); - $this->assertSame(file_get_contents(__FILE__), $contents); - } - - public function testGetContentsMinMax() - { - $loop = \React\EventLoop\Factory::create(); - $adapter = new Adapter($loop); - - $contents = $this->await($adapter->getContents(__FILE__, 5, 10), $loop); - $this->assertSame(file_get_contents(__FILE__, false, null, 5, 10), $contents); - } - - public function testPutContents() - { - $loop = \React\EventLoop\Factory::create(); - $adapter = new Adapter($loop); - - $tempFile = $this->tmpDir . uniqid('', true); - $contents = sha1_file(__FILE__); - - $this->await($adapter->putContents($tempFile, $contents), $loop); - $this->assertSame($contents, file_get_contents($tempFile)); - } - - public function testAppendContents() - { - $loop = \React\EventLoop\Factory::create(); - $adapter = new Adapter($loop); - - $tempFile = $this->tmpDir . uniqid('', true); - $contents = sha1_file(__FILE__); - - file_put_contents($tempFile, $contents); - $time = sha1(time()); - $contents .= $time; - - $this->await($adapter->appendContents($tempFile, $time, FILE_APPEND), $loop); - $this->assertSame($contents, file_get_contents($tempFile)); - } -} diff --git a/tests/ChildProcess/PoolRpcErrorMock.php b/tests/ChildProcess/PoolRpcErrorMock.php deleted file mode 100644 index d029a836..00000000 --- a/tests/ChildProcess/PoolRpcErrorMock.php +++ /dev/null @@ -1,44 +0,0 @@ - [ - 'message' => 'oops', - ], - ]); - } - - public function message(Message $message) - { - return new FulfilledPromise(); - } - - public function terminate(Message $message, $timeout = 5, $signal = null) - { - return new FulfilledPromise(); - } - - public function info() - { - return []; - } -} diff --git a/tests/ChildProcess/PoolRpcErrorMockFactory.php b/tests/ChildProcess/PoolRpcErrorMockFactory.php deleted file mode 100644 index 4ff77615..00000000 --- a/tests/ChildProcess/PoolRpcErrorMockFactory.php +++ /dev/null @@ -1,32 +0,0 @@ -getMockBuilder('WyriHaximus\React\ChildProcess\Messenger\Messenger') - ->disableOriginalConstructor() - ->getMock() - ; - - $messenger - ->expects($this->atLeastOnce()) - ->method('registerRpc') - ; - - new Process($messenger); - } - - public function testStat() - { - - $messenger = $this->getMockBuilder('WyriHaximus\React\ChildProcess\Messenger\Messenger') - ->disableOriginalConstructor() - ->getMock() - ; - - $resultCallbackRan = false; - (new Process($messenger))->stat([ - 'path' => __FILE__, - ])->then(function ($result) use (&$resultCallbackRan) { - foreach ([ - 'dev', - 'ino', - 'mode', - 'nlink', - 'uid', - 'size', - 'gid', - 'rdev', - 'blksize', - 'blocks', - 'atime', - 'mtime', - 'ctime', - ] as $item) { - $this->assertArrayHasKey($item, $result); - } - $resultCallbackRan = true; - }); - $this->assertTrue($resultCallbackRan); - } -} diff --git a/tests/ChildProcess/SingletonPoolStub.php b/tests/ChildProcess/SingletonPoolStub.php deleted file mode 100644 index 1cf7c022..00000000 --- a/tests/ChildProcess/SingletonPoolStub.php +++ /dev/null @@ -1,80 +0,0 @@ -await($filesystem->detect(__DIR__)->then(static function (DirectoryInterface $directory): PromiseInterface { + return $directory->stat(); + })); + + self::assertInstanceOf(Stat::class, $stat); + self::assertSame(stat(__DIR__)['size'], $stat->size()); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function ls(AdapterInterface $filesystem): void + { + $expectedListing = []; + + $d = dir(__DIR__); + while (false !== ($entry = $d->read())) { + if ($entry === '.' || $entry === '..') { + continue; + } + + $expectedListing[__DIR__ . DIRECTORY_SEPARATOR . $entry] = is_file(__DIR__ . DIRECTORY_SEPARATOR . $entry) ? FileInterface::class : DirectoryInterface::class; + } + $d->close(); + + ksort($expectedListing); + + $directoryListing = $this->await($filesystem->detect(__DIR__)->then(static function (DirectoryInterface $directory): PromiseInterface { + return $directory->ls(); + })); + + $listing = []; + foreach ($directoryListing as $node) { + $listing[$node->path() . $node->name()] = $node instanceof FileInterface ? FileInterface::class : DirectoryInterface::class; + } + ksort($listing); + + self::assertSame($expectedListing, $listing); + } +} diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php new file mode 100644 index 00000000..a87fd0e0 --- /dev/null +++ b/tests/FactoryTest.php @@ -0,0 +1,24 @@ +await(Factory::create()->detect(__FILE__)); + + self::assertInstanceOf(FileInterface::class, $node); + } +} diff --git a/tests/FileTest.php b/tests/FileTest.php new file mode 100644 index 00000000..438b62fa --- /dev/null +++ b/tests/FileTest.php @@ -0,0 +1,276 @@ +await($filesystem->detect(__FILE__)->then(static function (FileInterface $file): PromiseInterface { + return $file->stat(); + })); + + self::assertInstanceOf(Stat::class, $stat); + self::assertSame(filesize(__FILE__), $stat->size()); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function getContents(AdapterInterface $filesystem): void + { + $fileContents = $this->await($filesystem->detect(__FILE__)->then(static function (FileInterface $file): PromiseInterface { + return $file->getContents(); + })); + + self::assertSame(file_get_contents(__FILE__), $fileContents); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function getContents34and5thCharacterFromFile(AdapterInterface $filesystem): void + { + $directoryName = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(13)) . DIRECTORY_SEPARATOR; + $fileName = $directoryName . bin2hex(random_bytes(13)); + mkdir($directoryName); + \file_put_contents($fileName, 'abcdefghijklmnopqrstuvwxyz'); + $fileContents = $this->await($filesystem->detect($fileName)->then(static function (FileInterface $file): PromiseInterface { + return $file->getContents(3, 3); + })); + + self::assertSame('def', $fileContents); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContents(AdapterInterface $filesystem): void + { + $fileName = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(13)) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(9)); + $fileContents = bin2hex(random_bytes(128)); + + $writtenLength = $this->await($filesystem->detect($fileName)->then(static fn (NotExistInterface $notExist): PromiseInterface => $notExist->createFile())->then(function (FileInterface $file) use ($fileContents): PromiseInterface { + return $file->putContents($fileContents); + })); + + self::assertSame($writtenLength, strlen(file_get_contents($fileName))); + self::assertSame($fileContents, file_get_contents($fileName)); + + unlink($fileName); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContentsMultipleBigFiles(AdapterInterface $filesystem): void + { + $directoryName = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(13)) . DIRECTORY_SEPARATOR; + $this->await($filesystem->detect($directoryName)->then(static fn(NotExistInterface $notExist): PromiseInterface => $notExist->createDirectory())); + $fileNames = []; + $fileContents = []; + for ($i = 0; $i < 25; $i++) { + $fileNames[] = $directoryName . bin2hex(random_bytes(13)); + } + foreach ($fileNames as $fileName) { + $fileContents[$fileName] = bin2hex(random_bytes(4096)); + touch($fileName); + } + + $promises = []; + foreach ($fileContents as $fileName => $fileContent) { + $promises[$fileName] = $filesystem->detect($fileName)->then(static function (FileInterface $file) use ($fileContent): PromiseInterface { + return $file->putContents($fileContent); + }); + } + + $writtenLengths = $this->await(all($promises)); + + foreach ($writtenLengths as $fileName => $writtenLength) { + self::assertSame($writtenLength, strlen(file_get_contents($fileName))); + self::assertSame($fileContents[$fileName], file_get_contents($fileName)); + unlink($fileName); + } + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContentsAppend(AdapterInterface $filesystem): void + { + $fileName = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(13)) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(9)); + $fileContentsFirst = bin2hex(random_bytes(128)); + $fileContentsSecond = bin2hex(random_bytes(128)); + $writtenLengthFirst = $this->await($filesystem->detect($fileName)->then(static fn (NotExistInterface $notExist): PromiseInterface => $notExist->createFile())->then(static function (FileInterface $file) use ($fileContentsFirst): PromiseInterface { + return $file->putContents($fileContentsFirst); + })); + + self::assertSame($writtenLengthFirst, strlen(file_get_contents($fileName))); + self::assertSame($fileContentsFirst, file_get_contents($fileName)); + + $writtenLengthSecond = $this->await($filesystem->detect($fileName)->then(static function (FileInterface $file) use ($fileContentsSecond): PromiseInterface { + return $file->putContents($fileContentsSecond, \FILE_APPEND); + })); + + self::assertSame($writtenLengthFirst + $writtenLengthSecond, strlen(file_get_contents($fileName))); + self::assertSame($fileContentsFirst . $fileContentsSecond, file_get_contents($fileName)); + + unlink($fileName); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContentsAppendBigFile(AdapterInterface $filesystem): void + { + $fileName = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(13)) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(9)); + $this->await($filesystem->detect($fileName)->then(static fn(NotExistInterface $notExist): PromiseInterface => $notExist->createFile())); + + $fileContents = []; + $writtenLength = 0; + for ($i = 0; $i < 13; $i++) { + $fileContents[] = bin2hex(random_bytes(4096)); + } + + foreach ($fileContents as $fileContent) { + $writtenLength += $this->await($filesystem->detect($fileName)->then(static function (FileInterface $file) use ($fileContent): PromiseInterface { + return $file->putContents($fileContent, \FILE_APPEND); + })); + } + + self::assertSame($writtenLength, strlen(file_get_contents($fileName))); + self::assertSame(implode('', $fileContents), file_get_contents($fileName)); + + unlink($fileName); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContentsAppendMultipleBigFiles(AdapterInterface $filesystem): void + { + $this->runMultipleFilesTests($filesystem, 8, 4096, 4); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContentsAppendLotsOfSmallFiles(AdapterInterface $filesystem): void + { + $this->runMultipleFilesTests($filesystem, 16, 16, 4); + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function putContentsAppendLoadsOfSmallFiles(AdapterInterface $filesystem): void + { + $this->runMultipleFilesTests($filesystem, 32, 8, 8); + } + + public function runMultipleFilesTests(AdapterInterface $filesystem, int $fileCount, int $fileSize, int $chunkCount): void + { + $directoryName = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(13)) . DIRECTORY_SEPARATOR; + mkdir($directoryName, 0777, true); + $fileNames = []; + $fileContents = []; + for ($i = 0; $i < $fileCount; $i++) { + $fileNames[] = $directoryName . bin2hex(random_bytes(13)); + } + foreach ($fileNames as $fileName) { + $fileContents[$fileName] = []; + touch($fileName); + } + + foreach ($fileNames as $fileName) { + for ($i = 0; $i < $chunkCount; $i++) { + $fileContents[$fileName][] = bin2hex(random_bytes($fileSize)); + } + } + + $promises = []; + foreach ($fileContents as $fileName => $fileContent) { + $queue = new \SplQueue(); + foreach ($fileContent as $chunk) { + $queue->enqueue($chunk); + } + $promises[$fileName] = $filesystem->detect($fileName)->then(static function (FileInterface $file) use ($queue): PromiseInterface { + return new Promise(function (callable $resolve, callable $reject) use ($queue, $file): void { + $bytesWritten = 0; + $writeFunction = function () use (&$writeFunction, &$bytesWritten, $queue, $file, $resolve, $reject) { + if ($queue->count() > 0) { + $file->putContents($queue->dequeue(), \FILE_APPEND)->then(function (int $writtenBytes) use (&$writeFunction, &$bytesWritten): void { + $bytesWritten += $writtenBytes; + $writeFunction(); + }, $reject); + return; + } + + $resolve($bytesWritten); + }; + $writeFunction(); + }); + }); + } + + $writtenLengths = $this->await(all($promises)); + + foreach ($writtenLengths as $fileName => $writtenLength) { + self::assertSame($writtenLength, strlen(file_get_contents($fileName))); + self::assertSame(implode('', $fileContents[$fileName]), file_get_contents($fileName)); + unlink($fileName); + } + } + + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function unlink(AdapterInterface $filesystem): void + { + $fileName = __FILE__ . '.' . time(); + $fileContents = bin2hex(random_bytes(2048)); + file_put_contents($fileName, $fileContents); + self::assertFileExists($fileName); + $this->await($filesystem->detect($fileName)->then(static function (FileInterface $file): PromiseInterface { + return $file->unlink(); + })); + + + self::assertFileDoesNotExist($fileName); + } +} diff --git a/tests/FilesystemTest.php b/tests/FilesystemTest.php index 5a7ea944..fb91c620 100644 --- a/tests/FilesystemTest.php +++ b/tests/FilesystemTest.php @@ -2,84 +2,48 @@ namespace React\Tests\Filesystem; -use React\Filesystem\Filesystem; -use React\Promise\FulfilledPromise; -use React\Promise\RejectedPromise; +use React\EventLoop\LoopInterface; +use React\Filesystem\AdapterInterface; +use React\Filesystem\Node\DirectoryInterface; +use React\Filesystem\Node\FileInterface; +use React\Filesystem\Node\NotExistInterface; +use function Clue\React\Block\await; -class FilesystemTest extends TestCase +final class FilesystemTest extends AbstractFilesystemTestCase { - public function testCreate() + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function file(AdapterInterface $filesystem): void { - $this->assertInstanceOf( - 'React\Filesystem\Filesystem', - Filesystem::create($this->getMock('React\EventLoop\LoopInterface'), [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ]) - ); - } - public function testCreateWithAdapter() - { - $this->assertInstanceOf( - 'React\Filesystem\Filesystem', - Filesystem::createFromAdapter($this->mockAdapter()) - ); - } + $node = $this->await($filesystem->detect(__FILE__)); - public function testFactory() - { - try { - $this->assertInstanceOf('React\Filesystem\Filesystem', Filesystem::create(null, [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ])); - } catch (\PHPUnit_Framework_Error $typeError) { - $this->assertTrue(true); - } catch (\TypeError $typeError) { - $this->assertTrue(true); - } + self::assertInstanceOf(FileInterface::class, $node); } - public function testFile() + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function directory(AdapterInterface $filesystem): void { - $file = Filesystem::create($this->getMock('React\EventLoop\LoopInterface'), [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ])->file('foo.bar'); - $this->assertInstanceOf('React\Filesystem\Node\File', $file); - $this->assertInstanceOf('React\Filesystem\Node\GenericOperationInterface', $file); - } + $node = $this->await($filesystem->detect(__DIR__)); - public function testDir() - { - $directory = Filesystem::create($this->getMock('React\EventLoop\LoopInterface'), [ - 'pool' => [ - 'class' => 'WyriHaximus\React\ChildProcess\Pool\Pool\Dummy', - ], - ])->dir('foo.bar'); - $this->assertInstanceOf('React\Filesystem\Node\Directory', $directory); - $this->assertInstanceOf('React\Filesystem\Node\GenericOperationInterface', $directory); + self::assertInstanceOf(DirectoryInterface::class, $node); } - public function testGetContents() + /** + * @test + * + * @dataProvider provideFilesystems + */ + public function notExists(AdapterInterface $filesystem): void { - $adapter = $this->mockAdapter(); - $adapter - ->expects($this->any()) - ->method('stat') - ->will($this->returnValue(new FulfilledPromise([]))) - ; - $adapter - ->expects($this->any()) - ->method('open') - ->will($this->returnValue(new RejectedPromise())) - ; - $this->assertInstanceOf( - 'React\Promise\PromiseInterface', - Filesystem::createFromAdapter($adapter)->getContents('foo.bar') - ); + $node = $this->await($filesystem->detect(bin2hex(random_bytes(13)))); + + self::assertInstanceOf(NotExistInterface::class, $node); } } diff --git a/tests/FlagResolverTest.php b/tests/FlagResolverTest.php deleted file mode 100644 index 9d4b03ab..00000000 --- a/tests/FlagResolverTest.php +++ /dev/null @@ -1,35 +0,0 @@ -getMock('React\Filesystem\FlagResolver', [ - 'defaultFlags', - 'flagMapping', - ]); - - $resolver - ->expects($this->once()) - ->method('defaultFlags') - ->with() - ->will($this->returnValue(0)) - ; - - $resolver - ->expects($this->once()) - ->method('flagMapping') - ->with() - ->will($this->returnValue([ - 'b' => 1, - 'a' => 2, - 'r' => 4, - ])) - ; - - $this->assertSame(7, $resolver->resolve('bar')); - } -} diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php deleted file mode 100644 index f1abbd3d..00000000 --- a/tests/FunctionsTest.php +++ /dev/null @@ -1,20 +0,0 @@ -assertSame($limit, \React\Filesystem\getOpenFileLimit([ - 'open_file_limit' => $limit, - ])); - } - public function testGetOpenFileLimitFallback() - { - $this->assertSame(OpenFileLimiter::DEFAULT_LIMIT, \React\Filesystem\getOpenFileLimit([])); - } -} diff --git a/tests/ModeTypeDetectorTest.php b/tests/ModeTypeDetectorTest.php deleted file mode 100644 index b8f1e497..00000000 --- a/tests/ModeTypeDetectorTest.php +++ /dev/null @@ -1,79 +0,0 @@ -mockAdapter(); - $adapter - ->expects($this->any()) - ->method('stat') - ->with('foo.bar') - ->will($this->returnValue(new FulfilledPromise([ - 'mode' => $mode, - ]))) - ; - $filesystem = Filesystem::createFromAdapter($adapter); - (new ModeTypeDetector($filesystem))->detect([ - 'path' => 'foo.bar', - ])->then(function ($result) use ($filesystem, $method, &$callbackFired) { - $this->assertSame([ - $filesystem, - $method, - ], $result); - $callbackFired = true; - }); - - $this->assertTrue($callbackFired); - } - - public function testDetectUnknown() - { - $callbackFired = false; - - $adapter = $this->mockAdapter(); - $adapter - ->expects($this->any()) - ->method('stat') - ->with('foo.bar') - ->will($this->returnValue(new FulfilledPromise([ - 'mode' => 0x3000, - ]))) - ; - $filesystem = Filesystem::createFromAdapter($adapter); - (new ModeTypeDetector($filesystem))->detect([ - 'path' => 'foo.bar', - ])->otherwise(function ($result) use (&$callbackFired) { - $this->assertInstanceOf('Exception', $result); - $callbackFired = true; - }); - - $this->assertTrue($callbackFired); - } -} diff --git a/tests/Node/DirectoryTest.php b/tests/Node/DirectoryTest.php deleted file mode 100644 index 34a8c8a4..00000000 --- a/tests/Node/DirectoryTest.php +++ /dev/null @@ -1,405 +0,0 @@ -assertSame($path . NodeInterface::DS, (new Directory($path, Filesystem::createFromAdapter($this->mockAdapter())))->getPath()); - } - - public function testLs() - { - $path = '/home/foo/bar'; - $loop = $this->getMock('React\EventLoop\LoopInterface'); - - $filesystem = $this->mockAdapter($loop); - - $ls = \React\Promise\resolve(); - - $filesystem - ->expects($this->once()) - ->method('ls') - ->with() - ->will($this->returnValue($ls)) - ; - - $directory = new Directory($path, Filesystem::createFromAdapter($filesystem)); - - $this->assertInstanceOf('React\Promise\PromiseInterface', $directory->ls()); - } - - public function testLsStream() - { - $path = '/home/foo/bar'; - $loop = $this->getMock('React\EventLoop\LoopInterface'); - - $filesystem = $this->mockAdapter($loop); - - $lsStream = $this->getMock('React\Filesystem\ObjectStream'); - - $filesystem - ->expects($this->once()) - ->method('lsStream') - ->with() - ->will($this->returnValue($lsStream)) - ; - - $directory = new Directory($path, Filesystem::createFromAdapter($filesystem)); - - $this->assertInstanceOf('React\Filesystem\ObjectStream', $directory->lsStreaming()); - } - - public function testCreate() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - $promise = new FulfilledPromise(); - - $filesystem - ->expects($this->once()) - ->method('mkdir') - ->with($path) - ->will($this->returnValue($promise)) - ; - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path . NodeInterface::DS) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $this->assertInstanceOf('React\Promise\PromiseInterface', (new Directory($path, Filesystem::createFromAdapter($filesystem)))->create()); - } - - public function testRename() - { - $pathFrom = 'foo.bar'; - $pathTo = 'bar.foo'; - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('rename') - ->with($pathFrom, $pathTo) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $newDirectory = \Clue\React\Block\await((new Directory($pathFrom, Filesystem::createFromAdapter($filesystem)))->rename($pathTo), Factory::create()); - $this->assertInstanceOf('React\Filesystem\Node\DirectoryInterface', $newDirectory); - $this->assertSame($pathTo . NodeInterface::DS, $newDirectory->getPath()); - } - - public function testRemove() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - $promise = $this->getMock('React\Promise\PromiseInterface'); - - $filesystem - ->expects($this->once()) - ->method('rmdir') - ->with($path) - ->will($this->returnValue($promise)) - ; - - $this->assertSame($promise, (new Directory($path, Filesystem::createFromAdapter($filesystem)))->remove()); - } - public function testSize() - { - $path = '/home/foo/bar'; - $loop = $this->getMock('React\EventLoop\LoopInterface'); - - $filesystem = $this->mockAdapter($loop); - - $lsPromise = $this->getMock('React\Promise\PromiseInterface', [ - 'then', - ]); - - $lsPromise - ->expects($this->once()) - ->method('then') - ->with($this->isType('callable')) - ->will($this->returnCallback(function ($callback) { - return $callback('foo.bar'); - })) - ; - - $directory = $this->getMock('React\Filesystem\Node\Directory', [ - 'ls', - 'processSizeContents', - ], [ - $path, - Filesystem::createFromAdapter($filesystem), - ]); - - $directory - ->expects($this->once()) - ->method('ls') - ->with() - ->will($this->returnValue($lsPromise)) - ; - - $directory - ->expects($this->once()) - ->method('processSizeContents') - ->with('foo.bar', $this->isType('boolean')) - ->will($this->returnValue($this->getMock('React\Promise\PromiseInterface'))) - ; - - $this->assertInstanceOf('React\Promise\PromiseInterface', $directory->size()); - } - - public function testChmodRecursive() - { - $filesystem = $this->mockAdapter(); - - $recursiveInvoker = $this->getMock('React\Filesystem\Node\RecursiveInvoker', [ - 'execute', - ], [ - $this->getMock('React\Filesystem\Node\DirectoryInterface', [], [ - 'foo/bar/', - Filesystem::createFromAdapter($filesystem), - ]), - ]); - - $promise = $this->getMock('React\Promise\PromiseInterface'); - - $recursiveInvoker - ->expects($this->once()) - ->method('execute') - ->with('chmod', [123]) - ->will($this->returnValue($promise)) - ; - - $this->assertSame($promise, (new Directory('foo/bar/', Filesystem::createFromAdapter($filesystem), $recursiveInvoker))->chmodRecursive(123)); - } - - public function testChownRecursive() - { - $filesystem = $this->mockAdapter(); - - $recursiveInvoker = $this->getMock('React\Filesystem\Node\RecursiveInvoker', [ - 'execute', - ], [ - $this->getMock('React\Filesystem\Node\DirectoryInterface', [], [ - 'foo/bar/', - Filesystem::createFromAdapter($filesystem), - ]), - ]); - - $promise = $this->getMock('React\Promise\PromiseInterface'); - - $recursiveInvoker - ->expects($this->once()) - ->method('execute') - ->with('chown', [1, 2]) - ->will($this->returnValue($promise)) - ; - - $this->assertSame($promise, (new Directory('foo/bar/', Filesystem::createFromAdapter($filesystem), $recursiveInvoker))->chownRecursive(1, 2)); - } - - public function testRemoveRecursive() - { - $filesystem = $this->mockAdapter(); - - $recursiveInvoker = $this->getMock('React\Filesystem\Node\RecursiveInvoker', [ - 'execute', - ], [ - $this->getMock('React\Filesystem\Node\DirectoryInterface', [], [ - 'foo/bar/', - Filesystem::createFromAdapter($filesystem), - ]), - ]); - - $promise = $this->getMock('React\Promise\PromiseInterface'); - - $recursiveInvoker - ->expects($this->once()) - ->method('execute') - ->with('remove', []) - ->will($this->returnValue($promise)) - ; - - $this->assertSame($promise, (new Directory('foo/bar/', Filesystem::createFromAdapter($filesystem), $recursiveInvoker))->removeRecursive()); - } - - public function testCopy() - { - $filesystem = $this->mockAdapter(); - - $directoryFrom = $this->getMock('React\Filesystem\Node\Directory', [ - 'copyStreaming', - ], [ - 'foo.bar', - Filesystem::createFromAdapter($filesystem), - ]); - - $fileTo = new Directory('bar.foo', Filesystem::createFromAdapter($filesystem)); - - $directoryFrom - ->expects($this->once()) - ->method('copyStreaming') - ->with($fileTo) - ->will($this->returnValue(new ObjectStream())) - ; - - $promise = $directoryFrom->copy($fileTo); - $this->assertInstanceOf('React\Promise\PromiseInterface', $promise); - } - - public function providerCopyStreamingUnknownNode() - { - return [ - [ - new UnknownNodeType(), - ], - [ - new File('foo.bar', Filesystem::createFromAdapter($this->mockAdapter())), - ], - ]; - } - - /** - * @dataProvider providerCopyStreamingUnknownNode - * @expectedException UnexpectedValueException - */ - public function testCopyStreamingUnknownNode($type) - { - $filesystem = Filesystem::createFromAdapter($this->mockAdapter()); - - (new Directory('foo.bar', $filesystem))->copyStreaming($type); - } - - public function testCopyStreamingABC() - { - - $adapter = $this->mockAdapter(); - - $filesystem = Filesystem::createFromAdapter($adapter); - - $adapter - ->expects($this->at(0)) - ->method('stat') - ->with('bar.foo/foo.bar/') - ->will($this->returnValue(new RejectedPromise())) - ; - - $adapter - ->expects($this->at(1)) - ->method('stat') - ->with('bar.foo/') - ->will($this->returnValue(new FulfilledPromise())) - ; - - $adapter - ->expects($this->at(3)) - ->method('stat') - ->with('bar.foo/foo.bar/') - ->will($this->returnValue(new FulfilledPromise())) - ; - - $adapter - ->expects($this->any()) - ->method('mkdir') - ->with($this->isType('string')) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $directoryFrom = $this->getMock('React\Filesystem\Node\Directory', [ - 'lsStreaming', - ], [ - 'foo.bar', - $filesystem, - ]); - - $stream = new ObjectStream(); - $directoryTo = new Directory('bar.foo', $filesystem); - - $directoryFrom - ->expects($this->once()) - ->method('lsStreaming') - ->with() - ->will($this->returnValue($stream)) - ; - - $returnedStream = $directoryFrom->copyStreaming($directoryTo); - $this->assertInstanceOf('React\Filesystem\ObjectStream', $returnedStream); - - $file = $this->getMock('React\Filesystem\Node\File', [ - 'copyStreaming', - ], [ - 'foo.bar', - $filesystem, - ]); - - $fileStream = new ObjectStream(); - - $file - ->expects($this->once()) - ->method('copyStreaming') - ->with($directoryTo) - ->will($this->returnValue($fileStream)) - ; - - $stream->emit('data', [ - $file, - ]); - - $directory = $this->getMock('React\Filesystem\Node\Directory', [ - 'copyStreaming', - ], [ - 'foo.bar', - $filesystem, - ]); - - $directoryStream = new ObjectStream(); - - $directory - ->expects($this->once()) - ->method('copyStreaming') - ->with($this->isInstanceOf('React\Filesystem\Node\Directory')) - ->will($this->returnValue($directoryStream)) - ; - - $stream->emit('data', [ - $directory, - ]); - - $directoryStream->end($directory); - - $stream->end(); - } -} diff --git a/tests/Node/FileTest.php b/tests/Node/FileTest.php deleted file mode 100644 index 1d0fedbf..00000000 --- a/tests/Node/FileTest.php +++ /dev/null @@ -1,424 +0,0 @@ -assertSame($path, (new File($path, Filesystem::createFromAdapter($this->mockAdapter())))->getPath()); - } - - public function testRemove() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - $promise = $this->getMock('React\Promise\PromiseInterface'); - - $filesystem - ->expects($this->once()) - ->method('unlink') - ->with($path) - ->will($this->returnValue($promise)) - ; - - $this->assertSame($promise, (new File($path, Filesystem::createFromAdapter($filesystem)))->remove()); - } - - public function testRename() - { - $pathFrom = 'foo.bar'; - $pathTo = 'bar.foo'; - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('rename') - ->with($pathFrom, $pathTo) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $newFile = \Clue\React\Block\await((new File($pathFrom, Filesystem::createFromAdapter($filesystem)))->rename($pathTo), Factory::create()); - $this->assertInstanceOf('React\Filesystem\Node\FileInterface', $newFile); - $this->assertSame($pathTo, $newFile->getPath()); - } - - public function testExists() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $file = $this->getMock('React\Filesystem\Node\File', [ - 'stat', - ], [ - $path, - Filesystem::createFromAdapter($filesystem), - ]); - - $promise = \React\Promise\resolve(); - - $file - ->expects($this->once()) - ->method('stat') - ->with() - ->will($this->returnValue($promise)) - ; - - $this->assertInstanceOf('React\Promise\PromiseInterface', $file->exists()); - } - - public function testDoesntExists() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $file = $this->getMock('React\Filesystem\Node\File', [ - 'stat', - ], [ - $path, - Filesystem::createFromAdapter($filesystem), - ]); - - $promise = \React\Promise\resolve(); - - $file - ->expects($this->once()) - ->method('stat') - ->with() - ->will($this->returnValue($promise)) - ; - - $this->assertInstanceOf('React\Promise\PromiseInterface', $file->exists()); - } - - public function testSize() - { - $size = 1337; - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - $deferred = new Deferred(); - $promise = $deferred->promise(); - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue($promise)) - ; - - $sizePromise = (new File($path, Filesystem::createFromAdapter($filesystem)))->size(); - $this->assertInstanceOf('React\Promise\PromiseInterface', $sizePromise); - - $callbackFired = false; - $sizePromise->then(function ($resultSize) use ($size, &$callbackFired) { - $this->assertSame($size, $resultSize); - $callbackFired = true; - }); - $deferred->resolve([ - 'size' => $size, - ]); - $this->assertTrue($callbackFired); - } - - public function testTime() - { - $times = [ - 'atime' => 1, - 'ctime' => 2, - 'mtime' => 3, - ]; - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - $deferred = new Deferred(); - $promise = $deferred->promise(); - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue($promise)) - ; - - $timePromise = (new File($path, Filesystem::createFromAdapter($filesystem)))->time(); - $this->assertInstanceOf('React\Promise\PromiseInterface', $timePromise); - - $callbackFired = false; - $timePromise->then(function ($time) use ($times, &$callbackFired) { - $this->assertSame($times, $time); - $callbackFired = true; - }); - $deferred->resolve($times); - $this->assertTrue($callbackFired); - } - - public function testCreate() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(new RejectedPromise())) - ; - - $filesystem - ->expects($this->once()) - ->method('touch') - ->with($path) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $callbackFired = false; - (new File($path, Filesystem::createFromAdapter($filesystem)))->create()->then(function () use (&$callbackFired) { - $callbackFired = true; - }); - - $this->assertTrue($callbackFired); - } - - public function testCreateFail() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $callbackFired = false; - (new File($path, Filesystem::createFromAdapter($filesystem)))->create()->then(null, function ($e) use (&$callbackFired) { - $this->assertInstanceOf('Exception', $e); - $this->assertSame('File exists already', $e->getMessage()); - $callbackFired = true; - }); - - $this->assertTrue($callbackFired); - } - - public function testOpen() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $fd = 'foo:bar'; - $flags = 'abc'; - - $filesystem - ->expects($this->once()) - ->method('open') - ->with($path, $flags) - ->will($this->returnValue(new FulfilledPromise($fd))) - ; - - $fs = Filesystem::createFromAdapter($filesystem); - $pass = $this->await((new File($path, $fs))->open($flags), $fs->getAdapter()->getLoop()); - - $this->assertInstanceOf('\React\Filesystem\Stream\GenericStreamInterface', $pass); - $this->assertSame($fd, $pass->getFiledescriptor()); - } - - - public function testOpenTwice() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $fd = 'foo:bar'; - $flags = 'abc'; - - $filesystem - ->expects($this->once()) - ->method('open') - ->with($path, $flags) - ->will($this->returnValue(new FulfilledPromise($fd))) - ; - - $file = new File($path, Filesystem::createFromAdapter($filesystem)); - $file->open($flags); - $this->assertInstanceOf('React\Promise\RejectedPromise', $file->open($flags)); - } - - public function testGetContents() - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('getContents') - ->with($path) - ->will($this->returnValue(new FulfilledPromise('a'))) - ; - - $getContentsPromise = (new File($path, Filesystem::createFromAdapter($filesystem)))->getContents(); - $this->assertInstanceOf('React\Promise\PromiseInterface', $getContentsPromise); - } - - public function testClose() - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - $filesystem = $this->mockAdapter(); - - $openPromise = new FulfilledPromise($fd); - - $filesystem - ->method('stat') - ->with($path) - ->will($this->returnValue(new FulfilledPromise([ - 'size' => 1, - ]))) - ; - - $filesystem - ->method('read') - ->with($path) - ->will($this->returnValue(new FulfilledPromise('a'))) - ; - - $filesystem - ->expects($this->once()) - ->method('open') - ->with($path, 'r') - ->will($this->returnValue($openPromise)) - ; - - $filesystem - ->expects($this->once()) - ->method('close') - ->with($fd) - ->will($this->returnValue(\React\Promise\resolve())) - ; - - $file = new File($path, Filesystem::createFromAdapter($filesystem)); - $file->open('r'); - $file->close(); - } - - public function testCloseNeverOpened() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - $this->assertInstanceOf('React\Promise\RejectedPromise', (new File($path, Filesystem::createFromAdapter($filesystem)))->close()); - } - - public function testTouch() - { - $path = 'foo.bar'; - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('touch') - ->with($path) - ->will($this->returnValue($this->getMock('React\Promise\PromiseInterface'))) - ; - - $this->assertInstanceOf('React\Promise\PromiseInterface', (new File($path, Filesystem::createFromAdapter($filesystem)))->touch()); - } - - public function testCopy() - { - $filesystem = $this->mockAdapter(); - - $fileFrom = $this->getMock('React\Filesystem\Node\File', [ - 'copyStreaming', - ], [ - 'foo.bar', - Filesystem::createFromAdapter($filesystem), - ]); - - $fileTo = new File('bar.foo', Filesystem::createFromAdapter($filesystem)); - - $fileFrom - ->expects($this->once()) - ->method('copyStreaming') - ->with($fileTo) - ->will($this->returnValue(new ObjectStream())) - ; - - $stream = $fileFrom->copy($fileTo); - $this->assertInstanceOf('React\Promise\PromiseInterface', $stream); - } - - /** - * @expectedException UnexpectedValueException - */ - public function testCopyUnknownNode() - { - $filesystem = $this->mockAdapter(); - - (new File('foo.bar', Filesystem::createFromAdapter($filesystem)))->copy(new UnknownNodeType()); - } - - public function testCopyDirectory() - { - $filesystem = $this->mockAdapter(); - - $file = $this->getMock('React\Filesystem\Node\File', [ - 'copyToFile', - ], [ - 'foo.bar', - Filesystem::createFromAdapter($filesystem), - ]); - - $directoryTo = new Directory('bar.foo', Filesystem::createFromAdapter($filesystem)); - - $file - ->expects($this->once()) - ->method('copyToFile') - ->with($this->isInstanceOf('React\Filesystem\Node\File')) - ->will($this->returnValue(new ObjectStream())) - ; - - $stream = $file->copyStreaming($directoryTo); - $this->assertInstanceOf('React\Filesystem\ObjectStream', $stream); - } - - /** - * @expectedException UnexpectedValueException - */ - public function testCopyStreamingUnknownNode() - { - $filesystem = $this->mockAdapter(); - - (new File('foo.bar', Filesystem::createFromAdapter($filesystem)))->copyStreaming(new UnknownNodeType()); - } -} diff --git a/tests/Node/GenericOperationTraitTest.php b/tests/Node/GenericOperationTraitTest.php deleted file mode 100644 index 09dde74c..00000000 --- a/tests/Node/GenericOperationTraitTest.php +++ /dev/null @@ -1,152 +0,0 @@ -getMockForTrait('React\Filesystem\Node\GenericOperationTrait'); - - $got->adapter = $this->mockAdapter(); - - $got->filesystem = Filesystem::createFromAdapter($got->adapter); - - $this->assertSame($got->filesystem, $got->getFilesystem()); - $this->assertSame($got->adapter, $got->getFilesystem()->getAdapter()); - } - - public function testStat() - { - $got = $this->getMockForTrait('React\Filesystem\Node\GenericOperationTrait', [], '', true, true, true, [ - 'getPath', - ]); - $got->expects($this->once()) - ->method('getPath') - ->will($this->returnValue('foo.bar')); - - $promise = new FulfilledPromise(); - - $got->adapter = $this->mockAdapter(); - $got->adapter->expects($this->once()) - ->method('stat') - ->with('foo.bar') - ->will($this->returnValue($promise)); - - $got->filesystem = Filesystem::createFromAdapter($got->adapter); - - $this->assertSame($promise, $got->stat()); - } - - public function testChmod() - { - $got = $this->getMockForTrait('React\Filesystem\Node\GenericOperationTrait', [], '', true, true, true, [ - 'getPath', - ]); - $got->expects($this->once()) - ->method('getPath') - ->will($this->returnValue('foo.bar')); - - $promise = new FulfilledPromise(); - - $got->adapter = $this->mockAdapter(); - $got->adapter->expects($this->once()) - ->method('chmod') - ->with('foo.bar', 'abc') - ->will($this->returnValue($promise)); - - $got->filesystem = Filesystem::createFromAdapter($got->adapter); - - $this->assertSame($promise, $got->chmod('abc')); - } - - public function testChown() - { - $got = $this->getMockForTrait('React\Filesystem\Node\GenericOperationTrait', [], '', true, true, true, [ - 'getPath', - ]); - $got->expects($this->once()) - ->method('getPath') - ->will($this->returnValue('foo.bar')); - - $promise = new FulfilledPromise(); - - $got->adapter = $this->mockAdapter(); - $got->adapter->expects($this->once()) - ->method('chown') - ->with('foo.bar', 1, 2) - ->will($this->returnValue($promise)); - - $got->filesystem = Filesystem::createFromAdapter($got->adapter); - - $this->assertSame($promise, $got->chown(1, 2)); - } - - public function testChownDefaults() - { - $got = $this->getMockForTrait('React\Filesystem\Node\GenericOperationTrait', [], '', true, true, true, [ - 'getPath', - ]); - $got->expects($this->once()) - ->method('getPath') - ->will($this->returnValue('foo.bar')); - - $promise = new FulfilledPromise(); - - $got->adapter = $this->mockAdapter(); - $got->adapter->expects($this->once()) - ->method('chown') - ->with('foo.bar', -1, -1) - ->will($this->returnValue($promise)); - - $got->filesystem = Filesystem::createFromAdapter($got->adapter); - - $this->assertSame($promise, $got->chown()); - } - - public function testCreateNameNParentFromFilename() - { - $node = new File('/foo/bar/baz/rabbit/kitten/index.php', Filesystem::createFromAdapter($this->mockAdapter())); - - foreach ([ - [ - 'index.php', - '/foo/bar/baz/rabbit/kitten/index.php', - ], - [ - 'kitten', - '/foo/bar/baz/rabbit/kitten/', - ], - [ - 'rabbit', - '/foo/bar/baz/rabbit/', - ], - [ - 'baz', - '/foo/bar/baz/', - ], - [ - 'bar', - '/foo/bar/', - ], - [ - 'foo', - '/foo/', - ], - [ - '', - '/', - ], - ] as $names) { - $this->assertSame($names[0], $node->getName()); - $this->assertSame($names[1], $node->getPath()); - $node = $node->getParent(); - } - } -} diff --git a/tests/Node/NodeTestTrait.php b/tests/Node/NodeTestTrait.php deleted file mode 100644 index 0e2c8e82..00000000 --- a/tests/Node/NodeTestTrait.php +++ /dev/null @@ -1,21 +0,0 @@ -getNodeClass(); - $this->assertSame($out, (string) (new $nodeClass($in, Filesystem::createFromAdapter($this->mockAdapter())))); - } - - abstract protected function getNodeClass(); -} diff --git a/tests/Node/RecursiveInvokerTest.php b/tests/Node/RecursiveInvokerTest.php deleted file mode 100644 index f04c9c38..00000000 --- a/tests/Node/RecursiveInvokerTest.php +++ /dev/null @@ -1,89 +0,0 @@ -mockAdapter(); - - $node = $this->getMock('React\Filesystem\Node\Directory', [ - 'ls', - 'chmod', - ], [ - 'foo.bar', - Filesystem::createFromAdapter($filesystem), - ]); - - $promise = $this->getMock('React\Promise\PromiseInterface'); - - $node - ->expects($this->once()) - ->method('ls') - ->with() - ->will($this->returnValue($promise)) - ; - - $fileDent = $this->getMock('React\Filesystem\Node\File', [ - 'chmod', - ], [ - 'foo', - Filesystem::createFromAdapter($filesystem), - ]); - - $node - ->expects($this->once()) - ->method('chmod') - ->with(123) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $directoryDent = $this->getMock('React\Filesystem\Node\Directory', [ - 'chmodRecursive', - ], [ - 'foo', - Filesystem::createFromAdapter($filesystem), - ]); - - $directoryDent - ->expects($this->once()) - ->method('chmodRecursive') - ->with(123) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $finalPromise = $this->getMock('React\Promise\PromiseInterface'); - - $node - ->expects($this->once()) - ->method('chmod') - ->with(123) - ->will($this->returnValue($finalPromise)) - ; - - $dents = [ - $fileDent, - $directoryDent, - ]; - - $promise - ->expects($this->once()) - ->method('then') - ->with($this->isType('callable')) - ->will($this->returnCallback(function ($resolveCb) use ($dents) { - return $resolveCb($dents); - })) - ; - - $this->assertInstanceOf('React\Promise\PromiseInterface', (new RecursiveInvoker($node))->execute('chmod', [ - 123, - ])); - } -} diff --git a/tests/NotExistTest.php b/tests/NotExistTest.php new file mode 100644 index 00000000..ada8fc75 --- /dev/null +++ b/tests/NotExistTest.php @@ -0,0 +1,25 @@ +await($filesystem->detect($dirName)->then(static function (NotExistInterface $notExist): PromiseInterface { + return $notExist->createDirectory(); + })); + + self::assertDirectoryExists($dirName); + } +} diff --git a/tests/ObjectStreamSinkTest.php b/tests/ObjectStreamSinkTest.php deleted file mode 100644 index efb0dd4d..00000000 --- a/tests/ObjectStreamSinkTest.php +++ /dev/null @@ -1,27 +0,0 @@ -getMock('React\Filesystem\Node\NodeInterface'); - $stream = new ObjectStream(); - $sink = ObjectStreamSink::promise($stream); - $this->assertInstanceOf('React\Promise\PromiseInterface', $sink); - $stream->emit('data', [$node]); - $stream->close(); - - $nodes = null; - $sink->then(function ($list) use (&$nodes) { - $nodes = $list; - }); - - $this->assertSame(1, count($nodes)); - $this->assertSame($node, reset($nodes)); - } -} diff --git a/tests/ObjectStreamTest.php b/tests/ObjectStreamTest.php deleted file mode 100644 index 164cfe42..00000000 --- a/tests/ObjectStreamTest.php +++ /dev/null @@ -1,31 +0,0 @@ -getMock('React\Filesystem\Node\NodeInterface'); - $stream = new ObjectStream(); - - $this->assertTrue($stream->isWritable()); - $this->assertTrue($stream->isReadable()); - - $stream->on('data', function (NodeInterface $data) use ($node) { - $this->assertEquals($node, $data); - }); - $stream->end($node); - - $this->assertFalse($stream->isWritable()); - $this->assertFalse($stream->isReadable()); - - $stream->close(); - - $this->assertFalse($stream->isWritable()); - $this->assertFalse($stream->isReadable()); - } -} diff --git a/tests/OpenFileLimiterTest.php b/tests/OpenFileLimiterTest.php deleted file mode 100644 index 14b67e4c..00000000 --- a/tests/OpenFileLimiterTest.php +++ /dev/null @@ -1,44 +0,0 @@ -assertSame(1, $limiter->getLimit()); - $this->assertSame(0, $limiter->getOutstanding()); - $this->assertSame(0, $limiter->getQueueSize()); - - $promise1 = $limiter->open(); - $this->assertInstanceOf('React\Promise\PromiseInterface', $promise1); - $promiseCallbackCalled1 = false; - $promise1->then(function () use (&$promiseCallbackCalled1) { - $promiseCallbackCalled1 = true; - }); - $this->assertSame(1, $limiter->getOutstanding()); - $this->assertSame(0, $limiter->getQueueSize()); - - $promise2 = $limiter->open(); - $this->assertInstanceOf('React\Promise\PromiseInterface', $promise2); - $promiseCallbackCalled2 = false; - $promise2->then(function () use (&$promiseCallbackCalled2) { - $promiseCallbackCalled2 = true; - }); - $this->assertSame(1, $limiter->getOutstanding()); - $this->assertSame(1, $limiter->getQueueSize()); - - $limiter->close(); - $this->assertSame(1, $limiter->getOutstanding()); - $this->assertSame(0, $limiter->getQueueSize()); - $this->assertTrue($promiseCallbackCalled1); - - $limiter->close(); - $this->assertSame(0, $limiter->getOutstanding()); - $this->assertSame(0, $limiter->getQueueSize()); - $this->assertTrue($promiseCallbackCalled2); - } -} diff --git a/tests/PermissionFlagResolverTest.php b/tests/PermissionFlagResolverTest.php deleted file mode 100644 index 097c86fb..00000000 --- a/tests/PermissionFlagResolverTest.php +++ /dev/null @@ -1,115 +0,0 @@ -assertSame($result, $resolver->resolve($flags)); - } -} diff --git a/tests/Stream/DuplexStreamTest.php b/tests/Stream/DuplexStreamTest.php deleted file mode 100644 index ab22db9e..00000000 --- a/tests/Stream/DuplexStreamTest.php +++ /dev/null @@ -1,24 +0,0 @@ -mockAdapter(); - - $stream = new DuplexStream($path, $fileDescriptor, $filesystem); - - $this->assertSame($stream, $stream->pipe($stream)); - } -} diff --git a/tests/Stream/GenericStreamTraitTest.php b/tests/Stream/GenericStreamTraitTest.php deleted file mode 100644 index 927d7773..00000000 --- a/tests/Stream/GenericStreamTraitTest.php +++ /dev/null @@ -1,19 +0,0 @@ -getMockForTrait('React\Filesystem\Stream\GenericStreamTrait', [ - 'foo.bar', - 'abc', - $this->mockAdapter(), - ]); - - $this->assertSame('abc', $gst->getFiledescriptor()); - } -} diff --git a/tests/Stream/ReadableStreamTest.php b/tests/Stream/ReadableStreamTest.php deleted file mode 100644 index 9aded959..00000000 --- a/tests/Stream/ReadableStreamTest.php +++ /dev/null @@ -1,275 +0,0 @@ -mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(\React\Promise\resolve([ - 'size' => 123, - ]))) - ; - - $mock = $this->getMock($className, [ - 'readChunk', - ], [ - $path, - $fileDescriptor, - $filesystem, - ]); - - if ($className == 'React\Filesystem\Stream\DuplexStream') { - $mock->resume(); - } - } - - /** - * @dataProvider classNamesProvider - */ - public function testResume($className) - { - $path = 'foo.bar'; - $fileDescriptor = '0123456789abcdef'; - - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(\React\Promise\resolve([ - 'size' => 123, - ]))) - ; - - $mock = $this->getMock($className, [ - 'readChunk', - ], [ - $path, - $fileDescriptor, - $filesystem, - ]); - - if ($className == 'React\Filesystem\Stream\DuplexStream') { - $mock->resume(); - } - } - - /** - * @dataProvider classNamesProvider - */ - public function testClose($className, $stat) - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - - $filesystem = $this->mockAdapter(); - - if ($stat) { - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(new RejectedPromise())) - ; - } - - $promise = $this->getMock('React\Promise\PromiseInterface', [ - 'then', - ]); - - $promise - ->expects($this->once()) - ->method('then') - ->with($this->isType('callable')) - ->will($this->returnCallback(function ($resolveCb) { - $resolveCb(); - })) - ; - - $filesystem - ->expects($this->once()) - ->method('close') - ->with($fd) - ->will($this->returnValue($promise)) - ; - - $stream = $this->getMock($className, [ - 'emit', - 'removeAllListeners', - ], [ - $path, - $fd, - $filesystem, - ]); - - $stream - ->expects($this->at(0)) - ->method('emit') - ->with('close', [$stream]) - ; - - $stream - ->expects($this->at(1)) - ->method('removeAllListeners') - ->with() - ; - - $stream->close(); - } - - /** - * @dataProvider classNamesProvider - */ - public function testAlreadyClosed($className, $stat) - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - $filesystem = $this->mockAdapter(); - - if ($stat) { - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(new RejectedPromise())) - ; - } - - $filesystem - ->expects($this->once()) - ->method('close') - ->with($fd) - ->will($this->returnValue(new RejectedPromise())) - ; - - - $stream = (new $className($path, $fd, $filesystem)); - $stream->close(); - $stream->close(); - } - - /** - * @dataProvider classNamesProvider - */ - public function testPipe($className, $stat) - { - $path = 'foo.bar'; - $fileDescriptor = '0123456789abcdef'; - - $filesystem = $this->mockAdapter(); - - if ($stat) { - $filesystem - ->expects($this->once()) - ->method('stat') - ->with($path) - ->will($this->returnValue(new RejectedPromise())) - ; - } - - $stream = new $className($path, $fileDescriptor, $filesystem); - $destination = new WritableStream($path, $fileDescriptor, $filesystem); - - $this->assertSame($destination, $stream->pipe($destination)); - } - - /** - * @dataProvider classNamesProvider - */ - public function testReadChunk($className, $stat) - { - $path = 'foo.bar'; - $fileDescriptor = '0123456789abcdef'; - - $readPromise = $this->getMock('React\Promise\PromiseInterface', [ - 'then', - ]); - - $readPromise - ->expects($this->exactly(2)) - ->method('then') - ->with($this->isType('callable')) - ->will($this->returnCallback(function ($resolveCb) { - $resolveCb('foo.bar' . (string)microtime(true)); - })) - ; - - $filesystem = $this->mockAdapter(); - - $filesystem - ->expects($this->at(0)) - ->method('stat') - ->with($path) - ->will($this->returnValue(\React\Promise\resolve([ - 'size' => 16384, - ]))) - ; - - $filesystem - ->expects($this->at(1)) - ->method('read') - ->with($fileDescriptor, 8192, 0) - ->will($this->returnValue($readPromise)) - ; - - $filesystem - ->expects($this->at(2)) - ->method('read') - ->with($fileDescriptor, 8192, 8192) - ->will($this->returnValue($readPromise)) - ; - - $filesystem - ->expects($this->at(3)) - ->method('close') - ->with($fileDescriptor) - ->will($this->returnValue(new FulfilledPromise())) - ; - - $mock = $this->getMock($className, [ - 'isReadable', - 'emit', - ], [ - $path, - $fileDescriptor, - $filesystem, - ]); - - if ($className == 'React\Filesystem\Stream\DuplexStream') { - $mock->resume(); - } - } -} diff --git a/tests/Stream/StreamFactoryTest.php b/tests/Stream/StreamFactoryTest.php deleted file mode 100644 index 8afc236f..00000000 --- a/tests/Stream/StreamFactoryTest.php +++ /dev/null @@ -1,46 +0,0 @@ -mockAdapter(); - $filesystem - ->expects($this->once()) - ->method('stat') - ->with('foo.bar') - ->will($this->returnValue(\React\Promise\resolve([]))) - ; - - $this->assertInstanceOf( - 'React\Filesystem\Stream\ReadableStream', - StreamFactory::create('foo.bar', null, 'r', $filesystem) - ); - } - - public function testCreateWrite() - { - $filesystem = $this->mockAdapter(); - - $this->assertInstanceOf( - 'React\Filesystem\Stream\WritableStream', - StreamFactory::create('foo.bar', null, 'w', $filesystem) - ); - } - - public function testCreateDuplex() - { - $filesystem = $this->mockAdapter(); - - $this->assertInstanceOf( - 'React\Filesystem\Stream\DuplexStream', - StreamFactory::create('foo.bar', null, '+', $filesystem) - ); - } -} diff --git a/tests/Stream/WritableStreamTest.php b/tests/Stream/WritableStreamTest.php deleted file mode 100644 index 3b732972..00000000 --- a/tests/Stream/WritableStreamTest.php +++ /dev/null @@ -1,231 +0,0 @@ -mockAdapter(); - - $filesystem - ->expects($this->at($offset + 0)) - ->method('write') - ->with($fd, 'abc', 3, 0) - ->will($this->returnValue($fd)) - ; - - $filesystem - ->expects($this->at($offset + 1)) - ->method('write') - ->with($fd, 'def', 3, 3) - ->will($this->returnValue($fd)) - ; - - $filesystem - ->expects($this->at($offset + 2)) - ->method('write') - ->with($fd, 'ghijklmnopqrstuvwxyz', 20, 6) - ->will($this->returnValue($fd)) - ; - - $stream = (new $className($path, $fd, $filesystem)); - $stream->write('abc'); - $stream->write('def'); - $stream->write('ghijklmnopqrstuvwxyz'); - } - - /** - * @dataProvider classNamesProvider - */ - public function testIsWritable($className) - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - $filesystem = $this->mockAdapter(); - - $this->assertTrue((new $className($path, $fd, $filesystem))->isWritable()); - } - - /** - * @dataProvider classNamesProvider - */ - public function testIsNotWritable($className) - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - $filesystem = $this->mockAdapter(); - - - $filesystem - ->expects($this->once()) - ->method('close') - ->with($fd) - ->will($this->returnValue(new RejectedPromise())) - ; - - - $stream = (new $className($path, $fd, $filesystem)); - $stream->close(); - $this->assertFalse($stream->isWritable()); - } - - /** - * @dataProvider classNamesProvider - */ - public function testEnd($className) - { - $data = 'iahbfeq'; - $stream = $this->getMock($className, [ - 'write', - 'close', - ], [ - 'foo.bar', - '0123456789abcdef', - $this->mockAdapter(), - ]); - - $stream - ->expects($this->once()) - ->method('write') - ->with($data) - ; - - $stream - ->expects($this->once()) - ->method('close') - ->with() - ; - - $stream->end($data); - } - - /** - * @dataProvider classNamesProvider - */ - public function testEndNoWrite($className) - { - $stream = $this->getMock($className, [ - 'write', - 'close', - ], [ - 'foo.bar', - '0123456789abcdef', - $this->mockAdapter(), - ]); - - $stream - ->expects($this->never()) - ->method('write') - ->with() - ; - - $stream - ->expects($this->once()) - ->method('close') - ->with() - ; - - $stream->end(); - } - - /** - * @dataProvider classNamesProvider - */ - public function testClose($className) - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - - $filesystem = $this->mockAdapter(); - - - $promise = $this->getMock('React\Promise\PromiseInterface', [ - 'then', - ]); - - $promise - ->expects($this->once()) - ->method('then') - ->with($this->isType('callable')) - ->will($this->returnCallback(function ($resolveCb) { - $resolveCb(); - })) - ; - - $filesystem - ->expects($this->once()) - ->method('close') - ->with($fd) - ->will($this->returnValue($promise)) - ; - - $stream = $this->getMock($className, [ - 'emit', - 'removeAllListeners', - ], [ - $path, - $fd, - $filesystem, - ]); - - $stream - ->expects($this->at(0)) - ->method('emit') - ->with('close', [$stream]) - ; - - $stream - ->expects($this->at(1)) - ->method('removeAllListeners') - ->with() - ; - - $stream->close(); - } - - /** - * @dataProvider classNamesProvider - */ - public function testAlreadyClosed($className) - { - $path = 'foo.bar'; - $fd = '0123456789abcdef'; - $filesystem = $this->mockAdapter(); - - - $filesystem - ->expects($this->once()) - ->method('close') - ->with($fd) - ->will($this->returnValue(new RejectedPromise())) - ; - - - $stream = (new $className($path, $fd, $filesystem)); - $stream->close(); - $stream->close(); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php deleted file mode 100644 index 06b973cb..00000000 --- a/tests/TestCase.php +++ /dev/null @@ -1,119 +0,0 @@ -getMock('React\EventLoop\LoopInterface'); - } - - $mock = $this->getMock('React\Filesystem\AdapterInterface', [ - '__construct', - 'getLoop', - 'getFilesystem', - 'setFilesystem', - 'callFilesystem', - 'isSupported', - 'mkdir', - 'rmdir', - 'unlink', - 'chmod', - 'chown', - 'stat', - 'ls', - 'lsStream', - 'touch', - 'open', - 'read', - 'write', - 'close', - 'getContents', - 'putContents', - 'appendContents', - 'rename', - 'readlink', - 'symlink', - 'detectType', - ], [ - $loop, - ]); - - $mock - ->expects($this->any()) - ->method('getLoop') - ->with() - ->will($this->returnValue($loop)) - ; - - return $mock; - } - - public function setUp() - { - $this->tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'react-filesystem-tests' . DIRECTORY_SEPARATOR . uniqid('', true) . DIRECTORY_SEPARATOR; - mkdir($this->tmpDir, 0777, true); - $this->startTime = time(); - } - - protected function checkIfTimedOut($maxExecutionTime = self::TIMEOUT) - { - if (($this->startTime + $maxExecutionTime) <= time()) { - $this->fail('Manual timeout'); - } - } - - protected function setLoopTimeout(LoopInterface $loop, $maxExecutionTime = self::TIMEOUT) - { - $loop->addTimer($maxExecutionTime, function () use ($loop) { - $loop->stop(); - $this->fail('Event loop timeout'); - }); - } - - public function tearDown() - { - $this->rmdir($this->tmpDir); - } - - protected function rmdir($dir) - { - $directory = dir($dir); - while (false !== ($entry = $directory->read())) { - if (in_array($entry, ['.', '..'])) { - continue; - } - - if (is_dir($dir . $entry)) { - $this->rmdir($dir . $entry . DIRECTORY_SEPARATOR); - continue; - } - - if (is_file($dir . $entry)) { - unlink($dir . $entry); - continue; - } - } - $directory->close(); - } - - protected function await(PromiseInterface $promise, LoopInterface $loop, $timeout = self::TIMEOUT) - { - $result = Block\await($promise, $loop, $timeout); - $loop->run(); // Ensure we let the loop run it's course to clean up - return $result; - } -} diff --git a/tests/UnknownNodeType.php b/tests/UnknownNodeType.php deleted file mode 100644 index b62eacce..00000000 --- a/tests/UnknownNodeType.php +++ /dev/null @@ -1,94 +0,0 @@ -getPath(); - } - - /** - * @return \React\Filesystem\AdapterInterface - */ - public function getFilesystem() - { - // TODO: Implement getFilesystem() method. - } - - /** - * @return \React\Promise\PromiseInterface - */ - public function stat() - { - // TODO: Implement stat() method. - } - - /** - * @param int $mode - * @return \React\Promise\PromiseInterface - */ - public function chmod($mode) - { - // TODO: Implement chmod() method. - } - - /** - * @param int $uid - * @param int $gid - * @return \React\Promise\PromiseInterface - */ - public function chown($uid = -1, $gid = -1) - { - // TODO: Implement chown() method. - } - - /** - * @param NodeInterface $node - * @return \React\Promise\PromiseInterface - */ - public function copy(NodeInterface $node) - { - // TODO: Implement copy() method. - } - - /** - * @param NodeInterface $node - * @return ObjectStream - */ - public function copyStreaming(NodeInterface $node) - { - // TODO: Implement copyStreaming() method. - } -}