TikiWiki/tiki-manager

View on GitHub
src/Manager/UpdateManager.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * @copyright (c) Copyright by authors of the Tiki Manager Project. All Rights Reserved.
 *     See copyright.txt for details and a complete list of authors.
 * @licence Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See LICENSE for details.
 */

namespace TikiManager\Manager;

use Exception;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\Process\Process;
use TikiManager\Config\Environment;
use TikiManager\Manager\Update\Exception\TrackingInformationNotFoundException;
use TikiManager\Manager\Update\Git;
use TikiManager\Manager\Update\Phar;
use TikiManager\Manager\Update\Src;
use Phar as PhpPhar;

abstract class UpdateManager
{
    use LoggerAwareTrait;

    protected $debug;
    protected $targetFolder;

    public const VERSION_FILENAME = '.version';
    public const VERSION_UPDATE_FILENAME = '.updateVersion';

    /**
     * VersionControlSystem constructor.
     * @param $targetFolder
     */
    public function __construct($targetFolder, LoggerInterface $logger = null)
    {
        $this->targetFolder = $targetFolder;
        $this->debug = filter_var(getenv('TRIM_DEBUG'), FILTER_VALIDATE_BOOLEAN);
        $this->logger = $logger ?? new NullLogger();
    }

    /**
     * Gets Tiki Manager updater
     * @param null $targetFolder
     * @return Git|Phar|Src
     */
    public static function getUpdater($targetFolder = null)
    {
        if (PhpPhar::running(false) ||
            (is_string($targetFolder) && substr($targetFolder, -4) == 'phar')) {
            return new Phar();
        }

        $basePath = $targetFolder ?? Environment::get('TRIM_ROOT', dirname(__FILE__, 3));
        $gitPath = $basePath . DIRECTORY_SEPARATOR . '.git';

        return is_dir($gitPath) ? new Git($basePath) : new Src($basePath);
    }

    protected function getApiBaseUrl()
    {
        $baseUrl = Environment::get('GITLAB_URL', 'https://gitlab.com');
        $projectId = Environment::get('GITLAB_PROJECT_ID', '9558938');

        return sprintf('%s/api/v4/projects/%s', $baseUrl, $projectId);
    }

    public function hasVersion()
    {
        return boolval($this->getCurrentVersion());
    }

    /**
     * @param $checkRemote
     * @return bool
     * @return TrackingInformationNotFoundException
     */
    public function hasUpdateAvailable($checkRemote)
    {
        $currentVersion = $this->getCurrentVersion();

        if (!$checkRemote) {
            $updateVersion = $this->getCacheVersionInfo();
        } else {
            $updateVersion = $this->getRemoteVersion();
            $this->setCacheVersionInfo($updateVersion);
        }

        if (empty($currentVersion) || empty($updateVersion)) {
            return false;
        }

        $versionDiff = $currentVersion['version'] !== $updateVersion['version'];
        $timeDiff = strtotime($currentVersion['date']) <= strtotime($updateVersion['date']);

        return $versionDiff && $timeDiff;
    }

    /**
     * Update tiki manager
     */
    abstract public function update();


    /**
     * return the local hash version
     * @return array|false versionStatus
     */
    abstract public function getCurrentVersion();


    /**
     * return the local hash version
     * @param null $branch
     * @return array|false versionStatus
     */
    public function getRemoteVersion($branch = null)
    {
        $client = HttpClient::create();
        $query = [
            'first_parent' => true,
            'per_page' => 1,
        ];
        if ($branch) {
            $query['ref_name'] = $branch;
        }
        $baseUrl = $this->getApiBaseUrl();
        $response = $client->request('GET', $baseUrl . '/repository/commits?', ['query' => $query]);
        if ($response->getStatusCode() == 200 && !empty($content = $response->toArray())) {
            return [
                'version' => $content[0]['short_id'],
                'date' => $content[0]['created_at']
            ];
        }
        return false;
    }

    /**
     * @return string
     */
    public function info()
    {
        $version = $this->getCurrentVersion();

        return sprintf(
            "%s detected\nVersion: %s\nDate: %s",
            $this->getType(),
            $version['version'],
            date(\DateTime::COOKIE, strtotime($version['date']))
        );
    }

    abstract public function getType();

    protected function runComposerInstall()
    {
        $composer = Environment::get('COMPOSER_PATH');
        $command = [$composer,
            'install',
            '-d',
            $this->targetFolder,
            '--no-interaction',
            '--prefer-source'
        ];

        if (!is_executable($composer)) {
            array_unshift($command, PHP_BINARY);
        }

        $process = new Process($command);
        $process->setTimeout(300);
        $process->run();

        if (!$process->isSuccessful()) {
            debug($process->getErrorOutput());
            throw new Exception('Unable to install composer dependencies. Please run composer install manually');
        }
    }

    public function getCacheVersionInfo()
    {
        $file = Environment::get('CACHE_FOLDER') . DIRECTORY_SEPARATOR . static::VERSION_UPDATE_FILENAME;

        return file_exists($file) ? json_decode(file_get_contents($file), true) : false;
    }

    public function setCacheVersionInfo($info)
    {
        $file = Environment::get('CACHE_FOLDER') . DIRECTORY_SEPARATOR . static::VERSION_UPDATE_FILENAME;
        file_put_contents($file, json_encode($info));
    }
}