upgraded dependencies

This commit is contained in:
RafficMohammed
2023-01-08 01:59:16 +05:30
parent 51056e3aad
commit f9ae387337
6895 changed files with 133617 additions and 178680 deletions

View File

@@ -3,7 +3,7 @@
/*
* This file is part of Psy Shell.
*
* (c) 2012-2018 Justin Hileman
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -13,19 +13,19 @@ namespace Psy\VersionUpdater;
interface Checker
{
const ALWAYS = 'always';
const DAILY = 'daily';
const WEEKLY = 'weekly';
const ALWAYS = 'always';
const DAILY = 'daily';
const WEEKLY = 'weekly';
const MONTHLY = 'monthly';
const NEVER = 'never';
const NEVER = 'never';
/**
* @return bool
*/
public function isLatest();
public function isLatest(): bool;
/**
* @return string
*/
public function getLatest();
public function getLatest(): string;
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\VersionUpdater;
use Psy\Exception\ErrorException;
interface Downloader
{
/**
* Set the directory where the download will be written to.
*
* @param string $tempDir
*/
public function setTempDir(string $tempDir);
/**
* @param string $url
*
* @return bool
*
* @throws ErrorException on failure
*/
public function download(string $url): bool;
/**
* Get the temporary file name the download was written to.
*
* @return string
*/
public function getFilename(): string;
/**
* Delete the downloaded file if it exists.
*
* @return void
*/
public function cleanup();
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\VersionUpdater\Downloader;
use Psy\Exception\ErrorException;
use Psy\Shell;
use Psy\VersionUpdater\Downloader;
class CurlDownloader implements Downloader
{
private $tempDir = null;
private $outputFile = null;
/** {@inheritDoc} */
public function setTempDir(string $tempDir)
{
$this->tempDir = $tempDir;
}
/** {@inheritDoc} */
public function download(string $url): bool
{
$tempDir = $this->tempDir ?: \sys_get_temp_dir();
$this->outputFile = \tempnam($tempDir, 'psysh-archive-');
$targetName = $this->outputFile.'.tar.gz';
if (!\rename($this->outputFile, $targetName)) {
return false;
}
$this->outputFile = $targetName;
$outputHandle = \fopen($this->outputFile, 'w');
if (!$outputHandle) {
return false;
}
$curl = \curl_init();
\curl_setopt_array($curl, [
\CURLOPT_FAILONERROR => true,
\CURLOPT_HEADER => 0,
\CURLOPT_FOLLOWLOCATION => true,
\CURLOPT_TIMEOUT => 10,
\CURLOPT_FILE => $outputHandle,
\CURLOPT_HTTPHEADER => [
'User-Agent' => 'PsySH/'.Shell::VERSION,
],
]);
\curl_setopt($curl, \CURLOPT_URL, $url);
$result = \curl_exec($curl);
$error = \curl_error($curl);
\curl_close($curl);
\fclose($outputHandle);
if (!$result) {
throw new ErrorException('cURL Error: '.$error);
}
return (bool) $result;
}
/** {@inheritDoc} */
public function getFilename(): string
{
return $this->outputFile;
}
/** {@inheritDoc} */
public function cleanup()
{
if (\file_exists($this->outputFile)) {
\unlink($this->outputFile);
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\VersionUpdater\Downloader;
use Psy\Exception\ErrorException;
use Psy\VersionUpdater\Downloader;
class Factory
{
/**
* @return Downloader
*
* @throws ErrorException If no downloaders can be used
*/
public static function getDownloader(): Downloader
{
if (\extension_loaded('curl')) {
return new CurlDownloader();
} elseif (\ini_get('allow_url_fopen')) {
return new FileDownloader();
}
throw new ErrorException('No downloader available.');
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\VersionUpdater\Downloader;
use Psy\VersionUpdater\Downloader;
class FileDownloader implements Downloader
{
private $tempDir = null;
private $outputFile = null;
/** {@inheritDoc} */
public function setTempDir(string $tempDir)
{
$this->tempDir = $tempDir;
}
/** {@inheritDoc} */
public function download(string $url): bool
{
$tempDir = $this->tempDir ?: \sys_get_temp_dir();
$this->outputFile = \tempnam($tempDir, 'psysh-archive-');
$targetName = $this->outputFile.'.tar.gz';
if (!\rename($this->outputFile, $targetName)) {
return false;
}
$this->outputFile = $targetName;
return (bool) \file_put_contents($this->outputFile, \file_get_contents($url));
}
/** {@inheritDoc} */
public function getFilename(): string
{
return $this->outputFile;
}
/** {@inheritDoc} */
public function cleanup()
{
if (\file_exists($this->outputFile)) {
\unlink($this->outputFile);
}
}
}

View File

@@ -3,7 +3,7 @@
/*
* This file is part of Psy Shell.
*
* (c) 2012-2018 Justin Hileman
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -22,15 +22,19 @@ class GitHubChecker implements Checker
/**
* @return bool
*/
public function isLatest()
public function isLatest(): bool
{
return \version_compare(Shell::VERSION, $this->getLatest(), '>=');
// version_compare doesn't handle semver completely;
// strip pre-release and build metadata before comparing
$version = \preg_replace('/[+-]\w+/', '', Shell::VERSION);
return \version_compare($version, $this->getLatest(), '>=');
}
/**
* @return string
*/
public function getLatest()
public function getLatest(): string
{
if (!isset($this->latest)) {
$this->setLatest($this->getVersionFromTag());
@@ -42,7 +46,7 @@ class GitHubChecker implements Checker
/**
* @param string $version
*/
public function setLatest($version)
public function setLatest(string $version)
{
$this->latest = $version;
}
@@ -70,8 +74,8 @@ class GitHubChecker implements Checker
{
$context = \stream_context_create([
'http' => [
'user_agent' => 'PsySH/' . Shell::VERSION,
'timeout' => 3,
'user_agent' => 'PsySH/'.Shell::VERSION,
'timeout' => 1.0,
],
]);

View File

@@ -0,0 +1,159 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\VersionUpdater;
use Psy\Exception\ErrorException;
class Installer
{
/**
* @var string
*/
protected $installLocation;
/**
* @var string
*/
protected $tempDirectory;
public function __construct(string $tempDirectory = null)
{
$this->tempDirectory = $tempDirectory ?: \sys_get_temp_dir();
$this->installLocation = \Phar::running(false);
}
/**
* Public to allow the Downloader to use the temporary directory if it's been set.
*
* @return string
*/
public function getTempDirectory(): string
{
return $this->tempDirectory;
}
/**
* Verify the currently installed PsySH phar is writable so it can be replaced.
*
* @return bool
*/
public function isInstallLocationWritable(): bool
{
return \is_writable($this->installLocation);
}
/**
* Verify the temporary directory is writable so downloads and backups can be saved there.
*
* @return bool
*/
public function isTempDirectoryWritable(): bool
{
return \is_writable($this->tempDirectory);
}
/**
* Verifies the downloaded archive can be extracted with \PharData.
*
* @param string $sourceArchive
*
* @return bool
*/
public function isValidSource(string $sourceArchive): bool
{
if (!\class_exists('\PharData')) {
return false;
}
$pharArchive = new \PharData($sourceArchive);
return $pharArchive->valid();
}
/**
* Extract the "psysh" phar from the archive and move it, replacing the currently installed phar.
*
* @param string $sourceArchive
*
* @return bool
*/
public function install(string $sourceArchive): bool
{
$pharArchive = new \PharData($sourceArchive);
$outputDirectory = \tempnam($this->tempDirectory, 'psysh-');
// remove the temp file, and replace it with a sub-directory
if (!\unlink($outputDirectory) || !\mkdir($outputDirectory, 0700)) {
return false;
}
$pharArchive->extractTo($outputDirectory, ['psysh'], true);
$renamed = \rename($outputDirectory.'/psysh', $this->installLocation);
// Remove the sub-directory created to extract the psysh binary/phar
\rmdir($outputDirectory);
return $renamed;
}
/**
* Create a backup of the currently installed PsySH phar in the temporary directory with a version number postfix.
*
* @param string $version
*
* @return bool
*/
public function createBackup(string $version): bool
{
$backupFilename = $this->getBackupFilename($version);
if (\file_exists($backupFilename) && !\is_writable($backupFilename)) {
return false;
}
return \rename($this->installLocation, $backupFilename);
}
/**
* Restore the backup file to the original PsySH install location.
*
* @param string $version
*
* @throws ErrorException If the backup file could not be found
*
* @return bool
*/
public function restoreFromBackup(string $version): bool
{
$backupFilename = $this->getBackupFilename($version);
if (!\file_exists($backupFilename)) {
throw new ErrorException("Cannot restore from backup. File not found! [{$backupFilename}]");
}
return \rename($backupFilename, $this->installLocation);
}
/**
* Get the full path for the backup target file location.
*
* @param string $version
*
* @return string
*/
public function getBackupFilename(string $version): string
{
$installFilename = \basename($this->installLocation);
return \sprintf('%s/%s.%s', $this->tempDirectory, $installFilename, $version);
}
}

View File

@@ -3,7 +3,7 @@
/*
* This file is part of Psy Shell.
*
* (c) 2012-2018 Justin Hileman
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -19,7 +19,7 @@ class IntervalChecker extends GitHubChecker
public function __construct($cacheFile, $interval)
{
$this->cacheFile = $cacheFile;
$this->interval = $interval;
$this->interval = $interval;
}
public function fetchLatestRelease()
@@ -43,7 +43,10 @@ class IntervalChecker extends GitHubChecker
return $release;
}
private function getDateInterval()
/**
* @throws \RuntimeException if interval passed to constructor is not supported
*/
private function getDateInterval(): \DateInterval
{
switch ($this->interval) {
case Checker::DAILY:
@@ -53,12 +56,14 @@ class IntervalChecker extends GitHubChecker
case Checker::MONTHLY:
return new \DateInterval('P1M');
}
throw new \RuntimeException('Invalid interval configured');
}
private function updateCache($release)
{
$data = [
'last_check' => \date(DATE_ATOM),
'last_check' => \date(\DATE_ATOM),
'release' => $release,
];

View File

@@ -3,7 +3,7 @@
/*
* This file is part of Psy Shell.
*
* (c) 2012-2018 Justin Hileman
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -14,14 +14,14 @@ namespace Psy\VersionUpdater;
use Psy\Shell;
/**
* A version checker stub which always thinks the current verion is up to date.
* A version checker stub which always thinks the current version is up to date.
*/
class NoopChecker implements Checker
{
/**
* @return bool
*/
public function isLatest()
public function isLatest(): bool
{
return true;
}
@@ -29,7 +29,7 @@ class NoopChecker implements Checker
/**
* @return string
*/
public function getLatest()
public function getLatest(): string
{
return Shell::VERSION;
}

View File

@@ -0,0 +1,192 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2022 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\VersionUpdater;
use Psy\Exception\ErrorException;
use Psy\Shell;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Self update command.
*
* If a new version is available, this command will download it and replace the currently installed version
*/
class SelfUpdate
{
const URL_PREFIX = 'https://github.com/bobthecow/psysh/releases/download';
const SUCCESS = 0;
const FAILURE = 1;
/** @var Checker */
private $checker;
/** @var Installer */
private $installer;
/** @var Downloader */
private $downloader;
public function __construct(Checker $checker, Installer $installer)
{
$this->checker = $checker;
$this->installer = $installer;
}
/**
* Allow the downloader to be injected for testing.
*
* @param Downloader $downloader
*
* @return void
*/
public function setDownloader(Downloader $downloader)
{
$this->downloader = $downloader;
}
/**
* Get the currently set Downloader or create one based on the capabilities of the php environment.
*
* @return Downloader
*
* @throws ErrorException if a downloader cannot be created for the php environment
*/
private function getDownloader(): Downloader
{
if (!isset($this->downloader)) {
return Downloader\Factory::getDownloader();
}
return $this->downloader;
}
/**
* Build the download URL for the latest release.
*
* The file name used in the URL will include the flavour postfix extracted from the current version
* if it's present
*
* @param string $latestVersion
*
* @return string
*/
private function getAssetUrl(string $latestVersion): string
{
$versionPostfix = '';
if (\strpos(Shell::VERSION, '+')) {
$versionPostfix = '-'.\substr(Shell::VERSION, \strpos(Shell::VERSION, '+') + 1);
}
$downloadFilename = \sprintf('psysh-%s%s.tar.gz', $latestVersion, $versionPostfix);
// check if latest release data contains an asset matching the filename?
return \sprintf('%s/%s/%s', self::URL_PREFIX, $latestVersion, $downloadFilename);
}
/**
* Execute the self-update process.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @throws ErrorException if the current version is not restored when installation fails
*
* @return int
*/
public function run(InputInterface $input, OutputInterface $output): int
{
$currentVersion = Shell::VERSION;
// already have the latest version?
if ($this->checker->isLatest()) {
// current version is latest version...
$output->writeln('<info>Current version is up-to-date.</info>');
return self::SUCCESS;
}
// can overwrite current version?
if (!$this->installer->isInstallLocationWritable()) {
$output->writeln('<error>Installed version is not writable.</error>');
return self::FAILURE;
}
// can download to, and create a backup in the temp directory?
if (!$this->installer->isTempDirectoryWritable()) {
$output->writeln('<error>Temporary directory is not writable.</error>');
return self::FAILURE;
}
$latestVersion = $this->checker->getLatest();
$downloadUrl = $this->getAssetUrl($latestVersion);
$output->write("Downloading PsySH $latestVersion ...");
try {
$downloader = $this->getDownloader();
$downloader->setTempDir($this->installer->getTempDirectory());
$downloaded = $downloader->download($downloadUrl);
} catch (ErrorException $e) {
$output->write(' <error>Failed.</error>');
$output->writeln(\sprintf('<error>%s</error>', $e->getMessage()));
return self::FAILURE;
}
if (!$downloaded) {
$output->writeln('<error>Download failed.</error>');
$downloader->cleanup();
return self::FAILURE;
} else {
$output->write(' <info>OK</info>'.\PHP_EOL);
}
$downloadedFile = $downloader->getFilename();
if (!$this->installer->isValidSource($downloadedFile)) {
$downloader->cleanup();
$output->writeln('<error>Downloaded file is not a valid archive.</error>');
return self::FAILURE;
}
// create backup as bin.old-version in the temporary directory
$backupCreated = $this->installer->createBackup($currentVersion);
if (!$backupCreated) {
$downloader->cleanup();
$output->writeln('<error>Failed to create a backup of the current version.</error>');
return self::FAILURE;
} elseif ($input->getOption('verbose')) {
$backupFilename = $this->installer->getBackupFilename($currentVersion);
$output->writeln('Created backup of current version: '.$backupFilename);
}
if (!$this->installer->install($downloadedFile)) {
$this->installer->restoreFromBackup($currentVersion);
$downloader->cleanup();
$output->writeln("<error>Failed to install new PsySH version $latestVersion.</error>");
return self::FAILURE;
}
// Remove the downloaded archive file from the temporary directory
$downloader->cleanup();
$output->writeln("Updated PsySH from $currentVersion to <info>$latestVersion</info>");
return self::SUCCESS;
}
}