From c7642c353fc4ee3fa7f5292091fb43bc5fa6d929 Mon Sep 17 00:00:00 2001 From: Harry Bragg Date: Thu, 9 Aug 2018 10:37:03 +0100 Subject: [PATCH] Initial, sort of over engineered version (#1) * fix tests, use table as a pool * fix tests and linting * sort files by largest first * support schema:tables input; * make the schema directory if it does not exist * update parallel-process * update Dockerfile to latest * remove mkdir section, todo: add injected filesystem * allow older yaml versions * update composer version, some fixes --- .travis.yml | 5 +- Dockerfile | 31 +- Makefile | 51 +- README.md | 104 +- bin/sprout | 3 +- bin/wait-for-db.sh | 13 + composer.json | 113 +- composer.lock | 1256 ++++++++++------- docker-compose.yml | 15 - docs/sprout.md | 7 + example/Makefile | 33 + example/config/morphism.yml | 9 + example/config/mysql.cnf | 76 + example/config/sprout.yml | 13 + example/data/core/the_schema/.DS_Store | 0 example/data/core/the_schema/country.sql | 251 ++++ example/docker-compose.yml | 40 + example/schema/the_schema/country.sql | 15 + hooks/build | 7 + phpunit.xml.dist | 3 - src/Chop/Chopper.php | 14 +- src/Chop/Mysql/MysqlTableChopper.php | 32 +- src/Chop/TableChopperFactory.php | 37 +- src/Command/ChopCommand.php | 81 +- src/Command/DumpCommand.php | 74 +- src/Command/SeedCommand.php | 109 +- src/Config/Config.php | 89 +- src/Config/ConnectionConfig.php | 54 +- src/Config/GroupConfig.php | 45 + src/Config/GroupConfigInterface.php | 8 + src/Config/SchemaConfig.php | 42 +- src/Config/SchemaConfigInterface.php | 7 + src/Dump/Dumper.php | 12 +- src/Dump/Mysql/MysqlTableDumper.php | 26 +- src/Dump/TableDumperFactory.php | 31 +- src/Parser/ParsedSchema.php | 72 + src/Parser/SchemaParser.php | 110 ++ src/Seed/Mysql/MysqlTableSeeder.php | 28 +- src/Seed/Seeder.php | 10 +- src/Seed/TableSeederFactory.php | 36 +- tests/src/TestCase.php | 5 +- tests/unit/Chop/ChopperTest.php | 18 +- .../unit/Chop/Mysql/MysqlTableChopperTest.php | 121 +- tests/unit/Chop/TableChopperFactoryTest.php | 18 +- .../unit/Dump/Mysql/MysqlTableDumperTest.php | 73 +- tests/unit/Dump/TableDumperFactoryTest.php | 13 +- .../unit/Seed/Mysql/MysqlTableSeederTest.php | 97 +- tests/unit/Seed/SeederTest.php | 10 +- tests/unit/Seed/TableSeederFactoryTest.php | 20 +- 49 files changed, 2176 insertions(+), 1161 deletions(-) create mode 100755 bin/wait-for-db.sh delete mode 100644 docker-compose.yml create mode 100644 docs/sprout.md create mode 100644 example/Makefile create mode 100644 example/config/morphism.yml create mode 100644 example/config/mysql.cnf create mode 100644 example/config/sprout.yml create mode 100644 example/data/core/the_schema/.DS_Store create mode 100644 example/data/core/the_schema/country.sql create mode 100644 example/docker-compose.yml create mode 100644 example/schema/the_schema/country.sql create mode 100644 hooks/build create mode 100644 src/Config/GroupConfig.php create mode 100644 src/Config/GroupConfigInterface.php create mode 100644 src/Parser/ParsedSchema.php create mode 100644 src/Parser/SchemaParser.php diff --git a/.travis.yml b/.travis.yml index b11c15f..18b7987 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,15 +2,15 @@ language: php dist: trusty +## Cache composer bits cache: directories: - $HOME/.composer/cache/files php: - - 5.6 - 7.0 - 7.1 - - hhvm + - 7.2 - nightly env: @@ -22,6 +22,7 @@ matrix: - php: nightly before_script: + - composer config platform.php $(php -r "echo PHP_VERSION;") - travis_retry composer update --no-interaction --prefer-dist $PREFER_LOWEST script: diff --git a/Dockerfile b/Dockerfile index 6b6eaed..654f84d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,37 @@ -FROM php:7.1-alpine +FROM composer AS build + +WORKDIR /app +COPY src /app/src +COPY composer.json /app/composer.json +COPY composer.lock /app/composer.lock + +RUN composer install --no-ansi --no-dev --no-interaction --no-progress --no-scripts --optimize-autoloader --prefer-dist + +FROM graze/php-alpine:7.2 AS run RUN set +xe \ && apk add --no-cache \ mariadb-client +WORKDIR /app +COPY --from=build /app/src /app/src +COPY --from=build /app/vendor /app/vendor COPY bin /app/bin -COPY src /app/src -COPY vendor /app/vendor -VOLUME ["/seed", "/app/config"] +ARG BUILD_DATE +ARG VCS_REF + +LABEL org.label-schema.schema-version="1.0" \ + org.label-schema.vendor="graze" \ + org.label-schema.name="morphism" \ + org.label-schema.description="seed your databases" \ + org.label-schema.vcs-url="https://github.com/graze/sprout" \ + org.label-schema.vcs-ref=$VCS_REF \ + org.label-schema.build-date=$BUILD_DATE \ + maintainer="developers@graze.com" \ + license="MIT" + +VOLUME ["/app/config", "/seed"] ENTRYPOINT ["php", "/app/bin/sprout"] CMD ["list"] diff --git a/Makefile b/Makefile index d5fc4d6..9a528d9 100644 --- a/Makefile +++ b/Makefile @@ -1,32 +1,45 @@ SHELL = /bin/sh -DOCKER ?= $(shell which docker) +DOCKER = $(shell which docker) +PHP_VER := 7.2 +IMAGE := graze/php-alpine:${PHP_VER}-test VOLUME := /srv -IMAGE ?= graze/php-alpine:test -DOCKER_RUN := ${DOCKER} run --rm -t -v $$(pwd):${VOLUME} -w ${VOLUME} ${IMAGE} +DOCKER_RUN_BASE := ${DOCKER} run --rm -t -v $$(pwd):${VOLUME} -w ${VOLUME} +DOCKER_RUN := ${DOCKER_RUN_BASE} ${IMAGE} PREFER_LOWEST ?= .PHONY: build build-update composer-% clean help run .PHONY: lint lint-fix -.PHONY: test test-unit test-lowest test-matrix test-coverage test-coverage-html test-coverage-clover +.PHONY: test test-unit test-integration test-lowest test-matrix test-coverage test-coverage-html test-coverage-clover .SILENT: help # Building -build: ## Download the dependencies then build the image :rocket:. - make 'composer-install --prefer-dist --optimize-autoloader' +build: ## Install the dependencies +build: ensure-composer-file + make 'composer-install --optimize-autoloader --prefer-dist ${PREFER_LOWEST}' -build-update: ## Update all dependencies - make 'composer-update --prefer-dist --optimize-autoloader ${PREFER_LOWEST}' +build-update: ## Update the dependencies +build-update: ensure-composer-file + make 'composer-update --optimize-autoloader --prefer-dist ${PREFER_LOWEST}' + +ensure-composer-file: # Update the composer file + make 'composer-config platform.php ${PHP_VER}' composer-%: ## Run a composer command, `make "composer- [...]"`. ${DOCKER} run -t --rm \ - -v $$(pwd):/app \ - -v ~/.composer:/tmp \ + -v $$(pwd):/app:delegated \ + -v ~/.composer:/tmp:delegated \ + -v ~/.ssh:/root/.ssh:ro \ composer --ansi --no-interaction $* $(filter-out $@,$(MAKECMDGOALS)) +build-docker: ## Build the docker image + docker build --build-arg BUILD_DATE="$$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ + --build-arg VCS_REF="$$(git rev-parse --short HEAD)" \ + -t graze/sprout . + # Testing test: ## Run the unit and integration testsuites. @@ -42,20 +55,18 @@ test-unit: ## Run the unit testsuite. ${DOCKER_RUN} vendor/bin/phpunit --testsuite unit test-lowest: ## Test using the lowest possible versions of the dependencies -test-lowest: PREFER_LOWEST=--prefer-lowest --prefer-stable +test-lowest: PREFER_LOWEST=--prefer-lowest test-lowest: build-update test -test-matrix: ## Run the unit tests against multiple targets. - ${MAKE} IMAGE="php:5.6-alpine" test - ${MAKE} IMAGE="php:7.0-alpine" test - ${MAKE} IMAGE="php:7.1-alpine" test - ${MAKE} IMAGE="hhvm/hhvm:latest" test - -test-matrix-lowest: ## Run the unit tests against - ${MAKE} build-update PREFER_LOWEST='--prefer-lowest --prefer-stable' - ${MAKE} test-matrix +test-matrix-lowest: ## Test all version, with the lowest version + ${MAKE} test-matrix PREFER_LOWEST=--prefer-lowest ${MAKE} build-update +test-matrix: ## Run the unit tests against multiple targets. + ${MAKE} PHP_VER="7.0" build-update test + ${MAKE} PHP_VER="7.1" build-update test + ${MAKE} PHP_VER="7.2" build-update test + test-coverage: ## Run all tests and output coverage to the console. ${DOCKER_RUN} phpdbg7 -qrr vendor/bin/phpunit --coverage-text diff --git a/README.md b/README.md index 8a5497f..445eb42 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# sprout +# Sprout [![Latest Version on Packagist](https://img.shields.io/packagist/v/graze/sprout.svg?style=flat-square)](https://packagist.org/packages/graze/sprout) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) @@ -7,59 +7,83 @@ [![Quality Score](https://img.shields.io/scrutinizer/g/graze/sprout.svg?style=flat-square)](https://scrutinizer-ci.com/g/graze/sprout) [![Total Downloads](https://img.shields.io/packagist/dt/graze/sprout.svg?style=flat-square)](https://packagist.org/packages/graze/sprout) ->You now have a copy of the files in this repository, in a new git repository with no previous history that can you manipulate and push to other remote repositories. -> -> ## Continuous Integration -> ->Your project should make use of the following remote CI services: -> -> ### [Travis CI](https://travis-ci.org/graze/) - automated testing -> -> 1. Log-in with github -> 1. visit: https://travis-ci.org/profile/graze -> 1. Click `sync with github` -> 1. Enable your project -> -> ### [Scrutinizer CI](https://scrutinizer-ci.com/organizations/graze/repositories) - code quality -> -> 1. Log-in via github -> 1. Click `+ Add Repository` -> 1. Select `graze` as the organisation (ask a graze/@open-source-team member for access) -> 1. Entry the repository name -> 1. Click `Add Repository` -> 1. Click on the šŸ”§ > `Configuration` set `Shared Config` to `graze/standards + open source` -> -> ### [Packagist](https://packagist.org/graze) - package repository -> -> 1. Log-in using the graze account -> 1. Click `Submit` -> 1. Paste the `git` url (e.g. `git@github.com:graze/sprout.git`) -> 1. Click `Check` -> 1. Follow the instructions on auto updating the project in packagist -> -> ## Github Teams -> -> Add this project to the graze [Open Source](https://github.com/orgs/graze/teams/open-source-team/members) team to allows others to contribute to this project +Sprout is a tool to help Dump, Truncate and Seed development data into your databases. +![](https://78.media.tumblr.com/534425eb11706448af8ce5838629f76d/tumblr_inline_n9t8gdzC7p1qzjzhu.gif) + +1. Seed sql data from local files +1. Dump data from mysql tables +1. Performs actions in parallel +1. Handle multiple groups of seed data (for example, `static`, `core`, `testing`) ## Install Via Composer ```bash -composer require graze/sprout +~$ composer require graze/sprout +``` + +Via docker + +```bash +`$ docker run -v [volumes] --rm graze/sprout [command] ``` ## Usage -```php -$skeleton = new Graze\Sprout\Skeleton('big', 'small', 'dog'); -echo $skeleton->sing(); +### Quick Start + +```bash +~$ # Dump all tables you are interested in +~$ sprout dump --config=config/sprout.yml --group=core a_schema:table_1,table_2 ... + +~$ # Store the data in your repository of choice +~$ git add /seed/data/* + +~$ # Seed the data from your seed data +~$ sprout seed --config=config/sprout.yml --group=core +``` + +### Seeding + +```bash +~$ sprout seed [--config=] [--group=] [--chop] [[:,...]] ... + +~$ sprout seed --config=config/sprout.yml the_schema +~$ sprout seed --config=config/sprout.yml --chop the_schema + +~$ sprout seed --config=config/sprout.yml the_schema:country +~$ sprout seed --config=config/sprout.yml --chop the_schema:country other_schema:planets + +~$ sprout seed --config=config/sprout.yml --group=core +~$ sprout seed --config=config/sprout.yml --group=core the_schema +~$ sprout seed --config=config/sprout.yml --chop --group=extra ``` -## Change log +### Truncating the data from all the tables in a schema -Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. +```bash +~$ sprout chop [--config=] [--group=] [[:
,...]] ... + +~$ sprout chop --config=config/sprout.yml the_schema +~$ sprout chop --config=config/sprout.yml the_schema:country + +~$ sprout chop --config=config/sprout.yml --group=core the_schema +~$ sprout chop --config=config/sprout.yml --group=extra the_schema:country +``` + +### Dumping the data from all tables in a schema + +```bash +~$ sprout dump [--config=] [--group=] [[:
,...]] ... + +~$ sprout dump --config=config/sprout.yml the_schema +~$ sprout dump --config=config/sprout.yml the_schema:country + +~$ sprout dump --config=config/sprout.yml --group=core +~$ sprout dump --config=config/sprout.yml --group=core the_schema:country +``` ## Testing diff --git a/bin/sprout b/bin/sprout index 5c31dea..c17fd03 100644 --- a/bin/sprout +++ b/bin/sprout @@ -2,11 +2,12 @@ /dev/null 2>&1 < /dev/null; do + i=`expr $i + 1` + if [ $i -ge 50 ]; then + echo "$(date) - $1:$2 still not reachable, giving up" + exit 1 + fi + echo "$(date) - waiting for $1:$2..." + sleep 1 +done +echo "$1 connection established" diff --git a/composer.json b/composer.json index 55ccdf0..4d5a2a2 100644 --- a/composer.json +++ b/composer.json @@ -1,61 +1,60 @@ { - "name": "graze/sprout", - "description": "Seed data for your project", - "keywords": [ - "graze", - "sprout" - ], - "homepage": "https://github.com/graze/sprout", - "license": "MIT", - "authors": [ - { - "name": "Harry Bragg", - "email": "harry.bragg@gmail.com", - "role": "Developer" - }, - { - "name": "Graze Developers", - "email": "developers@graze.com", - "homepage": "http://www.graze.com", - "role": "Development Team" - } - ], - "config": { - "platform": { - "ext-tokenizer": "1.0", - "ext-dom": "1.0", - "ext-xmlwriter": "1.0", - "ext-xml": "1.0", - "ext-simplexml": "1.0", - "php": "7.1" - } + "name": "graze/sprout", + "description": "Seed data for your project", + "keywords": [ + "graze", + "sprout", + "database seeder", + "database" + ], + "homepage": "https://github.com/graze/sprout", + "license": "MIT", + "authors": [ + { + "name": "Harry Bragg", + "email": "harry.bragg@gmail.com", + "role": "Developer" }, - "require": { - "php": "^5.5 | ^7.0", - "symfony/console": "^3.3", - "graze/parallel-process": "^0.4.0", - "graze/console-diff-renderer": "^0.6.1", - "symfony/filesystem": "^3.3", - "graze/data-structure": "^2.0", - "respect/validation": "^1.1", - "graze/config-validation": "^0.1.1", - "mockery/mockery": "^0.9.9" - }, - "require-dev": { - "phpunit/phpunit": "^4.2 | ^5.2", - "squizlabs/php_codesniffer": "^3", - "graze/standards": "^2.0" - }, - "autoload": { - "psr-4": { - "Graze\\Sprout\\": "src" - } - }, - "autoload-dev": { - "psr-4": { - "Graze\\Sprout\\Test\\": "tests/src", - "Graze\\Sprout\\Test\\Unit\\": "tests/unit", - "Graze\\Sprout\\Test\\Integration\\": "tests/integration" - } + { + "name": "Graze Developers", + "email": "developers@graze.com", + "homepage": "http://www.graze.com", + "role": "Development Team" + } + ], + "config": { + "platform": { + "php": "7.2" + } + }, + "require": { + "php": "^7.0", + "symfony/console": "^3.3 | ^4", + "symfony/filesystem": "^3.3 | ^4", + "symfony/yaml": "^3.3 | ^4", + "graze/parallel-process": "^0.7", + "graze/console-diff-renderer": "^0.6.1", + "graze/data-structure": "^2.0", + "respect/validation": "^1.1", + "graze/config-validation": "^0.2", + "psr/log": "^1.0" + }, + "require-dev": { + "graze/standards": "^2.0", + "phpunit/phpunit": "^5.7.21 | ^6 | ^7", + "squizlabs/php_codesniffer": "^3.0", + "mockery/mockery": "^1" + }, + "autoload": { + "psr-4": { + "Graze\\Sprout\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Graze\\Sprout\\Test\\": "tests/src", + "Graze\\Sprout\\Test\\Unit\\": "tests/unit", + "Graze\\Sprout\\Test\\Integration\\": "tests/integration" } + } } diff --git a/composer.lock b/composer.lock index 8fac334..be1e135 100644 --- a/composer.lock +++ b/composer.lock @@ -1,23 +1,23 @@ { "_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": "e6a70906934c9b7d26ca61f51e0bea80", + "content-hash": "d79ab2ef687778f5cd4b47b800663da3", "packages": [ { "name": "graze/config-validation", - "version": "0.1.1", + "version": "0.2", "source": { "type": "git", "url": "https://github.com/graze/config-validation.git", - "reference": "50974657e91aa2b116a80e0570588aa363448aa2" + "reference": "5c7adb14e53fe3149141d490f7fbe47dd2191dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/graze/config-validation/zipball/50974657e91aa2b116a80e0570588aa363448aa2", - "reference": "50974657e91aa2b116a80e0570588aa363448aa2", + "url": "https://api.github.com/repos/graze/config-validation/zipball/5c7adb14e53fe3149141d490f7fbe47dd2191dae", + "reference": "5c7adb14e53fe3149141d490f7fbe47dd2191dae", "shasum": "" }, "require": { @@ -26,8 +26,8 @@ }, "require-dev": { "graze/standards": "^2.0", - "phpunit/phpunit": "^4.2 | ^5.2", - "squizlabs/php_codesniffer": "^3" + "phpunit/phpunit": "^5.7.21 | ^6 | ^7", + "squizlabs/php_codesniffer": "^3.0" }, "type": "library", "autoload": { @@ -58,31 +58,31 @@ "config-validation", "graze" ], - "time": "2017-10-02T15:12:49+00:00" + "time": "2018-08-06T14:18:39+00:00" }, { "name": "graze/console-diff-renderer", - "version": "0.6.1", + "version": "0.6.2", "source": { "type": "git", "url": "https://github.com/graze/console-diff-renderer.git", - "reference": "42eb3f66ff13be4acb010c9a6c770b721fdadc4d" + "reference": "aafdaf504a96e6889f284bb15c75330318318df1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/graze/console-diff-renderer/zipball/42eb3f66ff13be4acb010c9a6c770b721fdadc4d", - "reference": "42eb3f66ff13be4acb010c9a6c770b721fdadc4d", + "url": "https://api.github.com/repos/graze/console-diff-renderer/zipball/aafdaf504a96e6889f284bb15c75330318318df1", + "reference": "aafdaf504a96e6889f284bb15c75330318318df1", "shasum": "" }, "require": { - "php": "^5.5 | ^7.0", - "symfony/console": "^2.8 | ^3.2" + "php": "^5.6 | ^7.0", + "symfony/console": "^2.8 | ^3.2 | ^4.0" }, "require-dev": { - "graze/standards": "^1.0", - "mockery/mockery": "^0.9.9", - "phpunit/phpunit": "^4.6 | ^5.2", - "squizlabs/php_codesniffer": "^2.6,!=2.8.1" + "graze/standards": "^2.0", + "mockery/mockery": "^1", + "phpunit/phpunit": "^5.7.21 | ^6 | ^7", + "squizlabs/php_codesniffer": "^3" }, "type": "library", "autoload": { @@ -113,29 +113,30 @@ "console-diff-renderer", "graze" ], - "time": "2017-06-29T15:21:43+00:00" + "time": "2018-06-22T14:35:55+00:00" }, { "name": "graze/data-structure", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/graze/data-structure.git", - "reference": "cebaa76aacdea90037a33d8a87aab6641891ea8f" + "reference": "24e0544b7828f65b1b93ce69ad702c9efb4a64d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/graze/data-structure/zipball/cebaa76aacdea90037a33d8a87aab6641891ea8f", - "reference": "cebaa76aacdea90037a33d8a87aab6641891ea8f", + "url": "https://api.github.com/repos/graze/data-structure/zipball/24e0544b7828f65b1b93ce69ad702c9efb4a64d0", + "reference": "24e0544b7828f65b1b93ce69ad702c9efb4a64d0", "shasum": "" }, "require": { "graze/sort": "~2.0", - "php": ">=5.5" + "php": ">=5.5|^7.0" }, "require-dev": { - "adlawson/timezone": "~1.0", - "phpunit/phpunit": "~4.0" + "graze/standards": "^2.0", + "phpunit/phpunit": "^4.2 | ^5.2", + "squizlabs/php_codesniffer": "^3" }, "type": "library", "autoload": { @@ -166,37 +167,38 @@ "reduce", "structure" ], - "time": "2015-11-20T12:13:51+00:00" + "time": "2017-11-29T09:06:31+00:00" }, { "name": "graze/parallel-process", - "version": "0.4", + "version": "0.7", "source": { "type": "git", "url": "https://github.com/graze/parallel-process.git", - "reference": "23d19d9334fdba8b1ab0bf587ae48b3f180d7403" + "reference": "6253338e5e9cb0ab17e8f06ec76a11673714c5ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/graze/parallel-process/zipball/23d19d9334fdba8b1ab0bf587ae48b3f180d7403", - "reference": "23d19d9334fdba8b1ab0bf587ae48b3f180d7403", + "url": "https://api.github.com/repos/graze/parallel-process/zipball/6253338e5e9cb0ab17e8f06ec76a11673714c5ab", + "reference": "6253338e5e9cb0ab17e8f06ec76a11673714c5ab", "shasum": "" }, "require": { "graze/data-structure": "^2.0", "php": "^5.5 | ^7.0", - "symfony/process": "^2.8 | ^3.2" + "symfony/event-dispatcher": "^2.8 | ^3.2 | ^4.0", + "symfony/process": "^2.8 | ^3.2 | ^4.0" }, "require-dev": { "graze/console-diff-renderer": "^0.6.1", - "graze/standards": "^1.0", - "mockery/mockery": "^0.9.9", - "phpunit/phpunit": "^4.2 | ^5.2", - "squizlabs/php_codesniffer": "^2.9", - "symfony/console": "^3.1" + "graze/standards": "^2", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^5.7.21|^6|^7", + "squizlabs/php_codesniffer": "^3", + "symfony/console": "^3.1 | ^4" }, "suggest": { - "graze/console-diff-renderer": "To use the Table efficiently", + "graze/console-diff-renderer": "required to use Table and Lines", "symfony/console": "To use the Table to print current runs" }, "type": "library", @@ -228,7 +230,7 @@ "graze", "parallel-process" ], - "time": "2017-06-30T14:38:57+00:00" + "time": "2018-08-08T17:22:30+00:00" }, { "name": "graze/sort", @@ -285,116 +287,6 @@ ], "time": "2014-09-23T17:01:23+00:00" }, - { - "name": "hamcrest/hamcrest-php", - "version": "v1.2.2", - "source": { - "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "1.3.3", - "satooshi/php-coveralls": "dev-master" - }, - "type": "library", - "autoload": { - "classmap": [ - "hamcrest" - ], - "files": [ - "hamcrest/Hamcrest.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD" - ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" - ], - "time": "2015-05-11T14:41:42+00:00" - }, - { - "name": "mockery/mockery", - "version": "0.9.9", - "source": { - "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "6fdb61243844dc924071d3404bb23994ea0b6856" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/6fdb61243844dc924071d3404bb23994ea0b6856", - "reference": "6fdb61243844dc924071d3404bb23994ea0b6856", - "shasum": "" - }, - "require": { - "hamcrest/hamcrest-php": "~1.1", - "lib-pcre": ">=7.0", - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9.x-dev" - } - }, - "autoload": { - "psr-0": { - "Mockery": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "PƔdraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" - } - ], - "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", - "homepage": "http://github.com/padraic/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "time": "2017-02-28T12:52:32+00:00" - }, { "name": "psr/log", "version": "1.0.2", @@ -444,16 +336,16 @@ }, { "name": "respect/validation", - "version": "1.1.12", + "version": "1.1.22", "source": { "type": "git", "url": "https://github.com/Respect/Validation.git", - "reference": "5ab87d1dd932872f6670136a513f72ff9ea41c67" + "reference": "19d6ec893994912d21b390c43d287816ab070772" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Respect/Validation/zipball/5ab87d1dd932872f6670136a513f72ff9ea41c67", - "reference": "5ab87d1dd932872f6670136a513f72ff9ea41c67", + "url": "https://api.github.com/repos/Respect/Validation/zipball/19d6ec893994912d21b390c43d287816ab070772", + "reference": "19d6ec893994912d21b390c43d287816ab070772", "shasum": "" }, "require": { @@ -462,7 +354,6 @@ }, "require-dev": { "egulias/email-validator": "~1.2", - "malkusch/bav": "~1.0", "mikey179/vfsstream": "^1.5", "phpunit/phpunit": "~4.0", "symfony/validator": "~2.6.9", @@ -472,8 +363,7 @@ "egulias/email-validator": "Strict (RFC compliant) email validation", "ext-bcmath": "Arbitrary Precision Mathematics", "ext-mbstring": "Multibyte String Functions", - "fabpot/php-cs-fixer": "Fix PSR2 and other coding style issues", - "malkusch/bav": "German bank account validation", + "friendsofphp/php-cs-fixer": "Fix PSR2 and other coding style issues", "symfony/validator": "Use Symfony validator through Respect\\Validation", "zendframework/zend-validator": "Use Zend Framework validator through Respect\\Validation" }, @@ -505,48 +395,48 @@ "validation", "validator" ], - "time": "2017-03-14T09:44:11+00:00" + "time": "2018-08-01T13:06:54+00:00" }, { "name": "symfony/console", - "version": "v3.3.9", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a1e1b01293a090cb9ae2ddd221a3251a4a7e4abf" + "reference": "ca80b8ced97cf07390078b29773dc384c39eee1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a1e1b01293a090cb9ae2ddd221a3251a4a7e4abf", - "reference": "a1e1b01293a090cb9ae2ddd221a3251a4a7e4abf", + "url": "https://api.github.com/repos/symfony/console/zipball/ca80b8ced97cf07390078b29773dc384c39eee1f", + "reference": "ca80b8ced97cf07390078b29773dc384c39eee1f", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0", + "php": "^7.1.3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3", - "symfony/dependency-injection": "~3.3", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/filesystem": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0" }, "suggest": { - "psr/log": "For using the console logger", + "psr/log-implementation": "For using the console logger", "symfony/event-dispatcher": "", - "symfony/filesystem": "", + "symfony/lock": "", "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -573,41 +463,48 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-09-06T16:40:18+00:00" + "time": "2018-07-26T11:24:31+00:00" }, { - "name": "symfony/debug", - "version": "v3.3.9", + "name": "symfony/event-dispatcher", + "version": "v4.1.3", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "8beb24eec70b345c313640962df933499373a944" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/8beb24eec70b345c313640962df933499373a944", - "reference": "8beb24eec70b345c313640962df933499373a944", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bfb30c2ad377615a463ebbc875eba64a99f6aa3e", + "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" + "php": "^7.1.3" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/dependency-injection": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0" + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.1-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -627,31 +524,32 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-09-01T13:23:39+00:00" + "time": "2018-07-26T09:10:45+00:00" }, { "name": "symfony/filesystem", - "version": "v3.3.9", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb" + "reference": "2e30335e0aafeaa86645555959572fe7cea22b43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/2e30335e0aafeaa86645555959572fe7cea22b43", + "reference": "2e30335e0aafeaa86645555959572fe7cea22b43", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -678,20 +576,78 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2018-07-26T11:24:31+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.5.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803" + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803", - "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", "shasum": "" }, "require": { @@ -703,7 +659,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -737,29 +693,29 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/process", - "version": "v3.3.9", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "b7666e9b438027a1ea0e1ee813ec5042d5d7f6f0" + "reference": "f01fc7a4493572f7f506c49dcb50ad01fb3a2f56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b7666e9b438027a1ea0e1ee813ec5042d5d7f6f0", - "reference": "b7666e9b438027a1ea0e1ee813ec5042d5d7f6f0", + "url": "https://api.github.com/repos/symfony/process/zipball/f01fc7a4493572f7f506c49dcb50ad01fb3a2f56", + "reference": "f01fc7a4493572f7f506c49dcb50ad01fb3a2f56", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -786,7 +742,66 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2018-07-26T11:24:31+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "46bc69aa91fc4ab78a96ce67873a6b0c148fd48c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/46bc69aa91fc4ab78a96ce67873a6b0c148fd48c", + "reference": "46bc69aa91fc4ab78a96ce67873a6b0c148fd48c", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:24:31+00:00" } ], "packages-dev": [ @@ -822,106 +837,328 @@ }, "autoload": { "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "graze/standards", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/graze/standards.git", + "reference": "0381502a55626f67b97dc85f0cb87cdf2c46bcbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/graze/standards/zipball/0381502a55626f67b97dc85f0cb87cdf2c46bcbc", + "reference": "0381502a55626f67b97dc85f0cb87cdf2c46bcbc", + "shasum": "" + }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graze Developers", + "email": "developers@graze.com" + } + ], + "description": "Graze coding standards", + "homepage": "https://github.com/graze/standards", + "keywords": [ + "coding", + "graze", + "standards" + ], + "time": "2017-11-06T11:45:35+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/776503d3a8e85d4f9a1148614f95b7a608b046ad", + "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "phpunit/phpunit": "~4.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2016-01-20T08:20:44+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "99e29d3596b16dabe4982548527d5ddf90232e99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/99e29d3596b16dabe4982548527d5ddf90232e99", + "reference": "99e29d3596b16dabe4982548527d5ddf90232e99", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~2.0", + "lib-pcre": ">=7.0", + "php": ">=5.6.0" + }, + "require-dev": { + "phpdocumentor/phpdocumentor": "^2.9", + "phpunit/phpunit": "~5.7.10|~6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "PƔdraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2018-05-08T08:54:48+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "description": "Create deep copies (clones) of your objects", "keywords": [ - "constructor", - "instantiate" + "clone", + "copy", + "duplicate", + "object", + "object graph" ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2018-06-11T23:09:50+00:00" }, { - "name": "graze/standards", - "version": "v2.0.0", + "name": "phar-io/manifest", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/graze/standards.git", - "reference": "4afc1e28509585f149b2a27c9849ca1ed53c3ee9" + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/graze/standards/zipball/4afc1e28509585f149b2a27c9849ca1ed53c3ee9", - "reference": "4afc1e28509585f149b2a27c9849ca1ed53c3ee9", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, - "require-dev": { - "squizlabs/php_codesniffer": "^3.0" + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Graze Developers", - "email": "developers@graze.com" + "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": "Graze coding standards", - "homepage": "https://github.com/graze/standards", - "keywords": [ - "coding", - "graze", - "standards" - ], - "time": "2017-08-23T09:31:18+00:00" + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2018-07-08T19:23:20+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.6.1", + "name": "phar-io/version", + "version": "2.0.1", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102" + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102", - "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "doctrine/collections": "1.*", - "phpunit/phpunit": "~4.1" + "php": "^5.6 || ^7.0" }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "Create deep copies (clones) of your objects", - "homepage": "https://github.com/myclabs/DeepCopy", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "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" + } ], - "time": "2017-04-12T18:52:22+00:00" + "description": "Library for handling version information and constraints", + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -979,29 +1216,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.1.1", + "version": "4.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2" + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2", - "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/reflection-common": "^1.0.0", "phpdocumentor/type-resolver": "^0.4.0", "webmozart/assert": "^1.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": [ @@ -1020,7 +1263,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-08-30T18:51:59+00:00" + "time": "2017-11-30T07:14:17+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -1071,33 +1314,33 @@ }, { "name": "phpspec/prophecy", - "version": "v1.7.2", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", - "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "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/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8 || ^5.6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -1130,44 +1373,44 @@ "spy", "stub" ], - "time": "2017-09-04T11:05:03+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "4.0.8", + "version": "6.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a", + "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "^1.3", - "phpunit/php-text-template": "^1.2", - "phpunit/php-token-stream": "^1.4.2 || ^2.0", - "sebastian/code-unit-reverse-lookup": "^1.0", - "sebastian/environment": "^1.3.2 || ^2.0", - "sebastian/version": "^1.0 || ^2.0" + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" }, "require-dev": { - "ext-xdebug": "^2.1.4", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.1" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -1182,7 +1425,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1193,29 +1436,29 @@ "testing", "xunit" ], - "time": "2017-04-02T07:44:40+00:00" + "time": "2018-06-01T07:51:50+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + "reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c", + "reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1230,7 +1473,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1240,7 +1483,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2018-06-11T11:44:00+00:00" }, { "name": "phpunit/php-text-template", @@ -1285,28 +1528,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1321,7 +1564,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1330,33 +1573,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2018-02-01T13:07:23+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0" + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9a02332089ac48e704c70f6cefed30c224e3c0b0", - "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1379,55 +1622,57 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20T05:47:52+00:00" + "time": "2018-02-01T13:16:43+00:00" }, { "name": "phpunit/phpunit", - "version": "5.7.22", + "version": "7.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "10df877596c9906d4110b5b905313829043f2ada" + "reference": "f9b14c17860eccb440a0352a117a81eb754cff5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/10df877596c9906d4110b5b905313829043f2ada", - "reference": "10df877596c9906d4110b5b905313829043f2ada", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f9b14c17860eccb440a0352a117a81eb754cff5a", + "reference": "f9b14c17860eccb440a0352a117a81eb754cff5a", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.6.2", - "phpunit/php-code-coverage": "^4.0.4", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "^3.2", - "sebastian/comparator": "^1.2.4", - "sebastian/diff": "^1.4.3", - "sebastian/environment": "^1.3.4 || ^2.0", - "sebastian/exporter": "~2.0", - "sebastian/global-state": "^1.1", - "sebastian/object-enumerator": "~2.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0.3|~2.0", - "symfony/yaml": "~2.1|~3.0" + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.0", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" }, "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" + "phpunit/phpunit-mock-objects": "*" }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "~1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -1435,7 +1680,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.7.x-dev" + "dev-master": "7.3-dev" } }, "autoload": { @@ -1461,66 +1706,7 @@ "testing", "xunit" ], - "time": "2017-09-24T07:23:38+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "3.4.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" - }, - "conflict": { - "phpunit/phpunit": "<5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2017-06-30T09:13:00+00:00" + "time": "2018-08-07T06:44:28+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1569,30 +1755,30 @@ }, { "name": "sebastian/comparator", - "version": "1.2.4", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1623,38 +1809,39 @@ } ], "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", "equality" ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "1.4.3", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + "reference": "366541b989927187c4ca70490a35615d3fef2dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", + "reference": "366541b989927187c4ca70490a35615d3fef2dce", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1679,34 +1866,37 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2018-06-10T07:54:39+00:00" }, { "name": "sebastian/environment", - "version": "2.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^5.0" + "phpunit/phpunit": "^6.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -1731,34 +1921,34 @@ "environment", "hhvm" ], - "time": "2016-11-26T07:53:53+00:00" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", - "version": "2.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~2.0" + "php": "^7.0", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -1798,27 +1988,27 @@ "export", "exporter" ], - "time": "2016-11-19T08:54:04+00:00" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/global-state", - "version": "1.1.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "^6.0" }, "suggest": { "ext-uopz": "*" @@ -1826,7 +2016,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1849,33 +2039,34 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", - "version": "2.0.1", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", "shasum": "" }, "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~2.0" + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~5" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1895,32 +2086,77 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/recursion-context", - "version": "2.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1948,7 +2184,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", @@ -2037,16 +2273,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.1.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "3c2d0a0fe39684ba0c1eb842a6a775d0b938d699" + "reference": "628a481780561150481a9ec74709092b9759b3ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/3c2d0a0fe39684ba0c1eb842a6a775d0b938d699", - "reference": "3c2d0a0fe39684ba0c1eb842a6a775d0b938d699", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/628a481780561150481a9ec74709092b9759b3ec", + "reference": "628a481780561150481a9ec74709092b9759b3ec", "shasum": "" }, "require": { @@ -2056,7 +2292,7 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "bin": [ "bin/phpcs", @@ -2084,75 +2320,60 @@ "phpcs", "standards" ], - "time": "2017-09-19T22:47:14+00:00" + "time": "2018-07-26T23:47:18+00:00" }, { - "name": "symfony/yaml", - "version": "v3.3.9", + "name": "theseer/tokenizer", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "1d8c2a99c80862bdc3af94c1781bf70f86bccac0" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/1d8c2a99c80862bdc3af94c1781bf70f86bccac0", - "reference": "1d8c2a99c80862bdc3af94c1781bf70f86bccac0", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" - }, - "require-dev": { - "symfony/console": "~2.8|~3.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.3-dev" - } - }, "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" }, { "name": "webmozart/assert", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", "shasum": "" }, "require": { @@ -2189,7 +2410,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2018-01-29T19:49:41+00:00" } ], "aliases": [], @@ -2198,15 +2419,10 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^5.5 | ^7.0" + "php": "^7.0" }, "platform-dev": [], "platform-overrides": { - "ext-tokenizer": "1.0", - "ext-dom": "1.0", - "ext-xmlwriter": "1.0", - "ext-xml": "1.0", - "ext-simplexml": "1.0", - "php": "7.1" + "php": "7.2" } } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index cf7bfc7..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: '2' - -services: - test: - image: graze/php-alpine:test - volumes: - - .:/srv - working_dir: /srv - - db: - image: mysql - environment: - MYSQL_USER: dev - MYSQL_PASSWORD: password - MYSQL_DATABASE: the_schema diff --git a/docs/sprout.md b/docs/sprout.md new file mode 100644 index 0000000..2744533 --- /dev/null +++ b/docs/sprout.md @@ -0,0 +1,7 @@ +# Sprout + +Sprout is a tool to help you Populate your databases with seed data. + +It's core method is by using .sql files that can be committed and diffed by your code repository. + + diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..ef5edff --- /dev/null +++ b/example/Makefile @@ -0,0 +1,33 @@ +# Examples + +start-db: ## Start the database + docker-compose up -d db + docker-compose run --rm netcat + +morphism: ## Populate the schema for the database +morphism: start-db + docker-compose run --rm morphism diff /config/morphism.yml --apply-changes=yes + +seed: ## Seed the data for the database +seed: start-db + docker-compose run --rm sprout seed -t the_schema -v + +seed-group: ## Seed the data in a group for a database +seed-group: start-db + docker-compose run --rm sprout seed -t --group=core -v + +chop: ## Truncate the data in the database +chop: start-db + docker-compose run --rm sprout chop the_schema:country -v + +chop-group: ## Truncate the data in the database +chop-group: start-db + docker-compose run --rm sprout chop --group=core -v + +dump: ## Dump the data from a table +dump: start-db + docker-compose run --rm sprout dump the_schema:* -v + +dump-group: ## Dump the data from a table +dump-group: start-db + docker-compose run --rm sprout dump --group=core the_schema -v diff --git a/example/config/morphism.yml b/example/config/morphism.yml new file mode 100644 index 0000000..0874adc --- /dev/null +++ b/example/config/morphism.yml @@ -0,0 +1,9 @@ +databases: + the_schema: + user: 'root' + password: 'rootpassword' + host: 'db' + driver: 'pdo_mysql' + morphism: + enable: true + schemaDefinitionPath: /schema/the_schema diff --git a/example/config/mysql.cnf b/example/config/mysql.cnf new file mode 100644 index 0000000..4e4abc0 --- /dev/null +++ b/example/config/mysql.cnf @@ -0,0 +1,76 @@ +# +# The MySQL Community Server configuration file. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +[client] +port = 3306 +socket = /var/run/mysqld/mysqld.sock + +[mysqld_safe] +pid-file = /var/run/mysqld/mysqld.pid +socket = /var/run/mysqld/mysqld.sock +nice = 0 + +[mysqld] +skip-host-cache +skip-name-resolve +user = mysql +socket = /var/run/mysqld/mysqld.sock +port = 3306 +basedir = /usr +datadir = /var/lib/mysql +tmpdir = /tmp +lc-messages-dir = /usr/share/mysql +explicit_defaults_for_timestamp + +# Instead of skip-networking the default is now to listen only on +# localhost which is more compatible and is not less secure. +#bind-address = 127.0.0.1 + +# Recommended in standard MySQL setup +sql_mode='' + +# Disabling symbolic-links is recommended to prevent assorted security risks +symbolic-links=0 + +innodb_buffer_pool_size=5M +innodb_log_buffer_size=256K +query_cache_size=0 +key_buffer_size=8 +thread_cache_size=0 +host_cache_size=0 +innodb_ft_cache_size=1600000 +innodb_ft_total_cache_size=32000000 + +# per thread or per operation settings +thread_stack=131072 +sort_buffer_size=32K +read_buffer_size=8200 +read_rnd_buffer_size=8200 +max_heap_table_size=16K +tmp_table_size=1K +bulk_insert_buffer_size=0 +join_buffer_size=128 +net_buffer_length=1K +innodb_sort_buffer_size=64K +innodb_doublewrite=OFF + +#settings that relate to the binary log (if enabled) +binlog_cache_size=4K +binlog_stmt_cache_size=4K + +performance_schema=OFF + +# Logging +log_error = /var/log/mysql/error.log +general_log = 1 +general_log_file = /var/log/mysql/general.log +slow_query_log = 1 +slow_query_log_file = /var/log/mysql/slow.log + +# * IMPORTANT: Additional settings that can override those from this file! +# The files must end with '.cnf', otherwise they'll be ignored. +# +!includedir /etc/mysql/conf.d/ diff --git a/example/config/sprout.yml b/example/config/sprout.yml new file mode 100644 index 0000000..d75e673 --- /dev/null +++ b/example/config/sprout.yml @@ -0,0 +1,13 @@ +defaults: + group: core + path: ./data +schemas: + the_schema: + connection: + user: 'dev' + password: 'password' + driver: 'mysql' + dbName: 'the_schema' + host: 'db' + port: 3306 + schema: the_schema diff --git a/example/data/core/the_schema/.DS_Store b/example/data/core/the_schema/.DS_Store new file mode 100644 index 0000000..e69de29 diff --git a/example/data/core/the_schema/country.sql b/example/data/core/the_schema/country.sql new file mode 100644 index 0000000..45e09f6 --- /dev/null +++ b/example/data/core/the_schema/country.sql @@ -0,0 +1,251 @@ +INSERT INTO `country` (`id`, `country_code`, `country_code_iso2`, `country_code_iso3`, `name`, `decimal_point`, `thousands_separator`, `added`, `updated`, `deleted`) VALUES +(1,'AF','AF','AFG','Afghanistan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(2,'AX','AX','ALA','Aland Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(3,'AL','AL','ALB','Albania','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(4,'DZ','DZ','DZA','Algeria','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(5,'AS','AS','ASM','American Samoa','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(6,'AD','AD','AND','Andorra','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(7,'AO','AO','AGO','Angola','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(8,'AI','AI','AIA','Anguilla','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(9,'A1','','','Anonymous Proxy','.',',','2012-09-20 12:43:09','2012-10-23 16:27:47',NULL), +(10,'AQ','AQ','ATA','Antarctica','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(11,'AG','AG','ATG','Antigua and Barbuda','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(12,'AR','AR','ARG','Argentina','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(13,'AM','AM','ARM','Armenia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(14,'AW','AW','ABW','Aruba','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(15,'AP','','','Asia/Pacific Region','.',',','2012-09-20 12:43:09','2012-10-23 16:27:47',NULL), +(16,'AU','AU','AUS','Australia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(17,'AT','AT','AUT','Austria','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(18,'AZ','AZ','AZE','Azerbaijan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(19,'BS','BS','BHS','Bahamas','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(20,'BH','BH','BHR','Bahrain','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(21,'BD','BD','BGD','Bangladesh','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(22,'BB','BB','BRB','Barbados','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(23,'BY','BY','BLR','Belarus','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(24,'BE','BE','BEL','Belgium','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(25,'BZ','BZ','BLZ','Belize','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(26,'BJ','BJ','BEN','Benin','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(27,'BM','BM','BMU','Bermuda','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(28,'BT','BT','BTN','Bhutan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(29,'BO','BO','BOL','Bolivia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(30,'BA','BA','BIH','Bosnia and Herzegovina','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(31,'BW','BW','BWA','Botswana','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(32,'BV','BV','BVT','Bouvet Island','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(33,'BR','BR','BRA','Brazil','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(34,'IO','IO','IOT','British Indian Ocean Territory','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(35,'BN','BN','BRN','Brunei Darussalam','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(36,'BG','BG','BGR','Bulgaria','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(37,'BF','BF','BFA','Burkina Faso','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(38,'BI','BI','BDI','Burundi','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(39,'KH','KH','KHM','Cambodia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(40,'CM','CM','CMR','Cameroon','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(41,'CA','CA','CAN','Canada','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(42,'CV','CV','CPV','Cape Verde','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(43,'KY','KY','CYM','Cayman Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(44,'CF','CF','CAF','Central African Republic','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(45,'TD','TD','TCD','Chad','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(46,'CL','CL','CHL','Chile','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(47,'CN','CN','CHN','China','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(48,'CX','CX','CXR','Christmas Island','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(49,'CC','CC','CCK','Cocos (Keeling) Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(50,'CO','CO','COL','Colombia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(51,'KM','KM','COM','Comoros','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(52,'CG','CG','COG','Congo','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(53,'CD','CD','COD','Congo, The Democratic Republic of the','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(54,'CK','CK','COK','Cook Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(55,'CR','CR','CRI','Costa Rica','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(56,'CI','CI','CIV','Cote D\'Ivoire','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(57,'HR','HR','HRV','Croatia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(58,'CU','CU','CUB','Cuba','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(59,'CY','CY','CYP','Cyprus','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(60,'CZ','CZ','CZE','Czech Republic','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(61,'DK','DK','DNK','Denmark','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(62,'DJ','DJ','DJI','Djibouti','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(63,'DM','DM','DMA','Dominica','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(64,'DO','DO','DOM','Dominican Republic','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(65,'EC','EC','ECU','Ecuador','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(66,'EG','EG','EGY','Egypt','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(67,'SV','SV','SLV','El Salvador','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(68,'GQ','GQ','GNQ','Equatorial Guinea','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(69,'ER','ER','ERI','Eritrea','.',',','2012-09-20 12:43:09','2015-10-07 11:05:58',NULL), +(70,'EE','EE','EST','Estonia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(71,'ET','ET','ETH','Ethiopia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(72,'EU','','','Europe','.',',','2012-09-20 12:43:09','2012-10-23 16:27:47',NULL), +(73,'FK','FK','FLK','Falkland Islands (Malvinas)','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(74,'FO','FO','FRO','Faroe Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(75,'FJ','FJ','FJI','Fiji','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(76,'FI','FI','FIN','Finland','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(77,'FR','FR','FRA','France','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(78,'GF','GF','GUF','French Guiana','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(79,'PF','PF','PYF','French Polynesia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(80,'TF','TF','ATF','French Southern Territories','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(81,'GA','GA','GAB','Gabon','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(82,'GM','GM','GMB','Gambia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(83,'GE','GE','GEO','Georgia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(84,'DE','DE','DEU','Germany','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(85,'GH','GH','GHA','Ghana','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(86,'GI','GI','GIB','Gibraltar','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(87,'GR','GR','GRC','Greece','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(88,'GL','GL','GRL','Greenland','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(89,'GD','GD','GRD','Grenada','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(90,'GP','GP','GLP','Guadeloupe','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(91,'GU','GU','GUM','Guam','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(92,'GT','GT','GTM','Guatemala','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(93,'GG','GG','GGY','Guernsey','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(94,'GN','GN','GIN','Guinea','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(95,'GW','GW','GNB','Guinea-Bissau','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(96,'GY','GY','GUY','Guyana','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(97,'HT','HT','HTI','Haiti','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(98,'HM','HM','HMD','Heard Island and McDonald Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(99,'VA','VA','VAT','Holy See (Vatican City State)','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(100,'HN','HN','HND','Honduras','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(101,'HK','HK','HKG','Hong Kong','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(102,'HU','HU','HUN','Hungary','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(103,'IS','IS','ISL','Iceland','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(104,'IN','IN','IND','India','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(105,'ID','ID','IDN','Indonesia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(106,'IR','IR','IRN','Iran, Islamic Republic of','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(107,'IQ','IQ','IRQ','Iraq','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(108,'IE','IE','IRL','Ireland','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(109,'IM','IM','IMN','Isle of Man','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(110,'IL','IL','ISR','Israel','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(111,'IT','IT','ITA','Italy','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(112,'JM','JM','JAM','Jamaica','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(113,'JP','JP','JPN','Japan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(114,'JE','JE','JEY','Jersey','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(115,'JO','JO','JOR','Jordan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(116,'KZ','KZ','KAZ','Kazakhstan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(117,'KE','KE','KEN','Kenya','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(118,'KI','KI','KIR','Kiribati','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(119,'KP','KP','PRK','Korea, Democratic People\'s Republic of','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(120,'KR','KR','KOR','Korea, Republic of','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(121,'KW','KW','KWT','Kuwait','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(122,'KG','KG','KGZ','Kyrgyzstan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(123,'LA','LA','LAO','Lao People\'s Democratic Republic','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(124,'LV','LV','LVA','Latvia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(125,'LB','LB','LBN','Lebanon','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(126,'LS','LS','LSO','Lesotho','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(127,'LR','LR','LBR','Liberia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(128,'LY','LY','LBY','Libyan Arab Jamahiriya','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(129,'LI','LI','LIE','Liechtenstein','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(130,'LT','LT','LTU','Lithuania','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(131,'LU','LU','LUX','Luxembourg','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(132,'MO','MO','MAC','Macau','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(133,'MK','MK','MKD','Macedonia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(134,'MG','MG','MDG','Madagascar','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(135,'MW','MW','MWI','Malawi','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(136,'MY','MY','MYS','Malaysia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(137,'MV','MV','MDV','Maldives','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(138,'ML','ML','MLI','Mali','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(139,'MT','MT','MLT','Malta','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(140,'MH','MH','MHL','Marshall Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(141,'MQ','MQ','MTQ','Martinique','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(142,'MR','MR','MRT','Mauritania','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(143,'MU','MU','MUS','Mauritius','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(144,'YT','YT','MYT','Mayotte','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(145,'MX','MX','MEX','Mexico','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(146,'FM','FM','FSM','Micronesia, Federated States of','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(147,'MD','MD','MDA','Moldova, Republic of','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(148,'MC','MC','MCO','Monaco','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(149,'MN','MN','MNG','Mongolia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(150,'ME','ME','MNE','Montenegro','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(151,'MS','MS','MSR','Montserrat','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(152,'MA','MA','MAR','Morocco','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(153,'MZ','MZ','MOZ','Mozambique','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(154,'MM','MM','MMR','Myanmar','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(155,'NA','NA','NAM','Namibia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(156,'NR','NR','NRU','Nauru','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(157,'NP','NP','NPL','Nepal','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(158,'NL','NL','NLD','Netherlands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(159,'AN','','','Netherlands Antilles','.',',','2012-09-20 12:43:09','2012-10-23 16:27:47',NULL), +(160,'NC','NC','NCL','New Caledonia','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(161,'NZ','NZ','NZL','New Zealand','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(162,'NI','NI','NIC','Nicaragua','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(163,'NE','NE','NER','Niger','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(164,'NG','NG','NGA','Nigeria','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(165,'NU','NU','NIU','Niue','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(166,'NF','NF','NFK','Norfolk Island','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(167,'MP','MP','MNP','Northern Mariana Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(168,'NO','NO','NOR','Norway','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(169,'OM','OM','OMN','Oman','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(170,'PK','PK','PAK','Pakistan','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(171,'PW','PW','PLW','Palau','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(172,'PS','PS','PSE','Palestinian Territory, Occupied','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(173,'PA','PA','PAN','Panama','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(174,'PG','PG','PNG','Papua New Guinea','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(175,'PY','PY','PRY','Paraguay','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(176,'PE','PE','PER','Peru','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(177,'PH','PH','PHL','Philippines','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(178,'PN','PN','PCN','Pitcairn Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:05:59',NULL), +(179,'PL','PL','POL','Poland','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(180,'PT','PT','PRT','Portugal','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(181,'PR','PR','PRI','Puerto Rico','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(182,'QA','QA','QAT','Qatar','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(183,'RE','RE','REU','Reunion','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(184,'RO','RO','ROU','Romania','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(185,'RU','RU','RUS','Russian Federation','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(186,'RW','RW','RWA','Rwanda','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(187,'BL','BL','BLM','Saint Barthelemy','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(188,'SH','SH','SHN','Saint Helena','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(189,'KN','KN','KNA','Saint Kitts and Nevis','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(190,'LC','LC','LCA','Saint Lucia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(191,'MF','MF','MAF','Saint Martin','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(192,'PM','PM','SPM','Saint Pierre and Miquelon','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(193,'VC','VC','VCT','Saint Vincent and the Grenadines','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(194,'WS','WS','WSM','Samoa','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(195,'SM','SM','SMR','San Marino','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(196,'ST','ST','STP','Sao Tome and Principe','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(197,'A2','','','Satellite Provider','.',',','2012-09-20 12:43:09','2012-10-23 16:27:47',NULL), +(198,'SA','SA','SAU','Saudi Arabia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(199,'SN','SN','SEN','Senegal','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(200,'RS','RS','SRB','Serbia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(201,'SC','SC','SYC','Seychelles','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(202,'SL','SL','SLE','Sierra Leone','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(203,'SG','SG','SGP','Singapore','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(204,'SK','SK','SVK','Slovakia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(205,'SI','SI','SVN','Slovenia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(206,'SB','SB','SLB','Solomon Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(207,'SO','SO','SOM','Somalia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(208,'ZA','ZA','ZAF','South Africa','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(209,'GS','GS','SGS','South Georgia and the South Sandwich Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(210,'ES','ES','ESP','Spain','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(211,'LK','LK','LKA','Sri Lanka','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(212,'SD','SD','SDN','Sudan','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(213,'SR','SR','SUR','Suriname','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(214,'SJ','SJ','SJM','Svalbard and Jan Mayen','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(215,'SZ','SZ','SWZ','Swaziland','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(216,'SE','SE','SWE','Sweden','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(217,'CH','CH','CHE','Switzerland','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(218,'SY','SY','SYR','Syrian Arab Republic','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(219,'TW','TW','TWN','Taiwan','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(220,'TJ','TJ','TJK','Tajikistan','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(221,'TZ','TZ','TZA','Tanzania, United Republic of','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(222,'TH','TH','THA','Thailand','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(223,'TL','TL','TLS','Timor-Leste','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(224,'TG','TG','TGO','Togo','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(225,'TK','TK','TKL','Tokelau','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(226,'TO','TO','TON','Tonga','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(227,'TT','TT','TTO','Trinidad and Tobago','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(228,'TN','TN','TUN','Tunisia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(229,'TR','TR','TUR','Turkey','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(230,'TM','TM','TKM','Turkmenistan','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(231,'TC','TC','TCA','Turks and Caicos Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(232,'TV','TV','TUV','Tuvalu','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(233,'UG','UG','UGA','Uganda','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(234,'UA','UA','UKR','Ukraine','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(235,'AE','AE','ARE','United Arab Emirates','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(236,'UK','GB','GBR','United Kingdom','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(237,'US','US','USA','United States','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(238,'UM','UM','UMI','United States Minor Outlying Islands','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(239,'UY','UY','URY','Uruguay','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(240,'UZ','UZ','UZB','Uzbekistan','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(241,'VU','VU','VUT','Vanuatu','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(242,'VE','VE','VEN','Venezuela','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(243,'VN','VN','VNM','Vietnam','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(244,'VG','VG','VGB','Virgin Islands, British','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(245,'VI','VI','VIR','Virgin Islands, U.S.','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(246,'WF','WF','WLF','Wallis and Futuna','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(247,'EH','EH','ESH','Western Sahara','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(248,'YE','YE','YEM','Yemen','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(249,'ZM','ZM','ZMB','Zambia','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL), +(250,'ZW','ZW','ZWE','Zimbabwe','.',',','2012-09-20 12:43:09','2015-10-07 11:06:00',NULL); diff --git a/example/docker-compose.yml b/example/docker-compose.yml new file mode 100644 index 0000000..9095a63 --- /dev/null +++ b/example/docker-compose.yml @@ -0,0 +1,40 @@ +version: '2' + +services: + sprout: + image: graze/sprout + build: ../ + depends_on: + - db + volumes: + - ../:/app:delegated + working_dir: /app/example + + morphism: + image: graze/morphism + depends_on: + - db + volumes: + - ./schema:/schema + - ./config:/config + + db: + image: mysql:5 + environment: + MYSQL_USER: dev + MYSQL_PASSWORD: password + MYSQL_DATABASE: the_schema + MYSQL_ROOT_PASSWORD: rootpassword + volumes: + - ./config/mysql.cnf:/etc/mysql/my.cnf + + netcat: + image: gophernet/netcat + depends_on: + - db + entrypoint: + - /bin/sh + command: ./wait-for-db.sh db 3306 + volumes: + - ../bin:/srv/bin + working_dir: /srv/bin diff --git a/example/schema/the_schema/country.sql b/example/schema/the_schema/country.sql new file mode 100644 index 0000000..a05854c --- /dev/null +++ b/example/schema/the_schema/country.sql @@ -0,0 +1,15 @@ +CREATE TABLE `country` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `country_code` char(2) NOT NULL, + `country_code_iso2` char(2) NOT NULL, + `country_code_iso3` char(3) NOT NULL, + `name` varchar(100) NOT NULL, + `decimal_point` varchar(2) NOT NULL, + `thousands_separator` varchar(2) NOT NULL, + `added` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `country_code` (`country_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + diff --git a/hooks/build b/hooks/build new file mode 100644 index 0000000..93df1c5 --- /dev/null +++ b/hooks/build @@ -0,0 +1,7 @@ +#!/bin/bash + +set +xe + +docker build --build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ + --build-arg VCS_REF="$(git rev-parse --short HEAD)" \ + -t "$IMAGE_NAME" . diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a27d8be..0d0de68 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -22,7 +22,4 @@ src/ - - - diff --git a/src/Chop/Chopper.php b/src/Chop/Chopper.php index ffdd71a..c4826d2 100644 --- a/src/Chop/Chopper.php +++ b/src/Chop/Chopper.php @@ -14,7 +14,6 @@ namespace Graze\Sprout\Chop; use Graze\Sprout\Config\SchemaConfigInterface; -use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Output\OutputInterface; class Chopper @@ -36,20 +35,19 @@ class Chopper public function __construct( SchemaConfigInterface $schemaConfig, OutputInterface $output, - TableChopperFactory $factory = null + TableChopperFactory $factory ) { $this->schemaConfig = $schemaConfig; $this->output = $output; - $this->factory = $factory ?: new TableChopperFactory($output); + $this->factory = $factory; } /** * Chop a collection of files to tables * - * @param string $path * @param string[] $tables */ - public function chop(string $path, array $tables = []) + public function chop(array $tables = []) { $tables = array_unique($tables); @@ -61,14 +59,8 @@ public function chop(string $path, array $tables = []) $tableChopper = $this->factory->getChopper($this->schemaConfig->getConnection()); $schema = $this->schemaConfig->getSchema(); - $progress = new ProgressBar($this->output); - $progress->start(count($tables)); - $progress->setMessage("chopping tables in {$schema} from {$path}"); - foreach ($tables as $table) { $tableChopper->chop($schema, $table); - $progress->advance(); } - $progress->finish(); } } diff --git a/src/Chop/Mysql/MysqlTableChopper.php b/src/Chop/Mysql/MysqlTableChopper.php index 4ec3181..50c60df 100644 --- a/src/Chop/Mysql/MysqlTableChopper.php +++ b/src/Chop/Mysql/MysqlTableChopper.php @@ -13,40 +13,41 @@ namespace Graze\Sprout\Chop\Mysql; -use Graze\Sprout\Config\ConnectionConfigInterface; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Chop\TableChopperInterface; -use InvalidArgumentException; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Exception\ProcessFailedException; +use Graze\Sprout\Config\ConnectionConfigInterface; use Symfony\Component\Process\Process; class MysqlTableChopper implements TableChopperInterface { /** @var ConnectionConfigInterface */ private $connection; - /** @var OutputInterface */ - private $output; + /** @var Pool */ + private $pool; /** * MysqlTableDumper constructor. * + * @param Pool $pool * @param ConnectionConfigInterface $connection - * @param OutputInterface $output */ - public function __construct(ConnectionConfigInterface $connection, OutputInterface $output) + public function __construct(Pool $pool, ConnectionConfigInterface $connection) { $this->connection = $connection; - $this->output = $output; + $this->pool = $pool; } + /** + * @param string $schema + * @param string $table + */ public function chop(string $schema, string $table) { - $this->output->write("chopping down {$schema}/{$table}... ", OutputInterface::VERBOSITY_DEBUG); - $process = new Process(''); $process->setCommandLine( sprintf( - 'mysql -h%1$s -u%2$s -p%3$s --default-character-set=utf8 %4$s < %5$s', + 'mysql -h%1$s -u%2$s -p%3$s --default-character-set=utf8 --execute=%5$s %4$s', escapeshellarg($this->connection->getHost()), escapeshellarg($this->connection->getUser()), escapeshellarg($this->connection->getPassword()), @@ -54,12 +55,7 @@ public function chop(string $schema, string $table) escapeshellarg(sprintf('TRUNCATE `%s`', $table)) ) ); - $process->run(); - - if (!$process->isSuccessful()) { - throw new ProcessFailedException($process); - } - $this->output->writeln("done", OutputInterface::VERBOSITY_DEBUG); + $this->pool->add($process, ['chop', 'schema' => $schema, 'table' => $table]); } } diff --git a/src/Chop/TableChopperFactory.php b/src/Chop/TableChopperFactory.php index 1d34a19..560d637 100644 --- a/src/Chop/TableChopperFactory.php +++ b/src/Chop/TableChopperFactory.php @@ -13,37 +13,50 @@ namespace Graze\Sprout\Chop; +use Graze\ParallelProcess\Pool; use Graze\Sprout\Chop\Mysql\MysqlTableChopper; use Graze\Sprout\Config\ConnectionConfigInterface; use InvalidArgumentException; -use Symfony\Component\Console\Output\OutputInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; -class TableChopperFactory +class TableChopperFactory implements LoggerAwareInterface { - /** @var OutputInterface */ - private $output; + use LoggerAwareTrait; + + /** @var Pool */ + private $processPool; /** * TableDumperFactory constructor. * - * @param OutputInterface $output + * @param Pool $processPool + * + * @internal param OutputInterface $output */ - public function __construct(OutputInterface $output) + public function __construct(Pool $processPool) { - $this->output = $output; + $this->processPool = $processPool; } + /** + * @param ConnectionConfigInterface $connection + * + * @return TableChopperInterface + */ public function getChopper(ConnectionConfigInterface $connection): TableChopperInterface { $driver = $connection->getDriver(); switch ($driver) { case 'mysql': - $this->output->writeln( - "Using mysql table chopper for driver: {$driver}", - OutputInterface::VERBOSITY_DEBUG - ); - return new MysqlTableChopper($connection, $this->output); + if ($this->logger) { + $this->logger->debug( + "getChopper: using mysql chopper for driver: {$driver}", + ['driver' => $driver] + ); + } + return new MysqlTableChopper($this->processPool, $connection); default: throw new InvalidArgumentException("getChopper: no chopper found for driver: `{$driver}`"); } diff --git a/src/Command/ChopCommand.php b/src/Command/ChopCommand.php index 5ff58fd..5799ce6 100644 --- a/src/Command/ChopCommand.php +++ b/src/Command/ChopCommand.php @@ -13,19 +13,26 @@ namespace Graze\Sprout\Command; -use Graze\ParallelProcess\Table; use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; +use Graze\Sprout\Chop\Chopper; +use Graze\Sprout\Chop\TableChopperFactory; use Graze\Sprout\Config; -use PDO; +use Graze\Sprout\Parser\ParsedSchema; +use Graze\Sprout\Parser\SchemaParser; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Process; class ChopCommand extends Command { + const OPTION_GROUP = 'group'; + const OPTION_CONFIG = 'config'; + + const ARGUMENT_SCHEMA_TABLES = 'schemaTables'; + protected function configure() { $this->setName('chop'); @@ -33,18 +40,24 @@ protected function configure() $this->setDescription('Chop down (truncate) all the tables'); $this->addOption( - 'config', + static::OPTION_CONFIG, 'c', InputOption::VALUE_OPTIONAL, 'The configuration file to use', Config::DEFAULT_CONFIG_PATH ); - $this->addArgument('schema', InputArgument::REQUIRED, 'The schema configuration to use'); + $this->addOption( + static::OPTION_GROUP, + 'g', + InputOption::VALUE_OPTIONAL, + 'The group to truncate' + ); + $this->addArgument( - 'table', + static::ARGUMENT_SCHEMA_TABLES, InputArgument::OPTIONAL | InputArgument::IS_ARRAY, - 'The tables to truncate, if not specified. Truncate will empty all the tables in a schema (not in an exclude regex)' + 'Collection of schema and tables to use, examples: schema1 schema2 | schema1:* schema2:table1,table2' ); } @@ -57,20 +70,54 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $schema = $input->getArgument('schema'); - $tables = $input->getArgument('table'); - + $schemas = $input->getArgument(static::ARGUMENT_SCHEMA_TABLES); $config = (new Config())->parse($input->getOption('config')); + $group = $input->getOption('group') ?: $config->get(Config::CONFIG_DEFAULT_GROUP); - $schemaConfiguration = $config->getSchemaConfiguration($schema); - $schemaPath = $config->getSchemaPath($schema); + $schemaParser = new SchemaParser($config, $group); + $parsedSchemas = $schemaParser->extractSchemas($schemas); - if (count($tables) === 0) { - $excludes = $schemaConfiguration->getExcludes(); - foreach ($excludes as $exclude) { - $wheres[] = "`table_name` NOT REGEXP ?"; - $binds[] = sprintf('^%s$', $exclude); + $numTables = array_sum(array_map( + function (ParsedSchema $schema) { + return count($schema->getTables()); + }, + $parsedSchemas + )); + + $useGlobal = $numTables <= 10; + + $globalPool = new Pool(); + $globalPool->setMaxSimultaneous($config->get(Config::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES)); + + foreach ($parsedSchemas as $schema) { + $output->writeln(sprintf( + 'Chopping down %d tables in %s schema in group %s', + count($schema->getTables()), + $schema->getSchameName(), + $group + )); + + if ($useGlobal) { + $pool = $globalPool; + } else { + $pool = new Pool( + [], + $config->get(Config::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES), + false, + ['chop', 'schema' => $schema->getSchameName()] + ); + $globalPool->add($pool); } + + $chopper = new Chopper($schema->getSchemaConfig(), $output, new TableChopperFactory($pool)); + $chopper->chop($schema->getTables()); + } + + $processTable = new Table($output, $globalPool); + $processTable->setShowSummary(true); + + if (!$processTable->run(0.1)) { + return 1; } return 0; diff --git a/src/Command/DumpCommand.php b/src/Command/DumpCommand.php index fea38bb..2bce915 100644 --- a/src/Command/DumpCommand.php +++ b/src/Command/DumpCommand.php @@ -14,8 +14,13 @@ namespace Graze\Sprout\Command; use Exception; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config; use Graze\Sprout\Dump\Dumper; +use Graze\Sprout\Dump\TableDumperFactory; +use Graze\Sprout\Parser\ParsedSchema; +use Graze\Sprout\Parser\SchemaParser; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -24,6 +29,8 @@ class DumpCommand extends Command { + const ARGUMENT_SCHEMA_TABLES = 'schemaTables'; + protected function configure() { $this->setName('dump'); @@ -37,11 +44,17 @@ protected function configure() Config::DEFAULT_CONFIG_PATH ); - $this->addArgument('schema', InputArgument::REQUIRED, 'The schema configuration to use'); + $this->addOption( + 'group', + 'g', + InputOption::VALUE_OPTIONAL, + 'The group to use' + ); + $this->addArgument( - 'table', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'The tables to dump' + static::ARGUMENT_SCHEMA_TABLES, + InputArgument::OPTIONAL | InputArgument::IS_ARRAY, + 'Collection of schema and tables to use, examples: schema1 schema2 | schema1:* schema2:table1,table2' ); } @@ -54,16 +67,55 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $schema = $input->getArgument('schema'); - $tables = $input->getArgument('table'); - + $schemas = $input->getArgument(static::ARGUMENT_SCHEMA_TABLES); $config = (new Config())->parse($input->getOption('config')); + $group = $input->getOption('group') ?: $config->get(Config::CONFIG_DEFAULT_GROUP); + + $schemaParser = new SchemaParser($config, $group); + $parsedSchemas = $schemaParser->extractSchemas($schemas); + + $numTables = array_sum(array_map( + function (ParsedSchema $schema) { + return count($schema->getTables()); + }, + $parsedSchemas + )); + + $useGlobal = $numTables <= 10; + + $globalPool = new Pool(); + $globalPool->setMaxSimultaneous($config->get(Config::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES)); + + foreach ($parsedSchemas as $schema) { + $output->writeln(sprintf( + 'Dumping %d tables in %s schema in group %s', + count($schema->getTables()), + $schema->getSchameName(), + $group + )); + + if ($useGlobal) { + $pool = $globalPool; + } else { + $pool = new Pool( + [], + $config->get(Config::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES), + false, + ['dump', 'schema' => $schema->getSchameName()] + ); + $globalPool->add($pool); + } + + $dumper = new Dumper($schema->getSchemaConfig(), $output, new TableDumperFactory($pool)); + $dumper->dump($schema->getPath(), $schema->getTables()); + } - $schemaConfiguration = $config->getSchemaConfiguration($schema); - $schemaPath = $config->getSchemaPath($schema); + $processTable = new Table($output, $globalPool); + $processTable->setShowSummary(true); - $dumper = new Dumper($schemaConfiguration, $output); - $dumper->dump($schemaPath, $tables); + if (!$processTable->run(0.1)) { + return 1; + } return 0; } diff --git a/src/Command/SeedCommand.php b/src/Command/SeedCommand.php index fc0fc0f..b82b2bd 100644 --- a/src/Command/SeedCommand.php +++ b/src/Command/SeedCommand.php @@ -14,9 +14,15 @@ namespace Graze\Sprout\Command; use Exception; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config; +use Graze\Sprout\Parser\ParsedSchema; +use Graze\Sprout\Parser\SchemaParser; use Graze\Sprout\Seed\Seeder; +use Graze\Sprout\Seed\TableSeederFactory; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -24,24 +30,42 @@ class SeedCommand extends Command { + const OPTION_CONFIG = 'config'; + const OPTION_CHOP = 'chop'; + const OPTION_GROUP = 'group'; + const ARGUMENT_SCHEMA_TABLES = 'schemaTables'; + protected function configure() { $this->setName('seed'); - $this->setDescription('Seed all the data for a given schema or tables'); + $this->setDescription('Seed all the data for a given group, schema or table'); $this->addOption( - 'config', + static::OPTION_CONFIG, 'c', InputOption::VALUE_OPTIONAL, 'The configuration file to use', Config::DEFAULT_CONFIG_PATH ); - $this->addArgument('schema', InputArgument::REQUIRED, 'The schema configuration to use'); + $this->addOption( + static::OPTION_CHOP, + 't', + InputOption::VALUE_NONE, + 'chop (truncate) tables before seeding them' + ); + + $this->addOption( + static::OPTION_GROUP, + 'g', + InputOption::VALUE_OPTIONAL, + 'group to seed' + ); + $this->addArgument( - 'table', + static::ARGUMENT_SCHEMA_TABLES, InputArgument::OPTIONAL | InputArgument::IS_ARRAY, - 'The tables to seed, if not specified. Seed all tables that there is a file for' + 'Collection of schema and tables to use, examples: schema1 schema2 | schema1:* schema2:table1,table2' ); } @@ -54,27 +78,70 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $schema = $input->getArgument('schema'); - $tables = $input->getArgument('table'); - + $schemas = $input->getArgument(static::ARGUMENT_SCHEMA_TABLES); $config = (new Config())->parse($input->getOption('config')); + $group = $input->getOption('group') ?: $config->get(Config::CONFIG_DEFAULT_GROUP); + + if ($input->getOption(static::OPTION_CHOP)) { + $chopCommand = new ChopCommand(); + $exitCode = $chopCommand->run( + new ArrayInput([ + static::ARGUMENT_SCHEMA_TABLES => $schemas, + '--' . static::OPTION_CONFIG => $input->getOption(static::OPTION_CONFIG), + '--' . static::OPTION_GROUP => $group, + ]), + $output + ); + if ($exitCode !== 0) { + throw new \RuntimeException('failed to chop down the tables'); + } + } + + $schemaParser = new SchemaParser($config, $group); + $parsedSchemas = $schemaParser->extractSchemas($schemas); + + $numTables = array_sum(array_map( + function (ParsedSchema $schema) { + return count($schema->getTables()); + }, + $parsedSchemas + )); + + $useGlobal = $numTables <= 10; - $schemaConfiguration = $config->getSchemaConfiguration($schema); - $schemaPath = $config->getSchemaPath($schema); - - if (count($tables) === 0) { - // find tables from existing dump - $files = new \FilesystemIterator($schemaPath); - foreach ($files as $file) { - if (in_array($file, ['.', '..'])) { - continue; - } - $tables[] = pathinfo($file, PATHINFO_FILENAME); + $globalPool = new Pool(); + $globalPool->setMaxSimultaneous($config->get(Config::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES)); + + foreach ($parsedSchemas as $schema) { + $output->writeln(sprintf( + 'Seeding %d tables in %s schema in group %s', + count($schema->getTables()), + $schema->getSchameName(), + $group + )); + + if ($useGlobal) { + $pool = $globalPool; + } else { + $pool = new Pool( + [], + $config->get(Config::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES), + false, + ['seed', 'schema' => $schema->getSchameName()] + ); + $globalPool->add($pool); } + + $seeder = new Seeder($schema->getSchemaConfig(), $output, new TableSeederFactory($pool)); + $seeder->seed($schema->getPath(), $schema->getTables()); } - $seeder = new Seeder($schemaConfiguration, $output); - $seeder->seed($schemaPath, $tables); + $processTable = new Table($output, $globalPool); + $processTable->setShowSummary(true); + + if (!$processTable->run(0.1)) { + return 1; + } return 0; } diff --git a/src/Config/Config.php b/src/Config/Config.php index 711e3cd..ec00741 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -15,6 +15,8 @@ use Graze\ConfigValidation\ConfigValidatorInterface; use Graze\ConfigValidation\Validate; +use Graze\Sprout\Config\ConnectionConfig; +use Graze\Sprout\Config\GroupConfig; use Graze\Sprout\Config\SchemaConfig; use Graze\Sprout\Config\SchemaConfigInterface; use InvalidArgumentException; @@ -28,7 +30,16 @@ class Config { const DEFAULT_GROUP = 'core'; const DEFAULT_PATH = '/seed'; - const DEFAULT_CONFIG_PATH = '/app/config/config.yml'; + const DEFAULT_CONFIG_PATH = 'config/sprout.yml'; + const DEFAULT_PROCESSES = 10; + + const CONFIG_DEFAULT_GROUP = 'defaults.group'; + const CONFIG_DEFAULT_PATH = 'defaults.path'; + const CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES = 'defaults.simultaneousProcesses'; + + const CONFIG_SCHEMAS = 'schemas'; + + const CONFIG_GROUPS = 'groups'; /** @var array */ private $config; @@ -36,21 +47,27 @@ class Config /** @var ConfigValidatorInterface */ private $validator; - /** - * Config constructor. - */ public function __construct() { - $this->validator = Validate::arr(false) - ->optional('defaults.group', v::stringType()->alnum('_'), static::DEFAULT_GROUP) - ->optional('defaults.path', v::stringType()->directory(), static::DEFAULT_PATH) - ->required( - 'schemas', - v::arrayVal()->each( - SchemaConfig::getValidator() - ->getValidator() - ) - ); + $this->validator = + Validate::arr(false) + ->optional(static::CONFIG_DEFAULT_GROUP, v::stringType()->alnum('_'), static::DEFAULT_GROUP) + ->optional(static::CONFIG_DEFAULT_PATH, v::stringType()->directory(), static::DEFAULT_PATH) + ->optional(static::CONFIG_DEFAULT_SIMULTANEOUS_PROCESSES, v::intVal(), static::DEFAULT_PROCESSES) + ->optional( + static::CONFIG_GROUPS, + v::arrayVal()->each( + GroupConfig::getValidator() + ->getValidator() + ) + ) + ->required( + static::CONFIG_SCHEMAS, + v::arrayVal()->length(1, null)->each( + SchemaConfig::getValidator() + ->getValidator() + ) + ); } /** @@ -59,17 +76,25 @@ public function __construct() * @param string $path * * @return $this + * @throws \Graze\ConfigValidation\Exceptions\ConfigValidationFailedException */ - public function parse(string $path) + public function parse(string $path): Config { + if (!file_exists($path)) { + throw new \RuntimeException(sprintf('The supplied path %s does not exist', $path)); + } + $parser = new Parser(); $fileConfig = $parser->parse(file_get_contents($path)); $config = $this->validator->validate($fileConfig); // populates the schema / connection.dbname properties for each defined schema if not set - $schemas = $this->config['schemas']; + $schemas = $config['schemas']; foreach ($schemas as $schema => $value) { + $value = SchemaConfig::getValidator()->validate($value); + $value['connection'] = ConnectionConfig::getValidator()->validate($value['connection']); + if (is_null($value['schema'])) { $config['schemas'][$schema]['schema'] = $schema; } @@ -94,7 +119,7 @@ public function parse(string $path) * * @return mixed the value of an item */ - public function get(string $keyPath, $default = null): mixed + public function get(string $keyPath, $default = null) { $paths = explode('.', $keyPath); $cur = $this->config; @@ -109,6 +134,11 @@ public function get(string $keyPath, $default = null): mixed return $cur; } + /** + * @param string $schema + * + * @return SchemaConfigInterface + */ public function getSchemaConfiguration(string $schema): SchemaConfigInterface { $value = $this->get("schemas.{$schema}"); @@ -121,16 +151,29 @@ public function getSchemaConfiguration(string $schema): SchemaConfigInterface /** * Get the path for a specific schema * - * @param string $schema The schema configuration to get - * @param string|null $group The group. If none supplied, uses the default + * @param SchemaConfigInterface $schema The schema configuration + * @param string|null $group The group. If none supplied, uses the default * * @return string */ - public function getSchemaPath(string $schema, string $group = null): string + public function getSchemaPath(SchemaConfigInterface $schema, string $group = null): string { - $group = $group ?: $this->get("default.group"); - $path = $this->get("default.path"); + $group = $group ?: $this->get("defaults.group"); + return sprintf('%s/%s/', $this->getGroupPath($group), $schema->getDirName()); + } - return sprintf('%s/%s/%s/', $path, $group, $schema); + /** + * @param string $group + * + * @return string + */ + public function getGroupPath(string $group): string + { + $configGroup = $this->get("groups.{$group}"); + if (!is_null($configGroup)) { + return $configGroup['path']; + } else { + return sprintf('%s/%s/', $this->get(static::CONFIG_DEFAULT_PATH), $group); + } } } diff --git a/src/Config/ConnectionConfig.php b/src/Config/ConnectionConfig.php index a783e3b..ebdeda7 100644 --- a/src/Config/ConnectionConfig.php +++ b/src/Config/ConnectionConfig.php @@ -19,60 +19,88 @@ class ConnectionConfig implements ConnectionConfigInterface { - /** - * @var array - */ + const CONFIG_DRIVER = 'driver'; + const CONFIG_HOST = 'host'; + const CONFIG_PORT = 'port'; + const CONFIG_USER = 'user'; + const CONFIG_PASSWORD = 'password'; + const CONFIG_DATABASE_NAME = 'dbName'; + + /** @var array */ private $options; /** - * ConnectionConfig constructor. + * @param array $options + * + * @throws \Graze\ConfigValidation\Exceptions\ConfigValidationFailedException */ public function __construct(array $options = []) { $this->options = static::getValidator()->validate($options); } + /** + * @return string + */ public function getDriver(): string { - return $this->options['driver']; + return $this->options[static::CONFIG_DRIVER]; } + /** + * @return string + */ public function getHost(): string { - return $this->options['host']; + return $this->options[static::CONFIG_HOST]; } + /** + * @return int + */ public function getPort(): int { - return (int)$this->options['port']; + return (int) $this->options[static::CONFIG_PORT]; } + /** + * @return string + */ public function getUser(): string { - return $this->options['user']; + return $this->options[static::CONFIG_USER]; } + /** + * @return string + */ public function getPassword(): string { - return $this->options['password']; + return $this->options[static::CONFIG_PASSWORD]; } + /** + * @return string + */ public function getDbName(): string { return $this->options['dbName']; } + /** + * @return ConfigValidatorInterface + */ public static function getValidator(): ConfigValidatorInterface { return Validate::arr(false) - ->required('driver', v::stringType()->in( - [ConnectionConfigInterface::DRIVER_MYSQL] - ) + ->required( + 'driver', + v::stringType()->in([ConnectionConfigInterface::DRIVER_MYSQL]) ) ->required('user', v::stringType()) ->required('password', v::stringType()) ->required('host', v::stringType()) ->optional('port', v::intVal(), 3306) - ->required('dbName', v::stringType()); + ->optional('dbName', v::stringType()); } } diff --git a/src/Config/GroupConfig.php b/src/Config/GroupConfig.php new file mode 100644 index 0000000..20ddaeb --- /dev/null +++ b/src/Config/GroupConfig.php @@ -0,0 +1,45 @@ +validate($options); + $this->path = $options[static::CONFIG_PATH]; + } + + /** + * @return ConfigValidatorInterface + */ + public static function getValidator(): ConfigValidatorInterface + { + return Validate::arr(false) + ->required(static::CONFIG_PATH, v::stringType()); + } + + /** + * @return string + */ + public function getPath(): string + { + return $this->path; + } +} diff --git a/src/Config/GroupConfigInterface.php b/src/Config/GroupConfigInterface.php new file mode 100644 index 0000000..15be62f --- /dev/null +++ b/src/Config/GroupConfigInterface.php @@ -0,0 +1,8 @@ +validate($options); - $this->schema = $options['schema']; - $this->exclude = $options['exclude']; - $this->connection = new ConnectionConfig($options['connection']); + $options = static::getValidator()->validate($options); + $this->schema = $options[static::CONFIG_SCHEMA]; + $this->exclude = $options[static::CONFIG_EXCLUDE]; + $this->connection = new ConnectionConfig($options[static::CONFIG_CONNECTION]); + $this->dirName = $options[static::CONFIG_DIR_NAME] ?? $this->schema; } + /** + * @return string + */ public function getSchema(): string { return $this->schema; } + /** + * @return ConnectionConfigInterface + */ public function getConnection(): ConnectionConfigInterface { return $this->connection; } + /** + * @return ConfigValidatorInterface + */ public static function getValidator(): ConfigValidatorInterface { return Validate::arr(false) - ->required('connection', v::arrayType()->addRule( - ConnectionConfig::getValidator()->getValidator() - )) - ->required('schema', v::stringType()) - ->optional('exclude', v::arrayVal()->each(v::stringType()), []); + ->addChild(static::CONFIG_CONNECTION, ConnectionConfig::getValidator()) + ->optional(static::CONFIG_SCHEMA, v::stringType()) + ->optional(static::CONFIG_EXCLUDE, v::arrayVal()->each(v::stringType()), []) + ->optional(static::CONFIG_DIR_NAME, v::stringType()); } /** @@ -57,4 +73,12 @@ public function getExcludes(): array { return $this->exclude; } + + /** + * @return string + */ + public function getDirName(): string + { + return $this->dirName; + } } diff --git a/src/Config/SchemaConfigInterface.php b/src/Config/SchemaConfigInterface.php index 16d4d7d..62eb24b 100644 --- a/src/Config/SchemaConfigInterface.php +++ b/src/Config/SchemaConfigInterface.php @@ -29,4 +29,11 @@ public function getConnection(): ConnectionConfigInterface; * @return string[] */ public function getExcludes(): array; + + /** + * Get the directory name for this schema + * + * @return string + */ + public function getDirName(): string; } diff --git a/src/Dump/Dumper.php b/src/Dump/Dumper.php index 221bdfa..dda5c36 100644 --- a/src/Dump/Dumper.php +++ b/src/Dump/Dumper.php @@ -14,7 +14,7 @@ namespace Graze\Sprout\Dump; use Graze\Sprout\Config\SchemaConfigInterface; -use Symfony\Component\Console\Helper\ProgressBar; +use RuntimeException; use Symfony\Component\Console\Output\OutputInterface; class Dumper @@ -36,11 +36,11 @@ class Dumper public function __construct( SchemaConfigInterface $schemaConfig, OutputInterface $output, - TableDumperFactory $factory = null + TableDumperFactory $factory ) { $this->schemaConfig = $schemaConfig; $this->output = $output; - $this->factory = $factory ?: new TableDumperFactory($output); + $this->factory = $factory; } /** @@ -61,15 +61,9 @@ public function dump(string $path, array $tables = []) $tableDumper = $this->factory->getDumper($this->schemaConfig->getConnection()); $schema = $this->schemaConfig->getSchema(); - $progress = new ProgressBar($this->output); - $progress->start(count($tables)); - $progress->setMessage("dumping tables in {$schema} to {$path}"); - foreach ($tables as $table) { $file = sprintf('%s/%s.sql', $path, $table); $tableDumper->dump($schema, $table, $file); - $progress->advance(); } - $progress->finish(); } } diff --git a/src/Dump/Mysql/MysqlTableDumper.php b/src/Dump/Mysql/MysqlTableDumper.php index cc7c4c1..7999221 100644 --- a/src/Dump/Mysql/MysqlTableDumper.php +++ b/src/Dump/Mysql/MysqlTableDumper.php @@ -13,29 +13,28 @@ namespace Graze\Sprout\Dump\Mysql; +use Graze\ParallelProcess\Pool; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Dump\TableDumperInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Process; class MysqlTableDumper implements TableDumperInterface { /** @var ConnectionConfigInterface */ private $connection; - /** @var OutputInterface */ - private $output; + /** @var Pool */ + private $pool; /** * MysqlTableDumper constructor. * + * @param Pool $pool * @param ConnectionConfigInterface $connection - * @param OutputInterface $output */ - public function __construct(ConnectionConfigInterface $connection, OutputInterface $output) + public function __construct(Pool $pool, ConnectionConfigInterface $connection) { $this->connection = $connection; - $this->output = $output; + $this->pool = $pool; } /** @@ -45,13 +44,11 @@ public function __construct(ConnectionConfigInterface $connection, OutputInterfa */ public function dump(string $schema, string $table, string $file) { - $this->output->write("dumping {$schema}/{$table} to {$file}... ", OutputInterface::VERBOSITY_DEBUG); - $process = new Process(''); $process->setCommandLine( sprintf( 'mysqldump -h%1$s -u%2$s -p%3$s --compress --compact --no-create-info' . - ' --extended-insert --hex-dump --quick %4$s %5$s' . + ' --extended-insert --quick --complete-insert %4$s %5$s' . '| sed \'s$VALUES ($VALUES\n($g\' | sed \'s$),($),\n($g\' > %6$s', escapeshellarg($this->connection->getHost()), escapeshellarg($this->connection->getUser()), @@ -62,13 +59,6 @@ public function dump(string $schema, string $table, string $file) ) ); - $process->run(); - - if (!$process->isSuccessful()) { - unlink($file); - throw new ProcessFailedException($process); - } - - $this->output->writeln("done", OutputInterface::VERBOSITY_DEBUG); + $this->pool->add($process, ['dump', 'schema' => $schema, 'table' => $table]); } } diff --git a/src/Dump/TableDumperFactory.php b/src/Dump/TableDumperFactory.php index 4650aed..ef630e2 100644 --- a/src/Dump/TableDumperFactory.php +++ b/src/Dump/TableDumperFactory.php @@ -2,24 +2,29 @@ namespace Graze\Sprout\Dump; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Dump\Mysql\MysqlTableDumper; use InvalidArgumentException; -use Symfony\Component\Console\Output\OutputInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; -class TableDumperFactory +class TableDumperFactory implements LoggerAwareInterface { - /** @var OutputInterface */ - private $output; + use LoggerAwareTrait; + + /** @var Pool */ + private $processPool; /** * TableDumperFactory constructor. * - * @param OutputInterface $output + * @param Pool $processPool */ - public function __construct(OutputInterface $output) + public function __construct(Pool $processPool) { - $this->output = $output; + $this->processPool = $processPool; } /** @@ -33,11 +38,13 @@ public function getDumper(ConnectionConfigInterface $connection): TableDumperInt switch ($driver) { case 'mysql': - $this->output->writeln( - "Using mysql table dumper for driver: {$driver}", - OutputInterface::VERBOSITY_DEBUG - ); - return new MysqlTableDumper($connection, $this->output); + if ($this->logger) { + $this->logger->debug( + "getDumper: using mysql dumper for driver: {$driver}", + ['driver' => $driver] + ); + } + return new MysqlTableDumper($this->processPool, $connection); default: throw new InvalidArgumentException("getDumper: no dumper found for driver: `{$driver}`"); } diff --git a/src/Parser/ParsedSchema.php b/src/Parser/ParsedSchema.php new file mode 100644 index 0000000..cf64da0 --- /dev/null +++ b/src/Parser/ParsedSchema.php @@ -0,0 +1,72 @@ +schemaConfig = $schemaConfig; + $this->path = $path; + $this->tables = $tables; + } + + /** + * @return SchemaConfigInterface + */ + public function getSchemaConfig(): SchemaConfigInterface + { + return $this->schemaConfig; + } + + /** + * @return string + */ + public function getPath(): string + { + return $this->path; + } + + /** + * @return array + */ + public function getTables(): array + { + return $this->tables; + } + + /** + * @param array $tables + * + * @return ParsedSchema + */ + public function setTables(array $tables): ParsedSchema + { + $this->tables = $tables; + return $this; + } + + /** + * @return string + */ + public function getSchameName(): string + { + return $this->schemaConfig->getSchema(); + } +} diff --git a/src/Parser/SchemaParser.php b/src/Parser/SchemaParser.php new file mode 100644 index 0000000..725ef05 --- /dev/null +++ b/src/Parser/SchemaParser.php @@ -0,0 +1,110 @@ +config = $config; + $this->group = $group; + } + + /** + * @param array $schemaTables + * + * @return ParsedSchema[] + */ + public function extractSchemas(array $schemaTables = []) + { + if (count($schemaTables) === 0) { + $schemaTables = array_map( + function (Config\SchemaConfigInterface $schemaConfig) { + return $schemaConfig->getSchema(); + }, + $this->config->get(Config::CONFIG_SCHEMAS) + ); + } + + $parsedSchemas = []; + foreach ($schemaTables as $schemaTable) { + if (preg_match('/^([a-z_]+):(.+)$/i', $schemaTable, $matches)) { + $schema = $matches[1]; + $tables = $matches[2] === '*' ? [] : explode(',', $matches[2]); + } else { + $schema = $schemaTable; + $tables = []; + } + + $parsedSchemas[] = new ParsedSchema( + $this->config->getSchemaConfiguration($schema), + $this->config->getSchemaPath($this->config->getSchemaConfiguration($schema), $this->group), + $tables + ); + }; + + return array_filter(array_map([$this, 'populateTables'], $parsedSchemas)); + } + + /** + * @param ParsedSchema $parsedSchema + * + * @return ParsedSchema|null + */ + public function populateTables(ParsedSchema $parsedSchema) + { + if (!is_dir($parsedSchema->getPath())) { + return null; + } + + if (count($parsedSchema->getTables()) === 0) { + // find existing tables + $files = iterator_to_array(new \FilesystemIterator($parsedSchema->getPath())); + $files = array_values(array_filter( + $files, + function (SplFileInfo $file) { + // ignore empty file names (`.bla`) files + return (!in_array($file->getFilename(), ['.', '..']) + && pathinfo($file, PATHINFO_FILENAME) !== ''); + } + )); + + // sort by file size, largest first + usort( + $files, + function (SplFileInfo $a, SplFileInfo $b) { + $left = $a->getSize(); + $right = $b->getSize(); + return ($left == $right) ? 0 : (($left > $right) ? -1 : 1); + } + ); + + // remove the file extensions to get the table names + $parsedSchema->setTables(array_map( + function (SplFileInfo $file) { + return pathinfo($file, PATHINFO_FILENAME); + }, + $files + )); + } + + if (count($parsedSchema->getTables()) === 0) { + return null; + } + return $parsedSchema; + } +} diff --git a/src/Seed/Mysql/MysqlTableSeeder.php b/src/Seed/Mysql/MysqlTableSeeder.php index 9366329..c51f88e 100644 --- a/src/Seed/Mysql/MysqlTableSeeder.php +++ b/src/Seed/Mysql/MysqlTableSeeder.php @@ -13,36 +13,39 @@ namespace Graze\Sprout\Seed\Mysql; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Seed\TableSeederInterface; use InvalidArgumentException; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Process; class MysqlTableSeeder implements TableSeederInterface { /** @var ConnectionConfigInterface */ private $connection; - /** @var OutputInterface */ - private $output; + /** @var Pool */ + private $pool; /** * MysqlTableDumper constructor. * + * @param Pool $pool * @param ConnectionConfigInterface $connection - * @param OutputInterface $output */ - public function __construct(ConnectionConfigInterface $connection, OutputInterface $output) + public function __construct(Pool $pool, ConnectionConfigInterface $connection) { + $this->pool = $pool; $this->connection = $connection; - $this->output = $output; } + /** + * @param string $file + * @param string $schema + * @param string $table + */ public function seed(string $file, string $schema, string $table) { - $this->output->write("seeding {$file} to {$schema}/{$table}... ", OutputInterface::VERBOSITY_DEBUG); - if (!file_exists($file)) { throw new InvalidArgumentException("seed: The file: {$file} does not exist"); } @@ -58,12 +61,7 @@ public function seed(string $file, string $schema, string $table) escapeshellarg($file) ) ); - $process->run(); - - if (!$process->isSuccessful()) { - throw new ProcessFailedException($process); - } - $this->output->writeln("done", OutputInterface::VERBOSITY_DEBUG); + $this->pool->add($process, ['seed', 'schema' => $schema, 'table' => $table]); } } diff --git a/src/Seed/Seeder.php b/src/Seed/Seeder.php index fb9f5dd..add8a63 100644 --- a/src/Seed/Seeder.php +++ b/src/Seed/Seeder.php @@ -36,11 +36,11 @@ class Seeder public function __construct( SchemaConfigInterface $schemaConfig, OutputInterface $output, - TableSeederFactory $factory = null + TableSeederFactory $factory ) { $this->schemaConfig = $schemaConfig; $this->output = $output; - $this->factory = $factory ?: new TableSeederFactory($output); + $this->factory = $factory; } /** @@ -61,15 +61,9 @@ public function seed(string $path, array $tables = []) $tableSeeder = $this->factory->getSeeder($this->schemaConfig->getConnection()); $schema = $this->schemaConfig->getSchema(); - $progress = new ProgressBar($this->output); - $progress->start(count($tables)); - $progress->setMessage("seeding tables in {$schema} from {$path}"); - foreach ($tables as $table) { $file = sprintf('%s/%s.sql', $path, $table); $tableSeeder->seed($file, $schema, $table); - $progress->advance(); } - $progress->finish(); } } diff --git a/src/Seed/TableSeederFactory.php b/src/Seed/TableSeederFactory.php index 6bfd39b..94770ca 100644 --- a/src/Seed/TableSeederFactory.php +++ b/src/Seed/TableSeederFactory.php @@ -2,37 +2,49 @@ namespace Graze\Sprout\Seed; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Seed\Mysql\MysqlTableSeeder; use InvalidArgumentException; -use Symfony\Component\Console\Output\OutputInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; -class TableSeederFactory +class TableSeederFactory implements LoggerAwareInterface { - /** @var OutputInterface */ - private $output; + use LoggerAwareTrait; + + /** @var Pool */ + private $processPool; /** * TableDumperFactory constructor. * - * @param OutputInterface $output + * @param Pool $processPool */ - public function __construct(OutputInterface $output) + public function __construct(Pool $processPool) { - $this->output = $output; + $this->processPool = $processPool; } + /** + * @param ConnectionConfigInterface $connection + * + * @return TableSeederInterface + */ public function getSeeder(ConnectionConfigInterface $connection): TableSeederInterface { $driver = $connection->getDriver(); switch ($driver) { case 'mysql': - $this->output->writeln( - "Using mysql table seeder for driver: {$driver}", - OutputInterface::VERBOSITY_DEBUG - ); - return new MysqlTableSeeder($connection, $this->output); + if ($this->logger) { + $this->logger->debug( + "getSeeder: using mysql seeder for driver: {$driver}", + ['driver' => $driver] + ); + } + return new MysqlTableSeeder($this->processPool, $connection); default: throw new InvalidArgumentException("getSeeder: no seeder found for driver: `{$driver}`"); } diff --git a/tests/src/TestCase.php b/tests/src/TestCase.php index 6f18396..cdda3dc 100644 --- a/tests/src/TestCase.php +++ b/tests/src/TestCase.php @@ -14,6 +14,9 @@ namespace Graze\Sprout\Test; -class TestCase extends \PHPUnit_Framework_TestCase +use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; + +class TestCase extends \PHPUnit\Framework\TestCase { + use MockeryPHPUnitIntegration; } diff --git a/tests/unit/Chop/ChopperTest.php b/tests/unit/Chop/ChopperTest.php index 12016e1..c8640a2 100644 --- a/tests/unit/Chop/ChopperTest.php +++ b/tests/unit/Chop/ChopperTest.php @@ -1,7 +1,7 @@ * * For the full copyright and license information, please view the LICENSE @@ -13,11 +13,11 @@ namespace Graze\Sprout\Test\Unit\Chop; -use Graze\Sprout\Config\ConnectionConfigInterface; -use Graze\Sprout\Config\SchemaConfigInterface; use Graze\Sprout\Chop\Chopper; use Graze\Sprout\Chop\TableChopperFactory; use Graze\Sprout\Chop\TableChopperInterface; +use Graze\Sprout\Config\ConnectionConfigInterface; +use Graze\Sprout\Config\SchemaConfigInterface; use Graze\Sprout\Test\TestCase; use Mockery; use Symfony\Component\Console\Output\OutputInterface; @@ -54,11 +54,11 @@ public function testChopperCallsChopForAllTables(array $tables = []) foreach ($tables as $table) { $tableChopper->shouldReceive('chop') - ->with('schema', $table) - ->once(); + ->with('schema', $table) + ->once(); } - $chopper->Chop('/some/path/schema', $tables); + $chopper->chop($tables); } /** @@ -97,8 +97,8 @@ public function testChopperIgnoresDuplicateTables() $tables = ['table1', 'table1']; $tableChopper->shouldReceive('chop') - ->with('schema', 'table1') - ->once(); + ->with('schema', 'table1') + ->once(); $chopper->chop($tables); } @@ -109,7 +109,7 @@ public function testChopperDoesNothingWithAnEmptyListOfTables() $config->shouldReceive('getConnection') ->andReturn($connConfig); $config->shouldReceive('getSchema') - ->andReturn('schema'); + ->andReturn('schema'); $output = Mockery::mock(OutputInterface::class); $output->shouldReceive('writeln')->with('No tables specified, nothing to do')->once(); diff --git a/tests/unit/Chop/Mysql/MysqlTableChopperTest.php b/tests/unit/Chop/Mysql/MysqlTableChopperTest.php index 061e1c5..78d541b 100644 --- a/tests/unit/Chop/Mysql/MysqlTableChopperTest.php +++ b/tests/unit/Chop/Mysql/MysqlTableChopperTest.php @@ -13,14 +13,15 @@ namespace Graze\Sprout\Chop\Mysql; +use Graze\ParallelProcess\Pool; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Test\TestCase; use Mockery; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; /** * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ class MysqlTableChopperTest extends TestCase { @@ -29,96 +30,9 @@ public function testChop() $process = Mockery::mock('overload:' . Process::class); $process->shouldReceive('setCommandLine') - ->with('mysql -h\'some-host\' -u\'some-user\' -p\'some-pass\' --default-character-set=utf8 \'some-schema\' < \'TRUNCATE `some-table`\'') + ->with('mysql -h\'some-host\' -u\'some-user\' -p\'some-pass\' --default-character-set=utf8 --execute=\'TRUNCATE `some-table`\' \'some-schema\'') ->once(); - $process->shouldReceive('run')->once(); - $process->shouldReceive('isSuccessful')->once()->andReturn(true); - - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('chopping down some-schema/some-table... ', 256) - ->once(); - $output->shouldReceive('writeln') - ->with('done', 256) - ->once(); - - $config = Mockery::mock(ConnectionConfigInterface::class); - $config->shouldReceive('getHost') - ->andReturn('some-host'); - $config->shouldReceive('getUser') - ->andReturn('some-user'); - $config->shouldReceive('getPassword') - ->andReturn('some-pass'); - - $tableChopper = new MysqlTableChopper($config, $output); - - /** - * @param string $file - * - * @return bool - */ - function file_exists($file) - { - TestCase::assertEquals('some-file', $file); - return true; - } - - $tableChopper->chop('some-file', 'some-schema', 'some-table'); - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testFileExistsFailure() - { - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('chopping down some-schema/some-table... ', 256) - ->once(); - - $config = Mockery::mock(ConnectionConfigInterface::class); - - $tableChopper = new MysqlTableChopper($config, $output); - - /** - * @param string $file - * - * @return bool - */ - function file_exists($file) - { - TestCase::assertEquals('some-file', $file); - return false; - } - - $tableChopper->chop('some-file', 'some-schema', 'some-table'); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\ProcessFailedException - */ - public function testFailure() - { - $process = Mockery::mock('overload:' . Process::class); - - $process->shouldReceive('setCommandLine') - ->with('mysql -h\'some-host\' -u\'some-user\' -p\'some-pass\' --default-character-set=utf8 \'some-schema\' < \'TRUNCATE `some-table`\'') - ->once(); - - $process->shouldReceive('run')->once(); - $process->shouldReceive('isSuccessful')->once()->andReturn(false); - $process->shouldReceive('getCommandLine')->andReturn('some command init'); - $process->shouldReceive('getExitCode')->andReturn(5); - $process->shouldReceive('getExitCodeText')->andReturn('poop'); - $process->shouldReceive('getWorkingDirectory')->andReturn('/tmp'); - $process->shouldReceive('isOutputDisabled')->andReturn(true); - - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('chopping down some-schema/some-table... ', 256) - ->once(); - $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getHost') ->andReturn('some-host'); @@ -127,29 +41,16 @@ public function testFailure() $config->shouldReceive('getPassword') ->andReturn('some-pass'); - /** - * @param string $file - * - * @return bool - */ - function file_exists($file) - { - TestCase::assertEquals('some-file', $file); - return true; - } + $pool = Mockery::mock(Pool::class); - $tableChopper = new MysqlTableChopper($config, $output); + $pool->shouldReceive('add') + ->with( + Mockery::type(Process::class), + ['chop', 'schema' => 'some-schema', 'table' => 'some-table'] + ); - /** - * overload unlink to test that we try and delete the file - * - * @param string $file - */ - function unlink($file) - { - TestCase::assertEquals('some-file', $file); - } + $tableChopper = new MysqlTableChopper($pool, $config); - $tableChopper->chop('some-file', 'some-schema', 'some-table'); + $tableChopper->chop('some-schema', 'some-table'); } } diff --git a/tests/unit/Chop/TableChopperFactoryTest.php b/tests/unit/Chop/TableChopperFactoryTest.php index b71ff89..2039142 100644 --- a/tests/unit/Chop/TableChopperFactoryTest.php +++ b/tests/unit/Chop/TableChopperFactoryTest.php @@ -1,7 +1,7 @@ * * For the full copyright and license information, please view the LICENSE @@ -13,27 +13,27 @@ namespace Graze\Sprout\Test\Unit\Chop; -use Graze\Sprout\Config\ConnectionConfigInterface; +use Graze\ParallelProcess\Pool; use Graze\Sprout\Chop\Mysql\MysqlTableChopper; use Graze\Sprout\Chop\TableChopperFactory; use Graze\Sprout\Chop\TableChopperInterface; +use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Test\TestCase; use Mockery; -use Symfony\Component\Console\Output\OutputInterface; class TableChopperFactoryTest extends TestCase { public function testMysqlReturnsMysqlTableChopper() { - $output = Mockery::mock(OutputInterface::class)->shouldIgnoreMissing(); + $processTable = Mockery::mock(Pool::class); $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getDriver') ->andReturn('mysql'); - $ChopperFactory = new TableChopperFactory($output); + $chopperFactory = new TableChopperFactory($processTable); - $tableChopper = $ChopperFactory->getChopper($config); + $tableChopper = $chopperFactory->getChopper($config); $this->assertInstanceOf(TableChopperInterface::class, $tableChopper); $this->assertInstanceOf(MysqlTableChopper::class, $tableChopper); @@ -44,14 +44,14 @@ public function testMysqlReturnsMysqlTableChopper() */ public function testUnknownThrowsException() { - $output = Mockery::mock(OutputInterface::class)->shouldIgnoreMissing(); + $processTable = Mockery::mock(Pool::class); $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getDriver') ->andReturn('pgsql'); - $ChopperFactory = new TableChopperFactory($output); + $chopperFactory = new TableChopperFactory($processTable); - $ChopperFactory->getChopper($config); + $chopperFactory->getChopper($config); } } diff --git a/tests/unit/Dump/Mysql/MysqlTableDumperTest.php b/tests/unit/Dump/Mysql/MysqlTableDumperTest.php index d7fca27..65c7e46 100644 --- a/tests/unit/Dump/Mysql/MysqlTableDumperTest.php +++ b/tests/unit/Dump/Mysql/MysqlTableDumperTest.php @@ -2,14 +2,15 @@ namespace Graze\Sprout\Dump\Mysql; +use Graze\ParallelProcess\Pool; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Test\TestCase; use Mockery; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; /** * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ class MysqlTableDumperTest extends TestCase { @@ -20,22 +21,11 @@ public function testDump() $process->shouldReceive('setCommandLine') ->with( 'mysqldump -h\'some-host\' -u\'some-user\' -p\'some-pass\' --compress --compact --no-create-info' . - ' --extended-insert --hex-dump --quick \'some-schema\' \'some-table\'' . + ' --extended-insert --quick --complete-insert \'some-schema\' \'some-table\'' . '| sed \'s$VALUES ($VALUES\n($g\' | sed \'s$),($),\n($g\' > \'some-file\'' ) ->once(); - $process->shouldReceive('run')->once(); - $process->shouldReceive('isSuccessful')->once()->andReturn(true); - - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('dumping some-schema/some-table to some-file... ', 256) - ->once(); - $output->shouldReceive('writeln') - ->with('done', 256) - ->once(); - $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getHost') ->andReturn('some-host'); @@ -44,58 +34,15 @@ public function testDump() $config->shouldReceive('getPassword') ->andReturn('some-pass'); - $tableDumper = new MysqlTableDumper($config, $output); - - $tableDumper->dump('some-schema', 'some-table', 'some-file'); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\ProcessFailedException - */ - public function testFailure() - { - $process = Mockery::mock('overload:' . Process::class); - - $process->shouldReceive('setCommandLine') - ->with( - 'mysqldump -h\'some-host\' -u\'some-user\' -p\'some-pass\' --compress --compact --no-create-info' . - ' --extended-insert --hex-dump --quick \'some-schema\' \'some-table\'' . - '| sed \'s$VALUES ($VALUES\n($g\' | sed \'s$),($),\n($g\' > \'some-file\'' - ) - ->once(); - - $process->shouldReceive('run')->once(); - $process->shouldReceive('isSuccessful')->once()->andReturn(false); - $process->shouldReceive('getCommandLine')->andReturn('some command init'); - $process->shouldReceive('getExitCode')->andReturn(5); - $process->shouldReceive('getExitCodeText')->andReturn('poop'); - $process->shouldReceive('getWorkingDirectory')->andReturn('/tmp'); - $process->shouldReceive('isOutputDisabled')->andReturn(true); - - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('dumping some-schema/some-table to some-file... ', 256) - ->once(); - - $config = Mockery::mock(ConnectionConfigInterface::class); - $config->shouldReceive('getHost') - ->andReturn('some-host'); - $config->shouldReceive('getUser') - ->andReturn('some-user'); - $config->shouldReceive('getPassword') - ->andReturn('some-pass'); + $pool = Mockery::mock(Pool::class); - $tableDumper = new MysqlTableDumper($config, $output); + $pool->shouldReceive('add') + ->with( + Mockery::type(Process::class), + ['dump', 'schema' => 'some-schema', 'table' => 'some-table'] + ); - /** - * overload unlink to test that we try and delete the file - * - * @param string $file - */ - function unlink($file) - { - TestCase::assertEquals('some-file', $file); - } + $tableDumper = new MysqlTableDumper($pool, $config); $tableDumper->dump('some-schema', 'some-table', 'some-file'); } diff --git a/tests/unit/Dump/TableDumperFactoryTest.php b/tests/unit/Dump/TableDumperFactoryTest.php index d0fd41c..7e9330f 100644 --- a/tests/unit/Dump/TableDumperFactoryTest.php +++ b/tests/unit/Dump/TableDumperFactoryTest.php @@ -2,25 +2,26 @@ namespace Graze\Sprout\Test\Unit\Dump; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Dump\Mysql\MysqlTableDumper; use Graze\Sprout\Dump\TableDumperFactory; use Graze\Sprout\Dump\TableDumperInterface; use Graze\Sprout\Test\TestCase; use Mockery; -use Symfony\Component\Console\Output\OutputInterface; class TableDumperFactoryTest extends TestCase { public function testMysqlReturnsMysqlTableDumper() { - $output = Mockery::mock(OutputInterface::class)->shouldIgnoreMissing(); + $processTable = Mockery::mock(Pool::class); $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getDriver') - ->andReturn('mysql'); + ->andReturn('mysql'); - $dumperFactory = new TableDumperFactory($output); + $dumperFactory = new TableDumperFactory($processTable); $tableDumper = $dumperFactory->getDumper($config); @@ -33,13 +34,13 @@ public function testMysqlReturnsMysqlTableDumper() */ public function testUnknownThrowsException() { - $output = Mockery::mock(OutputInterface::class)->shouldIgnoreMissing(); + $processTable = Mockery::mock(Pool::class); $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getDriver') ->andReturn('pgsql'); - $dumperFactory = new TableDumperFactory($output); + $dumperFactory = new TableDumperFactory($processTable); $dumperFactory->getDumper($config); } diff --git a/tests/unit/Seed/Mysql/MysqlTableSeederTest.php b/tests/unit/Seed/Mysql/MysqlTableSeederTest.php index 5ad045f..b2ad21f 100644 --- a/tests/unit/Seed/Mysql/MysqlTableSeederTest.php +++ b/tests/unit/Seed/Mysql/MysqlTableSeederTest.php @@ -13,36 +13,29 @@ namespace Graze\Sprout\Seed\Mysql; +use Graze\ParallelProcess\Pool; +use Graze\ParallelProcess\Table; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Test\TestCase; use Mockery; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; /** * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ class MysqlTableSeederTest extends TestCase { + // our standards don't handle sub functions properly, until this is fixed + // @codingStandardsIgnoreStart public function testSeed() { $process = Mockery::mock('overload:' . Process::class); $process->shouldReceive('setCommandLine') - ->with('mysql -h\'some-host\' -u\'some-user\' -p\'some-pass\' --default-character-set=utf8 \'some-schema\' < \'some-table\'') + ->with('mysql -h\'some-host\' -u\'some-user\' -p\'some-pass\' --default-character-set=utf8 \'some-schema\' < \'some-file\'') ->once(); - $process->shouldReceive('run')->once(); - $process->shouldReceive('isSuccessful')->once()->andReturn(true); - - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('seeding some-file to some-schema/some-table... ', 256) - ->once(); - $output->shouldReceive('writeln') - ->with('done', 256) - ->once(); - $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getHost') ->andReturn('some-host'); @@ -51,7 +44,15 @@ public function testSeed() $config->shouldReceive('getPassword') ->andReturn('some-pass'); - $tableSeeder = new MysqlTableSeeder($config, $output); + $pool = Mockery::mock(Pool::class); + + $pool->shouldReceive('add') + ->with( + Mockery::type(Process::class), + ['seed', 'schema' => 'some-schema', 'table' => 'some-table'] + ); + + $tableSeeder = new MysqlTableSeeder($pool, $config); /** * @param string $file @@ -66,21 +67,19 @@ function file_exists($file) $tableSeeder->seed('some-file', 'some-schema', 'some-table'); } + // @codingStandardsIgnoreEnd /** * @expectedException \InvalidArgumentException */ public function testFileExistsFailure() { - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('seeding some-file to some-schema/some-table... ', 256) - ->once(); - $config = Mockery::mock(ConnectionConfigInterface::class); + $pool = Mockery::mock(Pool::class); - $tableSeeder = new MysqlTableSeeder($config, $output); + $tableSeeder = new MysqlTableSeeder($pool, $config); + // @codingStandardsIgnoreStart /** * @param string $file * @@ -92,63 +91,7 @@ function file_exists($file) return false; } - $tableSeeder->seed('some-file', 'some-schema', 'some-table'); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\ProcessFailedException - */ - public function testFailure() - { - $process = Mockery::mock('overload:' . Process::class); - - $process->shouldReceive('setCommandLine') - ->with('mysql -h\'some-host\' -u\'some-user\' -p\'some-pass\' --default-character-set=utf8 \'some-schema\' < \'some-file\'') - ->once(); - - $process->shouldReceive('run')->once(); - $process->shouldReceive('isSuccessful')->once()->andReturn(false); - $process->shouldReceive('getCommandLine')->andReturn('some command init'); - $process->shouldReceive('getExitCode')->andReturn(5); - $process->shouldReceive('getExitCodeText')->andReturn('poop'); - $process->shouldReceive('getWorkingDirectory')->andReturn('/tmp'); - $process->shouldReceive('isOutputDisabled')->andReturn(true); - - $output = Mockery::mock(OutputInterface::class); - $output->shouldReceive('write') - ->with('seeding some-file to some-schema/some-table... ', 256) - ->once(); - - $config = Mockery::mock(ConnectionConfigInterface::class); - $config->shouldReceive('getHost') - ->andReturn('some-host'); - $config->shouldReceive('getUser') - ->andReturn('some-user'); - $config->shouldReceive('getPassword') - ->andReturn('some-pass'); - - /** - * @param string $file - * - * @return bool - */ - function file_exists($file) - { - TestCase::assertEquals('some-file', $file); - return true; - } - - $tableSeeder = new MysqlTableSeeder($config, $output); - - /** - * overload unlink to test that we try and delete the file - * - * @param string $file - */ - function unlink($file) - { - TestCase::assertEquals('some-file', $file); - } + // @codingStandardsIgnoreEnd $tableSeeder->seed('some-file', 'some-schema', 'some-table'); } diff --git a/tests/unit/Seed/SeederTest.php b/tests/unit/Seed/SeederTest.php index a6e4455..0257b63 100644 --- a/tests/unit/Seed/SeederTest.php +++ b/tests/unit/Seed/SeederTest.php @@ -17,7 +17,7 @@ use Graze\Sprout\Config\SchemaConfigInterface; use Graze\Sprout\Seed\Seeder; use Graze\Sprout\Seed\TableSeederFactory; -use Graze\Sprout\Seed\TableChopperInterface; +use Graze\Sprout\Seed\TableSeederInterface; use Graze\Sprout\Test\TestCase; use Mockery; use Symfony\Component\Console\Output\OutputInterface; @@ -48,7 +48,7 @@ public function testSeederCallsSeedForAllTables(array $tables = []) $seeder = new Seeder($config, $output, $factory); - $tableSeeder = Mockery::mock(TableChopperInterface::class); + $tableSeeder = Mockery::mock(TableSeederInterface::class); $factory->shouldReceive('getSeeder')->with($connConfig)->andReturn($tableSeeder); @@ -91,7 +91,7 @@ public function testSeederIgnoresDuplicateTables() $seeder = new Seeder($config, $output, $factory); - $tableSeeder = Mockery::mock(TableChopperInterface::class); + $tableSeeder = Mockery::mock(TableSeederInterface::class); $factory->shouldReceive('getSeeder')->with($connConfig)->andReturn($tableSeeder); @@ -109,7 +109,7 @@ public function testSeederDoesNothingWithAnEmptyListOfTables() $config->shouldReceive('getConnection') ->andReturn($connConfig); $config->shouldReceive('getSchema') - ->andReturn('schema'); + ->andReturn('schema'); $output = Mockery::mock(OutputInterface::class); $output->shouldReceive('writeln')->with('No tables specified, nothing to do')->once(); @@ -118,7 +118,7 @@ public function testSeederDoesNothingWithAnEmptyListOfTables() $seeder = new Seeder($config, $output, $factory); - $tableSeeder = Mockery::mock(TableChopperInterface::class); + $tableSeeder = Mockery::mock(TableSeederInterface::class); $factory->shouldReceive('getSeeder')->with($connConfig)->andReturn($tableSeeder); $tables = []; diff --git a/tests/unit/Seed/TableSeederFactoryTest.php b/tests/unit/Seed/TableSeederFactoryTest.php index 1cb95f1..a991882 100644 --- a/tests/unit/Seed/TableSeederFactoryTest.php +++ b/tests/unit/Seed/TableSeederFactoryTest.php @@ -1,7 +1,7 @@ * * For the full copyright and license information, please view the LICENSE @@ -13,29 +13,29 @@ namespace Graze\Sprout\Test\Unit\Seed; +use Graze\ParallelProcess\Pool; use Graze\Sprout\Config\ConnectionConfigInterface; use Graze\Sprout\Seed\Mysql\MysqlTableSeeder; use Graze\Sprout\Seed\TableSeederFactory; -use Graze\Sprout\Seed\TableChopperInterface; +use Graze\Sprout\Seed\TableSeederInterface; use Graze\Sprout\Test\TestCase; use Mockery; -use Symfony\Component\Console\Output\OutputInterface; class TableSeederFactoryTest extends TestCase { public function testMysqlReturnsMysqlTableSeeder() { - $output = Mockery::mock(OutputInterface::class)->shouldIgnoreMissing(); + $processTable = Mockery::mock(Pool::class); $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getDriver') ->andReturn('mysql'); - $SeederFactory = new TableSeederFactory($output); + $seederFactory = new TableSeederFactory($processTable); - $tableSeeder = $SeederFactory->getSeeder($config); + $tableSeeder = $seederFactory->getSeeder($config); - $this->assertInstanceOf(TableChopperInterface::class, $tableSeeder); + $this->assertInstanceOf(TableSeederInterface::class, $tableSeeder); $this->assertInstanceOf(MysqlTableSeeder::class, $tableSeeder); } @@ -44,14 +44,14 @@ public function testMysqlReturnsMysqlTableSeeder() */ public function testUnknownThrowsException() { - $output = Mockery::mock(OutputInterface::class)->shouldIgnoreMissing(); + $processTable = Mockery::mock(Pool::class); $config = Mockery::mock(ConnectionConfigInterface::class); $config->shouldReceive('getDriver') ->andReturn('pgsql'); - $SeederFactory = new TableSeederFactory($output); + $seederFactory = new TableSeederFactory($processTable); - $SeederFactory->getSeeder($config); + $seederFactory->getSeeder($config); } }