GreenCape/joomla-cli

View on GitHub
src/Command/Extension/InstallCommand.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * GreenCape Joomla Command Line Interface
 *
 * MIT License
 *
 * Copyright (c) 2012-2019, Niels Braczek <nbraczek@bsds.de>. All rights reserved.
 *
 * 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 the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS 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.
 *
 * @package         GreenCape\JoomlaCLI
 * @subpackage      Command
 * @author          Niels Braczek <nbraczek@bsds.de>
 * @copyright   (C) 2012-2019 GreenCape, Niels Braczek <nbraczek@bsds.de>
 * @license         http://opensource.org/licenses/MIT The MIT license (MIT)
 * @link            http://greencape.github.io
 * @since           File available since Release 0.1.0
 */

namespace GreenCape\JoomlaCLI\Command\Extension;

use Exception;
use GreenCape\JoomlaCLI\Command;
use JInstaller;
use JInstallerHelper;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * The Install command allows the installation of Joomla! extensions from the command line.
 *
 * @package     GreenCape\JoomlaCLI
 * @subpackage  Command
 * @since       Class available since Release 0.1.0
 */
class InstallCommand extends Command
{
    /**
     * Configure the options for the install command
     *
     * @return  void
     */
    protected function configure(): void
    {
        $this
            ->setName('extension:install')
            ->setDescription('Installs a Joomla! extension')
            ->addArgument(
                'extension',
                InputArgument::REQUIRED,
                'The path to the extension.'
            )
        ;
    }

    /**
     * Execute the install command
     *
     * @param  InputInterface   $input   An InputInterface instance
     * @param  OutputInterface  $output  An OutputInterface instance
     *
     * @return  integer  0 if everything went fine, 1 on error
     * @throws Exception
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->setupEnvironment('administrator', $input, $output);

        // Enable debug, so that JInstaller::install() throws exceptions on problems
        $this->joomla->setCfg('debug', 1);

        $installer = JInstaller::getInstance();

        if (!$installer->install($this->handleExtension($input, $output))) {
            $output->writeln($this->getExtensionInfo($installer));

            return 0;
        }

        $output->writeln('Installation failed due to unknown reason.');

        return 1;
    }

    /**
     * Handle the specified extension
     * An extension can be provided as a download, a directory, or an archive.
     * This method prepares the installation by providing the extension in a
     * temporary directory ready for install.
     *
     * @param  InputInterface   $input   An InputInterface instance
     * @param  OutputInterface  $output  An OutputInterface instance
     *
     * @return  string  The location of the prepared extension
     */
    protected function handleExtension(InputInterface $input, OutputInterface $output): string
    {
        $source = $input->getArgument('extension');

        if (strpos($source, '://')) {
            $tmpPath = $this->handleDownload($output, $source);
        } elseif (is_dir($source)) {
            $tmpPath = $this->handleDirectory($output, $source);
        } else {
            $tmpPath = $this->handleArchive($output, $source);
        }

        return $tmpPath;
    }

    /**
     * Get information about the installed extension
     *
     * @param  JInstaller  $installer
     *
     * @return  array  A message array suitable for OutputInterface::write[ln]
     */
    private function getExtensionInfo($installer): array
    {
        $manifest = $installer->getManifest();
        $data     = $this->joomla->getExtensionInfo($manifest);

        return [
            'Installed ' . $data['type'] . ' <info>' . $data['name'] . '</info> version <info>' . $data['version'] . '</info>',
            '',
            wordwrap($data['description'], 60),
            '',
        ];
    }

    /**
     * Prepare the installation for an extension specified by a URL
     *
     * @param  OutputInterface  $output  An OutputInterface instance
     * @param  string           $source  The extension source
     *
     * @return  string  The location of the prepared extension
     */
    private function handleDownload(OutputInterface $output, $source): string
    {
        $output->writeln("Downloading $source", OutputInterface::VERBOSITY_VERBOSE);

        return $this->unpack(JInstallerHelper::downloadPackage($source));
    }

    /**
     * Prepare the installation for an extension specified by a directory
     *
     * @param  OutputInterface  $output  An OutputInterface instance
     * @param  string           $source  The extension source
     *
     * @return  string  The location of the prepared extension
     */
    private function handleDirectory(OutputInterface $output, $source): string
    {
        $tmpDir  = $this->joomla->getCfg('tmp_path');
        $tmpPath = $tmpDir . '/' . uniqid('install_', true);
        $output->writeln("Copying $source", OutputInterface::VERBOSITY_VERBOSE);

        if (!mkdir($tmpPath) && !is_dir($tmpPath)) {
            throw new RuntimeException(sprintf('Directory "%s" was not created', $tmpPath));
        }
        copy($source, $tmpPath);

        return $tmpPath;
    }

    /**
     * Prepare the installation for an extension in an archive
     *
     * @param  OutputInterface  $output  An OutputInterface instance
     * @param  string           $source  The extension source
     *
     * @return  string  The location of the prepared extension
     */
    private function handleArchive(OutputInterface $output, $source): string
    {
        $tmpDir  = $this->joomla->getCfg('tmp_path');
        $tmpPath = $tmpDir . '/' . basename($source);
        $output->writeln("Extracting $source", OutputInterface::VERBOSITY_VERBOSE);

        copy($source, $tmpPath);

        return $this->unpack($tmpPath);
    }

    /**
     * Unpack an extension archive
     *
     * @param  string  $tmpPath  The location of the archive
     *
     * @return  string  The location of the unpacked extension
     */
    private function unpack($tmpPath): string
    {
        $result  = JInstallerHelper::unpack($tmpPath);
        $tmpPath = $result['extractdir'];

        return $tmpPath;
    }
}