Skip to content
Snippets Groups Projects
Handler.php 8.42 KiB
Newer Older
  • Learn to ignore specific revisions
  • jurgenhaas's avatar
    jurgenhaas committed
    <?php
    
    /**
     * @file
     * Contains \LakeDrops\Docker4Drupal\Handler.
     */
    
    namespace LakeDrops\Docker4Drupal;
    
    use Composer\Package\PackageInterface;
    use Composer\Composer;
    use Composer\IO\IOInterface;
    use Composer\Script\Event as ScriptEvent;
    use Symfony\Component\Filesystem\Filesystem;
    
    jurgenhaas's avatar
    jurgenhaas committed
    
    class Handler {
    
      /**
       * @var \Composer\Composer
       */
      protected $composer;
    
      /**
       * @var \Composer\IO\IOInterface
       */
      protected $io;
    
      /**
       * @var PackageInterface
       */
      protected $drupalCorePackage;
    
      /**
       * Handler constructor.
       *
       * @param Composer $composer
       * @param IOInterface $io
       */
      public function __construct(Composer $composer, IOInterface $io) {
        $this->composer = $composer;
        $this->io = $io;
      }
    
      /**
       * Look up the Drupal core package object, or return it from where we cached
       * it in the $drupalCorePackage field.
       *
       * @return PackageInterface
       */
      protected function getDrupalCorePackage() {
        if (!isset($this->drupalCorePackage)) {
          $this->drupalCorePackage = $this->getPackage('drupal/core');
        }
        return $this->drupalCorePackage;
      }
    
      /**
       * Retrieve a package from the current composer process.
       *
       * @param string $name
       *   Name of the package to get from the current composer installation.
       *
       * @return PackageInterface
       */
      protected function getPackage($name) {
        return $this->composer->getRepositoryManager()->getLocalRepository()->findPackage($name, '*');
      }
    
      /**
       * Configure Drupal Project for Docker.
       *
       * @param ScriptEvent $event
       */
    
      public function configureProject($event) {
    
    jurgenhaas's avatar
    jurgenhaas committed
    
        // We only do the fancy stuff for developers
        if (!$event->isDevMode()) {
          return;
        }
    
        $options = $this->getOptions();
        $fs = new Filesystem();
        $installationManager = $this->composer->getInstallationManager();
    
        $drupalCorePackage = $this->getDrupalCorePackage();
    
        if (!$drupalCorePackage) {
          // We are called too early, Drupal core is not available yet.
          return;
        }
    
    jurgenhaas's avatar
    jurgenhaas committed
        $corePath = $installationManager->getInstallPath($drupalCorePackage);
    
        // Directory where the root project is being created
        $projectRoot = getcwd();
        // Directory where Drupal's index.php is located
        $webRoot = dirname($corePath);
        // Directory where this plugin is being installed
        $pluginRoot = $installationManager->getInstallPath($this->getPackage('lakedrops/docker4drupal'));
    
    
        // If the d8-project-scaffold plugin is present we only execute this one
        // if $force is TRUE. This way we can make sure that we get executed after
        // d8-project-scaffold.
        $settingsPath = $webRoot . '/sites/default';
        if ($this->getPackage('lakedrops/d8-project-scaffold')) {
          if (!$fs->exists($projectRoot . '/settings/default')) {
            return;
          }
          $settingsPath = 'settings/default';
        }
    
    
    jurgenhaas's avatar
    jurgenhaas committed
        // Provide all the requiired files
    
    jurgenhaas's avatar
    jurgenhaas committed
        $twig_loader = new \Twig_Loader_Array([]);
        $twig = new \Twig_Environment($twig_loader);
    
    jurgenhaas's avatar
    jurgenhaas committed
        $options['webRoot'] = $webRoot . '/';
    
        foreach ($this->getFiles($projectRoot, $webRoot, $settingsPath) as $template => $def) {
    
    jurgenhaas's avatar
    jurgenhaas committed
          $file = $def['dest'] . '/' . $template;
          if (!$fs->exists($file)) {
            $twig_loader->setTemplate($template, file_get_contents($pluginRoot . '/templates/' . $template . '.twig'));
            $rendered = $twig->render($template, $options);
            file_put_contents($file, $rendered);
          }
    
          if (isset($def['link']) && ($def['link'] != $settingsPath)) {
    
    jurgenhaas's avatar
    jurgenhaas committed
            $link = $def['link'] . '/' . $template;
            if (!$fs->exists($link)) {
              $rel = substr($fs->makePathRelative($file, $projectRoot . '/' . $link), 3, -1);
              $fs->symlink($rel, $link);
            }
          }
          $fs->chmod($file, 0664);
        }
    
    
        // Make sure that settings.docker.php gets called from settings.php
    
        $settingsPhpFile = $settingsPath . '/settings.php';
        if ($fs->exists(($settingsPhpFile))) {
          $settingsPhp = file_get_contents($settingsPhpFile);
          if (strpos($settingsPhp, 'settings.docker.php') === FALSE) {
    
            $settingsPhp .= "\n\nif (file_exists(__DIR__ . '/settings.docker.php')) {\n  include __DIR__ . '/settings.docker.php';\n}\n";
    
            file_put_contents($settingsPhpFile, $settingsPhp);
          }
    
    jurgenhaas's avatar
    jurgenhaas committed
        // Initialize local git working copy
        try {
    
          foreach ($this->getFiles($projectRoot, $webRoot, $settingsPath) as $template => $def) {
            $this->git('ignore ' . $template);
          }
    
    jurgenhaas's avatar
    jurgenhaas committed
        }
        catch (\Exception $ex) {
          // We're ignoring this for now
        }
    
    
        // Update host wider traefik container
        $traefikPath = $_SERVER['HOME'] . '/.traefik';
        $traefikFile = $traefikPath . '/docker-compose.yml';
        if ($fs->exists($traefikFile)) {
          $traefik = Yaml::parse(file_get_contents($traefikFile));
        }
        else {
          $fs->mkdir($traefikPath);
          $traefik = [
            'version' => '2',
            'services' => [
              'traefik' => [
                'image' => 'traefik',
                'restart' => 'unless-stopped',
                'command' => '-c /dev/null --web --docker --logLevel=DEBUG',
                'networks' => [],
                'ports' => [
                  '8000:80',
                  '8080:8080',
                ],
                'volumes' => [
                  '/var/run/docker.sock:/var/run/docker.sock',
                ],
              ],
            ],
            'networks' => [],
          ];
        }
        if (!in_array($options['projectname'], $traefik['services']['traefik']['networks'])) {
          $traefik['services']['traefik']['networks'][] = $options['projectname'];
          $traefik['networks'][$options['projectname']] = [
            'external' => [
              'name' => $options['projectname'] . '_default',
            ],
          ];
    
          file_put_contents($traefikFile, Yaml::dump($traefik, 9, 2));
    
          exec('docker network create ' . $options['projectname'] . '_default');
          exec('docker-compose -f ' . $traefikFile . ' --project-name traefik stop');
          exec('docker-compose -f ' . $traefikFile . ' --project-name traefik up -d');
    
    jurgenhaas's avatar
    jurgenhaas committed
      }
    
    
      protected function getFiles($projectRoot, $webRoot, $settingsPath) {
    
    jurgenhaas's avatar
    jurgenhaas committed
        return [
          'settings.docker.php' => [
    
            'dest' => $projectRoot . '/' . $settingsPath,
    
    jurgenhaas's avatar
    jurgenhaas committed
            'link' => $webRoot . '/sites/default',
          ],
    
    jurgenhaas's avatar
    jurgenhaas committed
          'docker-compose.yml' => [
    
    jurgenhaas's avatar
    jurgenhaas committed
            'dest' => $projectRoot,
          ],
    
          'aliases.drushrc.php' => [
            'dest' => $projectRoot . '/drush',
          ],
          'drushrc.php' => [
            'dest' => $projectRoot . '/drush',
          ],
          '.env' => [
            'dest' => $projectRoot,
          ],
    
    jurgenhaas's avatar
    jurgenhaas committed
        ];
      }
    
      /**
       * Retrieve excludes from optional "extra" configuration.
       *
       * @return array
       */
      protected function getOptions() {
        $extra = $this->composer->getPackage()->getExtra() + ['docker4drupal' => []];
        $options = $extra['docker4drupal'] + [
    
            'projectname' => str_replace([' ', '-', '_', '.'], '', basename(getcwd())),
    
            'docker0' => [
              'ip' => $this->getLocalIpv4('docker0'),
            ],
    
            'drupal' => [
              'version' => '8',
            ],
            'php' => [
              'version' => '7.0',# 5.3|5.6|7.1
              'xdebug' => 1,
            ],
            'nginx' => [
              'version' => '1.10',
            ],
            'varnish' => [
              'enable' => 0,
            ],
            'solr' => [
              'enable' => 0,
            ],
            'node' => [
              'enable' => 0,
            ],
          ];
    
    jurgenhaas's avatar
    jurgenhaas committed
        return $options;
      }
    
      /**
       * Wrapper for git command in the root directory.
       *
       * @param $command
       *   Git command name, arguments and/or options.
       * @throws \Exception
       */
      protected function git($command) {
        passthru(escapeshellcmd('git -c "user.email=d8-project@lakedrops.com" ' . $command), $exit_code);
        if ($exit_code !== 0) {
          throw new \Exception('Git returned a non-zero exit code');
        }
      }
    
    
      private function getLocalIpv4($interface = NULL) {
        $out = explode(PHP_EOL, shell_exec('LC_ALL=C /sbin/ifconfig'));
        $local_addrs = array();
        $ifname = 'unknown';
        foreach ($out as $str) {
          $matches = array();
          if (preg_match('/^([a-z0-9]+)(:\d{1,2})?(\s)+Link/', $str, $matches)) {
            $ifname = $matches[1];
            if(strlen($matches[2])>0) {
              $ifname .= $matches[2];
            }
          } elseif (preg_match('/inet addr:((?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3})\s/', $str, $matches)) {
            $local_addrs[$ifname] = $matches[1];
          }
        }
    
        if (!isset($interface)) {
          return $local_addrs;
        }
        return isset($local_addrs[$interface]) ? $local_addrs[$interface] : '127.0.0.1';
      }
    
    
    jurgenhaas's avatar
    jurgenhaas committed
    }