diff --git a/.gitignore b/.gitignore index 57872d0..55940e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /vendor/ +composer.lock \ No newline at end of file diff --git a/README.md b/README.md index e8511dd..85f3eab 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ $configurator->onCompile[] = function ($config, Nette\Config\Compiler $compiler) composerUpdates: cacheDir: %tempDir%/cache - localConfigFile: %wwwDir%/../composer.json + rootDir: %wwwDir%/.. ``` Screenshots diff --git a/composer.json b/composer.json index 94ae20b..5502ae2 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,10 @@ { "name": "Matej Koubik", "email": "matej@koubik.name" + }, + { + "name": "Jáchym Toušek", + "email": "enumag@gmail.com" } ], "license": ["BSD-2-Clause"], diff --git a/src/ComposerUpdates/DI/ComposerUpdatesExtension.php b/src/ComposerUpdates/DI/ComposerUpdatesExtension.php index 3f19ebf..e077067 100644 --- a/src/ComposerUpdates/DI/ComposerUpdatesExtension.php +++ b/src/ComposerUpdates/DI/ComposerUpdatesExtension.php @@ -8,27 +8,27 @@ class ComposerUpdatesExtension extends Nette\DI\CompilerExtension { private $defaults = array( 'cacheDir' => NULL, - 'localConfigFile' => NULL, + 'rootDir' => NULL, ); public function loadConfiguration() { $config = $this->getConfig($this->defaults); - if (!is_dir($config['cacheDir']) || !is_file($config['localConfigFile'])) { + if (!is_dir($config['cacheDir']) || !is_dir($config['rootDir'])) { throw new \InvalidArgumentException("Please configure the ComposerUpdates extensions using the section '{$this->name}:' in your config file."); } $builder = $this->getContainerBuilder(); $builder->addDefinition($this->prefix('initializer')) - ->setClass('ComposerUpdates\Initializer', array($config['cacheDir'], $config['localConfigFile'])); + ->setClass('ComposerUpdates\Initializer', array($config['cacheDir'], $config['rootDir'])); $builder->addDefinition($this->prefix('service')) ->setClass('ComposerUpdates\Service'); $builder->addDefinition($this->prefix('panel')) - ->setClass('ComposerUpdates\Diagnostics\ComposerUpdatesPanel'); + ->setClass('ComposerUpdates\Diagnostics\ComposerUpdatesPanel', array($config['rootDir'])); } public function afterCompile(Nette\PhpGenerator\ClassType $class) diff --git a/src/ComposerUpdates/Diagnostics/ComposerUpdatesPanel.php b/src/ComposerUpdates/Diagnostics/ComposerUpdatesPanel.php index 2cd94ed..bc3bcfa 100644 --- a/src/ComposerUpdates/Diagnostics/ComposerUpdatesPanel.php +++ b/src/ComposerUpdates/Diagnostics/ComposerUpdatesPanel.php @@ -10,9 +10,19 @@ class ComposerUpdatesPanel extends Nette\Object implements Nette\Diagnostics\IBa /** @var ComposerUpdates\PackageInfo[] */ private $packages; - public function __construct(ComposerUpdates\Service $service) + public function __construct($rootDir, ComposerUpdates\Service $service, Nette\Caching\IStorage $storage) { - $this->packages = $service->getPackages(); + $cache = new Nette\Caching\Cache($storage, 'ComposerUpdates.panel'); + $this->packages = $cache->load($rootDir, function (& $dependencies) use ($rootDir, $service) { + $dependencies = array( + Nette\Caching\Cache::EXPIRATION => '1 hour', + Nette\Caching\Cache::FILES => array( + $rootDir . '/composer.json', + $rootDir . '/composer.lock', + ), + ); + return array_merge($service->getPackages(), $service->getDevPackages()); + }); } /** @@ -21,15 +31,21 @@ public function __construct(ComposerUpdates\Service $service) */ public function getTab() { - if (empty($this->packages)) { + if (!$this->packages) { return; } - - $updates = array_filter($this->packages, function(ComposerUpdates\PackageInfo $package) { - return $package->isUpdateAvailable(); - }); + + $status = max(array_map(function(ComposerUpdates\PackageInfo $package) { + return $package->getStatus(); + }, $this->packages)); + + $updates = count(array_filter($this->packages, function(ComposerUpdates\PackageInfo $package) { + $status = $package->getStatus(); + return $status !== ComposerUpdates\PackageInfo::STATUS_NO_UPDATE && $status !== ComposerUpdates\PackageInfo::STATUS_NOT_INSTALLED; + })); return self::render(__DIR__ . '/templates/tab.phtml', array( + 'status' => $status, 'updates' => $updates, )); } @@ -40,18 +56,19 @@ public function getTab() */ public function getPanel() { - if (empty($this->packages)) { + if (!$this->packages) { return; } - uasort($this->packages, function (ComposerUpdates\PackageInfo $package1, ComposerUpdates\PackageInfo $package2) { - $update1 = $package1->isUpdateAvailable(); - $update2 = $package2->isUpdateAvailable(); - return $update1 !== $update2 ? $update1 < $update2 : $package1->getName() > $package2->getName(); + $packages = $this->packages; + uksort($packages, function ($key1, $key2) use ($packages) { + $status1 = $packages[$key1]->getStatus(); + $status2 = $packages[$key2]->getStatus(); + return $status1 !== $status2 ? $status1 < $status2 : $key1 > $key2; }); return self::render(__DIR__ . '/templates/panel.phtml', array( - 'packages' => $this->packages, + 'packages' => $packages, )); } diff --git a/src/ComposerUpdates/Diagnostics/templates/panel.phtml b/src/ComposerUpdates/Diagnostics/templates/panel.phtml index f7b1a60..6048960 100644 --- a/src/ComposerUpdates/Diagnostics/templates/panel.phtml +++ b/src/ComposerUpdates/Diagnostics/templates/panel.phtml @@ -1,6 +1,6 @@ + 'not-installed', + \ComposerUpdates\PackageInfo::STATUS_NO_UPDATE => 'no-update', + \ComposerUpdates\PackageInfo::STATUS_INCOMPATIBLE_UPDATE => 'incompatible-update', + \ComposerUpdates\PackageInfo::STATUS_COMPATIBLE_UPDATE => 'compatible-update', +); +?> +

Composer updates

+ - + + + diff --git a/src/ComposerUpdates/Diagnostics/templates/tab.phtml b/src/ComposerUpdates/Diagnostics/templates/tab.phtml index 290ee62..1a35c23 100644 --- a/src/ComposerUpdates/Diagnostics/templates/tab.phtml +++ b/src/ComposerUpdates/Diagnostics/templates/tab.phtml @@ -1,6 +1,8 @@ + 'not-installed', + \ComposerUpdates\PackageInfo::STATUS_NO_UPDATE => 'no-update', + \ComposerUpdates\PackageInfo::STATUS_INCOMPATIBLE_UPDATE => 'incompatible-update', + \ComposerUpdates\PackageInfo::STATUS_COMPATIBLE_UPDATE => 'compatible-update', +); +?> + + -  up to date + no update -   + diff --git a/src/ComposerUpdates/Initializer.php b/src/ComposerUpdates/Initializer.php index 41749fb..fc1aa39 100644 --- a/src/ComposerUpdates/Initializer.php +++ b/src/ComposerUpdates/Initializer.php @@ -7,7 +7,7 @@ class Initializer { private $cacheDir; - private $localConfigFile; + private $rootDir; /** @var Composer\IO\IOInterface */ private $io; @@ -23,16 +23,16 @@ class Initializer /** @var Composer\Repository\RepositoryInterface */ private $installedRepository; - /** @var Composer\PAckage\RootPackageInterface */ + /** @var Composer\Package\RootPackageInterface */ private $rootPackage; /** @var Composer\DependencyResolver\Pool */ private $packagePool; - public function __construct($cacheDir, $localConfigFile) + public function __construct($cacheDir, $rootDir) { - $this->cacheDir = $cacheDir . '/_ComposerUpdates'; - $this->localConfigFile = $localConfigFile; + $this->cacheDir = $cacheDir . '/_ComposerUpdates.composer'; + $this->rootDir = $rootDir; $this->io = new Composer\IO\NullIO(); } @@ -82,7 +82,7 @@ public function getDevRequires() private function getConfig() { if ($this->config === NULL || $this->localConfig === NULL) { - $json = new Composer\Json\JsonFile($this->localConfigFile); + $json = new Composer\Json\JsonFile($this->rootDir . '/composer.json'); $this->localConfig = $json->read(); $this->config = new Composer\Config; @@ -98,7 +98,7 @@ private function getConfig() private function getVendorDir() { - return dirname($this->localConfigFile) . '/' . $this->getConfig()->get('vendor-dir'); + return $this->rootDir . '/' . $this->getConfig()->get('vendor-dir'); } private function getRepositoryManager() diff --git a/src/ComposerUpdates/NullVersion.php b/src/ComposerUpdates/NullVersion.php index b962af4..6edc2f1 100644 --- a/src/ComposerUpdates/NullVersion.php +++ b/src/ComposerUpdates/NullVersion.php @@ -2,16 +2,11 @@ namespace ComposerUpdates; -use composer\Package\PackageInterface; - class NullVersion extends Version { - protected $version; - - protected $prettyVersion; - public function __construct() { $this->version = -1; + $this->prettyVersion = 'none'; } } diff --git a/src/ComposerUpdates/PackageInfo.php b/src/ComposerUpdates/PackageInfo.php index 85757bf..54dccf0 100644 --- a/src/ComposerUpdates/PackageInfo.php +++ b/src/ComposerUpdates/PackageInfo.php @@ -4,26 +4,45 @@ class PackageInfo { + const STATUS_NOT_INSTALLED = 0; + const STATUS_NO_UPDATE = 1; + const STATUS_INCOMPATIBLE_UPDATE = 2; + const STATUS_COMPATIBLE_UPDATE = 3; + + /** @var string*/ private $name; /** @var Version */ private $installedVersion; - + /** @var Version[] */ - private $newVersions; + private $compatibleUpdates; + + /** @var Version[] */ + private $incompatibleUpdates; + + /** @var bool */ + private $devOnly; /** * @param string $name * @param Version $installedVersion - * @param Version[] $newVersions + * @param Version[] $compatibleUpdates + * @param Version[] $incompatibleUpdates + * @param bool $devOnly */ - public function __construct($name, Version $installedVersion, array $newVersions) + public function __construct($name, Version $installedVersion, array $compatibleUpdates, array $incompatibleUpdates, $devOnly) { $this->name = $name; $this->installedVersion = $installedVersion; - $this->newVersions = $newVersions; + $this->compatibleUpdates = $compatibleUpdates; + $this->incompatibleUpdates = $incompatibleUpdates; + $this->devOnly = $devOnly; } + /** + * @return string + */ public function getName() { return $this->name; @@ -37,21 +56,67 @@ public function getInstalledVersion() return $this->installedVersion; } + /** + * @return int + */ + public function getStatus() + { + if ($this->installedVersion instanceof NullVersion) { + return self::STATUS_NOT_INSTALLED; + } elseif ($this->compatibleUpdates) { + return self::STATUS_COMPATIBLE_UPDATE; + } elseif ($this->incompatibleUpdates) { + return self::STATUS_INCOMPATIBLE_UPDATE; + } else { + return self::STATUS_NO_UPDATE; + } + } + + /** + * @return bool + */ + public function isDevOnly() + { + return $this->devOnly; + } + /** * @return bool - */ - public function isUpdateAvailable() + */ + public function isCompatibleUpdateAvailable() + { + return (bool) $this->compatibleUpdates; + } + + /** + * @return bool + */ + public function isIncompatibleUpdateAvailable() { - return count($this->newVersions) > 0; + return (bool) $this->incompatibleUpdates; + } + + /** + * @return Version + */ + public function getCompatibleUpdate() + { + $max = new NullVersion(); + foreach ($this->compatibleUpdates as $version) { + if ($version->isGreaterThan($max)) { + $max = $version; + } + } + return $max; } /** * @return Version */ - public function getAvailableVersion() + public function getIncompatibleUpdate() { $max = new NullVersion(); - foreach ($this->newVersions as $version) { + foreach ($this->incompatibleUpdates as $version) { if ($version->isGreaterThan($max)) { $max = $version; } diff --git a/src/ComposerUpdates/Service.php b/src/ComposerUpdates/Service.php index 834e75d..79e7b54 100644 --- a/src/ComposerUpdates/Service.php +++ b/src/ComposerUpdates/Service.php @@ -27,32 +27,45 @@ public function getPackages() public function getDevPackages() { $requires = $this->initializer->getDevRequires(); - return $this->getPackagesFromRequires($requires); + return $this->getPackagesFromRequires($requires, TRUE); } - private function getPackagesFromRequires(array $requires) + private function getPackagesFromRequires(array $requires, $devOnly = FALSE) { $installedRepo = $this->initializer->getInstalledRepository(); - $pool = $this->initializer->getPackagePool(); $installedVersions = array(); foreach ($installedRepo->getPackages() as $package) { $installedVersions[$package->getName()] = new Version($package); } + $pool = $this->initializer->getPackagePool(); $packages = array(); foreach ($requires as $link) { $name = $link->getTarget(); + if (strpos($name, '/') === FALSE) { + continue; + } + $currentVersion = isset($installedVersions[$name]) ? $installedVersions[$name] : new NullVersion(); + $provides = $pool->whatProvides($name, $link->getConstraint()); $versions = array_map(function ($package) { return new Version($package); }, $provides); - $currentVersion = isset($installedVersions[$name]) ? $installedVersions[$name] : new NullVersion(); - $newVersions = array_filter($versions, function($version) use ($currentVersion) { + $compatibleUpdates = array_filter($versions, function($version) use ($currentVersion) { return $version->isGreaterThan($currentVersion); }); - $packages[] = new PackageInfo($name, $installedVersions[$name], $newVersions); + + $provides = $pool->whatProvides($name); + $versions = array_map(function ($package) { + return new Version($package); + }, $provides); + $incompatibleUpdates = array_filter($versions, function($version) use ($currentVersion) { + return $version->isGreaterThan($currentVersion); + }); + + $packages[] = new PackageInfo($name, $currentVersion, $compatibleUpdates, $incompatibleUpdates, $devOnly); } return $packages; diff --git a/src/ComposerUpdates/Version.php b/src/ComposerUpdates/Version.php index e0654ed..72345ee 100644 --- a/src/ComposerUpdates/Version.php +++ b/src/ComposerUpdates/Version.php @@ -17,13 +17,11 @@ class Version public function __construct(PackageInterface $package) { $this->version = $package->getVersion(); - $this->prettyVersion = $package->getPrettyVersion(); - // v0.9.0-alpha5 => 0.9.0-alpha5 - $semverString = preg_replace('/^v/', '', $this->prettyVersion); + $this->prettyVersion = preg_replace('/^v/', '', $package->getPrettyVersion()); try { - $this->semver = SemVer\Version::parse($semverString); + $this->semver = SemVer\Version::parse($this->prettyVersion); } catch (\InvalidArgumentException $e) { $this->semver = NULL; } diff --git a/tests/ComposerUpdates/PackageInfo.phpt b/tests/ComposerUpdates/PackageInfo.phpt index 213ac17..26ffce7 100644 --- a/tests/ComposerUpdates/PackageInfo.phpt +++ b/tests/ComposerUpdates/PackageInfo.phpt @@ -10,17 +10,20 @@ test(function() { $v2_0_10 = createVersion('nette/nette', '2.0.10.0', 'v2.0.10'); $v2_0_11 = createVersion('nette/nette', '2.0.11.0', 'v2.0.11'); $v2_0_12 = createVersion('nette/nette', '2.0.12.0', 'v2.0.12'); - $info = new PackageInfo('nette/nette', $v2_0_10, array($v2_0_11, $v2_0_12)); + $info = new PackageInfo('nette/nette', $v2_0_10, array($v2_0_11, $v2_0_12), array(), FALSE); - Assert::true($info->isUpdateAvailable()); - Assert::equal('v2.0.12', (string) $info->getAvailableVersion()); + Assert::true($info->isCompatibleUpdateAvailable()); + Assert::false($info->isIncompatibleUpdateAvailable()); + Assert::same(PackageInfo::STATUS_COMPATIBLE_UPDATE, $info->getStatus()); + Assert::equal('2.0.12', (string) $info->getCompatibleUpdate()); }); test(function() { $v2_0_12 = createVersion('nette/nette', '2.0.12.0', 'v2.0.12'); - $info = new PackageInfo('nette/nette', $v2_0_12, array()); + $info = new PackageInfo('nette/nette', $v2_0_12, array(), array(), FALSE); - Assert::false($info->isUpdateAvailable()); + Assert::false($info->isCompatibleUpdateAvailable()); + Assert::false($info->isIncompatibleUpdateAvailable()); }); function createVersion($name, $version, $prettyVersion) {
Package VersionUpdateCompatibleIncompatible
- isUpdateAvailable()) { ?> - - - - + getName()) ?> + isDevOnly()) { ?> + (dev only) + getInstalledVersion() ?> - isUpdateAvailable()) { ?> - getAvailableVersion() ?> available + isCompatibleUpdateAvailable()) { ?> + getCompatibleUpdate() ?> available + + + isIncompatibleUpdateAvailable()) { ?> + getIncompatibleUpdate() ?> available