From 30fce178f53df631938ee9597913c9c88df8e37b Mon Sep 17 00:00:00 2001
From: jurgenhaas <juergen@paragon-es.de>
Date: Thu, 20 Dec 2018 16:37:02 +0100
Subject: [PATCH] Make theme plugin compatible with latest LakeDrops tools

---
 ahoy.yml                 |  8 ++---
 composer.json            | 24 +------------
 src/BaseCommand.php      | 40 +++++++++++++++++++++
 src/CommandProvider.php  | 24 +++++++++++++
 src/Handler.php          | 55 ++++++++++++++--------------
 src/InitCommand.php      | 27 ++++++++++++++
 src/OverwriteCommand.php | 27 ++++++++++++++
 src/Plugin.php           | 77 ++++++++++------------------------------
 src/ResetCommand.php     | 27 ++++++++++++++
 src/UpdateCommand.php    | 27 ++++++++++++++
 10 files changed, 221 insertions(+), 115 deletions(-)
 create mode 100644 src/BaseCommand.php
 create mode 100644 src/CommandProvider.php
 create mode 100644 src/InitCommand.php
 create mode 100644 src/OverwriteCommand.php
 create mode 100644 src/ResetCommand.php
 create mode 100644 src/UpdateCommand.php

diff --git a/ahoy.yml b/ahoy.yml
index 9f0cb9b..090db36 100644
--- a/ahoy.yml
+++ b/ahoy.yml
@@ -1,14 +1,14 @@
 ahoyapi: v2
 commands:
   install:
-    cmd: composer lakedrops-theme-install "$@"
+    cmd: composer lakedrops:theme:init "$@"
     usage: Install custom theme
   update:
-    cmd: composer lakedrops-theme-update "$@"
+    cmd: composer lakedrops:theme:update "$@"
     usage: Update custom theme
   reset:
-    cmd: composer lakedrops-theme-reset "$@"
+    cmd: composer lakedrops:theme:reset "$@"
     usage: Reset custom theme
   overwrite:
-    cmd: composer lakedrops-theme-overwrite "$@"
+    cmd: composer lakedrops:theme:overwrite "$@"
     usage: Overwrite custom theme
diff --git a/composer.json b/composer.json
index 61cf3c6..41b0169 100644
--- a/composer.json
+++ b/composer.json
@@ -66,6 +66,7 @@
         "matthiasmullie/path-converter": "^1.0"
     },
     "require-dev": {
+        "roave/security-advisories": "dev-master",
         "composer/composer": "^1.5.0",
         "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
         "drupal/coder": "^8.2",
@@ -81,24 +82,6 @@
     "extra": {
         "class": "LakeDrops\\Drupal8Theme\\SASS\\Plugin",
         "lakedrops": {
-            "scripts": {
-                "lakedrops-theme-install": {
-                    "callback": "LakeDrops\\Drupal8Theme\\SASS\\Plugin::init",
-                    "description": "Initialize the LakeDrops based SASS theme."
-                },
-                "lakedrops-theme-update": {
-                    "callback": "LakeDrops\\Drupal8Theme\\SASS\\Plugin::update",
-                    "description": "Update the LakeDrops based SASS theme."
-                },
-                "lakedrops-theme-reset": {
-                    "callback": "LakeDrops\\Drupal8Theme\\SASS\\Plugin::reset",
-                    "description": "Reset the LakeDrops based SASS theme."
-                },
-                "lakedrops-theme-overwrite": {
-                    "callback": "LakeDrops\\Drupal8Theme\\SASS\\Plugin::overwrite",
-                    "description": "Update and overwrite the LakeDrops based SASS theme."
-                }
-            },
             "ahoy": {
                 "theme": {
                     "usage": "Drupal SASS Theme",
@@ -106,10 +89,5 @@
                 }
             }
         }
-    },
-    "scripts": {
-        "install-codestandards": ["Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run"],
-        "post-install-cmd": ["@install-codestandards"],
-        "post-update-cmd": ["@install-codestandards"]
     }
 }
diff --git a/src/BaseCommand.php b/src/BaseCommand.php
new file mode 100644
index 0000000..86e7412
--- /dev/null
+++ b/src/BaseCommand.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace LakeDrops\Drupal8Theme\SASS;
+
+use LakeDrops\Component\Composer\BaseCommand as ComposerBaseCommand;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+abstract class BaseCommand extends ComposerBaseCommand {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getHandlerClass() {
+    return Handler::class;
+  }
+
+  /**
+   * {@inheritdoc}
+   * @param bool $update
+   *   Whether to update (TRUE) or initially installing (FALSE).
+   * @param bool $reset
+   *   Whether to reset the theme.
+   * @param bool $overwrite
+   *   Whether to overwrite existing files.
+   *
+   * @throws \Exception
+   */
+  protected function _execute(InputInterface $input, OutputInterface $output, $update = FALSE, $reset = FALSE, $overwrite = FALSE) {
+    parent::execute($input, $output);
+    /** @var Handler $handler */
+    $handler = $this->handler;
+    $handler
+      ->setUpdate($update)
+      ->setReset($reset)
+      ->setOverwrite($overwrite)
+      ->updateTheme();
+  }
+
+}
diff --git a/src/CommandProvider.php b/src/CommandProvider.php
new file mode 100644
index 0000000..6a50bc6
--- /dev/null
+++ b/src/CommandProvider.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace LakeDrops\Drupal8Theme\SASS;
+
+use Composer\Plugin\Capability\CommandProvider as CommandProviderCapability;
+use Composer\Command\BaseCommand;
+
+class CommandProvider implements CommandProviderCapability {
+
+  /**
+   * Retrieves an array of commands
+   *
+   * @return BaseCommand[]
+   */
+  public function getCommands(): array {
+    return [
+      new InitCommand(),
+      new UpdateCommand(),
+      new ResetCommand(),
+      new OverwriteCommand(),
+    ];
+  }
+
+}
diff --git a/src/Handler.php b/src/Handler.php
index b77b3e0..218a4c7 100644
--- a/src/Handler.php
+++ b/src/Handler.php
@@ -2,10 +2,10 @@
 
 namespace LakeDrops\Drupal8Theme\SASS;
 
+use Composer\Installer\InstallationManager;
 use Composer\Package\Package;
 use Composer\Composer;
 use Composer\IO\IOInterface;
-use Composer\Script\Event;
 use LakeDrops\Component\Composer\BaseHandler;
 use LakeDrops\Component\Composer\Utils;
 use LakeDrops\Component\Dotenv\Dotenv;
@@ -82,7 +82,7 @@ class Handler extends BaseHandler {
    *
    * @return $this
    */
-  public function setUpdate($flag) {
+  public function setUpdate($flag): self {
     $this->update = $flag;
     return $this;
   }
@@ -95,7 +95,7 @@ class Handler extends BaseHandler {
    *
    * @return $this
    */
-  public function setReset($flag) {
+  public function setReset($flag): self {
     $this->reset = $flag;
     return $this;
   }
@@ -108,7 +108,7 @@ class Handler extends BaseHandler {
    *
    * @return $this
    */
-  public function setOverwrite($flag) {
+  public function setOverwrite($flag): self {
     $this->overwrite = $flag;
     return $this;
   }
@@ -119,7 +119,7 @@ class Handler extends BaseHandler {
    * @return \Composer\Installer\InstallationManager
    *   The installation manager.
    */
-  protected function getInstallationManager() {
+  protected function getInstallationManager(): InstallationManager {
     static $installationManager;
 
     if (!isset($installationManager)) {
@@ -137,7 +137,7 @@ class Handler extends BaseHandler {
    * @return string
    *   The installation path for the named package.
    */
-  protected function buildInstallationPath($name) {
+  protected function buildInstallationPath($name): string {
     $package = new Package($name, '1.0.0', '1.0.0');
     $package->setType('drupal-custom-theme');
     return $this->getInstallationManager()
@@ -150,7 +150,7 @@ class Handler extends BaseHandler {
    * @return string
    *   The installation path of this theme.
    */
-  protected function getInstallationPath() {
+  protected function getInstallationPath(): string {
     static $installationPath;
 
     if (!isset($installationPath)) {
@@ -165,7 +165,7 @@ class Handler extends BaseHandler {
    * @return array
    *   The settings from the extra configuration.
    */
-  protected function getOptions() {
+  protected function getOptions(): array {
     if (!isset($this->options)) {
       $extra = $this->composer->getPackage()
         ->getExtra() + ['theme-d8-sass' => []];
@@ -197,7 +197,7 @@ class Handler extends BaseHandler {
       $to = $this->buildInstallationPath($this->options['project_name']);
       foreach ($this->options['bower_assets'] as $key => $asset) {
         $package = $this->getPackage('bower-asset/' . $key);
-        $version = $package ? $package->getVersion() : (isset($asset['version']) ? $asset['version'] : 'latest');
+        $version = $package ? $package->getVersion() : ($asset['version'] ?? 'latest');
         if ($package) {
           // Installed globally as Composer package.
           $from = $this->getInstallationManager()->getInstallPath($package);
@@ -260,7 +260,7 @@ class Handler extends BaseHandler {
    * @return array
    *   The file list.
    */
-  protected function getCustomFiles() {
+  protected function getCustomFiles(): array {
     return [
       'config/install/{{ project_name }}.settings.yml',
       'config/schema/{{ project_name }}.schema.yml',
@@ -285,7 +285,7 @@ class Handler extends BaseHandler {
    * @return array
    *   The file list.
    */
-  protected function getIgnoredFiles() {
+  protected function getIgnoredFiles(): array {
     return array_merge((empty($this->getOption('bower_assets')['dependencies']) ? ['bower.json'] : []), [
       'templates/README.md',
       'README.md',
@@ -300,7 +300,7 @@ class Handler extends BaseHandler {
    * @return array
    *   The file list.
    */
-  protected function getBinaryFiles() {
+  protected function getBinaryFiles(): array {
     return [
       'favicon.ico',
       'screenshot.png',
@@ -316,14 +316,12 @@ class Handler extends BaseHandler {
    * @return string
    *   The tweaked string.
    */
-  protected function tweaks($string) {
+  protected function tweaks($string): string {
     $string = str_replace('THEMENAME', '{{ project_name }}', $string);
 
     $baseTheme = $this->getOption('base_theme');
-    if (isset($baseTheme['sasspath'])) {
-      if (strpos($string, $baseTheme['sasspath']) === 0) {
-        $string = 'sass' . substr($string, strlen($baseTheme['sasspath']));
-      }
+    if (isset($baseTheme['sasspath']) && strpos($string, $baseTheme['sasspath']) === 0) {
+      $string = 'sass' . substr($string, strlen($baseTheme['sasspath']));
     }
 
     return $string;
@@ -341,12 +339,13 @@ class Handler extends BaseHandler {
    * @throws \Twig_Error_Runtime
    * @throws \Twig_Error_Syntax
    */
-  protected function twig($string) {
+  protected function twig($string): string {
     if (empty($string)) {
       return '';
     }
 
     $this->twigLoader->setTemplate('fixed', $this->tweaks($string));
+    /** @noinspection PhpTemplateMissingInspection */
     return str_replace('&quot;', '"', $this->twig->render('fixed', $this->getOptions()));
   }
 
@@ -356,12 +355,12 @@ class Handler extends BaseHandler {
    * @param string $command
    *   NPM command name, arguments and/or options.
    *
-   * @throws \Exception
+   * @throws \RuntimeException
    */
   protected function npm($command) {
     passthru(escapeshellcmd('npm ' . $command), $exit_code);
     if ($exit_code !== 0) {
-      throw new \Exception('NPM returned a non-zero exit code');
+      throw new \RuntimeException('NPM returned a non-zero exit code');
     }
   }
 
@@ -371,12 +370,12 @@ class Handler extends BaseHandler {
    * @param string $command
    *   Bower command name, arguments and/or options.
    *
-   * @throws \Exception
+   * @throws \RuntimeException
    */
   protected function bower($command) {
     passthru(escapeshellcmd('bower --allow-root ' . $command), $exit_code);
     if ($exit_code !== 0) {
-      throw new \Exception('Bower returned a non-zero exit code');
+      throw new \RuntimeException('Bower returned a non-zero exit code');
     }
   }
 
@@ -386,12 +385,12 @@ class Handler extends BaseHandler {
    * @param string $command
    *   Gulp command name, arguments and/or options.
    *
-   * @throws \Exception
+   * @throws \RuntimeException
    */
   protected function gulp($command) {
     passthru(escapeshellcmd('node_modules/.bin/gulp ' . $command), $exit_code);
     if ($exit_code !== 0) {
-      throw new \Exception('Gulp returned a non-zero exit code');
+      throw new \RuntimeException('Gulp returned a non-zero exit code');
     }
   }
 
@@ -411,7 +410,7 @@ class Handler extends BaseHandler {
    * @throws \Twig_Error_Runtime
    * @throws \Twig_Error_Syntax
    */
-  protected function copyFiles(FileSystem $fs, $source, $destination) {
+  protected function copyFiles(FileSystem $fs, $source, $destination): array {
     $files = [];
 
     // Make sure all directories do exist.
@@ -468,11 +467,9 @@ class Handler extends BaseHandler {
   /**
    * Execute the theme creation or update.
    *
-   * @param \Composer\Script\Event $event
-   *   The event that triggered the plugin.
    * @throws \Exception
    */
-  public function updateTheme(Event $event) {
+  public function updateTheme() {
 
     $fs = new Filesystem();
     $destination = $this->getInstallationPath();
@@ -530,7 +527,7 @@ class Handler extends BaseHandler {
 
     // Run Gulp.
     $args = ['default'];
-    if (!$event->isDevMode()) {
+    if (!$this->isDevMode()) {
       $args[] = '--env production';
     }
     $this->gulp(implode(' ', $args));
diff --git a/src/InitCommand.php b/src/InitCommand.php
new file mode 100644
index 0000000..9a06f0c
--- /dev/null
+++ b/src/InitCommand.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8Theme\SASS;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class InitCommand extends BaseCommand {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function configure() {
+    $this->setName('lakedrops:theme:init');
+    $this->setDescription('Init custom theme.');
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @throws \Exception
+   */
+  protected function execute(InputInterface $input, OutputInterface $output) {
+    parent::_execute($input, $output);
+  }
+
+}
diff --git a/src/OverwriteCommand.php b/src/OverwriteCommand.php
new file mode 100644
index 0000000..4c86751
--- /dev/null
+++ b/src/OverwriteCommand.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8Theme\SASS;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class OverwriteCommand extends BaseCommand {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function configure() {
+    $this->setName('lakedrops:theme:overwrite');
+    $this->setDescription('Overwrite custom theme.');
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @throws \Exception
+   */
+  protected function execute(InputInterface $input, OutputInterface $output) {
+    parent::_execute($input, $output, FALSE, FALSE, TRUE);
+  }
+
+}
diff --git a/src/Plugin.php b/src/Plugin.php
index ba0fa97..ab5d05d 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -21,11 +21,20 @@ class Plugin extends BasePlugin {
   /**
    * {@inheritdoc}
    */
-  public static function getSubscribedEvents() {
-    return array(
+  public function getCapabilities(): array {
+    return [
+      \Composer\Plugin\Capability\CommandProvider::class => CommandProvider::class,
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents(): array {
+    return [
       ScriptEvents::POST_INSTALL_CMD => 'initThemeEvent',
       ScriptEvents::POST_UPDATE_CMD => 'updateThemeEvent',
-    );
+    ];
   }
 
   /**
@@ -33,6 +42,7 @@ class Plugin extends BasePlugin {
    *
    * @param \Composer\Script\Event $event
    *   The event that triggered the plugin.
+   * @throws \Exception
    */
   public function initThemeEvent(Event $event) {
     $this->updateThemeEvent($event, FALSE);
@@ -45,66 +55,15 @@ class Plugin extends BasePlugin {
    *   The event that triggered the plugin.
    * @param bool $update
    *   Whether to update (TRUE) or initially installing (FALSE).
-   */
-  public function updateThemeEvent(Event $event, $update = TRUE) {
-    $this->handler
-      ->setUpdate($update)
-      ->updateTheme($event);
-  }
-
-  /**
-   * Script callback for initializing the theme.
-   *
-   * @param \Composer\Script\Event $event
-   *   The event that triggered the plugin.
-   * @param bool $update
-   *   Whether to update (TRUE) or initially installing (FALSE).
-   * @param bool $reset
-   *   Whether to reset the theme.
-   * @param bool $overwrite
-   *   Whether to overwrite existing files.
    * @throws \Exception
    */
-  public static function init(Event $event, $update = FALSE, $reset = FALSE, $overwrite = FALSE) {
-    $handler = new Handler($event->getComposer(), $event->getIO());
+  public function updateThemeEvent(Event $event, $update = TRUE) {
+    /** @var Handler $handler */
+    $handler = $this->handler;
     $handler
+      ->setEvent($event)
       ->setUpdate($update)
-      ->setReset($reset)
-      ->setOverwrite($overwrite)
-      ->updateTheme($event);
-  }
-
-  /**
-   * Script callback for updating the theme.
-   *
-   * @param \Composer\Script\Event $event
-   *   The event that triggered the plugin.
-   * @throws \Exception
-   */
-  public static function update(Event $event) {
-    self::init($event, TRUE);
-  }
-
-  /**
-   * Script callback for resetting the theme.
-   *
-   * @param \Composer\Script\Event $event
-   *   The event that triggered the plugin.
-   * @throws \Exception
-   */
-  public static function reset(Event $event) {
-    self::init($event, FALSE, TRUE);
-  }
-
-  /**
-   * Script callback for updating the theme and overwriting existing files.
-   *
-   * @param \Composer\Script\Event $event
-   *   The event that triggered the plugin.
-   * @throws \Exception
-   */
-  public static function overwrite(Event $event) {
-    self::init($event, FALSE, FALSE, TRUE);
+      ->updateTheme();
   }
 
 }
diff --git a/src/ResetCommand.php b/src/ResetCommand.php
new file mode 100644
index 0000000..814fffd
--- /dev/null
+++ b/src/ResetCommand.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8Theme\SASS;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ResetCommand extends BaseCommand {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function configure() {
+    $this->setName('lakedrops:theme:reset');
+    $this->setDescription('Reset custom theme.');
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @throws \Exception
+   */
+  protected function execute(InputInterface $input, OutputInterface $output) {
+    parent::_execute($input, $output, FALSE, TRUE);
+  }
+
+}
diff --git a/src/UpdateCommand.php b/src/UpdateCommand.php
new file mode 100644
index 0000000..e61dd72
--- /dev/null
+++ b/src/UpdateCommand.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8Theme\SASS;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class UpdateCommand extends BaseCommand {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function configure() {
+    $this->setName('lakedrops:theme:update');
+    $this->setDescription('Update custom theme.');
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @throws \Exception
+   */
+  protected function execute(InputInterface $input, OutputInterface $output) {
+    parent::_execute($input, $output, TRUE);
+  }
+
+}
-- 
GitLab