From f453680b04c4a74fce4220c6f7ceb7a9f5570af2 Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:41:58 -0500 Subject: [PATCH 1/7] Fix licence formatting --- LICENCE | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/LICENCE b/LICENCE index c8c6c30..04d4c80 100644 --- a/LICENCE +++ b/LICENCE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) dana geier +Copyright (c) dana Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -18,4 +18,3 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - From 497b9d5e54414ad6d631d690e790e474ab644eed Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:46:57 -0500 Subject: [PATCH 2/7] Update .gitignore --- .gitignore | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 24bba68..fdeaaac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,15 @@ # PHP-related files -.idea/ -.phpintel/ /vendor/ /phpunit.xml /twigc.phar -# OS X-generated files +# macOS-generated files ._* .DS_Store .DS_Store? .Spotlight-V100 .Trashes -Icon\? +Icon? # Windows-generated files Desktop.ini @@ -19,7 +17,8 @@ ehthumbs.db Thumbs.db # Editor-generated files +.idea/ +.phpintel/ *~ .*.s[a-w][a-z] *.sublime-workspace - From 37528fc72e2618fd50277fbc23f77c4ed10921db Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:47:05 -0500 Subject: [PATCH 3/7] Update Composer dependencies --- composer.json | 46 +-- composer.lock | 868 +++++++++++++++++++++++++++++++------------------- 2 files changed, 572 insertions(+), 342 deletions(-) diff --git a/composer.json b/composer.json index 0e4b88c..056ae8c 100644 --- a/composer.json +++ b/composer.json @@ -1,25 +1,33 @@ { - "name": "dana/twigc", - "description": "A CLI utility for rendering Twig templates", - "homepage": "https://github.com/okdana/twigc", - "keywords": ["twig", "compile", "render", "template", "cli"], - "license": "MIT", + "_comments": { + "symfony/finder": [ + "This is only required for the Phar build, actually!", + "I added it to the regular requires just to fix a problem with Composer.", + "Some day i'd like to put it back..." + ] + }, - "require": { - "php": ">=5.5.0", - "symfony/console": "^3.1", - "twig/twig": "^1.24" - }, + "name": "dana/twigc", + "description": "CLI tool for rendering Twig templates", + "homepage": "https://github.com/okdana/twigc", + "keywords": ["twig", "compile", "render", "template", "cli"], + "license": "MIT", - "require-dev": { - "phpunit/phpunit": "^5.4", - "symfony/finder": "^3.1" - }, + "require": { + "php": ">=7.0", + "symfony/console": "^4.0", + "symfony/finder": "^4.0", + "twig/twig": "^2.4", + "ulrichsg/getopt-php": "^3.1" + }, - "autoload": { - "psr-4": {"Dana\\Twigc\\": "src/Twigc"} - }, + "require-dev": { + "phpunit/phpunit": "^6.5" + }, - "bin": ["bin/twigc"] + "autoload": { + "psr-4": {"Dana\\Twigc\\": "src/Twigc"} + }, + + "bin": ["bin/twigc"] } - diff --git a/composer.lock b/composer.lock index fa15257..a88d986 100644 --- a/composer.lock +++ b/composer.lock @@ -4,41 +4,48 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "82dee21e082fbfc691baba706593cce6", - "content-hash": "8074df00286610b4cb7454ad52e9bc99", + "content-hash": "b234d9c8670e17387f8accea1698cb89", "packages": [ { "name": "symfony/console", - "version": "v3.1.2", + "version": "v4.1.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "747154aa69b0f83cd02fc9aa554836dee417631a" + "reference": "2d5d973bf9933d46802b01010bd25c800c87c242" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/747154aa69b0f83cd02fc9aa554836dee417631a", - "reference": "747154aa69b0f83cd02fc9aa554836dee417631a", + "url": "https://api.github.com/repos/symfony/console/zipball/2d5d973bf9933d46802b01010bd25c800c87c242", + "reference": "2d5d973bf9933d46802b01010bd25c800c87c242", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": "^7.1.3", "symfony/polyfill-mbstring": "~1.0" }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~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/lock": "", "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -65,20 +72,69 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-06-29 07:02:31" + "time": "2018-05-30T07:26:09+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.2.0", + "name": "symfony/finder", + "version": "v4.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "dff51f72b0706335131b00a7f49606168c582594" + "url": "https://github.com/symfony/finder.git", + "reference": "087e2ee0d74464a4c6baac4e90417db7477dc238" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", - "reference": "dff51f72b0706335131b00a7f49606168c582594", + "url": "https://api.github.com/repos/symfony/finder/zipball/087e2ee0d74464a4c6baac4e90417db7477dc238", + "reference": "087e2ee0d74464a4c6baac4e90417db7477dc238", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "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 Finder Component", + "homepage": "https://symfony.com", + "time": "2018-05-16T14:33:22+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "3296adf6a6454a050679cde90f95350ad604b171" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", + "reference": "3296adf6a6454a050679cde90f95350ad604b171", "shasum": "" }, "require": { @@ -90,7 +146,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -124,38 +180,43 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2018-04-26T10:06:28+00:00" }, { "name": "twig/twig", - "version": "v1.24.1", + "version": "v2.4.8", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512" + "reference": "7b604c89da162034bdf4bb66310f358d313dd16d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512", - "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/7b604c89da162034bdf4bb66310f358d313dd16d", + "reference": "7b604c89da162034bdf4bb66310f358d313dd16d", "shasum": "" }, "require": { - "php": ">=5.2.7" + "php": "^7.0", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/debug": "~2.7", - "symfony/phpunit-bridge": "~2.7" + "psr/container": "^1.0", + "symfony/debug": "^2.7", + "symfony/phpunit-bridge": "^3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.24-dev" + "dev-master": "2.4-dev" } }, "autoload": { "psr-0": { "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -185,38 +246,84 @@ "keywords": [ "templating" ], - "time": "2016-05-30 09:11:59" + "time": "2018-04-02T09:24:19+00:00" + }, + { + "name": "ulrichsg/getopt-php", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/getopt-php/getopt-php.git", + "reference": "7acdfd07023c52b91fa426d1929736fbfd173e36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getopt-php/getopt-php/zipball/7acdfd07023c52b91fa426d1929736fbfd173e36", + "reference": "7acdfd07023c52b91fa426d1929736fbfd173e36", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8", + "squizlabs/php_codesniffer": "^2.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GetOpt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ulrich Schmidt-Goertz", + "email": "ulrich@schmidt-goertz.de" + }, + { + "name": "Thomas Flori", + "email": "thflori@gmail.com" + } + ], + "description": "Command line arguments parser for PHP 5.4 - 7.1", + "homepage": "http://getopt-php.github.io/getopt-php", + "time": "2018-05-29T19:37:10+00:00" } ], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -241,41 +348,47 @@ "constructor", "instantiate" ], - "time": "2015-06-14 21:17:01" + "time": "2017-07-22T11:58:36+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.5.1", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "a8773992b362b58498eed24bf85005f363c34771" + "reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771", - "reference": "a8773992b362b58498eed24bf85005f363c34771", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/478465659fd987669df0bd8a9bf22a8710e5f1b6", + "reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { - "doctrine/collections": "1.*", - "phpunit/phpunit": "~4.1" + "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" ], "description": "Create deep copies (clones) of your objects", - "homepage": "https://github.com/myclabs/DeepCopy", "keywords": [ "clone", "copy", @@ -283,20 +396,122 @@ "object", "object graph" ], - "time": "2015-11-20 12:04:31" + "time": "2018-05-29T17:25:09+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "1.0", + "name": "phar-io/manifest", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "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": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", "shasum": "" }, "require": { @@ -337,33 +552,39 @@ "reflection", "static analysis" ], - "time": "2015-12-27 11:43:31" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "3.1.0", + "version": "4.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", "shasum": "" }, "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", + "php": "^7.0", + "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\\": [ @@ -382,24 +603,24 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-06-10 09:48:41" + "time": "2017-11-30T07:14:17+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.2", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", "shasum": "" }, "require": { - "php": ">=5.5", + "php": "^5.5 || ^7.0", "phpdocumentor/reflection-common": "^1.0" }, "require-dev": { @@ -429,36 +650,37 @@ "email": "me@mikevanriel.com" } ], - "time": "2016-06-10 07:14:17" + "time": "2017-07-14T14:27:02+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.6.1", + "version": "1.7.6", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -491,44 +713,44 @@ "spy", "stub" ], - "time": "2016-06-07 08:13:47" + "time": "2018-04-18T13:57:24+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "4.0.0", + "version": "5.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "900370c81280cc0d942ffbc5912d80464eaee7e9" + "reference": "c89677919c5dd6d3b3852f230a663118762218ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/900370c81280cc0d942ffbc5912d80464eaee7e9", - "reference": "900370c81280cc0d942ffbc5912d80464eaee7e9", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", + "reference": "c89677919c5dd6d3b3852f230a663118762218ac", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "^1.4.2", - "sebastian/code-unit-reverse-lookup": "~1.0", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0|~2.0" + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^2.0.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" }, "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "^5.4" + "phpunit/phpunit": "^6.0" }, "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.4.0", - "ext-xmlwriter": "*" + "ext-xdebug": "^2.5.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "5.3.x-dev" } }, "autoload": { @@ -543,7 +765,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -554,20 +776,20 @@ "testing", "xunit" ], - "time": "2016-06-03 05:03:56" + "time": "2018-04-06T15:36:58+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.1", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", "shasum": "" }, "require": { @@ -601,7 +823,7 @@ "filesystem", "iterator" ], - "time": "2015-06-21 13:08:43" + "time": "2017-11-27T13:52:08+00:00" }, { "name": "phpunit/php-text-template", @@ -642,29 +864,34 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", - "version": "1.0.8", + "version": "1.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4|~5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -686,33 +913,33 @@ "keywords": [ "timer" ], - "time": "2016-05-12 18:03:57" + "time": "2017-02-26T11:10:40+00:00" }, { "name": "phpunit/php-token-stream", - "version": "1.4.8", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + "reference": "791198a2c6254db10131eecfe8c06670700904db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "^6.2.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -735,51 +962,57 @@ "keywords": [ "tokenizer" ], - "time": "2015-09-15 10:49:45" + "time": "2017-11-27T05:48:46+00:00" }, { "name": "phpunit/phpunit", - "version": "5.4.7", + "version": "6.5.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6c8a756c17a1a92a066c99860eb57922e8b723da" + "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6c8a756c17a1a92a066c99860eb57922e8b723da", - "reference": "6c8a756c17a1a92a066c99860eb57922e8b723da", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b", + "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b", "shasum": "" }, "require": { "ext-dom": "*", "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "^4.0", - "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.1", - "sebastian/diff": "~1.2", - "sebastian/environment": "^1.3 || ^2.0", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/object-enumerator": "~1.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0|~2.0", - "symfony/yaml": "~2.1|~3.0" + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.3", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^5.0.5", + "sebastian/comparator": "^2.1", + "sebastian/diff": "^2.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" + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, + "require-dev": { + "ext-pdo": "*" }, "suggest": { - "phpunit/php-invoker": "~1.1" + "ext-xdebug": "*", + "phpunit/php-invoker": "^1.1" }, "bin": [ "phpunit" @@ -787,7 +1020,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.4.x-dev" + "dev-master": "6.5.x-dev" } }, "autoload": { @@ -813,33 +1046,33 @@ "testing", "xunit" ], - "time": "2016-07-21 06:55:27" + "time": "2018-04-10T11:38:34+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.2.3", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "b13d0d9426ced06958bd32104653526a6c998a52" + "reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/b13d0d9426ced06958bd32104653526a6c998a52", - "reference": "b13d0d9426ced06958bd32104653526a6c998a52", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3eaf040f20154d27d6da59ca2c6e28ac8fd56dce", + "reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2" + "doctrine/instantiator": "^1.0.5", + "php": "^7.0", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" }, "conflict": { - "phpunit/phpunit": "<5.4.0" + "phpunit/phpunit": "<6.0" }, "require-dev": { - "phpunit/phpunit": "^5.4" + "phpunit/phpunit": "^6.5" }, "suggest": { "ext-soap": "*" @@ -847,7 +1080,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "5.0.x-dev" } }, "autoload": { @@ -862,7 +1095,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -872,27 +1105,27 @@ "mock", "xunit" ], - "time": "2016-06-12 07:37:26" + "time": "2018-05-29T13:50:43+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", - "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", "shasum": "" }, "require": { - "php": ">=5.6" + "php": "^5.6 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~5" + "phpunit/phpunit": "^5.7 || ^6.0" }, "type": "library", "extra": { @@ -917,34 +1150,34 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2016-02-13 06:45:14" + "time": "2017-03-04T06:30:41+00:00" }, { "name": "sebastian/comparator", - "version": "1.2.0", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" + "php": "^7.0", + "sebastian/diff": "^2.0 || ^3.0", + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { @@ -975,38 +1208,38 @@ } ], "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": "2015-07-26 15:48:44" + "time": "2018-02-01T13:46:46+00:00" }, { "name": "sebastian/diff", - "version": "1.4.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "^6.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1033,32 +1266,32 @@ "keywords": [ "diff" ], - "time": "2015-12-08 07:14:41" + "time": "2017-08-03T08:09:46+00:00" }, { "name": "sebastian/environment", - "version": "1.3.7", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", - "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -1083,34 +1316,34 @@ "environment", "hhvm" ], - "time": "2016-05-17 03:18:57" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", - "version": "1.2.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.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": "1.3.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -1150,27 +1383,27 @@ "export", "exporter" ], - "time": "2016-06-17 09:04:28" + "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": "*" @@ -1178,7 +1411,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1201,33 +1434,34 @@ "keywords": [ "global state" ], - "time": "2015-10-12 03:26:01" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", - "version": "1.0.0", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", - "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", "shasum": "" }, "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~1.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": "1.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1247,32 +1481,77 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2016-01-28 13:25:10" + "time": "2017-08-03T12:35:26+00:00" }, { - "name": "sebastian/recursion-context", - "version": "1.0.2", + "name": "sebastian/object-reflector", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", "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": "1.0.x-dev" + "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": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1300,7 +1579,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11 19:50:13" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", @@ -1342,20 +1621,20 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28 20:34:47" + "time": "2015-07-28T20:34:47+00:00" }, { "name": "sebastian/version", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", - "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, "require": { @@ -1385,130 +1664,73 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-02-04 12:56:52" + "time": "2016-10-03T07:35:21+00:00" }, { - "name": "symfony/finder", - "version": "v3.1.2", + "name": "theseer/tokenizer", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8201978de88a9fa0923e18601bb17f1df9c721e7", - "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", "shasum": "" }, "require": { - "php": ">=5.5.9" + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "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 Finder Component", - "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" - }, - { - "name": "symfony/yaml", - "version": "v3.1.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de", - "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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": "2016-06-29 05:41:56" + "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.0.2", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde" + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", - "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1532,7 +1754,7 @@ "check", "validate" ], - "time": "2015-08-24 13:29:44" + "time": "2018-01-29T19:49:41+00:00" } ], "aliases": [], @@ -1541,7 +1763,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.5.0" + "php": ">=7.0" }, "platform-dev": [] } From 9cbe7e75f902a2a4d76647561c185d3880931106 Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:47:11 -0500 Subject: [PATCH 4/7] Significantly rework application: 0.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Get rid of Symfony Console application/command/input components These were causing me serious problems — not least of all was the fact that the Console argument parser chokes on command lines lke `twigc -j - foo.twig`. I am not happy with the way i've structured this, but i just needed to get it *done*, so here we are. If someone has any advice on to how to make this nicer (maybe break it up into different classes, &c.), i would be appreciative - Add GetOpt.php for argument parsing and usage-help printing The usage help is really ugly, tbh. But whatever - Support multiple input data sources at once - Add `-E` short option for `--env` - Display an error when `-E` is used without the appropriate `variables_order` configuration in place - Add shell (`sh`) auto-escape method - Simplify/eliminate a lot of code (handling of version numbers, validation, &c.) - Change a lot of white space and formatting stuff (RIP `blame`) --- bin/compile | 16 +- bin/twigc | 9 +- src/Twigc/Application.php | 546 +++++++++++++++++++++++++---- src/Twigc/ComposerHelper.php | 88 +++++ src/Twigc/DefaultCommand.php | 438 ------------------------ src/Twigc/PharCompiler.php | 645 +++++++++++++++-------------------- src/Twigc/Twigc.php | 88 ----- src/bootstrap.php | 75 ++-- 8 files changed, 891 insertions(+), 1014 deletions(-) mode change 100644 => 100755 bin/compile mode change 100644 => 100755 bin/twigc create mode 100644 src/Twigc/ComposerHelper.php delete mode 100644 src/Twigc/DefaultCommand.php delete mode 100644 src/Twigc/Twigc.php diff --git a/bin/compile b/bin/compile old mode 100644 new mode 100755 index 6d4ec34..a91d5ea --- a/bin/compile +++ b/bin/compile @@ -4,21 +4,23 @@ /** * This file is part of twigc. * - * @author dana geier + * @author dana * @license MIT */ require_once __DIR__ . '/../src/bootstrap.php'; +use Symfony\Component\Console\Output\ConsoleOutput; +use Dana\Twigc\PharCompiler; + $verbose = false; $verboseArgs = ['v', 'vv', 'vvv', 'verbose', 'debug']; foreach ( $argv as $arg ) { - if ( in_array(ltrim($arg, '-'), $verboseArgs, true) ) { - $verbose = true; - break; - } + if ( in_array(ltrim($arg, '-'), $verboseArgs, true) ) { + $verbose = true; + break; + } } -(new \Dana\Twigc\PharCompiler($verbose))->compile(); - +(new PharCompiler(new ConsoleOutput(), $verbose))->compile('twigc.phar'); diff --git a/bin/twigc b/bin/twigc old mode 100644 new mode 100755 index 13e4af9..b785a16 --- a/bin/twigc +++ b/bin/twigc @@ -4,11 +4,16 @@ /** * This file is part of twigc. * - * @author dana geier + * @author dana * @license MIT */ require_once __DIR__ . '/../src/bootstrap.php'; -(new \Dana\Twigc\Application())->run(); +use Symfony\Component\Console\Output\ConsoleOutput; +use Dana\Twigc\Application; +$output = new ConsoleOutput(); +$app = new Application(); + +exit($app->run($output)); diff --git a/src/Twigc/Application.php b/src/Twigc/Application.php index ae1d898..dc5e025 100644 --- a/src/Twigc/Application.php +++ b/src/Twigc/Application.php @@ -3,97 +3,495 @@ /** * This file is part of twigc. * - * @author dana geier + * @author dana * @license MIT */ namespace Dana\Twigc; -use Symfony\Component\Console\Application as BaseApplication; -use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputDefinition; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use GetOpt\{Argument,GetOpt,Operand,Option}; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Output\{ConsoleOutputInterface,OutputInterface}; +use Twig\Environment; +use Twig\Loader\{ArrayLoader,FilesystemLoader}; + +use Dana\Twigc\ComposerHelper; /** - * twigc application container. + * This class represents the entire `twigc` application. * - * This class overrides a bunch of the default Console behaviour to make the - * application work like a more traditional UNIX CLI tool. + * To be completely honest, this feels really shitty to me, and i don't like it. + * But after eliminating the standard Symfony\Console structure (due to + * Console's woefully inadequate argument handling, amongst other things), i + * find myself unsure of the best way to structure this, especially given how + * simple the application is, and just kind of want to be done with it. I guess + * this works for now, but i would welcome any improvements. */ -class Application extends BaseApplication { - /** - * {@inheritdoc} - */ - public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') { - parent::__construct('twigc', \Dana\Twigc\Twigc::VERSION_NUMBER); - } +class Application { + const NAME = 'twigc'; + const VERSION = '0.3.0'; + const BUILD_DATE = '%BUILD_DATE%'; // Replaced during build - /** - * {@inheritdoc} - * - * In a normal Console application, this method handles the --version and - * --help options. In our application, the default command handles all of - * that. - */ - public function doRun(InputInterface $input, OutputInterface $output) { - $name = $this->getCommandName($input); + protected $name; + protected $version; - if ( ! $name ) { - $name = $this->defaultCommand; - $input = new ArrayInput(['command' => $this->defaultCommand]); - } + /** + * Construct the object. + * + * @param string|null $name + * (optional) The name of the application, to be used in error messages and + * the like. + * + * @param string|null $version + * (optional) The version number of the application, to be used in the + * `--version` output. + * + * @return self + */ + public function __construct(string $name = null, string $version = null) { + $this->name = $name ?? static::NAME; + $this->version = $version ?? static::VERSION; + } - $command = $this->find($name); + /** + * Run the application. + * + * This is mostly a wrapper around doRun() to handle error printing. + * + * @param OutputInterface $output + * The output to write to. + * + * @param array|null $argv + * (optional) Command-line arguments to the application (with the 0th member + * as the application name). + * + * @return int + */ + public function run(OutputInterface $output, array $argv = null): int { + if ( $output instanceof ConsoleOutputInterface ) { + $error = $output->getErrorOutput(); + } else { + $error = $output; + } - $this->runningCommand = $command; - $exitCode = $this->doRunCommand($command, $input, $output); - $this->runningCommand = null; + try { + return $this->doRun($output, $argv); + } catch ( \Exception $e ) { + $error->writeln(sprintf( + '%s: %s', $this->name, + rtrim($e->getMessage(), "\r\n")) + ); + return 1; + } + } - return $exitCode; - } + /** + * Run the application (for real). + * + * @param OutputInterface $output + * The output to write to. + * + * @param array|null $argv + * (optional) Command-line arguments to the application (with the 0th member + * as the application name). + * + * @return int + */ + public function doRun(OutputInterface $output, array $argv = null): int { + $argv = $argv ?? $_SERVER['argv']; + $getopt = $this->getGetOpt(); - /** - * {@inheritdoc} - */ - public function getDefinition() { - $definition = parent::getDefinition(); - $definition->setArguments(); - return $definition; - } + $getopt->process(array_slice($argv, 1)); - /** - * {@inheritdoc} - * - * Since we're a one-command application, we always use the name of the - * default command. - */ - protected function getCommandName(InputInterface $input) { - return $this->getDefaultCommands()[0]->getName(); - } + if ( $getopt->getOption('help') ) { + $this->doHelp($output, $getopt); + return 0; + } + if ( $getopt->getOption('version') ) { + $this->doVersion($output); + return 0; + } + if ( $getopt->getOption('credits') ) { + $this->doCredits($output); + return 0; + } - /** - * {@inheritdoc} - * - * Since we're a one-command application, we always use the definition of - * the default command. This means that none of the built-in Console options - * like --help and --ansi are automatically defined — the default command - * must handle all of that. - */ - protected function getDefaultInputDefinition() { - return $this->getDefaultCommands()[0]->getDefinition(); - } + $inputData = []; + $template = $getopt->getOperand('template'); + $dirs = $getopt->getOption('dir'); + $temp = false; - /** - * {@inheritdoc} - * - * Since we're a one-command application, we always return just the default - * command. - */ - protected function getDefaultCommands() { - return [new \Dana\Twigc\DefaultCommand()]; - } + // If we're receiving data on standard input, and we didn't get a template, + // assume `-` — we'll make sure this doesn't conflict with `-j` below + if ( ! posix_isatty(\STDIN) ) { + $template = $template ?? '-'; + } + // Add the template's parent directory if we're not using standard input + if ( ($template ?? '-') !== '-' ) { + $dirs = array_merge([dirname($template)], $dirs); + } + + if ( $template === null ) { + $this->doHelp($output, $getopt, 'No template specified'); + return 1; + } + + // Input data via environment + if ( $getopt->getOption('env') ) { + if ( empty($_ENV) && strpos(ini_get('variables_order'), 'E') === false ) { + throw new \RuntimeException( + "INI setting 'variables_order' must include 'E' to use option 'env'" + ); + } + $inputData = array_merge($inputData, $_ENV); + } + + // Input data via query string + foreach ( $getopt->getOption('query') as $query ) { + $query = ltrim($query, '?'); + $parsed = []; + + parse_str($query, $parsed); + + $inputData = array_merge($inputData, $parsed); + } + + // Input data via JSON + foreach ( $getopt->getOption('json') as $json ) { + // JSON supplied via standard input + if ( $json === '-' ) { + if ( $template === '-' ) { + throw new \InvalidArgumentException( + 'Can not read both template and JSON input from stdin' + ); + } + + $json = file_get_contents('php://stdin'); + + // JSON supplied via file + } elseif ( (ltrim($json)[0] ?? '') !== '{' ) { + if ( ! file_exists($json) || is_dir($json) ) { + throw new \InvalidArgumentException( + "Missing or invalid JSON file: ${json}" + ); + } + $json = file_get_contents($json); + } + + // This check is here to prevent errors if the input is just empty + if ( trim($json) !== '' ) { + $json = json_decode($json, true); + } + + if ( ! is_array($json) ) { + throw new \InvalidArgumentException( + 'JSON input must be a dictionary' + ); + } + + $inputData = array_merge($inputData, $json); + } + + // Input data via key=value pair + foreach ( $getopt->getOption('pair') as $pair ) { + $kv = explode('=', $pair, 2); + + if ( count($kv) !== 2 ) { + throw new \InvalidArgumentException( + "Illegal key=value pair: ${pair}" + ); + } + + $inputData[$kv[0]] = $kv[1]; + } + + // Template supplied via file path + if ( $template !== '-' ) { + $loader = new FilesystemLoader($dirs); + // Template supplied via standard input + } else { + // If we've been supplied one or more search directories, we'll need to + // write the template out to a temp directory so we can use the file- + // system loader + if ( $dirs ) { + $temp = true; + $template = implode('/', [ + sys_get_temp_dir(), + implode('.', ['', $this->name, getmypid(), md5(time())]), + $template, + ]); + + mkdir(dirname($template)); + file_put_contents($template, file_get_contents('php://stdin'), \LOCK_EX); + + $dirs = array_merge([dirname($template)], $dirs); + $loader = new FilesystemLoader($dirs); + + // Otherwise, we can just use the array loader, which is a little faster + // and cleaner + } else { + $loader = new ArrayLoader([ + $template => file_get_contents('php://stdin'), + ]); + } + } + + // Render + try { + $twig = new Environment($loader, [ + 'cache' => $getopt->getOption('cache') ?? false, + 'debug' => false, + 'strict_variables' => (bool) $getopt->getOption('strict'), + 'autoescape' => $this->getEscaper( + $getopt->getOption('escape'), + $template + ), + ]); + + $twig->getExtension('Twig_Extension_Core')->setEscaper( + 'json', + function($twigEnv, $string, $charset) { + return json_encode( + $string, + \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE + ); + } + ); + $twig->getExtension('Twig_Extension_Core')->setEscaper( + 'sh', + function($twigEnv, $string, $charset) { + return '"' . addcslashes($string, '$`\\"') . '"'; + } + ); + + $output->writeln( + rtrim($twig->render(basename($template), $inputData), "\r\n") + ); + + // Clean up + } finally { + if ( $temp ) { + unlink($template); + rmdir(dirname($template)); + } + } + + return 0; + } + + /** + * Display the application's usage help. + * + * @param OutputInterface $output + * The output to write to. + * + * @param GetOpt $getopt + * The GetOpt instance from which to derive the usage help. + * + * @param string|null $message + * (optional) An additional message to print above the usage help. This is + * intended primarily for error messages. + * + * @return int + */ + public function doHelp( + OutputInterface $output, + GetOpt $getopt, + string $message = null + ): int { + if ( $message !== null && $message !== '' ) { + $output->writeln("{$this->name}: " . rtrim($message, "\r\n") . "\n"); + } + $output->writeln(rtrim($getopt->getHelpText(), "\r\n")); + return 0; + } + + /** + * Display the application's version information. + * + * @param OutputInterface $output The output to write to. + * + * @return int + */ + public function doVersion(OutputInterface $output): int { + $version = sprintf('%s version %s', $this->name, $this->version); + + if ( strpos(static::BUILD_DATE, '%') === false ) { + $version .= sprintf(' (built %s)', static::BUILD_DATE); + } + + $output->writeln($version); + return 0; + } + + /** + * Display the application's dependency information. + * + * @param OutputInterface $output The output to write to. + * + * @return int + */ + public function doCredits(OutputInterface $output): int { + $packages = (new ComposerHelper())->getPackages(); + + $table = new Table($output); + $table->setStyle('compact'); + $table->getStyle()->setVerticalBorderChar(''); + $table->getStyle()->setCellRowContentFormat('%s '); + $table->setHeaders(['name', 'version', 'licence']); + + foreach ( $packages as $package ) { + $table->addRow([ + $package->name, + ltrim($package->version, 'v'), + implode(', ', $package->license) ?: '?', + ]); + } + $table->render(); + + return 0; + } + + /** + * Get an instance of GetOpt configured for this application. + * + * @return GetOpt + */ + public function getGetOpt(): GetOpt { + $getopt = new GetOpt(null, [ + GetOpt::SETTING_SCRIPT_NAME => $this->name, + GetOpt::SETTING_STRICT_OPERANDS => true, + ]); + $getopt->addOptions([ + Option::create('h', 'help', GetOpt::NO_ARGUMENT) + ->setDescription('Display this usage help and exit') + , + Option::create('V', 'version', GetOpt::NO_ARGUMENT) + ->setDescription('Display version information and exit') + , + Option::create(null, 'credits', GetOpt::NO_ARGUMENT) + ->setDescription('Display dependency information and exit') + , + Option::create(null, 'cache', GetOpt::REQUIRED_ARGUMENT) + ->setDescription('Enable caching to specified directory') + ->setArgumentName('dir') + ->setValidation('is_dir') + , + Option::create('d', 'dir', GetOpt::MULTIPLE_ARGUMENT) + ->setDescription('Add specified search directory to loader') + ->setArgumentName('dir') + ->setValidation('is_dir') + , + Option::create('e', 'escape', GetOpt::REQUIRED_ARGUMENT) + ->setArgumentName('strategy') + ->setDescription('Specify default auto-escaping strategy') + , + Option::create('E', 'env', GetOpt::NO_ARGUMENT) + ->setDescription('Derive input data from environment') + , + Option::create('j', 'json', GetOpt::MULTIPLE_ARGUMENT) + ->setArgumentName('dict/file') + ->setDescription('Derive input data from specified JSON file or dictionary string') + , + Option::create('p', 'pair', GetOpt::MULTIPLE_ARGUMENT) + ->setArgumentName('input') + ->setDescription('Derive input data from specified key=value pair') + , + Option::create(null, 'query', GetOpt::MULTIPLE_ARGUMENT) + ->setArgumentName('input') + ->setDescription('Derive input data from specified URL query string') + , + Option::create('s', 'strict', GetOpt::NO_ARGUMENT) + ->setDescription('Throw exception when undefined variable is referenced') + , + ]); + $getopt->addOperands([ + Operand::create('template', Operand::OPTIONAL), + ]); + + return $getopt; + } + + /** + * Get the correct Twig escape method given the provided options. + * + * @param string|null $escape + * The user-provided escape option, or null if not provided. + * + * @param string|null $template + * The name/path of the template file, or null if not provided. This is only + * used when $escape is null or 'auto'. + * + * @return string|false + */ + public function getEscaper($escape, string $template = null) { + $escape = $escape === null ? $escape : strtolower($escape); + $template = $template ?? ''; + + if ( $escape === null || $escape === 'auto' ) { + if ( + substr($template, -5) === '.twig' + && + strpos(substr($template, 0, -5), '.') + ) { + $ext = pathinfo(substr($template, 0, -5), \PATHINFO_EXTENSION); + } else { + $ext = pathinfo($template, \PATHINFO_EXTENSION); + } + + switch ( strtolower($ext) ) { + case 'htm': + case 'html': + case 'phtml': + case 'thtml': + case 'xhtml': + case 'template': + case 'tmpl': + case 'tpl': + return 'html'; + case 'css': + case 'scss': + return 'css'; + case 'js': + return 'js'; + case 'json': + return 'json'; + case 'bash': + case 'ksh': + case 'sh': + case 'zsh': + return 'sh'; + } + + return false; + } + + // Otherwise, try to parse the supplied method + switch ( $escape ) { + case 'f': + case 'n': + case 'none': + case 'never': + $escape = 'false'; + break; + case 't': + case 'y': + case 'always': + $escape = 'true'; + break; + } + + $bool = filter_var( + $escape, + \FILTER_VALIDATE_BOOLEAN, + \FILTER_NULL_ON_FAILURE + ); + + if ( $bool !== null ) { + $escape = $bool ? 'html' : false; + } + + return $escape; + } } - diff --git a/src/Twigc/ComposerHelper.php b/src/Twigc/ComposerHelper.php new file mode 100644 index 0000000..5bce15b --- /dev/null +++ b/src/Twigc/ComposerHelper.php @@ -0,0 +1,88 @@ + + * @license MIT + */ + +namespace Dana\Twigc; + +/** + * Helper class with various functions for interacting with Composer's lock + * file. + */ +class ComposerHelper { + /** + * Get an array of the installed non-dev packages listed in a Composer lock + * file. + * + * @param string|null (optional) The path to the lock file to parse. + * + * @return object[] + */ + public function getPackages(string $lockFile = null) { + $packages = $this->parseLockFile($lockFile)['packages']; + return $this->massagePackages($packages); + } + + /** + * Get an array of the installed dev packages listed in a Composer lock file. + * + * @param string|null (optional) The path to the lock file to parse. + * + * @return object[] + */ + public function getDevPackages(string $lockFile = null) { + $packages = $this->parseLockFile($lockFile)['packages-dev']; + return $this->massagePackages($packages); + } + + /** + * Get an array of data representing a Composer lock file. + * + * @param string $path + * (optional) The path to the lock file to parse. The default is the lock + * file associated with the current project. + * + * @return array + * + * @throws \RuntimeException if composer.lock doesn't exist + * @throws \RuntimeException if composer.lock can't be decoded + */ + public function parseLockFile(string $lockFile = null): array { + $lockFile = $lockFile ?? __DIR__ . '/../../composer.lock'; + + if ( ! file_exists($lockFile) ) { + throw new \RuntimeException('Missing ' . basename($lockFile)); + } + + $lock = json_decode(file_get_contents($lockFile), true); + + if ( empty($lock) || ! isset($lock['packages']) ) { + throw new \RuntimeException('Error decoding ' . basename($lockFile)); + } + + return $lock; + } + + /** + * Sort and object-ify an array of package data. + * + * @param array $packages Package data from composer.lock. + * + * @return object[] + */ + public function massagePackages(array $packages): array { + usort($packages, function ($a, $b) { + return strcasecmp($a['name'], $b['name']); + }); + + foreach ( $packages as &$package ) { + $package = (object) $package; + } + + return $packages; + } +} diff --git a/src/Twigc/DefaultCommand.php b/src/Twigc/DefaultCommand.php deleted file mode 100644 index cfe3bb3..0000000 --- a/src/Twigc/DefaultCommand.php +++ /dev/null @@ -1,438 +0,0 @@ - - * @license MIT - */ - -namespace Dana\Twigc; - -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\DescriptorHelper; -use Symfony\Component\Console\Helper\Table; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; - -/** - * Default twigc command. - */ -class DefaultCommand extends Command { - /** - * {@inheritdoc} - */ - protected function configure() { - $this - ->setName('twigc') - ->setDescription('Compile a Twig template') - ->addArgument( - 'template', - InputArgument::OPTIONAL, - 'Twig template file to render (use `-` for STDIN)' - ) - ->addOption( - 'help', - 'h', - InputOption::VALUE_NONE, - 'Display this usage help' - ) - ->addOption( - 'version', - 'V', - InputOption::VALUE_NONE, - 'Display version information' - ) - ->addOption( - 'credits', - null, - InputOption::VALUE_NONE, - 'Display dependency credits (including Twig version)' - ) - ->addOption( - 'cache', - null, - InputOption::VALUE_REQUIRED, - 'Enable caching to specified directory' - ) - ->addOption( - 'dir', - 'd', - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Add search directory to loader' - ) - ->addOption( - 'env', - null, - InputOption::VALUE_NONE, - 'Treat environment variables as input data' - ) - ->addOption( - 'escape', - 'e', - InputOption::VALUE_REQUIRED, - 'Set autoescape environment option' - ) - ->addOption( - 'json', - 'j', - InputOption::VALUE_REQUIRED, - 'Pass variables as JSON (dictionary string or file path)' - ) - ->addOption( - 'pair', - 'p', - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Pass variable as key=value pair' - ) - ->addOption( - 'query', - null, - InputOption::VALUE_REQUIRED, - 'Pass variables as URL query string' - ) - ->addOption( - 'strict', - 's', - InputOption::VALUE_NONE, - 'Enable strict_variables environment option' - ) - ; - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) { - switch ( true ) { - // Display usage help - case $input->getOption('help'): - return $this->doHelp($input, $output); - // Display version information - case $input->getOption('version'): - return $this->doVersion($input, $output); - // Display package credits - case $input->getOption('credits'): - return $this->doCredits($input, $output); - } - // Render Twig template - return $this->doRender($input, $output); - } - - /** - * {@inheritdoc} - * - * Overriding this prevents TextDescriptor from displaying the Help section. - */ - public function getProcessedHelp() { - return ''; - } - - /** - * Displays usage help. - * - * @param InputInterface $input - * @param OutputInterface $output - * - * @return int - */ - public function doHelp(InputInterface $input, OutputInterface $output) { - (new DescriptorHelper())->describe($output, $this); - return 0; - } - - /** - * Displays version information. - * - * @param InputInterface $input - * @param OutputInterface $output - * - * @return int - */ - public function doVersion(InputInterface $input, OutputInterface $output) { - $nameFmt = 'twigc'; - $versionFmt = '%s (%s @ %s)'; - - $output->writeln(sprintf( - "${nameFmt} version ${versionFmt}", - \Dana\Twigc\Twigc::VERSION_NUMBER, - \Dana\Twigc\Twigc::VERSION_COMMIT, - \Dana\Twigc\Twigc::VERSION_DATE - )); - - return 0; - } - - /** - * Displays package credits. - * - * @param InputInterface $input - * @param OutputInterface $output - * - * @return int - */ - public function doCredits(InputInterface $input, OutputInterface $output) { - $installed = \Dana\Twigc\Twigc::getComposerPackages(); - - $table = new Table($output); - $table->setStyle('compact'); - $table->getStyle()->setVerticalBorderChar(''); - $table->getStyle()->setCellRowContentFormat('%s '); - $table->setHeaders(['name', 'version', 'licence']); - - foreach ( $installed as $package ) { - $table->addRow([ - $package->name, - ltrim($package->version, 'v'), - implode(', ', $package->license) ?: '?', - ]); - } - $table->render(); - } - - /** - * Renders a Twig template. - * - * @param InputInterface $input - * @param OutputInterface $output - * - * @return int - */ - public function doRender(InputInterface $input, OutputInterface $output) { - $inputData = []; - $template = $input->getArgument('template'); - $template = $template === null ? '-' : $template; - $cache = $input->getOption('cache'); - $cache = $cache === null ? false : $cache; - $dirs = $template === '-' ? [] : [dirname($template)]; - $dirs = array_merge($dirs, $input->getOption('dir')); - $temp = false; - $strict = (bool) $input->getOption('strict'); - $escape = $input->getOption('escape'); - $inputs = [ - 'json' => (int) ($input->getOption('json') !== null), - 'pair' => (int) (! empty($input->getOption('pair'))), - 'query' => (int) ($input->getOption('query') !== null), - ]; - - // If we're reading from STDIN, but STDIN is a TTY, print help and die - if ( $template === '-' && posix_isatty(\STDIN) ) { - $this->doHelp($input, $output); - return 1; - } - - // Validate search directories - foreach ( $dirs as $dir ) { - if ( ! is_dir($dir) ) { - throw new \InvalidArgumentException( - "Illegal search directory: ${dir}" - ); - } - } - - // If no escape option was supplied, try to auto-detect - // (we could do this with Twig's 'filename' method, but i have some - // control over this) - if ( $escape === null ) { - if ( substr($template, -5) === '.twig' ) { - $ext = pathinfo(substr($template, -5), \PATHINFO_EXTENSION); - } else { - $ext = pathinfo($template, \PATHINFO_EXTENSION); - } - - switch ( strtolower($ext) ) { - case 'template': - case 'tmpl': - case 'tpl': - case 'htm': - case 'html': - case 'phtml': - case 'thtml': - case 'xhtml': - $escape = 'html'; - break; - case 'css': - case 'scss': - $escape = 'css'; - break; - case 'js': - $escape = 'js'; - break; - case 'json': - $escape = 'json'; - break; - default: - $escape = false; - break; - } - - // Otherwise, try to parse the supplied method - } else { - // Normalise some boolean values - $escape = strtolower($escape); - $escape = $escape === 'f' ? 'false' : $escape; - $escape = $escape === 'n' ? 'false' : $escape; - $escape = $escape === 'none' ? 'false' : $escape; - $escape = $escape === 'never' ? 'false' : $escape; - $escape = $escape === 't' ? 'true' : $escape; - $escape = $escape === 'y' ? 'true' : $escape; - $escape = $escape === 'always' ? 'true' : $escape; - - $bool = filter_var($escape, \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE); - - if ( $bool !== null ) { - $escape = $bool ? 'html' : false; - } - } - - // Because Console doesn't allow us to see the order of options supplied - // at the command line, there's no good way to sort out the precedence - // amongst the different input methods... so let's just say we can only - // use one of them at a time - if ( array_sum($inputs) > 1 ) { - throw new \InvalidArgumentException( - '-j, -p, and --query options are mutually exclusive' - ); - } - - // Input data supplied via query string - if ( ($query = $input->getOption('query')) !== null ) { - if ( $query && $query[0] === '?' ) { - $query = substr($query, 1); - } - parse_str($query, $inputData); - - // Input data supplied via JSON - } elseif ( ($json = $input->getOption('json')) !== null ) { - $json = trim($json); - - // JSON supplied via STDIN - if ( $json === '-' ) { - if ( $template === '-' ) { - throw new \InvalidArgumentException( - 'Can not read both template and JSON input from STDIN' - ); - } - if ( posix_isatty(\STDIN) ) { - throw new \InvalidArgumentException( - 'Expected JSON input on STDIN' - ); - } - $json = file_get_contents('php://stdin'); - - // JSON supplied via file - } elseif ( $json && $json[0] !== '{' ) { - if ( ! file_exists($json) || is_dir($json) ) { - throw new \InvalidArgumentException( - "Missing or illegal JSON file name: ${json}" - ); - } - $json = file_get_contents($json); - } - - // This check is here to prevent errors if the input is just empty - if ( trim($json) !== '' ) { - $inputData = json_decode($json, true); - } - - if ( ! is_array($inputData) ) { - throw new \InvalidArgumentException( - 'JSON input must be a dictionary' - ); - } - - // Input data supplied via key=value pair - } elseif ( count($input->getOption('pair')) ) { - foreach ( $input->getOption('pair') as $pair ) { - $kv = explode('=', $pair, 2); - - if ( count($kv) !== 2 ) { - throw new \InvalidArgumentException( - "Illegal key=value pair: ${pair}" - ); - } - - $inputData[$kv[0]] = $kv[1]; - } - } - - if ( $input->getOption('env') ) { - $inputData = array_merge($_ENV, $inputData); - } - - // Validate key names now - foreach ( $inputData as $key => $value ) { - if ( ! preg_match('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#', $key) ) { - throw new \InvalidArgumentException( - "Illegal variable name: ${key}" - ); - } - } - - // Template supplied via STDIN - if ( $template === '-' ) { - // If we've been supplied one or more search directories, we'll need - // to write the template out to a temp directory so we can use the - // file-system loader - if ( $dirs ) { - $temp = true; - $template = implode('/', [ - sys_get_temp_dir(), - implode('.', ['twigc', getmypid(), md5(time())]), - '-', - ]); - - mkdir(dirname($template)); - file_put_contents($template, file_get_contents('php://stdin'), LOCK_EX); - - $dirs = array_merge([dirname($template)], $dirs); - - $loader = new \Twig_Loader_Filesystem($dirs); - - // Otherwise, we can just use the array loader, which is a little - // faster and cleaner - } else { - $loader = new \Twig_Loader_Array([ - $template => file_get_contents('php://stdin'), - ]); - } - - // Template supplied via file path - } else { - $loader = new \Twig_Loader_Filesystem($dirs); - } - - try { - $twig = new \Twig_Environment($loader, [ - 'cache' => $cache, - 'debug' => false, - 'strict_variables' => $strict, - 'autoescape' => $escape, - ]); - - $twig->getExtension('core')->setEscaper( - 'json', - function($twigEnv, $string, $charset) { - return json_encode( - $string, - \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE - ); - } - ); - - $output->writeln( - rtrim($twig->render(basename($template), $inputData), "\r\n") - ); - } finally { - if ( $temp ) { - unlink($template); - rmdir(dirname($template)); - } - } - - return 0; - } -} - diff --git a/src/Twigc/PharCompiler.php b/src/Twigc/PharCompiler.php index 681fbc7..8a36570 100644 --- a/src/Twigc/PharCompiler.php +++ b/src/Twigc/PharCompiler.php @@ -3,18 +3,19 @@ /** * This file is part of twigc. * - * @author dana geier + * @author dana * @license MIT */ namespace Dana\Twigc; -use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Finder\Finder; +use Dana\Twigc\Application; + /** - * Compiles twigc into an executable phar file. + * Compile twigc to an executable phar. * * This clas is heavily inspired by Composer's Compiler: * @@ -39,407 +40,321 @@ use Symfony\Component\Finder\Finder; * THE SOFTWARE. */ class PharCompiler { - protected $output; - protected $baseDir; - protected $finderSort; - protected $versionNumber; - protected $versionCommit; - protected $versionDate; + protected $output; + protected $baseDir; + protected $finderSort; - /** - * Object constructor. - * - * @param (bool) $verbose (optional) Whether to display verbose output. - * - * @return self - */ - public function __construct($verbose = false) { - $this->output = new ConsoleOutput(); - $this->baseDir = realpath(\Dana\Twigc\Twigc::BASE_DIR); - $this->finderSort = function ($a, $b) { - return strcmp( - strtr($a->getRealPath(), '\\', '/'), - strtr($b->getRealPath(), '\\', '/') - ); - }; + /** + * Object constructor. + * + * @param OutputInterface $output The output to write to. + * @param bool $verbose (optional) Whether to display verbose output. + * + * @return self + */ + public function __construct(OutputInterface $output, bool $verbose = false) { + $this->output = $output; + $this->baseDir = realpath(__DIR__ . '/../..'); + $this->finderSort = function ($a, $b) { + return strcmp( + strtr($a->getRealPath(), '\\', '/'), + strtr($b->getRealPath(), '\\', '/') + ); + }; - if ( $verbose ) { - $this->output->setVerbosity(ConsoleOutput::VERBOSITY_VERBOSE); - } - } + if ( $verbose ) { + $this->output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + } + } - /** - * Compiles the project into an executable phar file. - * - * @param string $pharFile - * (optional) The path (absolute or relative to the CWD) to write the - * resulting phar file to. - * - * @return void - */ - public function compile($pharFile = 'twigc.phar') { - $this->output->writeln('Compiling phar...'); + /** + * Compiles the project into an executable phar file. + * + * @param string $phar + * (optional) The path (absolute or relative to the CWD) to write the + * resulting phar file to. + * + * @return void + */ + public function compile(string $phar) { + $this->output->writeln('Compiling phar...'); - $this->output->writeln('', ConsoleOutput::VERBOSITY_VERBOSE); - $this->extractVersionInformation(); + $this->output->writeln('', OutputInterface::VERBOSITY_VERBOSE); - if ( file_exists($pharFile) ) { - unlink($pharFile); - } + if ( file_exists($phar) ) { + unlink($phar); + } - $phar = new \Phar($pharFile, 0, 'twigc.phar'); - $phar->setSignatureAlgorithm(\Phar::SHA1); - $phar->startBuffering(); + $obj = new \Phar($phar, 0, basename($phar)); + $obj->setSignatureAlgorithm(\Phar::SHA1); + $obj->startBuffering(); - $this->output->writeln('', ConsoleOutput::VERBOSITY_VERBOSE); - $this->output->writeln('Adding src files...'); - $this->addSrc($phar); + $this->output->writeln('', OutputInterface::VERBOSITY_VERBOSE); + $this->output->writeln('Adding src files...'); + $this->addSrc($obj); - $this->output->writeln('', ConsoleOutput::VERBOSITY_VERBOSE); - $this->output->writeln('Adding vendor files...'); - $this->addVendor($phar); + $this->output->writeln('', OutputInterface::VERBOSITY_VERBOSE); + $this->output->writeln('Adding vendor files...'); + $this->addVendor($obj); - $this->output->writeln('', ConsoleOutput::VERBOSITY_VERBOSE); - $this->output->writeln('Adding root files...'); - $this->addRoot($phar); + $this->output->writeln('', OutputInterface::VERBOSITY_VERBOSE); + $this->output->writeln('Adding root files...'); + $this->addRoot($obj); - $this->output->writeln('', ConsoleOutput::VERBOSITY_VERBOSE); - $this->output->writeln('Adding bin files...'); - $this->addBin($phar); + $this->output->writeln('', OutputInterface::VERBOSITY_VERBOSE); + $this->output->writeln('Adding bin files...'); + $this->addBin($obj); - $phar->setStub($this->getStub()); - $phar->stopBuffering(); + $obj->setStub($this->getStub()); + $obj->stopBuffering(); + unset($obj); - unset($phar); + chmod($phar, 0755); - chmod($pharFile, 0755); + $this->output->writeln('', OutputInterface::VERBOSITY_VERBOSE); + $this->output->writeln("Compiled to ${phar}."); + } - $this->output->writeln('', ConsoleOutput::VERBOSITY_VERBOSE); - $this->output->writeln("Compiled to ${pharFile}."); + /** + * Add a file to a phar archive. + * + * @param \Phar $phar + * The phar file to add to. + * + * @param \SplFileInfo|string $file + * The file to add, or its path. + * + * @param bool|null $strip + * (optional) Whether to strip extraneous white space from the file in + * order to reduce its size. The default is to auto-detect based on file + * extension. + * + * @return void + */ + protected function addFile(\Phar $phar, $file, bool $strip = null) { + if ( is_string($file) ) { + $file = new \SplFileInfo($file); + } - /* - // Re-sign the phar with reproducible time stamps and signature - $util = new Timestamps($pharFile); - $util->updateTimestamps($this->versionDate); - $util->save($pharFile, \Phar::SHA1); - */ - } + // Strip the absolute base directory off the front of the path + $prefix = $this->baseDir . DIRECTORY_SEPARATOR; + $path = strtr( + str_replace($prefix, '', $file->getRealPath()), + '\\', + '/' + ); - /** - * Extracts the application version information from the git repository and - * sets the associated object properties. - * - * @return void - * - * @throws \RuntimeException if `git describe` fails - * @throws \RuntimeException if `git log` fails - * @throws \RuntimeException if `git log` fails (2) - */ - protected function extractVersionInformation() { - $workDir = escapeshellarg(__DIR__); + $this->output->writeln( + "Adding file: ${path}", + OutputInterface::VERBOSITY_VERBOSE + ); - // Get version number - $output = []; - exec("cd ${workDir} && git describe --tags --match='v*.*.*' --dirty='!'", $output, $ret); + $content = file_get_contents($file); - if ( $ret !== 0 || empty($output) ) { - $output = ['0.0.0']; - } + // Strip interpreter directives + if ( strpos($path, 'bin/') === 0 ) { + $content = preg_replace('%^#!/usr/bin/env php\s*%', '', $content); - $tokens = explode('-', trim($output[0])); + // Replace build-date place-holder + } elseif ( $path === 'src/Twigc/Application.php' ) { + $date = new \DateTime('now', new \DateTimeZone('UTC')); - $this->versionNumber = rtrim(ltrim($tokens[0], 'v'), '!'); + $content = str_replace( + '%BUILD_DATE%', + $date->format('D Y-m-d H:i:s T'), + $content + ); + } - // If we're ahead of a tag, add the number of commits - if ( count($tokens) > 1 ) { - $this->versionNumber .= '-plus' . rtrim($tokens[1], '!'); - } + if ( $strip === null ) { + $strip = in_array($file->getExtension(), ['json', 'lock', 'php'], true); + } - // If the index is dirty, add that - if ( rtrim(implode('-', $tokens), '!') !== implode('-', $tokens) ) { - $this->versionNumber .= '-dirty'; - } + if ( $strip ) { + $content = $this->stripWhiteSpace($content); + } - // Get version last commit hash - $output = []; - exec("cd ${workDir} && git log -1 --pretty='%H' HEAD", $output, $ret); + $phar->addFromString($path, $content); + } - if ( $ret !== 0 || empty($output) ) { - throw new \RuntimeException( - 'An error occurred whilst running `git log`' - ); - } + /** + * Remove extraneous white space from a string whilst preserving PHP line + * numbers. + * + * @param string $source + * The PHP or JSON string to strip white space from. + * + * @param string $type + * (optional) The type of file the string represents. Available options + * are 'php' and 'json'. The default is 'php'. + * + * @return string + */ + protected function stripWhiteSpace( + string $source, + string $type = 'php' + ): string { + $output = ''; - $this->versionCommit = trim($output[0]); + if ( $type === 'json' ) { + $output = json_encode(json_decode($json, true)); - // Get version last commit date - $output = []; - exec("cd ${workDir} && git log -1 --pretty='%ci' HEAD", $output, $ret); + return $output === null ? $source : $output . "\n"; + } - if ( $ret !== 0 || empty($output) ) { - throw new \RuntimeException( - 'An error occurred whilst running `git log`' - ); - } + if ( ! function_exists('token_get_all') ) { + return $source; + } - $this->versionDate = new \DateTime(trim($output[0])); - $this->versionDate->setTimezone(new \DateTimeZone('UTC')); + foreach ( token_get_all($source) as $token ) { + // Arbitrary text, return as-is + if ( is_string($token) ) { + $output .= $token; + // Replace comments by empty lines + } elseif ( in_array($token[0], [\T_COMMENT, \T_DOC_COMMENT]) ) { + $output .= str_repeat("\n", substr_count($token[1], "\n")); + // Collapse and normalise white-space + } elseif ($token[0] === \T_WHITESPACE) { + // Collapse consecutive spaces + $space = preg_replace('/[ \t]+/', ' ', $token[1]); + // Normalise new-lines to \n + $space = preg_replace('/(?:\r\n|\r|\n)/', "\n", $space); + // Trim leading spaces + $space = preg_replace('/\n[ ]+/', "\n", $space); + $output .= $space; + // Anything else, return as-is + } else { + $output .= $token[1]; + } + } - if ( $this->output->isVerbose() ) { - $this->output->writeln( - 'Got version number: ' . $this->versionNumber - ); - $this->output->writeln( - 'Got version commit: ' . $this->versionCommit - ); - $this->output->writeln( - 'Got version date: ' . $this->versionDate->getTimestamp() - ); - } - } + return $output; + } - /** - * Adds a file to a phar. - * - * @param \Phar $phar - * The phar file to add to. - * - * @param \SplFileInfo|string $file - * The file to add, or its path. - * - * @param null|bool $strip - * (optional) Whether to strip extraneous white space from the file in - * order to reduce its size. The default is to auto-detect based on file - * extension. - * - * @return void - */ - protected function addFile($phar, $file, $strip = null) { - if ( is_string($file) ) { - $file = new \SplFileInfo($file); - } + /** + * Add files from src directory to a phar. + * + * @param \Phar $phar The phar file to add to. + * + * @return void + */ + protected function addSrc(\Phar $phar) { + $finder = new Finder(); + $finder + ->files() + ->in($this->baseDir . '/src') + ->ignoreDotFiles(true) + ->ignoreVCS(true) + ->name('*.php') + ->notName('PharCompiler.php') + ->sort($this->finderSort) + ; - // Strip the absolute base directory off the front of the path - $prefix = $this->baseDir . DIRECTORY_SEPARATOR; - $path = strtr( - str_replace($prefix, '', $file->getRealPath()), - '\\', - '/' - ); + foreach ( $finder as $file ) { + $this->addFile($phar, $file); + } + } - $this->output->writeln("Adding file: ${path}", ConsoleOutput::VERBOSITY_VERBOSE); + /** + * Adds files from vendor directory to a phar. + * + * @param \Phar $phar The phar file to add to. + * + * @return void + */ + protected function addVendor($phar) { + $devPaths = (new ComposerHelper())->getDevPackages(); + $devPaths = array_map(function ($x) { + return $x->name . '/'; + }, $devPaths); - $content = file_get_contents($file); + $finder = new Finder(); + $finder + ->files() + ->in($this->baseDir . '/vendor') + ->ignoreDotFiles(true) + ->ignoreVCS(true) + ; - // Strip interpreter directives - if ( strpos($path, 'bin/') === 0 ) { - $content = preg_replace('%^#!/usr/bin/env php\s*%', '', $content); + // Exclude files from dev packages + foreach ( $devPaths as $path ) { + $finder->notPath($path); + } - // Replace version place-holders - } elseif ( $path === 'src/Twigc/Twigc.php' ) { - $content = str_replace( - [ - '%version_number%', - '%version_commit%', - '%version_date%', - ], - [ - $this->versionNumber, - $this->versionCommit, - $this->versionDate->format('Y-m-d H:i:s'), - ], - $content - ); - } + $finder + ->exclude('bin') + ->exclude('doc') + ->exclude('docs') + ->exclude('test') + ->exclude('tests') + ->notPath('/^[^\/]+\/[^\/]+\/Tests?\//') + ->notName('*.c') + ->notName('*.h') + ->notName('*.m4') + ->notName('*.w32') + ->notName('*.xml.dist') + ->notName('build.xml') + ->notName('composer.json') + ->notName('composer.lock') + ->notName('travis-ci.xml') + ->notName('phpunit.xml') + ->notName('ChangeLog*') + ->notName('CHANGE*') + ->notName('*CONDUCT*') + ->notName('CONTRIBUT*') + ->notName('README*') + ->sort($this->finderSort) + ; - if ( $strip === null ) { - $strip = in_array($file->getExtension(), ['json', 'lock', 'php'], true); - } + foreach ( $finder as $file ) { + $this->addFile($phar, $file); + } + } - if ( $strip ) { - $content = $this->stripWhiteSpace($content); - } + /** + * Adds files from project root directory to a phar. + * + * @param \Phar $phar The phar file to add to. + * + * @return void + */ + protected function addRoot(\Phar $phar) { + $this->addFile($phar, $this->baseDir . '/composer.json'); + $this->addFile($phar, $this->baseDir . '/composer.lock'); + } - $phar->addFromString($path, $content); - } + /** + * Adds files from bin directory to a phar. + * + * @param \Phar $phar The phar file to add to. + * + * @return void + */ + protected function addBin(\Phar $phar) { + $this->addFile($phar, $this->baseDir . '/bin/twigc'); + } - /** - * Removes extraneous white space from a string whilst preserving PHP line - * numbers. - * - * @param string $source - * The PHP or JSON string to strip white space from. - * - * @param string $type - * (optional) The type of file the string represents. Available options - * are 'php' and 'json'. The default is 'php'. - * - * @return string - */ - protected function stripWhiteSpace($source, $type = 'php') { - $output = ''; + /** + * Returns the phar stub. + * + * @return string + */ + protected function getStub() { + $stub = " + #!/usr/bin/env php + + * @license MIT + */ - return $output === null ? $source : $output . "\n"; - } - - if ( ! function_exists('token_get_all') ) { - return $source; - } - - foreach ( token_get_all($source) as $token ) { - // Arbitrary text, return as-is - if ( is_string($token) ) { - $output .= $token; - // Replace comments by empty lines - } elseif ( in_array($token[0], [\T_COMMENT, \T_DOC_COMMENT]) ) { - $output .= str_repeat("\n", substr_count($token[1], "\n")); - // Collapse and normalise white-space - } elseif (T_WHITESPACE === $token[0]) { - // Collapse consecutive spaces - $space = preg_replace('#[ \t]+#', ' ', $token[1]); - // Normalise new-lines to \n - $space = preg_replace('#(?:\r\n|\r|\n)#', "\n", $space); - // Trim leading spaces - $space = preg_replace('#\n[ ]+#', "\n", $space); - $output .= $space; - // Anything else, return as-is - } else { - $output .= $token[1]; - } - } - - return $output; - } - - /** - * Adds files from src directory to a phar. - * - * @param \Phar $phar The phar file to add to. - * - * @return void - */ - protected function addSrc($phar) { - $finder = new Finder(); - $finder - ->files() - ->in($this->baseDir . '/src') - ->ignoreDotFiles(true) - ->ignoreVCS(true) - ->name('*.php') - ->notName('PharCompiler.php') - ->sort($this->finderSort) - ; - - foreach ( $finder as $file ) { - $this->addFile($phar, $file); - } - } - - /** - * Adds files from vendor directory to a phar. - * - * @param \Phar $phar The phar file to add to. - * - * @return void - */ - protected function addVendor($phar) { - $devPaths = \Dana\Twigc\Twigc::getComposerDevPackages(); - $devPaths = array_map(function ($x) { - return $x->name . '/'; - }, $devPaths); - - $finder = new Finder(); - $finder - ->files() - ->in($this->baseDir . '/vendor') - ->ignoreDotFiles(true) - ->ignoreVCS(true) - ; - - // Exclude files from dev packages - foreach ( $devPaths as $path ) { - $finder->notPath($path); - } - - $finder - ->exclude('bin') - ->exclude('doc') - ->exclude('docs') - ->exclude('test') - ->exclude('tests') - ->notPath('/^[^\/]+\/[^\/]+\/Tests?\//') - ->notName('*.c') - ->notName('*.h') - ->notName('*.m4') - ->notName('*.w32') - ->notName('*.xml.dist') - ->notName('build.xml') - ->notName('composer.json') - ->notName('composer.lock') - ->notName('travis-ci.xml') - ->notName('phpunit.xml') - ->notName('ChangeLog*') - ->notName('CHANGE*') - ->notName('*CONDUCT*') - ->notName('CONTRIBUT*') - ->notName('README*') - ->sort($this->finderSort) - ; - - foreach ( $finder as $file ) { - $this->addFile($phar, $file); - } - } - - /** - * Adds files from project root directory to a phar. - * - * @param \Phar $phar The phar file to add to. - * - * @return void - */ - protected function addRoot($phar) { - $this->addFile($phar, $this->baseDir . '/composer.json'); - $this->addFile($phar, $this->baseDir . '/composer.lock'); - } - - /** - * Adds files from bin directory to a phar. - * - * @param \Phar $phar The phar file to add to. - * - * @return void - */ - protected function addBin($phar) { - $this->addFile($phar, $this->baseDir . '/bin/twigc'); - } - - /** - * Returns the phar stub. - * - * @return string - */ - protected function getStub() { - $stub = " - #!/usr/bin/env php - - * @license MIT - */ - - \Phar::mapPhar('twigc.phar'); - require 'phar://twigc.phar/bin/twigc'; - __HALT_COMPILER(); - "; - - return str_replace("\t", '', trim($stub)) . "\n"; - } + \Phar::mapPhar('twigc.phar'); + require 'phar://twigc.phar/bin/twigc'; + __HALT_COMPILER(); + "; + return preg_replace('/^\s+/m', '', trim($stub)) . "\n"; + } } - diff --git a/src/Twigc/Twigc.php b/src/Twigc/Twigc.php deleted file mode 100644 index 09e6fc1..0000000 --- a/src/Twigc/Twigc.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @license MIT - */ - -namespace Dana\Twigc; - -/** - * Holds various project-specific constants and methods. - */ -class Twigc { - const BASE_DIR = __DIR__ . '/../..'; - const VERSION_NUMBER = '%version_number%'; - const VERSION_COMMIT = '%version_commit%'; - const VERSION_DATE = '%version_date%'; - - /** - * Returns an array of data representing the project's Composer lock file. - * - * @return array - * - * @throws \RuntimeException if composer.lock doesn't exist - * @throws \RuntimeException if composer.lock can't be decoded - */ - private static function parseComposerLock() { - $lockFile = static::BASE_DIR . '/composer.lock'; - - if ( ! file_exists($lockFile) ) { - throw new \RuntimeException('Missing ' . basename($lockFile)); - } - - $installed = json_decode(file_get_contents($lockFile), true); - - if ( empty($installed) || ! isset($installed['packages']) ) { - throw new \RuntimeException('Error decoding ' . basename($lockFile)); - } - - return $installed; - } - - /** - * Sorts and object-ifies an array of package data. - * - * @param array $packages Package data from composer.lock. - * - * @return array - */ - private static function massagePackages(array $packages) { - usort($packages, function ($a, $b) { - return strcasecmp($a['name'], $b['name']); - }); - - foreach ( $packages as &$package ) { - $package = (object) $package; - } - - return $packages; - } - - /** - * Returns an array of installed non-dev Composer packages based on the - * project's Composer lock file. - * - * @return object[] An array of objects representing Composer packages. - */ - public static function getComposerPackages() { - $packages = static::parseComposerLock()['packages']; - - return static::massagePackages($packages); - } - - /** - * Returns an array of installed dev Composer packages based on the - * project's lock file. - * - * @return object[] An array of objects representing Composer packages. - */ - public static function getComposerDevPackages() { - $packages = static::parseComposerLock()['packages-dev']; - - return static::massagePackages($packages); - } -} - diff --git a/src/bootstrap.php b/src/bootstrap.php index da8f7d1..f872de4 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -3,62 +3,57 @@ /** * This file is part of twigc. * - * @author dana geier + * @author dana * @license MIT */ /** - * Helper function for printing an error message. + * Print an error message. * - * Uses fprintf() to print to STDERR if available; uses echo otherwise. + * Uses fprintf() to print to stderr if available; uses echo otherwise. * * @param string $string - * (optional) The message to print. Will be passed through rtrim(); if the - * result is an empty string, only an empty line will be printed; otherwise, - * the text 'twigc: ' will be appended to the beginning. + * (optional) The message to print. Is passed through rtrim(); if the result + * is an empty string, only an empty line is printed; otherwise, the text + * 'twigc: ' is appended to the beginning. * * @return void */ function twigc_puts_error($string = '') { - $string = rtrim($string); - $string = $string === '' ? '' : "twigc: ${string}"; + $string = rtrim($string); + $string = $string === '' ? '' : "twigc: ${string}"; - // \STDERR only exists when we're using the CLI SAPI - if ( defined('\\STDERR') ) { - fprintf(\STDERR, "%s\n", $string); - } else { - echo $string, "\n"; - } + if ( defined('\\STDERR') ) { + fprintf(\STDERR, "%s\n", $string); + } else { + echo $string, "\n"; + } } -// Find Composer's auto-loader -$autoloaders = [ - // Phar/repo path - __DIR__ . '/../vendor/autoload.php', - // Composer path - __DIR__ . '/../../../autoload.php', -]; - -foreach ( $autoloaders as $autoloader ) { - if ( file_exists($autoloader) ) { - define('TWIGC_AUTOLOADER', $autoloader); - break; - } -} - -unset($autoloaders, $autoloader); - -// Disallow running from non-CLI SAPIs if ( \PHP_SAPI !== 'cli' ) { - twigc_puts_error("This tool must be invoked via PHP's CLI SAPI."); - exit(1); + twigc_puts_error("This tool must be invoked via PHP's CLI SAPI."); + exit(1); } -// Give a meaningful error if we don't have the auto-loader -if ( ! defined('TWIGC_AUTOLOADER') ) { - twigc_puts_error('Auto-loader is missing — try running `composer install`.'); - exit(1); +(function () { + $paths = [ + // Phar/repo path + __DIR__ . '/../vendor/autoload.php', + // Composer path + __DIR__ . '/../../../autoload.php', + ]; + + foreach ( $paths as $path ) { + if ( file_exists($path) ) { + define('TWIGC_AUTOLOADER', $path); + return; + } + } +})(); + +if ( ! defined('\\TWIGC_AUTOLOADER') ) { + twigc_puts_error('Auto-loader is missing — try running `composer install`.'); + exit(1); } -require_once TWIGC_AUTOLOADER; - +require_once \TWIGC_AUTOLOADER; From 97f8acb902b8462cf5782f6c53ed4438a0d637bb Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:44:08 -0500 Subject: [PATCH 5/7] Add unit tests --- phpunit.xml.dist | 29 +++ tests/ApplicationTest.php | 462 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 491 insertions(+) create mode 100644 phpunit.xml.dist create mode 100644 tests/ApplicationTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..8d8746e --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + + + + + + + + src + + + + + + + tests + + + diff --git a/tests/ApplicationTest.php b/tests/ApplicationTest.php new file mode 100644 index 0000000..9ded86a --- /dev/null +++ b/tests/ApplicationTest.php @@ -0,0 +1,462 @@ + + * @license MIT + */ + +namespace Dana\Test\Twigc; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Output\BufferedOutput; + +use Dana\Twigc\Application; + +/** + * Tests for twigc. + * + * This doesn't feel very 'DRY'. Would like to improve it somehow. + */ +class ApplicationTest extends TestCase { + protected $output; + protected $app; + protected $template; + protected $tempDir; + protected $tempFiles = []; + + /** + * Set up before tests. + * + * @return void + */ + protected function setUp() { + $this->output = new BufferedOutput(); + $this->app = new Application(); + $this->template = $this->makeFile('default', 'testEnv: {{ testEnv }}'); + } + + /** + * Tear down after tests. + * + * @return void + */ + protected function tearDown() { + $this->output->fetch(); + + // This is slow, but i'm too lazy to handle recursive deletion properly + if ( ! empty($this->tempFiles) ) { + $dir = escapeshellarg($this->tempDir); + exec("rm -rf ${dir}/?* 2> /dev/null"); + $this->tempFiles = []; + } + } + + /** + * Create a temporary file, and optionally populate it with data. + * + * @param string $name + * The temporary file name/suffix. If the name contains an internal slash, + * all leading directories are created. + * + * @param string|null $content + * (optional) Any data to populate the file with. + * + * @return string The name of the created file. + */ + protected function makeFile(string $name, string $data = null): string { + // Create our temp directory if we don't already have it + if ( ! $this->tempDir ) { + $rand = base64_encode(random_bytes(32)); + $rand = substr(str_replace(['/', '+', '='], '', $rand), 0, 10); + $this->tempDir = sys_get_temp_dir(); + $this->tempDir .= "/Dana.Test.Twigc.ApplicationTest.${rand}"; + + if ( ! is_dir($this->tempDir) ) { + mkdir($this->tempDir, 0700); + } + } + + $dir = $this->tempDir; + $name = trim($name, '/.'); + + if ( strlen($name) === 0 ) { + throw \RuntimeException('Expected file name'); + } + + if ( strpos($name, '/') !== false ) { + $dir .= '/' . dirname($name); + + if ( ! is_dir($dir) ) { + mkdir($dir, 0700, true); + } + + $name = basename($name); + } + + $file = "${dir}/${name}"; + $this->tempFiles[] = $file; + + if ( $data !== null ) { + if ( file_put_contents($file, $data, \LOCK_EX) === false ) { + throw \RuntimeException("Write failed: ${file}"); + } + } elseif ( touch($file) === false ) { + throw \RuntimeException("Write failed: ${file}"); + } + + return $file; + } + + /** + * Run the application and return common test data. + * + * @param $args + * (optional) Zero or more arguments to pass to the application. This should + * NOT include argv[0]. + * + * @return array + * An array containing the application return status as an integer, the raw + * output as a string, and the output as an array of lines. + */ + protected function runApp(...$args) { + $argv = ['', '-e', 'none']; + + if ( is_array($args[0]) ) { + $argv = array_merge($argv, $args[0]); + } else { + $argv = array_merge($argv, $args); + } + + $argv = array_filter($argv, function ($v) { + return $v !== null; + }); + + $ret = $this->app->run($this->output, $argv); + $buffer = $this->output->fetch(); + $lines = explode("\n", rtrim($buffer, "\r\n")); + + return [$ret, $buffer, $lines]; + } + + /** + * Provide data for testEscape(). + * + * All tests assume the following input data (value is literal): + * + * testEnv="" + * + * All tests assume the following template: + * + * testEnv: {{ testEnv }} + * + * @return array[] + */ + public function provideTestEscape() { + return [ + // Escape method: none + ['f', 'testEnv: ""'], + ['false', 'testEnv: ""'], + ['n', 'testEnv: ""'], + ['no', 'testEnv: ""'], + ['none', 'testEnv: ""'], + ['never', 'testEnv: ""'], + + // Escape method: html + ['always', 'testEnv: "<foo$bar>"'], + ['t', 'testEnv: "<foo$bar>"'], + ['true', 'testEnv: "<foo$bar>"'], + ['y', 'testEnv: "<foo$bar>"'], + ['yes', 'testEnv: "<foo$bar>"'], + ['html', 'testEnv: "<foo$bar>"'], + + // Escape method: css + ['css', 'testEnv: \\22 \\3C foo\\24 bar\\3E \\22'], + + // Escape method: html_attr + ['html_attr', 'testEnv: "<foo$bar>"'], + + // Escape method: js + ['js', 'testEnv: \\x22\\x3Cfoo\\x24bar\\x3E\\x22'], + + // Escape method: json + ['json', 'testEnv: "\"\""'], + + // Escape method: sh + ['sh', 'testEnv: "\"\""'], + + // Escape method: url + ['url', 'testEnv: %22%3Cfoo%24bar%3E%22'], + ]; + } + + /** + * Test `-h` / `--help` function. + * + * @return void + */ + public function testHelp() { + foreach ( ['-h', '--help'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp($opt); + + $this->assertSame(0, $ret); + $this->assertGreaterThan(3, count($lines)); + $this->assertContains('--help', $buffer); + $this->assertContains('--version', $buffer); + } + } + + /** + * Test `-V` / `--version` function. + * + * @return void + */ + public function testVersion() { + foreach ( ['-V', '--version'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp($opt); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains(' version ', $lines[0]); + } + } + + /** + * Test `--credits` function. + * + * @return void + */ + public function testCredits() { + list($ret, $buffer, $lines) = $this->runApp('--credits'); + + $this->assertSame(0, $ret); + $this->assertGreaterThan(1, count($lines)); + $this->assertContains('licence', $lines[0]); + } + + /** + * Test `-d` / `--dir` function, as well as default include-directory + * functionality. + * + * @return void + */ + public function testDir() { + $templateSame = $this->makeFile('dir1/a.twig', '{% include "b.twig" %}'); + $includeSame = $this->makeFile('dir1/b.twig', 'included: {{ testEnv }}'); + + $templateDiff = $this->makeFile('dir2/a.twig', '{% include "b.twig" %}'); + $includeDiff = $this->makeFile('dir3/b.twig', 'included: {{ testEnv }}'); + + // $includeSame's directory should be searched by default + list($ret, $buffer, $lines) = $this->runApp( + '-p', + 'testEnv=abc123', + $templateSame + ); + $this->assertSame(0, $ret); + + // $includeDiff's directory should have to be specified manually + list($ret, $buffer, $lines) = $this->runApp( + '-p', + 'testEnv=abc123', + $templateDiff + ); + $this->assertNotSame(0, $ret); + + // Now we confirm that that works + foreach ( ['-d', '--dir'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp( + $opt, + dirname($includeDiff), + '-p', + 'testEnv=abc123', + $templateDiff + ); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('included: abc123', $lines[0]); + } + } + + /** + * Test `-E` / `--env` function. + * + * @return void + */ + public function testEnv() { + foreach ( ['-E', '--env'] as $opt ) { + // This option can't be set at run time; we'll just test what we have + if ( strpos(ini_get('variables_order'), 'E') === false ) { + list($ret, $buffer, $lines) = $this->runApp($opt, $this->template); + + $this->assertGreaterThan(0, $ret); + $this->assertContains('variables_order', $buffer); + return; + } + + $_ENV['testEnv'] = 'abc123'; + list($ret, $buffer, $lines) = $this->runApp($opt, $this->template); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv: abc123', $lines[0]); + } + } + + /** + * Test `-j` / `--json` function (dictionary string). + * + * @return void + */ + public function testJsonDict() { + foreach ( ['-j', '--json'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp( + $opt, + '{"testEnv": "abc123"}', + $this->template + ); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv: abc123', $lines[0]); + } + } + + /** + * Test `-j` / `--json` function (file). + * + * @return void + */ + public function testJsonFile() { + $jsonFile = $this->makeFile('json', '{"testEnv": "abc123"}'); + + foreach ( ['-j', '--json'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp( + $opt, + $jsonFile, + $this->template + ); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv: abc123', $lines[0]); + } + } + + /** + * Test `-p` / `--pair` function. + * + * @return void + */ + public function testPair() { + foreach ( ['-p', '--pair'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp( + $opt, + 'testEnv=abc123', + $this->template + ); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv: abc123', $lines[0]); + } + } + + /** + * Test `--query` function. + * + * @return void + */ + public function testQuery() { + list($ret, $buffer, $lines) = $this->runApp( + '--query', + '?testEnv=abc123&testEnv2=x&testEnv3=y', + $this->template + ); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv: abc123', $lines[0]); + } + + /** + * Test input-data precedence. + * + * Input precedence should be as follows (ascending): + * + * env -> query -> json -> pair + * + * @return void + */ + public function testInputDataPrecedence() { + list($ret, $buffer, $lines) = $this->runApp( + '--pair', + 'testEnv=aaa', + '--query', + '?testEnv=bbb', + '--json', + '{ "testEnv": "ccc" }', + $this->template + ); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv: aaa', $lines[0]); + } + + /** + * Test handling of undefined variable WITHOUT `-s` / `--strict`. + * + * @return void + */ + public function testUndefinedNoStrict() { + list($ret, $buffer, $lines) = $this->runApp($this->template); + + $this->assertSame(0, $ret); + $this->assertSame(1, count($lines)); + $this->assertContains('testEnv:', $lines[0]); + $this->assertNotContains('abc123', $lines[0]); + } + + /** + * Test handling of undefined variable WITHOUT `-s` / `--strict`. + * + * @return void + */ + public function testUndefinedStrict() { + foreach ( ['-s', '--strict'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp($opt, $this->template); + + $this->assertSame(1, $ret); + $this->assertContains('testEnv', $lines[0]); + $this->assertNotContains('abc123', $lines[0]); + } + } + + /** + * Test various escape methods with `-e` / `--escape`. + * + * @param string $method The method to test. + * @param string $expected The expected output. + * + * @dataProvider provideTestEscape + * + * @return void + */ + public function testEcape(string $method, string $expected) { + foreach ( ['-e', '--escape'] as $opt ) { + list($ret, $buffer, $lines) = $this->runApp( + $opt, + $method, + '-p', + 'testEnv=""', + $this->template + ); + + $this->assertSame(0, $ret); + $this->assertContains($expected, $lines[0] ?? ''); + } + } +} From aa45391808fba1c58f04e68f26ee439e67dd8355 Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:46:50 -0500 Subject: [PATCH 6/7] Improve Makefile --- Makefile | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9dad973..7a66a01 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,45 @@ ## # This file is part of twigc. # -# @author dana geier +# @author dana # @license MIT -all: build +all: build +build: phar +phar: clean twigc.phar +test: test-unit test-integration + +help: + @echo 'Available targets:' + @echo 'all ................ Equivalent to `build`' + @echo 'build .............. Equivalent to `vendor`' + @echo 'install ............ Install phar to `/usr/local/bin/twigc`' + @echo 'clean .............. Remove phar' + @echo 'distclean .......... Remove phar and vendor directory' + @echo 'phar ............... Equivalent to `twigc.phar`' + @echo 'test ............... Run unit and integration tests' + @echo 'test-integration ... Run integration tests against phar' + @echo 'test-unit .......... Run unit tests against source' + @echo 'twigc.phar ......... Build phar' + @echo 'vendor ............. Install vendor directory via Composer' vendor: composer install -twigc.phar: vendor +twigc.phar: + composer install -q --no-dev php -d phar.readonly=0 bin/compile + composer install -q -build: twigc.phar +test-unit: vendor + vendor/bin/phpunit -install: build +test-integration: twigc.phar + ./twigc.phar --help | grep -q -- --version + echo 'hello {{ name }}' | ./twigc.phar -j '{ "name": "foo" }' | grep -qF 'hello foo' + echo 'hello {{ name }}' | ./twigc.phar -p name=foo | grep -qF 'hello foo' + +install: twigc.phar cp twigc.phar /usr/local/bin/twigc clean: @@ -23,5 +48,4 @@ clean: distclean: clean rm -rf vendor/ -.PHONY: all build install clean distclean - +.PHONY: all clean distclean install test test-integration test-unit From 33e945b4bca4e52631cd78fd64dda047d5ef3d42 Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 2 Jun 2018 01:42:26 -0500 Subject: [PATCH 7/7] Update README --- README.md | 226 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 180 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 36264b7..708e7e8 100644 --- a/README.md +++ b/README.md @@ -5,99 +5,201 @@ for interacting with Twig through shell scripts and other command-line applications. -## Usage overview - -``` -Usage: - twigc [options] [--] [