diff --git a/composer.json b/composer.json index 687766b6fd10fe2dd92d5f156137920b7aac71ce..d34d5be8db8e246d9c1bec1416aa61b72a52676d 100644 --- a/composer.json +++ b/composer.json @@ -52,6 +52,7 @@ "laminas/laminas-text": "2.7.1", "laminas/laminas-validator": "2.13.0", "laminas/laminas-view": "2.11.2", + "league/commonmark": "1.4.0", "matthiasmullie/minify": "1.3.62", "misd/linkify": "1.1.4", "ocramius/proxy-manager": "2.1.1", @@ -61,6 +62,7 @@ "pear/validate_ispn": "dev-master", "phing/phing": "2.16.3", "ppito/laminas-whoops": "2.0.0", + "scssphp/scssphp": "1.1.0", "serialssolutions/summon": "1.3.0", "symfony/console": "4.4.4", "symfony/yaml": "3.4.36", @@ -74,8 +76,7 @@ "yajra/laravel-pdo-via-oci8": "2.1.1", "zendframework/zendrest": "2.0.2", "zendframework/zendservice-amazon": "2.3.1", - "zf-commons/zfc-rbac": "2.6.3", - "league/commonmark": "1.4.0" + "zf-commons/zfc-rbac": "2.6.3" }, "require-dev": { "behat/mink": "1.7.1", diff --git a/composer.lock b/composer.lock index a097924295008a7277ba9c6c2af4910dd8afe158..803a4d74424ded3c2d8615932a99faf6af0871c6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2fa106f50dfdef1a435e63ce5689d508", + "content-hash": "9919518ab3dc824de4962304a832b927", "packages": [ { "name": "ahand/mobileesp", @@ -937,16 +937,16 @@ }, { "name": "laminas/laminas-dependency-plugin", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/laminas/laminas-dependency-plugin.git", - "reference": "f269716dc584cd7b69e7f6e8ac1092d645ab56d5" + "reference": "38bf91861f5b4d49f9a1c530327c997f7a7fb2db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-dependency-plugin/zipball/f269716dc584cd7b69e7f6e8ac1092d645ab56d5", - "reference": "f269716dc584cd7b69e7f6e8ac1092d645ab56d5", + "url": "https://api.github.com/repos/laminas/laminas-dependency-plugin/zipball/38bf91861f5b4d49f9a1c530327c997f7a7fb2db", + "reference": "38bf91861f5b4d49f9a1c530327c997f7a7fb2db", "shasum": "" }, "require": { @@ -979,7 +979,13 @@ "BSD-3-Clause" ], "description": "Replace zendframework and zfcampus packages with their Laminas Project equivalents.", - "time": "2020-01-14T19:36:52+00:00" + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-05-20T13:45:39+00:00" }, { "name": "laminas/laminas-dom", @@ -3161,6 +3167,12 @@ "laminas", "zf" ], + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], "time": "2020-04-03T16:01:00+00:00" }, { @@ -3235,6 +3247,32 @@ "md", "parser" ], + "funding": [ + { + "url": "https://enjoy.gitstore.app/repositories/thephpleague/commonmark", + "type": "custom" + }, + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://www.patreon.com/colinodell", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], "time": "2020-04-18T20:46:13+00:00" }, { @@ -4437,6 +4475,67 @@ ], "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "scssphp/scssphp", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/scssphp/scssphp.git", + "reference": "4363ddce8d750f055c436833dd77d83517946532" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scssphp/scssphp/zipball/4363ddce8d750f055c436833dd77d83517946532", + "reference": "4363ddce8d750f055c436833dd77d83517946532", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", + "squizlabs/php_codesniffer": "~3.5", + "twbs/bootstrap": "~4.3", + "zurb/foundation": "~6.5" + }, + "bin": [ + "bin/pscss" + ], + "type": "library", + "autoload": { + "psr-4": { + "ScssPhp\\ScssPhp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "description": "scssphp is a compiler for SCSS written in PHP.", + "homepage": "http://scssphp.github.io/scssphp/", + "keywords": [ + "css", + "less", + "sass", + "scss", + "stylesheet" + ], + "time": "2020-04-21T15:53:32+00:00" + }, { "name": "serialssolutions/summon", "version": "v1.3.0", @@ -4745,16 +4844,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294" + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1aab00e39cebaef4d8652497f46c15c1b7e45294", - "reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", "shasum": "" }, "require": { @@ -4766,7 +4865,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -4813,20 +4912,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T16:50:20+00:00" + "time": "2020-05-12T16:14:59+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "a54881ec0ab3b2005c406aed0023c062879031e7" + "reference": "fa79b11539418b02fc5e1897267673ba2c19419c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a54881ec0ab3b2005c406aed0023c062879031e7", - "reference": "a54881ec0ab3b2005c406aed0023c062879031e7", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c", + "reference": "fa79b11539418b02fc5e1897267673ba2c19419c", "shasum": "" }, "require": { @@ -4838,7 +4937,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -4886,20 +4985,20 @@ "type": "tidelift" } ], - "time": "2020-05-08T16:50:20+00:00" + "time": "2020-05-12T16:47:27+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "7e95fe59d12169fcf4041487e4bf34fca37ee0ed" + "reference": "a760d8964ff79ab9bf057613a5808284ec852ccc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/7e95fe59d12169fcf4041487e4bf34fca37ee0ed", - "reference": "7e95fe59d12169fcf4041487e4bf34fca37ee0ed", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a760d8964ff79ab9bf057613a5808284ec852ccc", + "reference": "a760d8964ff79ab9bf057613a5808284ec852ccc", "shasum": "" }, "require": { @@ -4908,7 +5007,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -4958,7 +5057,7 @@ "type": "tidelift" } ], - "time": "2020-05-02T14:56:09+00:00" + "time": "2020-05-12T16:47:27+00:00" }, { "name": "symfony/property-access", @@ -6009,6 +6108,12 @@ "Xdebug", "performance" ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + } + ], "time": "2020-03-01T12:26:26+00:00" }, { @@ -8580,16 +8685,16 @@ }, { "name": "symfony/polyfill-php70", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "6cc55bd2a085dbe05b4122c1987a82897b8da419" + "reference": "82225c2d7d23d7e70515496d249c0152679b468e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6cc55bd2a085dbe05b4122c1987a82897b8da419", - "reference": "6cc55bd2a085dbe05b4122c1987a82897b8da419", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/82225c2d7d23d7e70515496d249c0152679b468e", + "reference": "82225c2d7d23d7e70515496d249c0152679b468e", "shasum": "" }, "require": { @@ -8599,7 +8704,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -8649,20 +8754,20 @@ "type": "tidelift" } ], - "time": "2020-05-02T14:56:09+00:00" + "time": "2020-05-12T16:47:27+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "42fda6d7380e5c940d7f68341ccae89d5ab9963b" + "reference": "f048e612a3905f34931127360bdd2def19a5e582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/42fda6d7380e5c940d7f68341ccae89d5ab9963b", - "reference": "42fda6d7380e5c940d7f68341ccae89d5ab9963b", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/f048e612a3905f34931127360bdd2def19a5e582", + "reference": "f048e612a3905f34931127360bdd2def19a5e582", "shasum": "" }, "require": { @@ -8671,7 +8776,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -8718,7 +8823,7 @@ "type": "tidelift" } ], - "time": "2020-05-08T17:28:34+00:00" + "time": "2020-05-12T16:47:27+00:00" }, { "name": "symfony/process", diff --git a/module/VuFindConsole/src/VuFindConsole/Command/PluginManager.php b/module/VuFindConsole/src/VuFindConsole/Command/PluginManager.php index 998130e7544c2a6e62a579708d7a3551f0b0da2f..b1222e7fab0ba618fdcd1492a7c02060e4390d6d 100644 --- a/module/VuFindConsole/src/VuFindConsole/Command/PluginManager.php +++ b/module/VuFindConsole/src/VuFindConsole/Command/PluginManager.php @@ -80,6 +80,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager 'util/index_reserves' => Util\IndexReservesCommand::class, 'util/lint_marc' => Util\LintMarcCommand::class, 'util/optimize' => Util\OptimizeCommand::class, + 'util/scssBuilder' => Util\ScssBuilderCommand::class, 'util/sitemap' => Util\SitemapCommand::class, 'util/suppressed' => Util\SuppressedCommand::class, 'util/switch_db_hash' => Util\SwitchDbHashCommand::class, @@ -142,6 +143,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager Util\AbstractSolrAndIlsCommandFactory::class, Util\LintMarcCommand::class => InvokableFactory::class, Util\OptimizeCommand::class => Util\AbstractSolrCommandFactory::class, + Util\ScssBuilderCommand::class => Util\ScssBuilderCommandFactory::class, Util\SitemapCommand::class => Util\SitemapCommandFactory::class, Util\SuppressedCommand::class => Util\AbstractSolrAndIlsCommandFactory::class, diff --git a/module/VuFindConsole/src/VuFindConsole/Command/Util/AbstractCssBuilderCommand.php b/module/VuFindConsole/src/VuFindConsole/Command/Util/AbstractCssBuilderCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..876c9535197a1ec83931853a4326093e31bce753 --- /dev/null +++ b/module/VuFindConsole/src/VuFindConsole/Command/Util/AbstractCssBuilderCommand.php @@ -0,0 +1,114 @@ +<?php +/** + * Abstract console command: build CSS with precompiler. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2020. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Console + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFindConsole\Command\Util; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Abstract console command: build CSS with precompiler. + * + * @category VuFind + * @package Console + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +abstract class AbstractCssBuilderCommand extends Command +{ + /** + * Cache directory for compiler + * + * @var string + */ + protected $cacheDir; + + /** + * Name of precompiler format + * + * @var string + */ + protected $format; + + /** + * Constructor + * + * @param string $cacheDir Cache directory for compiler + * @param string|null $name The name of the command; passing null means it + * must be set in configure() + */ + public function __construct($cacheDir, $name = null) + { + $this->cacheDir = $cacheDir; + parent::__construct($name); + } + + /** + * Configure the command. + * + * @return void + */ + protected function configure() + { + $this + ->setDescription($this->format . ' compiler') + ->setHelp('Compiles CSS files from ' . $this->format . '.') + ->addArgument( + 'themes', + InputArgument::IS_ARRAY | InputArgument::OPTIONAL, + 'Name of theme(s) to compile; omit to compile everything' + ); + } + + /** + * Build the compiler. + * + * @param OutputInterface $output Output object + * + * @return \VuFindTheme\AbstractCssPreCompiler + */ + abstract protected function getCompiler(OutputInterface $output); + + /** + * Run the command. + * + * @param InputInterface $input Input object + * @param OutputInterface $output Output object + * + * @return int 0 for success + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $compiler = $this->getCompiler($output); + $compiler->setTempPath($this->cacheDir); + $compiler->compile(array_unique($input->getArgument('themes'))); + return 0; + } +} diff --git a/module/VuFindConsole/src/VuFindConsole/Command/Util/CssBuilderCommand.php b/module/VuFindConsole/src/VuFindConsole/Command/Util/CssBuilderCommand.php index 28b650523bf833cd1e78ce12a67f34f6bc5c877b..2ee3356ad229a294f6a26c2aaa9d135653148c10 100644 --- a/module/VuFindConsole/src/VuFindConsole/Command/Util/CssBuilderCommand.php +++ b/module/VuFindConsole/src/VuFindConsole/Command/Util/CssBuilderCommand.php @@ -1,6 +1,6 @@ <?php /** - * Console command: build CSS. + * Console command: build CSS from LESS. * * PHP version 7 * @@ -28,13 +28,11 @@ namespace VuFindConsole\Command\Util; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use VuFindTheme\LessCompiler; /** - * Console command: build CSS. + * Console command: build CSS from LESS. * * @category VuFind * @package Console @@ -42,7 +40,7 @@ use VuFindTheme\LessCompiler; * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development Wiki */ -class CssBuilderCommand extends Command +class CssBuilderCommand extends AbstractCssBuilderCommand { /** * The name of the command (the part after "public/index.php") @@ -52,41 +50,11 @@ class CssBuilderCommand extends Command protected static $defaultName = 'util/cssBuilder'; /** - * Cache directory for compiler + * Name of precompiler format * * @var string */ - protected $cacheDir; - - /** - * Constructor - * - * @param string $cacheDir Cache directory for compiler - * @param string|null $name The name of the command; passing null means it - * must be set in configure() - */ - public function __construct($cacheDir, $name = null) - { - $this->cacheDir = $cacheDir; - parent::__construct($name); - } - - /** - * Configure the command. - * - * @return void - */ - protected function configure() - { - $this - ->setDescription('LESS compiler') - ->setHelp('Compiles CSS files from LESS.') - ->addArgument( - 'themes', - InputArgument::IS_ARRAY | InputArgument::OPTIONAL, - 'Name of theme(s) to compile; omit to compile everything' - ); - } + protected $format = 'LESS'; /** * Build the LESS compiler. @@ -99,20 +67,4 @@ class CssBuilderCommand extends Command { return new LessCompiler($output); } - - /** - * Run the command. - * - * @param InputInterface $input Input object - * @param OutputInterface $output Output object - * - * @return int 0 for success - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $compiler = $this->getCompiler($output); - $compiler->setTempPath($this->cacheDir); - $compiler->compile(array_unique($input->getArgument('themes'))); - return 0; - } } diff --git a/module/VuFindConsole/src/VuFindConsole/Command/Util/ScssBuilderCommand.php b/module/VuFindConsole/src/VuFindConsole/Command/Util/ScssBuilderCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..708ab5ec58022dfe68960019af9e574925e90bfc --- /dev/null +++ b/module/VuFindConsole/src/VuFindConsole/Command/Util/ScssBuilderCommand.php @@ -0,0 +1,70 @@ +<?php +/** + * Console command: build CSS from SCSS. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2020. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Console + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFindConsole\Command\Util; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Output\OutputInterface; +use VuFindTheme\ScssCompiler; + +/** + * Console command: build CSS from SCSS. + * + * @category VuFind + * @package Console + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ScssBuilderCommand extends AbstractCssBuilderCommand +{ + /** + * The name of the command (the part after "public/index.php") + * + * @var string + */ + protected static $defaultName = 'util/scssBuilder'; + + /** + * Name of precompiler format + * + * @var string + */ + protected $format = 'SCSS'; + + /** + * Build the LESS compiler. + * + * @param OutputInterface $output Output object + * + * @return ScssCompiler + */ + protected function getCompiler(OutputInterface $output) + { + return new ScssCompiler($output); + } +} diff --git a/module/VuFindConsole/src/VuFindConsole/Command/Util/ScssBuilderCommandFactory.php b/module/VuFindConsole/src/VuFindConsole/Command/Util/ScssBuilderCommandFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..238f4024b0dc0a5181dfa74586c4a406431bc4ee --- /dev/null +++ b/module/VuFindConsole/src/VuFindConsole/Command/Util/ScssBuilderCommandFactory.php @@ -0,0 +1,65 @@ +<?php +/** + * Factory for Util/ScssBuilder command. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2020. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Console + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFindConsole\Command\Util; + +use Interop\Container\ContainerInterface; +use Laminas\ServiceManager\Factory\FactoryInterface; + +/** + * Factory for Util/ScssBuilder command. + * + * @category VuFind + * @package Console + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ScssBuilderCommandFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + $cacheManager = $container->get(\VuFind\Cache\Manager::class); + $cacheDir = $cacheManager->getCacheDir() . 'scss/'; + return new $requestedName($cacheDir, ...($options ?? [])); + } +} diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/ScssBuilderCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/ScssBuilderCommandTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8e2626ec5e7da8336c2f417fb4daf3bb8fee0bbb --- /dev/null +++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/ScssBuilderCommandTest.php @@ -0,0 +1,69 @@ +<?php +/** + * ScssBuilderCommand test. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2020. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:testing:unit_tests Wiki + */ +namespace VuFindTest\Command\Util; + +use Symfony\Component\Console\Tester\CommandTester; +use VuFindConsole\Command\Util\ScssBuilderCommand; + +/** + * ScssBuilderCommand test. + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:testing:unit_tests Wiki + */ +class ScssBuilderCommandTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test that the command delegates proper behavior. + * + * @return void + */ + public function testBasicOperation() + { + $cacheDir = '/foo'; + $compiler = $this->getMockBuilder(\VuFindTheme\ScssCompiler::class) + ->disableOriginalConstructor()->getMock(); + $compiler->expects($this->once())->method('setTempPath') + ->with($this->equalTo($cacheDir)); + $compiler->expects($this->once())->method('compile') + ->with($this->equalTo(['foo', 'bar'])); + $command = $this->getMockBuilder(ScssBuilderCommand::class) + ->setMethods(['getCompiler']) + ->setConstructorArgs([$cacheDir]) + ->getMock(); + $command->expects($this->once())->method('getCompiler') + ->will($this->returnValue($compiler)); + $commandTester = new CommandTester($command); + $commandTester->execute(['themes' => ['foo', 'bar', 'foo']]); + $this->assertEquals('', $commandTester->getDisplay()); + $this->assertEquals(0, $commandTester->getStatusCode()); + } +} diff --git a/module/VuFindTheme/src/VuFindTheme/AbstractCssPreCompiler.php b/module/VuFindTheme/src/VuFindTheme/AbstractCssPreCompiler.php new file mode 100644 index 0000000000000000000000000000000000000000..9135eed68157a1b34d01b83c97f8042ce994d0b5 --- /dev/null +++ b/module/VuFindTheme/src/VuFindTheme/AbstractCssPreCompiler.php @@ -0,0 +1,220 @@ +<?php +/** + * Abstract base class to precompile CSS within a theme. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2020. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Theme + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +namespace VuFindTheme; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Abstract base class to precompile CSS within a theme. + * + * @category VuFind + * @package Theme + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +abstract class AbstractCssPreCompiler +{ + /** + * Key in theme.config.php that lists all files + * + * @var string + */ + protected $themeConfigKey; + + /** + * Base path of VuFind. + * + * @var string + */ + protected $basePath; + + /** + * Temporary directory for cached files. + * + * @var string + */ + protected $tempPath; + + /** + * Fake base path used for generating absolute paths in CSS. + * + * @var string + */ + protected $fakePath = '/zzzz_basepath_zzzz/'; + + /** + * Output object (set for logging) + * + * @var OutputInterface + */ + protected $output; + + /** + * Constructor + * + * @param OutputInterface $output Output interface for logging (optional) + */ + public function __construct(OutputInterface $output = null) + { + $this->basePath = realpath(__DIR__ . '/../../../../'); + $this->tempPath = sys_get_temp_dir(); + $this->output = $output; + } + + /** + * Compile scripts for the specified theme. + * + * @param string $theme Theme name + * + * @return void + */ + abstract protected function processTheme($theme); + + /** + * Set base path + * + * @param string $path Path to set + * + * @return void + */ + public function setBasePath($path) + { + $this->basePath = $path; + } + + /** + * Set temporary directory + * + * @param string $path Path to set + * + * @return void + */ + public function setTempPath($path) + { + $this->tempPath = rtrim($path, '/'); + } + + /** + * Compile the scripts. + * + * @param array $themes Array of themes to process (empty for ALL themes). + * + * @return void + */ + public function compile(array $themes) + { + if (empty($themes)) { + $themes = $this->getAllThemes(); + } + + foreach ($themes as $theme) { + $this->processTheme($theme); + } + } + + /** + * Get all less files that might exist in a theme. + * + * @param string $theme Theme to retrieve files from + * + * @return array + */ + protected function getAllFiles($theme) + { + $config = $this->basePath . '/themes/' . $theme . '/theme.config.php'; + if (!file_exists($config)) { + return []; + } + $configArr = include $config; + $base = (isset($configArr['extends'])) + ? $this->getAllFiles($configArr['extends']) + : []; + $current = $configArr[$this->themeConfigKey] ?? []; + return array_merge($base, $current); + } + + /** + * Get a list of all available themes. + * + * @return array + */ + protected function getAllThemes() + { + $baseDir = $this->basePath . '/themes/'; + $dir = opendir($baseDir); + $list = []; + while ($line = readdir($dir)) { + if (is_dir($baseDir . $line) + && file_exists($baseDir . $line . '/theme.config.php') + ) { + $list[] = $line; + } + } + closedir($dir); + return $list; + } + + /** + * Convert fake absolute paths to working relative paths. + * + * @param string $css Generated CSS + * @param string $less Relative LESS filename + * + * @return string + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + protected function makeRelative($css, $less) + { + // Figure out how deep the LESS file is nested -- this will + // affect our relative path. Note: we don't actually need + // to use $matches for anything, but some versions of PHP + // seem to be unhappy if we omit the parameter. + $depth = preg_match_all('|/|', $less, $matches); + $relPath = '../../../'; + for ($i = 0; $i < $depth; $i++) { + $relPath .= '/../'; + } + return str_replace($this->fakePath, $relPath, $css); + } + + /** + * Log a message to the console + * + * @param string $str message string + * + * @return void + */ + protected function logMessage($str) + { + if ($this->output) { + $this->output->writeln($str); + } + } +} diff --git a/module/VuFindTheme/src/VuFindTheme/LessCompiler.php b/module/VuFindTheme/src/VuFindTheme/LessCompiler.php index d6bccff42af748de6326ed029c058d8d0ef5b1f0..80236ef7e8ba4467d4059acfca187a476ed418e7 100644 --- a/module/VuFindTheme/src/VuFindTheme/LessCompiler.php +++ b/module/VuFindTheme/src/VuFindTheme/LessCompiler.php @@ -27,8 +27,6 @@ */ namespace VuFindTheme; -use Symfony\Component\Console\Output\OutputInterface; - /** * Class to compile LESS into CSS within a theme. * @@ -38,89 +36,14 @@ use Symfony\Component\Console\Output\OutputInterface; * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org Main Site */ -class LessCompiler +class LessCompiler extends AbstractCssPreCompiler { /** - * Base path of VuFind. - * - * @var string - */ - protected $basePath; - - /** - * Temporary directory for cached files. - * - * @var string - */ - protected $tempPath; - - /** - * Fake base path used for generating absolute paths in CSS. + * Key in theme.config.php that lists all files * * @var string */ - protected $fakePath = '/zzzz_basepath_zzzz/'; - - /** - * Output object (set for logging) - * - * @var OutputInterface - */ - protected $output; - - /** - * Constructor - * - * @param OutputInterface $output Output interface for logging (optional) - */ - public function __construct(OutputInterface $output = null) - { - $this->basePath = realpath(__DIR__ . '/../../../../'); - $this->tempPath = sys_get_temp_dir(); - $this->output = $output; - } - - /** - * Set base path - * - * @param string $path Path to set - * - * @return void - */ - public function setBasePath($path) - { - $this->basePath = $path; - } - - /** - * Set temporary directory - * - * @param string $path Path to set - * - * @return void - */ - public function setTempPath($path) - { - $this->tempPath = rtrim($path, '/'); - } - - /** - * Compile the scripts. - * - * @param array $themes Array of themes to process (empty for ALL themes). - * - * @return void - */ - public function compile(array $themes) - { - if (empty($themes)) { - $themes = $this->getAllThemes(); - } - - foreach ($themes as $theme) { - $this->processTheme($theme); - } - } + protected $themeConfigKey = 'less'; /** * Compile scripts for the specified theme. @@ -131,7 +54,7 @@ class LessCompiler */ protected function processTheme($theme) { - $lessFiles = $this->getAllLessFiles($theme); + $lessFiles = $this->getAllFiles($theme); if (empty($lessFiles)) { $this->logMessage("No LESS in " . $theme); return; @@ -144,27 +67,6 @@ class LessCompiler } } - /** - * Get all less files that might exist in a theme. - * - * @param string $theme Theme to retrieve files from - * - * @return array - */ - protected function getAllLessFiles($theme) - { - $config = $this->basePath . '/themes/' . $theme . '/theme.config.php'; - if (!file_exists($config)) { - return []; - } - $configArr = include $config; - $base = (isset($configArr['extends'])) - ? $this->getAllLessFiles($configArr['extends']) - : []; - $current = $configArr['less'] ?? []; - return array_merge($base, $current); - } - /** * Compile a LESS file inside a theme. * @@ -215,63 +117,4 @@ class LessCompiler $this->logMessage("\t\t" . (microtime(true) - $start) . ' sec'); } - - /** - * Convert fake absolute paths to working relative paths. - * - * @param string $css Generated CSS - * @param string $less Relative LESS filename - * - * @return string - * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - */ - protected function makeRelative($css, $less) - { - // Figure out how deep the LESS file is nested -- this will - // affect our relative path. Note: we don't actually need - // to use $matches for anything, but some versions of PHP - // seem to be unhappy if we omit the parameter. - $depth = preg_match_all('|/|', $less, $matches); - $relPath = '../../../'; - for ($i = 0; $i < $depth; $i++) { - $relPath .= '/../'; - } - return str_replace($this->fakePath, $relPath, $css); - } - - /** - * Get a list of all available themes. - * - * @return array - */ - protected function getAllThemes() - { - $baseDir = $this->basePath . '/themes/'; - $dir = opendir($baseDir); - $list = []; - while ($line = readdir($dir)) { - if (is_dir($baseDir . $line) - && file_exists($baseDir . $line . '/theme.config.php') - ) { - $list[] = $line; - } - } - closedir($dir); - return $list; - } - - /** - * Log a message to the console - * - * @param string $str message string - * - * @return void - */ - protected function logMessage($str) - { - if ($this->output) { - $this->output->writeln($str); - } - } } diff --git a/module/VuFindTheme/src/VuFindTheme/ScssCompiler.php b/module/VuFindTheme/src/VuFindTheme/ScssCompiler.php new file mode 100644 index 0000000000000000000000000000000000000000..6cd99963ddb0bb34e82ff547ce42a83c2f879bc7 --- /dev/null +++ b/module/VuFindTheme/src/VuFindTheme/ScssCompiler.php @@ -0,0 +1,108 @@ +<?php +/** + * Class to compile SCSS into CSS within a theme. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2014. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Theme + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +namespace VuFindTheme; + +/** + * Class to compile SCSS into CSS within a theme. + * + * @category VuFind + * @package Theme + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +class ScssCompiler extends AbstractCssPreCompiler +{ + /** + * Key in theme.config.php that lists all files + * + * @var string + */ + protected $themeConfigKey = 'scss'; + + /** + * Compile scripts for the specified theme. + * + * @param string $theme Theme name + * + * @return void + */ + protected function processTheme($theme) + { + // Get files + $files = $this->getAllFiles($theme); + if (empty($files)) { + $this->logMessage("No SCSS in " . $theme); + return; + } + + // Build parent stack + $themeInfo = new ThemeInfo($this->basePath . '/themes', $theme); + $importPaths = []; + foreach (array_keys($themeInfo->getThemeInfo()) as $currTheme) { + $importPaths[] = $this->basePath . '/themes/' . $currTheme . '/scss/'; + } + + // Compile + $scss = new \ScssPhp\ScssPhp\Compiler(); + $scss->setImportPaths($importPaths); + $this->logMessage('Processing ' . $theme); + $finalOutDir = $this->basePath . '/themes/' . $theme . '/css/'; + foreach ($files as $key => $file) { + if ($key === 'active') { + continue; + } + + $this->logMessage("\t" . $file); + + // Check importPaths for file + $exists = false; + foreach ($importPaths as $path) { + if (file_exists($path . $file)) { + $exists = true; + break; + } + } + if (!$exists) { + $this->logMessage("\t\tnot found; skipping."); + continue; + } + + $start = microtime(true); + $finalFile = $finalOutDir . str_replace('.scss', '.css', $file) . '.css'; + if (!is_dir(dirname($finalFile))) { + mkdir(dirname($finalFile)); + } + file_put_contents( + $finalOutDir . str_replace('.scss', '.css', $file), + $scss->compile('@import "' . $file . '";') + ); + $this->logMessage("\t\t" . (microtime(true) - $start) . ' sec'); + } + } +} diff --git a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/LessCompilerTest.php b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/CssPreCompilerTest.php similarity index 63% rename from module/VuFindTheme/tests/unit-tests/src/VuFindTest/LessCompilerTest.php rename to module/VuFindTheme/tests/unit-tests/src/VuFindTest/CssPreCompilerTest.php index 469e5ddffd0d85ca782ae42ba15881bc1b6804a5..f1e3d24f278fe8f528a1ce634f692e3a925add81 100644 --- a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/LessCompilerTest.php +++ b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/CssPreCompilerTest.php @@ -1,6 +1,6 @@ <?php /** - * LessCompiler Test Class + * CssPreCompilerTest Test Class * * PHP version 7 * @@ -28,9 +28,10 @@ namespace VuFindTest; use VuFindTheme\LessCompiler; +use VuFindTheme\ScssCompiler; /** - * LessCompiler Test Class + * CssPreCompilerTest Test Class * * @category VuFind * @package Tests @@ -38,7 +39,7 @@ use VuFindTheme\LessCompiler; * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development:testing:unit_tests Wiki */ -class LessCompilerTest extends Unit\TestCase +class CssPreCompilerTest extends Unit\TestCase { /** * Our brave test subject @@ -50,110 +51,119 @@ class LessCompilerTest extends Unit\TestCase /** * Our brave test subject * - * @var LessCompiler + * @var $extCompiler */ protected $compiler; /** - * Initial class setup. + * Data Provider for extensions and classes * * @return void */ - public static function setUpBeforeClass(): void + public static function extClassProvider() + { + return [ + ['less', LessCompiler::class], + ['scss', ScssCompiler::class] + ]; + } + + /** + * Create fixture files in temp folder + * + * @return void + */ + protected function makeFakeThemeStructure($ext) { $temp = sys_get_temp_dir(); - $testDest = $temp . '/vufind_less_comp_test/'; + $testDest = $temp . "/vufind_${ext}_comp_test/"; // Create directory structure, recursively - mkdir($testDest . 'themes/child/less', 0777, true); + mkdir($testDest . "themes/child/$ext", 0777, true); mkdir($testDest . 'themes/empty', 0777, true); mkdir($testDest . 'themes/parent/css', 0777, true); - mkdir($testDest . 'themes/parent/less/relative', 0777, true); + mkdir($testDest . "themes/parent/$ext/relative", 0777, true); file_put_contents( $testDest . 'themes/empty/theme.config.php', '<?php return array("extends"=>false);' ); file_put_contents( $testDest . 'themes/parent/theme.config.php', - '<?php return array("extends"=>false, "less"=>array("compiled.less", "relative/relative.less"));' + "<?php return array(\"extends\"=>false, \"$ext\"=>array(\"compiled.$ext\", \"relative/relative.$ext\"));" ); file_put_contents( $testDest . 'themes/child/theme.config.php', - '<?php return array("extends"=>"parent", "less"=>array("compiled.less", "missing.less"));' + "<?php return array(\"extends\"=>\"parent\", \"$ext\"=>array(\"compiled.$ext\", \"missing.$ext\"));" ); file_put_contents( - $testDest . 'themes/parent/less/compiled.less', + $testDest . "themes/parent/$ext/compiled.$ext", '@import "parent";' ); file_put_contents( - $testDest . 'themes/parent/less/parent.less', + $testDest . "themes/parent/$ext/parent.$ext", 'body { background:url("../fake.png");color:#00D; a { color:#F00; } }' ); file_put_contents( - $testDest . 'themes/parent/less/relative/relative.less', + $testDest . "themes/parent/$ext/relative/relative.$ext", 'div {background:#EEE}' ); file_put_contents( - $testDest . 'themes/child/less/compiled.less', - '@import "parent"; @black: #000; div {border:1px solid @black;}' + $testDest . "themes/child/$ext/compiled.$ext", + $ext == 'less' + ? '@import "parent"; @black: #000; div {border:1px solid @black;}' + : '@import "parent"; $black: #000; div {border:1px solid $black;}' ); } /** - * Individual test setup. + * Initial class setup. * * @return void */ - public function setUp(): void + public static function setUpBeforeClass(): void { - $temp = sys_get_temp_dir(); - $perms = fileperms($temp); - $this->testDest = $temp . '/vufind_less_comp_test/'; - if (!($perms & 0x0002)) { - $this->markTestSkipped('No write permissions in system temporary file'); + foreach (self::extClassProvider() as [$ext, $class]) { + self::makeFakeThemeStructure($ext); } - $this->compiler = new LessCompiler(); - $this->compiler->setBasePath($temp . '/vufind_less_comp_test'); - $this->compiler->setTempPath($temp . '/vufind_less_comp_test/cache'); } /** - * Final teardown method. + * Individual test setup. * * @return void */ - public static function tearDownAfterClass(): void + public function setUp(): void { $temp = sys_get_temp_dir(); - $testDest = $temp . '/vufind_less_comp_test/'; - // Delete directory structure - self::delTree($testDest); + $perms = fileperms($temp); + if (!($perms & 0x0002)) { + $this->markTestSkipped('No write permissions in system temporary file'); + } } /** - * Delete a directory tree; adapted from - * http://php.net/manual/en/function.rmdir.php - * - * @param string $dir Directory to delete. + * Assign appropriate values to $this->testDest and $this->compiler * * @return void */ - protected static function delTree($dir) + protected function setupCompiler($ext, $class) { - $files = array_diff(scandir($dir), ['.', '..']); - foreach ($files as $file) { - is_dir("$dir/$file") - ? self::delTree("$dir/$file") : unlink("$dir/$file"); - } - rmdir($dir); + $temp = sys_get_temp_dir(); + $this->testDest = "$temp/vufind_${ext}_comp_test/"; + $this->compiler = new $class(); + $this->compiler->setBasePath("$temp/vufind_${ext}_comp_test"); + $this->compiler->setTempPath("$temp/vufind_${ext}_comp_test/cache"); } /** * Test compiling a single theme. * + * @dataProvider extClassProvider + * * @return void */ - public function testThemeCompile() + public function testThemeCompile($ext, $class) { + $this->setupCompiler($ext, $class); $this->compiler->compile(['child']); $this->assertTrue(file_exists($this->testDest . 'themes/child/css/compiled.css')); $this->assertFalse(file_exists($this->testDest . 'themes/parent/css/compiled.css')); @@ -161,12 +171,15 @@ class LessCompilerTest extends Unit\TestCase } /** - * Test compiling all themes. + * Test compiling all themes (default). + * + * @dataProvider extClassProvider * * @return void */ - public function testAllCompile() + public function testAllCompile($ext, $class) { + $this->setupCompiler($ext, $class); $this->compiler->compile([]); $this->assertTrue(file_exists($this->testDest . 'themes/child/css/compiled.css')); $this->assertTrue(file_exists($this->testDest . 'themes/parent/css/compiled.css')); @@ -175,4 +188,36 @@ class LessCompilerTest extends Unit\TestCase unlink($this->testDest . 'themes/parent/css/compiled.css'); unlink($this->testDest . 'themes/parent/css/relative/relative.css'); } + + /** + * Delete a directory tree; adapted from + * http://php.net/manual/en/function.rmdir.php + * + * @param string $dir Directory to delete. + * + * @return void + */ + protected static function delTree($dir) + { + $files = array_diff(scandir($dir), ['.', '..']); + foreach ($files as $file) { + is_dir("$dir/$file") + ? self::delTree("$dir/$file") + : unlink("$dir/$file"); + } + rmdir($dir); + } + + /** + * Final teardown method. + * + * @return void + */ + public static function tearDownAfterClass(): void + { + $temp = sys_get_temp_dir(); + // Delete directory structure + self::delTree("$temp/vufind_less_comp_test/"); + self::delTree("$temp/vufind_scss_comp_test/"); + } }