From b59cdbfdcffce0f8e808fd68fa5bc106e199d523 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 15 Feb 2016 16:53:26 +0100 Subject: [PATCH 01/41] Lint --- .../src/Grav/Console/Gpm/InstallCommand.php | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index dca4fe77b..0d919c4ac 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -91,7 +91,7 @@ class InstallCommand extends ConsoleCommand $packages = array_map('strtolower', $this->input->getArgument('package')); $this->data = $this->gpm->findPackages($packages); - if (false === $this->isWindows() && @is_file(getenv("HOME").'/.grav/config')) { + if (false === $this->isWindows() && @is_file(getenv("HOME") . '/.grav/config')) { $local_config_file = exec('eval echo ~/.grav/config'); if (file_exists($local_config_file)) { $this->local_config = Yaml::parse($local_config_file); @@ -126,7 +126,7 @@ class InstallCommand extends ConsoleCommand foreach ($data as $package) { //Check for dependencies if (isset($package->dependencies)) { - $this->output->writeln("Package " . $package->name . " has ". count($package->dependencies) . " required dependencies that must be installed first..."); + $this->output->writeln("Package " . $package->name . " has " . count($package->dependencies) . " required dependencies that must be installed first..."); $this->output->writeln(''); $dependency_data = $this->gpm->findPackages($package->dependencies); @@ -137,9 +137,8 @@ class InstallCommand extends ConsoleCommand } else { unset($dependency_data['total']); - foreach($dependency_data as $type => $dep_data) { - foreach($dep_data as $name => $dep_package) { - + foreach ($dependency_data as $type => $dep_data) { + foreach ($dep_data as $name => $dep_package) { $this->processPackage($dep_package); } } @@ -180,6 +179,7 @@ class InstallCommand extends ConsoleCommand if (count($install_options) == 0) { // no valid install options - error and return $this->output->writeln("not valid installation methods found!"); + return; } elseif (count($install_options) == 1) { // only one option, use it... @@ -187,7 +187,7 @@ class InstallCommand extends ConsoleCommand } else { $helper = $this->getHelper('question'); $question = new ChoiceQuestion( - 'Please select installation method for ' . $package->name . ' ('.$install_options[0].' is default)', array_values($install_options), 0 + 'Please select installation method for ' . $package->name . ' (' . $install_options[0] . ' is default)', array_values($install_options), 0 ); $question->setErrorMessage('Method %s is invalid'); $method = $helper->ask($this->input, $this->output, $question); @@ -195,7 +195,7 @@ class InstallCommand extends ConsoleCommand $this->output->writeln(''); - $method_name = 'process'.$method; + $method_name = 'process' . $method; $this->$method_name($package); $this->installDemoContent($package); @@ -213,24 +213,26 @@ class InstallCommand extends ConsoleCommand if (file_exists($demo_dir)) { // Demo content exists, prompt to install it. - $this->output->writeln("Attention: ".$package->name . " contains demo content"); + $this->output->writeln("Attention: " . $package->name . " contains demo content"); $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Do you wish to install this demo content? [y|N] ', false); if (!$helper->ask($this->input, $this->output, $question)) { $this->output->writeln(" '- Skipped! "); $this->output->writeln(''); + return; } // if pages folder exists in demo if (file_exists($demo_dir . DS . 'pages')) { $pages_backup = 'pages.' . date('m-d-Y-H-i-s'); - $question = new ConfirmationQuestion('This will backup your current `user/pages` folder to `user/'. $pages_backup. '`, continue? [y|N]', false); + $question = new ConfirmationQuestion('This will backup your current `user/pages` folder to `user/' . $pages_backup . '`, continue? [y|N]', false); if (!$helper->ask($this->input, $this->output, $question)) { $this->output->writeln(" '- Skipped! "); $this->output->writeln(''); + return; } @@ -294,6 +296,7 @@ class InstallCommand extends ConsoleCommand return $from; } } + return false; } @@ -336,6 +339,7 @@ class InstallCommand extends ConsoleCommand } + return; } From 503ff8d70f2e8c2b85a8cfa9a11bc71fd45c9af9 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 16 Feb 2016 15:24:33 +0100 Subject: [PATCH 02/41] First step towards versions in dependencies Add InstallCommand::calculateMergedDependenciesOfPackages and InstallCommand::calculateVersionNumberFromDependencyVersion and corresponding unit tests --- .../src/Grav/Console/Gpm/InstallCommand.php | 96 ++++++++++++- .../Grav/Console/Gpm/InstallCommandTest.php | 130 ++++++++++++++++++ 2 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 tests/unit/Grav/Console/Gpm/InstallCommandTest.php diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 0d919c4ac..fed169b21 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -14,6 +14,7 @@ use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Yaml\Yaml; define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/(.*)/'); +define('SECOND_IS_HIGHER', -1); /** * Class InstallCommand @@ -25,18 +26,22 @@ class InstallCommand extends ConsoleCommand * @var */ protected $data; + /** * @var */ protected $gpm; + /** * @var */ protected $destination; + /** * @var */ protected $file; + /** * @var */ @@ -44,7 +49,6 @@ class InstallCommand extends ConsoleCommand protected $local_config; - /** * */ @@ -153,6 +157,96 @@ class InstallCommand extends ConsoleCommand $this->clearCache(); } + /** + * Calculates and merges the dependencies of the passed packages + * + * @param array $packages + * + * @return mixed + * @throws \Exception + */ + public function calculateMergedDependenciesOfPackages($packages) + { + foreach ($packages as $data) { + foreach ($data as $package) { + + //Check for dependencies + if (isset($package->dependencies_versions)) { + foreach ($package->dependencies_versions as $dependency) { + + $current_package_name = $dependency->name; + if (isset($dependency->version)) { + $current_package_version_information = $dependency->version; + } + + if (!isset($dependencies[$current_package_name])) { // Dependency added for the first time + + if (!isset($current_package_version_information)) { + $dependencies[$current_package_name] = '*'; + } else { + $dependencies[$current_package_name] = $current_package_version_information; + } + + } else { // Dependency already added by another package + + //if this package requires a version higher than the currently stored one, store this requirement instead + if (isset($current_package_version_information) && $current_package_version_information !== '*') { + + $currently_stored_version_information = $dependencies[$current_package_name]; + + $currently_stored_version_number = $this->calculateVersionNumberFromDependencyVersion($currently_stored_version_information); + if (!$currently_stored_version_number) { + $currently_stored_version_number = '*'; + } + + $current_package_version_number = $this->calculateVersionNumberFromDependencyVersion($current_package_version_information); + if (!$current_package_version_number) { + throw new \Exception('Bad format for package ' . $current_package_name); + } + + //If I had stored '*', change right away with the more specific version required + if ($currently_stored_version_number === '*') { + $dependencies[$current_package_name] = $current_package_version_information; + } else { + + if (version_compare($currently_stored_version_number, $current_package_version_number) == SECOND_IS_HIGHER) { + $dependencies[$current_package_name] = $current_package_version_information; + } + + } + } + } + } + } + } + } + + return $dependencies; + } + + /** + * Returns the actual version from a dependency version string. + * Examples: + * $versionInformation == '~2.0' => returns '2.0' + * $versionInformation == '>=2.0.2' => returns '2.0.2' + * $versionInformation == '*' => returns null + * $versionInformation == '' => returns null + * + * @param $versionInformation + * + * @return null|string + */ + public function calculateVersionNumberFromDependencyVersion($versionInformation) + { + if (substr($versionInformation, 0, 1) == '~') { + return substr($versionInformation, 1); + } elseif (substr($versionInformation, 0, 2) == '>=') { + return substr($versionInformation, 2); + } + + return null; + } + /** * @param $package */ diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php new file mode 100644 index 000000000..59e9c24dd --- /dev/null +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -0,0 +1,130 @@ +grav = Fixtures::get('grav'); + $this->installCommand = new InstallCommand(); + } + + protected function _after() + { + } + + public function testTest() + { + ////////////////////////////////////////////////////////////////////////////////////////// + //First example + ////////////////////////////////////////////////////////////////////////////////////////// + $this->data = [ + [ + 'admin' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "grav", "version" => ">=1.0.10"], + (object)["name" => "form", "version" => "~2.0"], + (object)["name" => "login", "version" => ">=2.0"], + (object)["name" => "errors", "version" => "*"], + (object)["name" => "problems"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=1.0"] + ] + ] + ] + ]; + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + + $this->assertTrue(is_array($dependencies)); + $this->assertTrue(count($dependencies) == 5); + + $this->assertTrue($dependencies['grav'] == '>=1.0.10'); + $this->assertTrue($dependencies['errors'] == '>=1.0'); + $this->assertFalse($dependencies['errors'] == '*'); + $this->assertTrue($dependencies['problems'] == '*'); + + ////////////////////////////////////////////////////////////////////////////////////////// + //Second example + ////////////////////////////////////////////////////////////////////////////////////////// + $this->data = [ + [ + 'admin' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => "*"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=1.0"] + ] + ], + 'another' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=3.2"] + ] + ] + ] + ]; + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + + $this->assertTrue(is_array($dependencies)); + $this->assertTrue(count($dependencies) == 1); + $this->assertTrue($dependencies['errors'] == '>=3.2'); + + ////////////////////////////////////////////////////////////////////////////////////////// + //Second example + ////////////////////////////////////////////////////////////////////////////////////////// + $this->data = [ + [ + 'admin' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=4.0"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=1.0"] + ] + ], + 'another' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=3.2"] + ] + ] + ] + ]; + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + + $this->assertTrue(is_array($dependencies)); + $this->assertTrue(count($dependencies) == 1); + $this->assertTrue($dependencies['errors'] == '>=4.0'); + + } + + + public function testCalculateVersionNumberFromDependencyVersion() + { + $this->assertSame('2.0', $this->installCommand->calculateVersionNumberFromDependencyVersion('>=2.0')); + $this->assertSame('2.0.2', $this->installCommand->calculateVersionNumberFromDependencyVersion('>=2.0.2')); + $this->assertSame('2.0.2', $this->installCommand->calculateVersionNumberFromDependencyVersion('~2.0.2')); + $this->assertSame('1', $this->installCommand->calculateVersionNumberFromDependencyVersion('~1')); + $this->assertSame(null, $this->installCommand->calculateVersionNumberFromDependencyVersion('')); + $this->assertSame(null, $this->installCommand->calculateVersionNumberFromDependencyVersion('*')); + $this->assertSame(null, $this->installCommand->calculateVersionNumberFromDependencyVersion('2.0.2')); + } +} \ No newline at end of file From b331758d9c005b9b57259696acd1193443f59280 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 17 Feb 2016 14:19:14 +0100 Subject: [PATCH 03/41] Add checkNextSignificantReleasesAreCompatible method Added own tests too. Returns true if two releases are compatible by the 'next significant release' meaning. ~1.2 is equivalent to >=1.2 <2.0.0 ~1.2.3 is equivalent to >=1.2.3 <1.3.0 In short, allows the last digit specified to go up --- .../src/Grav/Console/Gpm/InstallCommand.php | 35 +++++++++++++++++++ .../Grav/Console/Gpm/InstallCommandTest.php | 21 +++++++++++ 2 files changed, 56 insertions(+) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index fed169b21..bccdb8fb1 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -247,6 +247,41 @@ class InstallCommand extends ConsoleCommand return null; } + /** + + /** + * Check if two releases are compatible by next significant release + * + * ~1.2 is equivalent to >=1.2 <2.0.0 + * ~1.2.3 is equivalent to >=1.2.3 <1.3.0 + * + * In short, allows the last digit specified to go up + * + * @param string $version1 the version string (e.g. '2.0.0' or '1.0') + * @param string $version2 the version string (e.g. '2.0.0' or '1.0') + * + * @return bool + */ + public function checkNextSignificantReleasesAreCompatible($version1, $version2) + { + $version1array = explode('.', $version1); + $version2array = explode('.', $version2); + + if (count($version1array) > count($version2array)) { + list($version1array, $version2array) = [$version2array, $version1array]; + } + + $i = 0; + while ($i < count($version1array) - 1) { + if ($version1array[$i] != $version2array[$i]) { + return false; + } + $i++; + } + + return true; + } + /** * @param $package */ diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index 59e9c24dd..b16bc6ee3 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -114,6 +114,27 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertTrue(count($dependencies) == 1); $this->assertTrue($dependencies['errors'] == '>=4.0'); + + public function testCheckNextSignificantReleasesAreCompatible() + { + /* + * ~1.0 is equivalent to >=1.0 < 2.0.0 + * ~1.2 is equivalent to >=1.2 <2.0.0 + * ~1.2.3 is equivalent to >=1.2.3 <1.3.0 + */ + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.0', '1.2')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.2', '1.0')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.0', '1.0.10')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.1', '1.1.10')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('30.0', '30.10')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.0', '1.1.10')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.0', '1.8')); + $this->assertTrue($this->installCommand->checkNextSignificantReleasesAreCompatible('1.0.1', '1.1')); + + $this->assertFalse($this->installCommand->checkNextSignificantReleasesAreCompatible('1.0', '2.2')); + $this->assertFalse($this->installCommand->checkNextSignificantReleasesAreCompatible('0.9.99', '1.0.0')); + $this->assertFalse($this->installCommand->checkNextSignificantReleasesAreCompatible('0.9.99', '1.0.10')); + $this->assertFalse($this->installCommand->checkNextSignificantReleasesAreCompatible('0.9.99', '1.0.10.2')); } From 5cdc10075a97e7dd21c32478e18bca799c53412e Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 17 Feb 2016 14:22:59 +0100 Subject: [PATCH 04/41] Add versionFormatIsNextSignificantRelease and versionFormatIsEqualOrHigher methods And corresponding tests --- .../src/Grav/Console/Gpm/InstallCommand.php | 24 +++++++++++++++++++ .../Grav/Console/Gpm/InstallCommandTest.php | 18 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index bccdb8fb1..caea451b3 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -248,6 +248,30 @@ class InstallCommand extends ConsoleCommand } /** + * Check if the passed version information contains next significant release (tilde) operator + * + * Example: returns true for $version: '~2.0' + * + * @param $version + * + * @return bool + */ + public function versionFormatIsNextSignificantRelease($version) { + return substr($version, 0, 1) == '~'; + } + + /** + * Check if the passed version information contains equal or higher operator + * + * Example: returns true for $version: '>=2.0' + * + * @param $version + * + * @return bool + */ + public function versionFormatIsEqualOrHigher($version) { + return substr($version, 0, 2) == '>='; + } /** * Check if two releases are compatible by next significant release diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index b16bc6ee3..d25d3d43e 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -114,6 +114,24 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertTrue(count($dependencies) == 1); $this->assertTrue($dependencies['errors'] == '>=4.0'); + public function testVersionFormatIsNextSignificantRelease() + { + $this->assertFalse($this->installCommand->versionFormatIsNextSignificantRelease('>=1.0')); + $this->assertFalse($this->installCommand->versionFormatIsNextSignificantRelease('>=2.3.4')); + $this->assertFalse($this->installCommand->versionFormatIsNextSignificantRelease('>=2.3.x')); + $this->assertFalse($this->installCommand->versionFormatIsNextSignificantRelease('1.0')); + $this->assertTrue($this->installCommand->versionFormatIsNextSignificantRelease('~2.3.x')); + $this->assertTrue($this->installCommand->versionFormatIsNextSignificantRelease('~2.0')); + } + + public function testVersionFormatIsEqualOrHigher() + { + $this->assertTrue($this->installCommand->versionFormatIsEqualOrHigher('>=1.0')); + $this->assertTrue($this->installCommand->versionFormatIsEqualOrHigher('>=2.3.4')); + $this->assertTrue($this->installCommand->versionFormatIsEqualOrHigher('>=2.3.x')); + $this->assertFalse($this->installCommand->versionFormatIsEqualOrHigher('~2.3.x')); + $this->assertFalse($this->installCommand->versionFormatIsEqualOrHigher('1.0')); + } public function testCheckNextSignificantReleasesAreCompatible() { From 17c47889a6b27dda7914df3e33363b8963e6365e Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 17 Feb 2016 14:33:27 +0100 Subject: [PATCH 05/41] Improve calculateMergedDependenciesOfPackages Raise exceptions if two merged versions in "next significant release" format are incompatible Wrote appropriate tests. --- .../src/Grav/Console/Gpm/InstallCommand.php | 37 ++++++++--- .../Grav/Console/Gpm/InstallCommandTest.php | 64 +++++++++++++++++-- 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index caea451b3..b8897ff98 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -14,7 +14,6 @@ use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Yaml\Yaml; define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/(.*)/'); -define('SECOND_IS_HIGHER', -1); /** * Class InstallCommand @@ -160,6 +159,8 @@ class InstallCommand extends ConsoleCommand /** * Calculates and merges the dependencies of the passed packages * + * @todo handle recursive dependencies + * * @param array $packages * * @return mixed @@ -168,11 +169,11 @@ class InstallCommand extends ConsoleCommand public function calculateMergedDependenciesOfPackages($packages) { foreach ($packages as $data) { - foreach ($data as $package) { + foreach ($data as $packageName => $packageData) { //Check for dependencies - if (isset($package->dependencies_versions)) { - foreach ($package->dependencies_versions as $dependency) { + if (isset($packageData->dependencies_versions)) { + foreach ($packageData->dependencies_versions as $dependency) { $current_package_name = $dependency->name; if (isset($dependency->version)) { @@ -195,24 +196,44 @@ class InstallCommand extends ConsoleCommand $currently_stored_version_information = $dependencies[$current_package_name]; $currently_stored_version_number = $this->calculateVersionNumberFromDependencyVersion($currently_stored_version_information); + + $currently_stored_version_is_in_next_significant_release_format = false; + if ($this->versionFormatIsNextSignificantRelease($currently_stored_version_information)) { + $currently_stored_version_is_in_next_significant_release_format = true; + } + if (!$currently_stored_version_number) { $currently_stored_version_number = '*'; } $current_package_version_number = $this->calculateVersionNumberFromDependencyVersion($current_package_version_information); if (!$current_package_version_number) { - throw new \Exception('Bad format for package ' . $current_package_name); + throw new \Exception('Bad format for version of dependency ' . $current_package_name . ' for package ' . $packageName, 1); + } + + $current_package_version_is_in_next_significant_release_format = false; + if ($this->versionFormatIsNextSignificantRelease($current_package_version_information)) { + $current_package_version_is_in_next_significant_release_format = true; } //If I had stored '*', change right away with the more specific version required if ($currently_stored_version_number === '*') { $dependencies[$current_package_name] = $current_package_version_information; } else { + $version1 = $currently_stored_version_is_in_next_significant_release_format; + $version2 = $current_package_version_is_in_next_significant_release_format; - if (version_compare($currently_stored_version_number, $current_package_version_number) == SECOND_IS_HIGHER) { - $dependencies[$current_package_name] = $current_package_version_information; + if (!$version1 && !$version2) { + //Comparing versions equals or higher, a simple version_compare is enough + if (version_compare($currently_stored_version_number, $current_package_version_number) == -1) { //Current package version is higher + $dependencies[$current_package_name] = $current_package_version_information; + } + } else { + $compatible = $this->checkNextSignificantReleasesAreCompatible($currently_stored_version_number, $current_package_version_number); + if (!$compatible) { + throw new \Exception('Dependency ' . $current_package_name . ' is required in two incompatible versions', 2); + } } - } } } diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index d25d3d43e..08eccd04e 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -4,6 +4,9 @@ use Codeception\Util\Fixtures; use Grav\Common\Grav; use Grav\Console\Gpm\InstallCommand; +define('EXCEPTION_BAD_FORMAT', 1); +define('EXCEPTION_INCOMPATIBLE_VERSIONS', 2); + /** * Class InstallCommandTest */ @@ -22,10 +25,10 @@ class InstallCommandTest extends \Codeception\TestCase\Test { } - public function testTest() + public function testCalculateMergedDependenciesOfPackages() { ////////////////////////////////////////////////////////////////////////////////////////// - //First example + // First working example ////////////////////////////////////////////////////////////////////////////////////////// $this->data = [ [ @@ -57,7 +60,7 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertTrue($dependencies['problems'] == '*'); ////////////////////////////////////////////////////////////////////////////////////////// - //Second example + // Second working example ////////////////////////////////////////////////////////////////////////////////////////// $this->data = [ [ @@ -86,7 +89,7 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertTrue($dependencies['errors'] == '>=3.2'); ////////////////////////////////////////////////////////////////////////////////////////// - //Second example + // Third working example ////////////////////////////////////////////////////////////////////////////////////////// $this->data = [ [ @@ -114,6 +117,59 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertTrue(count($dependencies) == 1); $this->assertTrue($dependencies['errors'] == '>=4.0'); + ////////////////////////////////////////////////////////////////////////////////////////// + // Raise exception if no version is specified + ////////////////////////////////////////////////////////////////////////////////////////// + $this->data = [ + [ + 'admin' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">=4.0"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => ">="] + ] + ], + ] + ]; + + try { + $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + $this->fail("Expected Exception not thrown"); + } catch (Exception $e) { + $this->assertEquals(EXCEPTION_BAD_FORMAT, $e->getCode()); + $this->assertStringStartsWith("Bad format for version of dependency", $e->getMessage()); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Raise exception if incompatible versions are specified + ////////////////////////////////////////////////////////////////////////////////////////// + $this->data = [ + [ + 'admin' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => "~4.0"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + (object)["name" => "errors", "version" => "~3.0"] + ] + ], + ] + ]; + + try { + $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + $this->fail("Expected Exception not thrown"); + } catch (Exception $e) { + $this->assertEquals(EXCEPTION_INCOMPATIBLE_VERSIONS, $e->getCode()); + $this->assertStringEndsWith("required in two incompatible versions", $e->getMessage()); + } + } + public function testVersionFormatIsNextSignificantRelease() { $this->assertFalse($this->installCommand->versionFormatIsNextSignificantRelease('>=1.0')); From 0143ac22e35419b5bb7c72503cdc1ad48659b440 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 17 Feb 2016 14:33:52 +0100 Subject: [PATCH 06/41] Improve calculateVersionNumberFromDependencyVersion using extracted method --- system/src/Grav/Console/Gpm/InstallCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index b8897ff98..30470e23a 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -259,9 +259,9 @@ class InstallCommand extends ConsoleCommand */ public function calculateVersionNumberFromDependencyVersion($versionInformation) { - if (substr($versionInformation, 0, 1) == '~') { + if ($this->versionFormatIsNextSignificantRelease($versionInformation)) { return substr($versionInformation, 1); - } elseif (substr($versionInformation, 0, 2) == '>=') { + } elseif ($this->versionFormatIsEqualOrHigher($versionInformation)) { return substr($versionInformation, 2); } From eb120a2cdab9159d3c8ad7cde232a6062cf28cf1 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 14:02:48 +0100 Subject: [PATCH 07/41] Drop duplicate docblock --- system/src/Grav/Common/GPM/GPM.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php index 3cdb64bba..bf53de485 100644 --- a/system/src/Grav/Common/GPM/GPM.php +++ b/system/src/Grav/Common/GPM/GPM.php @@ -349,11 +349,6 @@ class GPM extends Iterator return false; } - /** - * Returns the list of Plugins and Themes available in the repository - * @return array Array of available Plugins and Themes - * Format: ['plugins' => array, 'themes' => array] - */ /** * Searches for a list of Packages in the repository * @param array $searches An array of either slugs or names From 4a16fe68c328e63c02d8e9af48be1ac38126bdc9 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 14:03:50 +0100 Subject: [PATCH 08/41] Add an processDependencies() method to InstallCommand Fetch the dependencies, check the installed packages and return an array with the list of packages with associated an information on what to do: install, update or ignore --- .../src/Grav/Console/Gpm/InstallCommand.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 30470e23a..77f0791e6 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -156,6 +156,52 @@ class InstallCommand extends ConsoleCommand $this->clearCache(); } + + /** + * Fetch the dependencies, check the installed packages and return an array with + * the list of packages with associated an information on what to do: install, update or ignore. + * + * `ignore` means the package is already installed and can be safely left as-is. + * `install` means the package is not installed and must be installed. + * `update` means the package is already installed and must be updated as a dependency needs a higher version. + * + * @param array $packages + * + * @return mixed + * @throws \Exception + */ + public function processDependencies($packages) { + $dependencies = $this->calculateMergedDependenciesOfPackages($packages); + + + //TODO: if version 0.9 is installed already, and 0.9 is required by some plugin, but 1.0 is out, don't update to 1.0, alert + + foreach ($dependencies as $dependencySlug => $dependencyVersion) { + + if ($this->gpm->isPluginInstalled($dependencySlug)) { + + // check the version, if an update is not strictly required mark as 'ignore' + $locator = self::getGrav()['locator']; + $blueprints_path = $locator->findResource('plugins://' . $dependencySlug . DS . 'blueprints.yaml'); + $package_yaml = Yaml::parse(file_get_contents($blueprints_path)); + + $currentlyInstalledVersion = $package_yaml['version']; + + if ($currentlyInstalledVersion < $dependencyVersion) { + $dependencies[$dependencySlug] = 'update'; + } else { + //TODO: check if there's really a new release, or remove + $dependencies[$dependencySlug] = 'ignore'; + } + + } else { + $dependencies[$dependencySlug] = 'install'; + } + } + + return $dependencies; + } + /** * Calculates and merges the dependencies of the passed packages * From 43d63f6976ebc87a31ba946d468b8cff471fe0da Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 14:08:36 +0100 Subject: [PATCH 09/41] Add installDependencies() Prompts to install the dependencies of the passed type --- .../src/Grav/Console/Gpm/InstallCommand.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 77f0791e6..e3ca80f7d 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -156,6 +156,36 @@ class InstallCommand extends ConsoleCommand $this->clearCache(); } + /** + * Given a $dependencies list, filters their type according to $type and + * shows $message prior to listing them to the user. Then asks the user a confirmation prior + * to installing them. + * + * @param array $dependencies The dependencies array + * @param string $type The type of dependency to show: install, update, ignore + * @param string $message A message to be shown prior to listing the dependencies + * + * @throws \Exception + */ + public function installDependencies($dependencies, $type, $message) { + $this->output->writeln($message); + $packages = array_filter($dependencies, function ($action) use ($type) { return $action === $type; }); + foreach ($packages as $dependencyName => $dependencyVersion) { + $this->output->writeln(" |- Package " . $dependencyName . ""); + } + + $helper = $this->getHelper('question'); + $question = new ConfirmationQuestion('Do you wish to update these dependencies? [y|N] ', false); + + if ($helper->ask($this->input, $this->output, $question)) { + foreach ($packages as $dependencyName => $dependencyVersion) { + $this->processPackage($dependencyName); + } + $this->output->writeln(''); + } else { + throw new \Exception(); + } + } /** * Fetch the dependencies, check the installed packages and return an array with From c3afb68e9a8e49006f74c22c592e77160b255ac4 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 17:35:32 +0100 Subject: [PATCH 10/41] Add getLatestVersionOfPackage() to GPM --- system/src/Grav/Common/GPM/GPM.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php index bf53de485..ab1ac74ed 100644 --- a/system/src/Grav/Common/GPM/GPM.php +++ b/system/src/Grav/Common/GPM/GPM.php @@ -194,6 +194,28 @@ class GPM extends Iterator return $items; } + /** + * Get the latest release of a package from the GPM + * + * @param $package_name + * + * @return string + */ + public function getLatestVersionOfPackage($package_name) + { + $repository = $this->repository['plugins']; + + if (isset($repository[$package_name])) { + return $repository[$package_name]->version; + } + + //Not a plugin, it's a theme? + $repository = $this->repository['themes']; + if (isset($repository[$package_name])) { + return $repository[$package_name]->version; + } + } + /** * Check if a Plugin or Theme is updatable * @param string $slug The slug of the package From 9a87ab1a4d0b228b8ef2514a9afb4c2d37652e54 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 17:36:57 +0100 Subject: [PATCH 11/41] Improve installDependencies() Better output, fix flow --- .../src/Grav/Console/Gpm/InstallCommand.php | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index e3ca80f7d..4f3b4b904 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -168,22 +168,27 @@ class InstallCommand extends ConsoleCommand * @throws \Exception */ public function installDependencies($dependencies, $type, $message) { - $this->output->writeln($message); $packages = array_filter($dependencies, function ($action) use ($type) { return $action === $type; }); - foreach ($packages as $dependencyName => $dependencyVersion) { - $this->output->writeln(" |- Package " . $dependencyName . ""); - } + if (count($packages) > 0) { + $this->output->writeln($message); - $helper = $this->getHelper('question'); - $question = new ConfirmationQuestion('Do you wish to update these dependencies? [y|N] ', false); - - if ($helper->ask($this->input, $this->output, $question)) { foreach ($packages as $dependencyName => $dependencyVersion) { - $this->processPackage($dependencyName); + $this->output->writeln(" |- Package " . $dependencyName . " requires a newer version"); + } + + $this->output->writeln(""); + + $helper = $this->getHelper('question'); + $question = new ConfirmationQuestion('Update these packages? [y|N] ', false); + + if ($helper->ask($this->input, $this->output, $question)) { + foreach ($packages as $dependencyName => $dependencyVersion) { + $this->processPackage($dependencyName); + } + $this->output->writeln(''); + } else { + throw new \Exception(); } - $this->output->writeln(''); - } else { - throw new \Exception(); } } From a5821948e1f368a70dcc1be1d58d67561c68f436 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 17:38:28 +0100 Subject: [PATCH 12/41] Add more logic to processDependencies() - if I already have the latest release of a package, remove the dependency - throw an exception if a required version cannot be found in the GPM yet --- .../src/Grav/Console/Gpm/InstallCommand.php | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 4f3b4b904..3514a73d5 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -208,11 +208,10 @@ class InstallCommand extends ConsoleCommand public function processDependencies($packages) { $dependencies = $this->calculateMergedDependenciesOfPackages($packages); - - //TODO: if version 0.9 is installed already, and 0.9 is required by some plugin, but 1.0 is out, don't update to 1.0, alert - foreach ($dependencies as $dependencySlug => $dependencyVersion) { + $dependencyVersion = $this->calculateVersionNumberFromDependencyVersion($dependencyVersion); + if ($this->gpm->isPluginInstalled($dependencySlug)) { // check the version, if an update is not strictly required mark as 'ignore' @@ -222,11 +221,23 @@ class InstallCommand extends ConsoleCommand $currentlyInstalledVersion = $package_yaml['version']; - if ($currentlyInstalledVersion < $dependencyVersion) { + //if I already have the latest release, remove the dependency + $latestRelease = $this->gpm->getLatestVersionOfPackage($dependencySlug); + + if (version_compare($latestRelease, $dependencyVersion) == -1) { + //throw an exception if a required version cannot be found in the GPM yet + throw new \Exception('Dependency ' . $package_yaml['name'] . ' is required in a version higher than the latest release. Try running `bin/gpm -f index` to force a refresh of the GPM cache', 1); + } + + if (version_compare($currentlyInstalledVersion, $dependencyVersion) == -1) { $dependencies[$dependencySlug] = 'update'; } else { - //TODO: check if there's really a new release, or remove - $dependencies[$dependencySlug] = 'ignore'; + + if ($currentlyInstalledVersion == $latestRelease) { + unset($dependencies[$dependencySlug]); + } else { + $dependencies[$dependencySlug] = 'ignore'; + } } } else { From 9cca14338b469c6208753ca710fedadd84861eab Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 17:38:51 +0100 Subject: [PATCH 13/41] Use proper structure --- system/src/Grav/Console/Gpm/InstallCommand.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 3514a73d5..b2a3cf7cf 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -266,10 +266,9 @@ class InstallCommand extends ConsoleCommand //Check for dependencies if (isset($packageData->dependencies_versions)) { foreach ($packageData->dependencies_versions as $dependency) { - - $current_package_name = $dependency->name; - if (isset($dependency->version)) { - $current_package_version_information = $dependency->version; + $current_package_name = $dependency['name']; + if (isset($dependency['version'])) { + $current_package_version_information = $dependency['version']; } if (!isset($dependencies[$current_package_name])) { // Dependency added for the first time From 4c7fd6866c80ff4c8e76eaa4acad8221072a13f4 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 18 Feb 2016 17:39:50 +0100 Subject: [PATCH 14/41] Use the new methods in serve() to actually process the dependencies. --- .../src/Grav/Console/Gpm/InstallCommand.php | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index b2a3cf7cf..18834d027 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -125,29 +125,42 @@ class InstallCommand extends ConsoleCommand unset($this->data['not_found']); unset($this->data['total']); + try { + $dependencies = $this->processDependencies($this->data); + } catch (\Exception $e) { + //Error out if there are incompatible packages requirements and tell which ones, and what to do + //Error out if there is any error in parsing the dependencies and their versions, and tell which one is broken + $this->output->writeln("" . $e->getMessage() . ""); + return false; + } + + //TODO: handle packages prepended with author slug. How to handle with currently installed packages? + + if ($dependencies) { + + //First, check for Grav dependency. If a dependency requires Grav > the current version, abort and tell. + if (isset($dependencies['grav'])) { + if (version_compare($this->calculateVersionNumberFromDependencyVersion($dependencies['grav']), GRAV_VERSION) === 1) { + //Needs a Grav update first + $this->output->writeln("One of the package dependencies requires Grav " . $dependencies['grav'] . ". Please update Grav first with `bin/gpm selfupgrade`"); + return false; + } + unset($dependencies['grav']); + } + + try { + $this->installDependencies($dependencies, 'install', "The following dependencies need to be installed..."); + $this->installDependencies($dependencies, 'update', "The following dependencies need to be updated..."); + $this->installDependencies($dependencies, 'ignore', "The following dependencies can be updated as there is a newer version, but it's not mandatory..."); + } catch (\Exception $e) { + $this->output->writeln("Installation aborted"); + return; + } + } + + //We're done installing dependencies. Install the actual packages foreach ($this->data as $data) { foreach ($data as $package) { - //Check for dependencies - if (isset($package->dependencies)) { - $this->output->writeln("Package " . $package->name . " has " . count($package->dependencies) . " required dependencies that must be installed first..."); - $this->output->writeln(''); - - $dependency_data = $this->gpm->findPackages($package->dependencies); - - if (!$dependency_data['total']) { - $this->output->writeln("No dependencies found..."); - $this->output->writeln(''); - } else { - unset($dependency_data['total']); - - foreach ($dependency_data as $type => $dep_data) { - foreach ($dep_data as $name => $dep_package) { - $this->processPackage($dep_package); - } - } - } - } - $this->processPackage($package); } } @@ -252,6 +265,7 @@ class InstallCommand extends ConsoleCommand * Calculates and merges the dependencies of the passed packages * * @todo handle recursive dependencies + * @todo handle alpha, beta, rc. not just numeric versions * * @param array $packages * From d67da7bed6e4d53bb369b15ae864fcd2ea0d2c5a Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 11:21:29 +0100 Subject: [PATCH 15/41] Check version only if needed --- system/src/Grav/Console/Gpm/InstallCommand.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 18834d027..5e172f70f 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -222,16 +222,13 @@ class InstallCommand extends ConsoleCommand $dependencies = $this->calculateMergedDependenciesOfPackages($packages); foreach ($dependencies as $dependencySlug => $dependencyVersion) { - - $dependencyVersion = $this->calculateVersionNumberFromDependencyVersion($dependencyVersion); - if ($this->gpm->isPluginInstalled($dependencySlug)) { + $dependencyVersion = $this->calculateVersionNumberFromDependencyVersion($dependencyVersion); // check the version, if an update is not strictly required mark as 'ignore' $locator = self::getGrav()['locator']; $blueprints_path = $locator->findResource('plugins://' . $dependencySlug . DS . 'blueprints.yaml'); $package_yaml = Yaml::parse(file_get_contents($blueprints_path)); - $currentlyInstalledVersion = $package_yaml['version']; //if I already have the latest release, remove the dependency @@ -245,14 +242,12 @@ class InstallCommand extends ConsoleCommand if (version_compare($currentlyInstalledVersion, $dependencyVersion) == -1) { $dependencies[$dependencySlug] = 'update'; } else { - if ($currentlyInstalledVersion == $latestRelease) { unset($dependencies[$dependencySlug]); } else { $dependencies[$dependencySlug] = 'ignore'; } } - } else { $dependencies[$dependencySlug] = 'install'; } From 9302610e8f38fe664f221406600e4c2b50b86d6b Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 13:50:08 +0100 Subject: [PATCH 16/41] Handle recursive dependencies --- .../src/Grav/Console/Gpm/InstallCommand.php | 167 ++++++++++-------- 1 file changed, 95 insertions(+), 72 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 5e172f70f..b382f30dd 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -27,7 +27,7 @@ class InstallCommand extends ConsoleCommand protected $data; /** - * @var + * @var GPM */ protected $gpm; @@ -126,7 +126,7 @@ class InstallCommand extends ConsoleCommand unset($this->data['total']); try { - $dependencies = $this->processDependencies($this->data); + $dependencies = $this->processDependencies($packages); } catch (\Exception $e) { //Error out if there are incompatible packages requirements and tell which ones, and what to do //Error out if there is any error in parsing the dependencies and their versions, and tell which one is broken @@ -256,6 +256,96 @@ class InstallCommand extends ConsoleCommand return $dependencies; } + /** + * Calculates and merges the dependencies of a package + * + * @param $packageName The package information + * + * @param array $dependencies The dependencies array + * + * @return array + * @throws \Exception + */ + private function calculateMergedDependenciesOfPackage($packageName, $dependencies) + { + $packageData = $this->gpm->findPackage($packageName); + + //Check for dependencies + if (isset($packageData->dependencies_versions)) { + foreach ($packageData->dependencies_versions as $dependency) { + $current_package_name = $dependency['name']; + if (isset($dependency['version'])) { + $current_package_version_information = $dependency['version']; + } + + if (!isset($dependencies[$current_package_name])) { + // Dependency added for the first time + + if (!isset($current_package_version_information)) { + $dependencies[$current_package_name] = '*'; + } else { + $dependencies[$current_package_name] = $current_package_version_information; + } + + //Factor in the package dependencies too + $this->calculateMergedDependenciesOfPackage($current_package_name, $dependencies); + } + else { + // Dependency already added by another package + + //if this package requires a version higher than the currently stored one, store this requirement instead + if (isset($current_package_version_information) && $current_package_version_information !== '*') { + + $currently_stored_version_information = $dependencies[$current_package_name]; + + $currently_stored_version_number = $this->calculateVersionNumberFromDependencyVersion($currently_stored_version_information); + + $currently_stored_version_is_in_next_significant_release_format = false; + if ($this->versionFormatIsNextSignificantRelease($currently_stored_version_information)) { + $currently_stored_version_is_in_next_significant_release_format = true; + } + + if (!$currently_stored_version_number) { + $currently_stored_version_number = '*'; + } + + $current_package_version_number = $this->calculateVersionNumberFromDependencyVersion($current_package_version_information); + if (!$current_package_version_number) { + throw new \Exception('Bad format for version of dependency ' . $current_package_name . ' for package ' . $packageName, 1); + } + + $current_package_version_is_in_next_significant_release_format = false; + if ($this->versionFormatIsNextSignificantRelease($current_package_version_information)) { + $current_package_version_is_in_next_significant_release_format = true; + } + + //If I had stored '*', change right away with the more specific version required + if ($currently_stored_version_number === '*') { + $dependencies[$current_package_name] = $current_package_version_information; + } else { + $version1 = $currently_stored_version_is_in_next_significant_release_format; + $version2 = $current_package_version_is_in_next_significant_release_format; + + if (!$version1 && !$version2) { + //Comparing versions equals or higher, a simple version_compare is enough + if (version_compare($currently_stored_version_number, $current_package_version_number) == -1) { //Current package version is higher + $dependencies[$current_package_name] = $current_package_version_information; + } + } else { + $compatible = $this->checkNextSignificantReleasesAreCompatible($currently_stored_version_number, $current_package_version_number); + if (!$compatible) { + throw new \Exception('Dependency ' . $current_package_name . ' is required in two incompatible versions', 2); + } + } + } + } + } + } + } + + return $dependencies; + } + /** * Calculates and merges the dependencies of the passed packages * @@ -269,77 +359,10 @@ class InstallCommand extends ConsoleCommand */ public function calculateMergedDependenciesOfPackages($packages) { - foreach ($packages as $data) { - foreach ($data as $packageName => $packageData) { + $dependencies = []; - //Check for dependencies - if (isset($packageData->dependencies_versions)) { - foreach ($packageData->dependencies_versions as $dependency) { - $current_package_name = $dependency['name']; - if (isset($dependency['version'])) { - $current_package_version_information = $dependency['version']; - } - - if (!isset($dependencies[$current_package_name])) { // Dependency added for the first time - - if (!isset($current_package_version_information)) { - $dependencies[$current_package_name] = '*'; - } else { - $dependencies[$current_package_name] = $current_package_version_information; - } - - } else { // Dependency already added by another package - - //if this package requires a version higher than the currently stored one, store this requirement instead - if (isset($current_package_version_information) && $current_package_version_information !== '*') { - - $currently_stored_version_information = $dependencies[$current_package_name]; - - $currently_stored_version_number = $this->calculateVersionNumberFromDependencyVersion($currently_stored_version_information); - - $currently_stored_version_is_in_next_significant_release_format = false; - if ($this->versionFormatIsNextSignificantRelease($currently_stored_version_information)) { - $currently_stored_version_is_in_next_significant_release_format = true; - } - - if (!$currently_stored_version_number) { - $currently_stored_version_number = '*'; - } - - $current_package_version_number = $this->calculateVersionNumberFromDependencyVersion($current_package_version_information); - if (!$current_package_version_number) { - throw new \Exception('Bad format for version of dependency ' . $current_package_name . ' for package ' . $packageName, 1); - } - - $current_package_version_is_in_next_significant_release_format = false; - if ($this->versionFormatIsNextSignificantRelease($current_package_version_information)) { - $current_package_version_is_in_next_significant_release_format = true; - } - - //If I had stored '*', change right away with the more specific version required - if ($currently_stored_version_number === '*') { - $dependencies[$current_package_name] = $current_package_version_information; - } else { - $version1 = $currently_stored_version_is_in_next_significant_release_format; - $version2 = $current_package_version_is_in_next_significant_release_format; - - if (!$version1 && !$version2) { - //Comparing versions equals or higher, a simple version_compare is enough - if (version_compare($currently_stored_version_number, $current_package_version_number) == -1) { //Current package version is higher - $dependencies[$current_package_name] = $current_package_version_information; - } - } else { - $compatible = $this->checkNextSignificantReleasesAreCompatible($currently_stored_version_number, $current_package_version_number); - if (!$compatible) { - throw new \Exception('Dependency ' . $current_package_name . ' is required in two incompatible versions', 2); - } - } - } - } - } - } - } - } + foreach ($packages as $package) { + $dependencies = $this->calculateMergedDependenciesOfPackage($package, $dependencies); } return $dependencies; From 05ec395f4d31477dec56ed039f36ad9afa6e6a0e Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 19:59:04 +0100 Subject: [PATCH 17/41] Allow a GPM stub, used for tests --- system/src/Grav/Console/Gpm/InstallCommand.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index b382f30dd..e11efc3ea 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -83,6 +83,11 @@ class InstallCommand extends ConsoleCommand ->setHelp('The install command allows to install plugins and themes'); } + public function setGpm($gpm) + { + $this->gpm = $gpm; + } + /** * @return int|null|void */ From 49f9cff9cdcbe9d800c36580bb6de9a9f417aa65 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 19:59:13 +0100 Subject: [PATCH 18/41] Fix getting the return value --- system/src/Grav/Console/Gpm/InstallCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index e11efc3ea..6c8b212bc 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -293,7 +293,7 @@ class InstallCommand extends ConsoleCommand } //Factor in the package dependencies too - $this->calculateMergedDependenciesOfPackage($current_package_name, $dependencies); + $dependencies = $this->calculateMergedDependenciesOfPackage($current_package_name, $dependencies); } else { // Dependency already added by another package From 2ab22e46df58a513dd1c5bd7ada92b8c716641da Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 19:59:18 +0100 Subject: [PATCH 19/41] Cleanup --- system/src/Grav/Console/Gpm/InstallCommand.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 6c8b212bc..ff4091d1e 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -264,7 +264,7 @@ class InstallCommand extends ConsoleCommand /** * Calculates and merges the dependencies of a package * - * @param $packageName The package information + * @param string $packageName The package information * * @param array $dependencies The dependencies array * @@ -277,6 +277,7 @@ class InstallCommand extends ConsoleCommand //Check for dependencies if (isset($packageData->dependencies_versions)) { + foreach ($packageData->dependencies_versions as $dependency) { $current_package_name = $dependency['name']; if (isset($dependency['version'])) { @@ -297,12 +298,10 @@ class InstallCommand extends ConsoleCommand } else { // Dependency already added by another package - //if this package requires a version higher than the currently stored one, store this requirement instead if (isset($current_package_version_information) && $current_package_version_information !== '*') { $currently_stored_version_information = $dependencies[$current_package_name]; - $currently_stored_version_number = $this->calculateVersionNumberFromDependencyVersion($currently_stored_version_information); $currently_stored_version_is_in_next_significant_release_format = false; @@ -328,10 +327,7 @@ class InstallCommand extends ConsoleCommand if ($currently_stored_version_number === '*') { $dependencies[$current_package_name] = $current_package_version_information; } else { - $version1 = $currently_stored_version_is_in_next_significant_release_format; - $version2 = $current_package_version_is_in_next_significant_release_format; - - if (!$version1 && !$version2) { + if (!$currently_stored_version_is_in_next_significant_release_format && !$current_package_version_is_in_next_significant_release_format) { //Comparing versions equals or higher, a simple version_compare is enough if (version_compare($currently_stored_version_number, $current_package_version_number) == -1) { //Current package version is higher $dependencies[$current_package_name] = $current_package_version_information; @@ -354,7 +350,6 @@ class InstallCommand extends ConsoleCommand /** * Calculates and merges the dependencies of the passed packages * - * @todo handle recursive dependencies * @todo handle alpha, beta, rc. not just numeric versions * * @param array $packages From 78864ecc037b6854188462b7b12cc949f5aaf33b Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 19:59:36 +0100 Subject: [PATCH 20/41] GpmStub in test --- .../Grav/Console/Gpm/InstallCommandTest.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index 08eccd04e..9454de7bf 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -7,6 +7,22 @@ use Grav\Console\Gpm\InstallCommand; define('EXCEPTION_BAD_FORMAT', 1); define('EXCEPTION_INCOMPATIBLE_VERSIONS', 2); +class GpmStub extends stdClass +{ + public function findPackage($packageName) + { + if (isset($this->data[$packageName])) { + return $this->data[$packageName]; + } + + } + + public function findPackages() + { + return $this->data; + } +} + /** * Class InstallCommandTest */ @@ -15,10 +31,18 @@ class InstallCommandTest extends \Codeception\TestCase\Test /** @var Grav $grav */ protected $grav; + /** @var InstallCommand */ + protected $installCommand; + + /** @var GpmStub */ + protected $gpm; + protected function _before() { $this->grav = Fixtures::get('grav'); $this->installCommand = new InstallCommand(); + + $this->gpm = new GpmStub(); } protected function _after() From 5c887495bf5e815197525cfba0977125dcef722a Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 19:59:54 +0100 Subject: [PATCH 21/41] Fix tests with GpmStub --- .../Grav/Console/Gpm/InstallCommandTest.php | 158 +++++++++--------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index 9454de7bf..3315ba9a7 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -54,113 +54,109 @@ class InstallCommandTest extends \Codeception\TestCase\Test ////////////////////////////////////////////////////////////////////////////////////////// // First working example ////////////////////////////////////////////////////////////////////////////////////////// - $this->data = [ - [ - 'admin' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "grav", "version" => ">=1.0.10"], - (object)["name" => "form", "version" => "~2.0"], - (object)["name" => "login", "version" => ">=2.0"], - (object)["name" => "errors", "version" => "*"], - (object)["name" => "problems"], - ] - ], - 'test' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=1.0"] - ] + $this->gpm->data = [ + 'admin' => (object)[ + 'dependencies_versions' => [ + ["name" => "grav", "version" => ">=1.0.10"], + ["name" => "form", "version" => "~2.0"], + ["name" => "login", "version" => ">=2.0"], + ["name" => "errors", "version" => "*"], + ["name" => "problems"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">=1.0"] + ] + ], + 'grav', + 'form' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">=3.2"] ] ] - ]; - $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + + ]; + $this->installCommand->setGpm($this->gpm); + + $packages = ['admin', 'test']; + +// dump($this->gpm->findPackages());exit(); + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($packages); $this->assertTrue(is_array($dependencies)); - $this->assertTrue(count($dependencies) == 5); + $this->assertSame(5, count($dependencies)); $this->assertTrue($dependencies['grav'] == '>=1.0.10'); - $this->assertTrue($dependencies['errors'] == '>=1.0'); - $this->assertFalse($dependencies['errors'] == '*'); - $this->assertTrue($dependencies['problems'] == '*'); + $this->assertTrue(isset($dependencies['errors'])); + $this->assertTrue(isset($dependencies['problems'])); ////////////////////////////////////////////////////////////////////////////////////////// // Second working example ////////////////////////////////////////////////////////////////////////////////////////// - $this->data = [ - [ - 'admin' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => "*"], - ] - ], - 'test' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=1.0"] - ] - ], - 'another' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=3.2"] - ] - ] - ] - ]; - - $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + $packages = ['admin', 'form']; + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($packages); $this->assertTrue(is_array($dependencies)); - $this->assertTrue(count($dependencies) == 1); + $this->assertSame(5, count($dependencies)); $this->assertTrue($dependencies['errors'] == '>=3.2'); ////////////////////////////////////////////////////////////////////////////////////////// // Third working example ////////////////////////////////////////////////////////////////////////////////////////// - $this->data = [ - [ - 'admin' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=4.0"], - ] - ], - 'test' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=1.0"] - ] - ], - 'another' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=3.2"] - ] + $this->gpm->data = [ + + 'admin' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">=4.0"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">=1.0"] + ] + ], + 'another' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">=3.2"] ] ] + ]; + $this->installCommand->setGpm($this->gpm); - $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + $packages = ['admin', 'test', 'another']; + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($packages); $this->assertTrue(is_array($dependencies)); - $this->assertTrue(count($dependencies) == 1); + $this->assertSame(1, count($dependencies)); $this->assertTrue($dependencies['errors'] == '>=4.0'); ////////////////////////////////////////////////////////////////////////////////////////// // Raise exception if no version is specified ////////////////////////////////////////////////////////////////////////////////////////// - $this->data = [ - [ - 'admin' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">=4.0"], - ] - ], - 'test' => (object)[ - 'dependencies_versions' => [ - (object)["name" => "errors", "version" => ">="] - ] - ], - ] + $this->gpm->data = [ + + 'admin' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">=4.0"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + ["name" => "errors", "version" => ">="] + ] + ], + ]; + $this->installCommand->setGpm($this->gpm); + $packages = ['admin', 'test']; try { - $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + $this->installCommand->calculateMergedDependenciesOfPackages($packages); $this->fail("Expected Exception not thrown"); } catch (Exception $e) { $this->assertEquals(EXCEPTION_BAD_FORMAT, $e->getCode()); @@ -170,23 +166,23 @@ class InstallCommandTest extends \Codeception\TestCase\Test ////////////////////////////////////////////////////////////////////////////////////////// // Raise exception if incompatible versions are specified ////////////////////////////////////////////////////////////////////////////////////////// - $this->data = [ - [ + $this->gpm->data = [ 'admin' => (object)[ 'dependencies_versions' => [ - (object)["name" => "errors", "version" => "~4.0"], + ["name" => "errors", "version" => "~4.0"], ] ], 'test' => (object)[ 'dependencies_versions' => [ - (object)["name" => "errors", "version" => "~3.0"] + ["name" => "errors", "version" => "~3.0"] ] ], - ] ]; + $this->installCommand->setGpm($this->gpm); + $packages = ['admin', 'test']; try { - $this->installCommand->calculateMergedDependenciesOfPackages($this->data); + $this->installCommand->calculateMergedDependenciesOfPackages($packages); $this->fail("Expected Exception not thrown"); } catch (Exception $e) { $this->assertEquals(EXCEPTION_INCOMPATIBLE_VERSIONS, $e->getCode()); From 30640ae8211381629f4fd504220f8a7dd68983b0 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Fri, 19 Feb 2016 19:59:59 +0100 Subject: [PATCH 22/41] Test dependencies of dependencies --- .../Grav/Console/Gpm/InstallCommandTest.php | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index 3315ba9a7..0847e7496 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -188,6 +188,50 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertEquals(EXCEPTION_INCOMPATIBLE_VERSIONS, $e->getCode()); $this->assertStringEndsWith("required in two incompatible versions", $e->getMessage()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Test dependencies of dependencies + ////////////////////////////////////////////////////////////////////////////////////////// + $this->gpm->data = [ + 'admin' => (object)[ + 'dependencies_versions' => [ + ["name" => "grav", "version" => ">=1.0.10"], + ["name" => "form", "version" => "~2.0"], + ["name" => "login", "version" => ">=2.0"], + ["name" => "errors", "version" => "*"], + ["name" => "problems"], + ] + ], + 'login' => (object)[ + 'dependencies_versions' => [ + ["name" => "antimatter", "version" => ">=1.0"] + ] + ], + 'grav', + 'antimatter' => (object)[ + 'dependencies_versions' => [ + ["name" => "something", "version" => ">=3.2"] + ] + ] + + + ]; + $this->installCommand->setGpm($this->gpm); + + $packages = ['admin']; + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($packages); + + $this->assertTrue(is_array($dependencies)); + $this->assertSame(7, count($dependencies)); + + $this->assertSame('>=1.0.10', $dependencies['grav']); + $this->assertTrue(isset($dependencies['errors'])); + $this->assertTrue(isset($dependencies['problems'])); + $this->assertTrue(isset($dependencies['antimatter'])); + $this->assertTrue(isset($dependencies['something'])); + $this->assertSame('>=3.2', $dependencies['something']); + } public function testVersionFormatIsNextSignificantRelease() From 0a5d9935b5b7dc4f475bbac9bbc6a6a564c2c452 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 22 Feb 2016 16:14:02 +0100 Subject: [PATCH 23/41] Drop processGit --- .../src/Grav/Console/Gpm/InstallCommand.php | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index ff4091d1e..4fe8dbc9e 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -644,33 +644,6 @@ class InstallCommand extends ConsoleCommand $this->output->writeln(" '- Installation failed or aborted."); } - /** - * @param $package - */ - private function processGit($package) - { - $matches = $this->getGitRegexMatches($package); - - $this->output->writeln("Preparing to Git clone " . $package->name . " from " . $matches[0]); - - $this->output->write(" |- Checking destination... "); - $checks = $this->checkDestination($package); - - if (!$checks) { - $this->output->writeln(" '- Installation failed or aborted."); - $this->output->writeln(''); - } else { - $cmd = 'cd ' . $this->destination . ' && git clone ' . $matches[0] . ' ' . $package->install_path; - exec($cmd); - - // extra white spaces to clear out the buffer properly - $this->output->writeln(" |- Cloning package... ok "); - - $this->output->writeln(" '- Success! "); - $this->output->writeln(''); - } - } - /** * @param $package */ From 6a78fa633a4eaec5258417e924ed164b68679ecb Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 22 Feb 2016 16:14:12 +0100 Subject: [PATCH 24/41] Rename method --- system/src/Grav/Console/Gpm/InstallCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 4fe8dbc9e..98422d4ec 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -647,7 +647,7 @@ class InstallCommand extends ConsoleCommand /** * @param $package */ - private function processGPM($package) + private function processGpm($package) { $version = isset($package->available) ? $package->available : $package->version; From 604b6f07f69b8776926d9d76f63e9fd47c9d9233 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 22 Feb 2016 16:14:24 +0100 Subject: [PATCH 25/41] Format vars --- .../src/Grav/Console/Gpm/InstallCommand.php | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 98422d4ec..d3a49a5bf 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -21,31 +21,22 @@ define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/ */ class InstallCommand extends ConsoleCommand { - /** - * @var - */ + /** @var */ protected $data; - /** - * @var GPM - */ + /** @var GPM */ protected $gpm; - /** - * @var - */ + /** @var */ protected $destination; - /** - * @var - */ + /** @var */ protected $file; - /** - * @var - */ + /** @var */ protected $tmp; + /** @var */ protected $local_config; /** From 01570baa6b436363afd3ceb12fc483aa68295029 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 22 Feb 2016 16:15:35 +0100 Subject: [PATCH 26/41] Ask once if should symlinks if symlinks are setup --- .../src/Grav/Console/Gpm/InstallCommand.php | 69 ++++++++----------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index d3a49a5bf..dc7448829 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -39,6 +39,9 @@ class InstallCommand extends ConsoleCommand /** @var */ protected $local_config; + /** @var bool */ + protected $use_symlinks; + /** * */ @@ -80,7 +83,7 @@ class InstallCommand extends ConsoleCommand } /** - * @return int|null|void + * @return int|null|void|bool */ protected function serve() { @@ -121,6 +124,20 @@ class InstallCommand extends ConsoleCommand unset($this->data['not_found']); unset($this->data['total']); + if (isset($this->local_config)) { + // Symlinks available, ask if Grav should use them + + $this->use_symlinks = false; + $helper = $this->getHelper('question'); + $question = new ConfirmationQuestion('Should Grav use the symlinks if available? [y|N] ', false); + + if ($helper->ask($this->input, $this->output, $question)) { + $this->use_symlinks = true; + } + } + + $this->output->writeln(''); + try { $dependencies = $this->processDependencies($packages); } catch (\Exception $e) { @@ -150,7 +167,7 @@ class InstallCommand extends ConsoleCommand $this->installDependencies($dependencies, 'ignore', "The following dependencies can be updated as there is a newer version, but it's not mandatory..."); } catch (\Exception $e) { $this->output->writeln("Installation aborted"); - return; + return false; } } @@ -446,45 +463,17 @@ class InstallCommand extends ConsoleCommand */ private function processPackage($package) { - $install_options = ['GPM']; + $this->output->writeln("fake processing"); + return; - // if no name, not found in GPM - if (!isset($package->version)) { - unset($install_options[0]); - } - // if local config found symlink is a valid option - if (isset($this->local_config) && $this->getSymlinkSource($package)) { - $install_options[] = 'Symlink'; - } - // if override set, can install via git - if (isset($package->override_repository)) { - $install_options[] = 'Git'; + $symlink = false; + if ($this->use_symlinks) { + if ($this->getSymlinkSource($package) || !isset($package->version)) { + $symlink = true; + } } - // reindex list - $install_options = array_values($install_options); - - if (count($install_options) == 0) { - // no valid install options - error and return - $this->output->writeln("not valid installation methods found!"); - - return; - } elseif (count($install_options) == 1) { - // only one option, use it... - $method = $install_options[0]; - } else { - $helper = $this->getHelper('question'); - $question = new ChoiceQuestion( - 'Please select installation method for ' . $package->name . ' (' . $install_options[0] . ' is default)', array_values($install_options), 0 - ); - $question->setErrorMessage('Method %s is invalid'); - $method = $helper->ask($this->input, $this->output, $question); - } - - $this->output->writeln(''); - - $method_name = 'process' . $method; - $this->$method_name($package); + $symlink ? $this->processSymlink($package) : $this->processGpm($package); $this->installDemoContent($package); } @@ -549,9 +538,7 @@ class InstallCommand extends ConsoleCommand */ private function getGitRegexMatches($package) { - if (isset($package->override_repository)) { - $repository = $package->override_repository; - } elseif (isset($package->repository)) { + if (isset($package->repository)) { $repository = $package->repository; } else { return false; From 8b2d72797042075b733505c92d5b19d64a0fc591 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 22 Feb 2016 16:16:00 +0100 Subject: [PATCH 27/41] Don't reinstall packages if already installed as dependencies --- system/src/Grav/Console/Gpm/InstallCommand.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index dc7448829..c09ff48de 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -173,8 +173,12 @@ class InstallCommand extends ConsoleCommand //We're done installing dependencies. Install the actual packages foreach ($this->data as $data) { - foreach ($data as $package) { - $this->processPackage($package); + foreach ($data as $packageName => $package) { + if (in_array($packageName, array_keys($dependencies))) { + $this->output->writeln("Package " . $packageName . " already installed as dependency"); + } else { + $this->processPackage($package); + } } } From 5c33bd37eb697d77e69b2e5eed90adac2e8bb73a Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 22 Feb 2016 17:12:41 +0100 Subject: [PATCH 28/41] Drop debugging placeholder --- system/src/Grav/Console/Gpm/InstallCommand.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index c09ff48de..208c97906 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -150,7 +150,6 @@ class InstallCommand extends ConsoleCommand //TODO: handle packages prepended with author slug. How to handle with currently installed packages? if ($dependencies) { - //First, check for Grav dependency. If a dependency requires Grav > the current version, abort and tell. if (isset($dependencies['grav'])) { if (version_compare($this->calculateVersionNumberFromDependencyVersion($dependencies['grav']), GRAV_VERSION) === 1) { @@ -467,9 +466,6 @@ class InstallCommand extends ConsoleCommand */ private function processPackage($package) { - $this->output->writeln("fake processing"); - return; - $symlink = false; if ($this->use_symlinks) { if ($this->getSymlinkSource($package) || !isset($package->version)) { From 8bf0f2dbabe3d8b7f3761e82e12a559878e9be0a Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 23 Feb 2016 15:43:12 +0100 Subject: [PATCH 29/41] Process available demo content after installing all packages --- .../src/Grav/Console/Gpm/InstallCommand.php | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 208c97906..31584079a 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -42,6 +42,9 @@ class InstallCommand extends ConsoleCommand /** @var bool */ protected $use_symlinks; + /** @var array */ + protected $demo_processing = []; + /** * */ @@ -147,8 +150,6 @@ class InstallCommand extends ConsoleCommand return false; } - //TODO: handle packages prepended with author slug. How to handle with currently installed packages? - if ($dependencies) { //First, check for Grav dependency. If a dependency requires Grav > the current version, abort and tell. if (isset($dependencies['grav'])) { @@ -181,6 +182,12 @@ class InstallCommand extends ConsoleCommand } } + if (count($this->demo_processing) > 0) { + foreach ($this->demo_processing as $package) { + $this->installDemoContent($package); + } + } + // clear cache after successful upgrade $this->clearCache(); } @@ -475,9 +482,16 @@ class InstallCommand extends ConsoleCommand $symlink ? $this->processSymlink($package) : $this->processGpm($package); - $this->installDemoContent($package); + $this->processDemo($package); } + private function processDemo($package) + { + $demo_dir = $this->destination . DS . $package->install_path . DS . '_demo'; + if (file_exists($demo_dir)) { + $this->demo_processing[] = $package; + } + } /** * @param $package @@ -485,10 +499,11 @@ class InstallCommand extends ConsoleCommand private function installDemoContent($package) { $demo_dir = $this->destination . DS . $package->install_path . DS . '_demo'; - $dest_dir = $this->destination . DS . 'user'; - $pages_dir = $dest_dir . DS . 'pages'; if (file_exists($demo_dir)) { + $dest_dir = $this->destination . DS . 'user'; + $pages_dir = $dest_dir . DS . 'pages'; + // Demo content exists, prompt to install it. $this->output->writeln("Attention: " . $package->name . " contains demo content"); $helper = $this->getHelper('question'); From 797e5133952ce5c3af50f41688def754b3040fdd Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 23 Feb 2016 22:07:56 +0100 Subject: [PATCH 30/41] Make sure version dependencies work with alpha / beta / rc versioning too --- .../Grav/Console/Gpm/InstallCommandTest.php | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index 0847e7496..96c524c2c 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -82,8 +82,6 @@ class InstallCommandTest extends \Codeception\TestCase\Test $packages = ['admin', 'test']; -// dump($this->gpm->findPackages());exit(); - $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($packages); $this->assertTrue(is_array($dependencies)); @@ -135,6 +133,46 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertSame(1, count($dependencies)); $this->assertTrue($dependencies['errors'] == '>=4.0'); + + + ////////////////////////////////////////////////////////////////////////////////////////// + // Test alpha / beta / rc + ////////////////////////////////////////////////////////////////////////////////////////// + $this->gpm->data = [ + 'admin' => (object)[ + 'dependencies_versions' => [ + ["name" => "package1", "version" => ">=4.0.0-rc1"], + ["name" => "package4", "version" => ">=3.2.0"], + ] + ], + 'test' => (object)[ + 'dependencies_versions' => [ + ["name" => "package1", "version" => ">=4.0.0-rc2"], + ["name" => "package2", "version" => ">=3.2.0-alpha"], + ["name" => "package3", "version" => ">=3.2.0-alpha.2"], + ["name" => "package4", "version" => ">=3.2.0-alpha"], + ] + ], + 'another' => (object)[ + 'dependencies_versions' => [ + ["name" => "package2", "version" => ">=3.2.0-beta.11"], + ["name" => "package3", "version" => ">=3.2.0-alpha.1"], + ["name" => "package4", "version" => ">=3.2.0-beta"], + ] + ] + ]; + $this->installCommand->setGpm($this->gpm); + + $packages = ['admin', 'test', 'another']; + + + $dependencies = $this->installCommand->calculateMergedDependenciesOfPackages($packages); + $this->assertTrue($dependencies['package1'] == '>=4.0.0-rc2'); + $this->assertTrue($dependencies['package2'] == '>=3.2.0-beta.11'); + $this->assertTrue($dependencies['package3'] == '>=3.2.0-alpha.2'); + $this->assertTrue($dependencies['package4'] == '>=3.2.0'); + + ////////////////////////////////////////////////////////////////////////////////////////// // Raise exception if no version is specified ////////////////////////////////////////////////////////////////////////////////////////// @@ -231,7 +269,6 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->assertTrue(isset($dependencies['antimatter'])); $this->assertTrue(isset($dependencies['something'])); $this->assertSame('>=3.2', $dependencies['something']); - } public function testVersionFormatIsNextSignificantRelease() From a83b8513f4b6c9718f940c51e2985aa95dcb3b3a Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 23 Feb 2016 22:35:51 +0100 Subject: [PATCH 31/41] Doc improvements --- system/src/Grav/Console/Gpm/InstallCommand.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 31584079a..651a4c23d 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -368,8 +368,6 @@ class InstallCommand extends ConsoleCommand /** * Calculates and merges the dependencies of the passed packages * - * @todo handle alpha, beta, rc. not just numeric versions - * * @param array $packages * * @return mixed @@ -485,6 +483,11 @@ class InstallCommand extends ConsoleCommand $this->processDemo($package); } + /** + * Add package to the queue to process the demo content, if demo content exists + * + * @param $package + */ private function processDemo($package) { $demo_dir = $this->destination . DS . $package->install_path . DS . '_demo'; @@ -494,6 +497,8 @@ class InstallCommand extends ConsoleCommand } /** + * Prompt to install the demo content of a package + * * @param $package */ private function installDemoContent($package) From 6caaeedf939b308eae037cb5b17b92257f8e7085 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 23 Feb 2016 22:41:44 +0100 Subject: [PATCH 32/41] Lint --- system/src/Grav/Console/Gpm/InstallCommand.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 651a4c23d..220e910b3 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -10,7 +10,6 @@ use Grav\Console\ConsoleCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Question\ConfirmationQuestion; -use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Yaml\Yaml; define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/(.*)/'); @@ -80,6 +79,11 @@ class InstallCommand extends ConsoleCommand ->setHelp('The install command allows to install plugins and themes'); } + /** + * Allows to set the GPM object, used for testing the class + * + * @param $gpm + */ public function setGpm($gpm) { $this->gpm = $gpm; @@ -190,6 +194,8 @@ class InstallCommand extends ConsoleCommand // clear cache after successful upgrade $this->clearCache(); + + return true; } /** From 9e6ae57caa1979823c3852e4dab04d1c56161e20 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 23 Feb 2016 22:58:51 +0100 Subject: [PATCH 33/41] Happify linter for Grav/Console --- system/src/Grav/Common/GPM/Common/Package.php | 11 ++++++++++ system/src/Grav/Console/Cli/BackupCommand.php | 3 +++ system/src/Grav/Console/Cli/CleanCommand.php | 20 ++++++++++--------- .../src/Grav/Console/Cli/ComposerCommand.php | 1 - .../Grav/Console/Cli/NewProjectCommand.php | 8 ++++---- .../src/Grav/Console/Cli/SandboxCommand.php | 20 +++++++++---------- system/src/Grav/Console/ConsoleCommand.php | 1 - system/src/Grav/Console/Gpm/InfoCommand.php | 4 ++-- .../Grav/Console/Gpm/SelfupgradeCommand.php | 2 +- system/src/Grav/Console/Gpm/UpdateCommand.php | 6 +++--- .../src/Grav/Console/Gpm/VersionCommand.php | 3 ++- 11 files changed, 46 insertions(+), 33 deletions(-) diff --git a/system/src/Grav/Common/GPM/Common/Package.php b/system/src/Grav/Common/GPM/Common/Package.php index ff9a087c9..b6dd3febd 100644 --- a/system/src/Grav/Common/GPM/Common/Package.php +++ b/system/src/Grav/Common/GPM/Common/Package.php @@ -3,6 +3,17 @@ namespace Grav\Common\GPM\Common; use Grav\Common\Data\Data; +/** + * @property string name + * @property string version + * @property string available + * @property string package_type + * @property string description_plain + * @property string slug + * @property array author + * @property mixed changelog + */ + class Package { protected $data; diff --git a/system/src/Grav/Console/Cli/BackupCommand.php b/system/src/Grav/Console/Cli/BackupCommand.php index d8b8500fb..70b621d38 100644 --- a/system/src/Grav/Console/Cli/BackupCommand.php +++ b/system/src/Grav/Console/Cli/BackupCommand.php @@ -13,7 +13,10 @@ use Symfony\Component\Console\Input\InputArgument; */ class BackupCommand extends ConsoleCommand { + /** @var string $source */ protected $source; + + /** @var ProgressBar $progress */ protected $progress; /** diff --git a/system/src/Grav/Console/Cli/CleanCommand.php b/system/src/Grav/Console/Cli/CleanCommand.php index ff6d28614..d664942bc 100644 --- a/system/src/Grav/Console/Cli/CleanCommand.php +++ b/system/src/Grav/Console/Cli/CleanCommand.php @@ -4,7 +4,6 @@ namespace Grav\Console\Cli; use Grav\Common\Filesystem\Folder; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Formatter\OutputFormatterStyle; @@ -184,6 +183,9 @@ class CleanCommand extends Command } /** + * @param InputInterface $input + * @param OutputInterface $output + * * @return int|null|void */ protected function execute(InputInterface $input, OutputInterface $output) @@ -214,7 +216,7 @@ class CleanCommand extends Command } } - /** + /** * Set colors style definition for the formatter. * * @param InputInterface $input @@ -222,16 +224,16 @@ class CleanCommand extends Command */ public function setupConsole(InputInterface $input, OutputInterface $output) { - $this->input = $input; + $this->input = $input; $this->output = $output; $this->output->getFormatter()->setStyle('normal', new OutputFormatterStyle('white')); - $this->output->getFormatter()->setStyle('yellow', new OutputFormatterStyle('yellow', null, array('bold'))); - $this->output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, array('bold'))); - $this->output->getFormatter()->setStyle('cyan', new OutputFormatterStyle('cyan', null, array('bold'))); - $this->output->getFormatter()->setStyle('green', new OutputFormatterStyle('green', null, array('bold'))); - $this->output->getFormatter()->setStyle('magenta', new OutputFormatterStyle('magenta', null, array('bold'))); - $this->output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, array('bold'))); + $this->output->getFormatter()->setStyle('yellow', new OutputFormatterStyle('yellow', null, ['bold'])); + $this->output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, ['bold'])); + $this->output->getFormatter()->setStyle('cyan', new OutputFormatterStyle('cyan', null, ['bold'])); + $this->output->getFormatter()->setStyle('green', new OutputFormatterStyle('green', null, ['bold'])); + $this->output->getFormatter()->setStyle('magenta', new OutputFormatterStyle('magenta', null, ['bold'])); + $this->output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, ['bold'])); } } diff --git a/system/src/Grav/Console/Cli/ComposerCommand.php b/system/src/Grav/Console/Cli/ComposerCommand.php index 729b425a8..259bf23c6 100644 --- a/system/src/Grav/Console/Cli/ComposerCommand.php +++ b/system/src/Grav/Console/Cli/ComposerCommand.php @@ -2,7 +2,6 @@ namespace Grav\Console\Cli; use Grav\Console\ConsoleCommand; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; /** diff --git a/system/src/Grav/Console/Cli/NewProjectCommand.php b/system/src/Grav/Console/Cli/NewProjectCommand.php index 2d63f04dd..e0854f776 100644 --- a/system/src/Grav/Console/Cli/NewProjectCommand.php +++ b/system/src/Grav/Console/Cli/NewProjectCommand.php @@ -43,17 +43,17 @@ class NewProjectCommand extends ConsoleCommand $sandboxCommand = $this->getApplication()->find('sandbox'); $installCommand = $this->getApplication()->find('install'); - $sandboxArguments = new ArrayInput(array( + $sandboxArguments = new ArrayInput([ 'command' => 'sandbox', 'destination' => $this->input->getArgument('destination'), '-s' => $this->input->getOption('symlink') - )); + ]); - $installArguments = new ArrayInput(array( + $installArguments = new ArrayInput([ 'command' => 'install', 'destination' => $this->input->getArgument('destination'), '-s' => $this->input->getOption('symlink') - )); + ]); $sandboxCommand->run($sandboxArguments, $this->output); $installCommand->run($installArguments, $this->output); diff --git a/system/src/Grav/Console/Cli/SandboxCommand.php b/system/src/Grav/Console/Cli/SandboxCommand.php index be692dc02..5fa320b67 100644 --- a/system/src/Grav/Console/Cli/SandboxCommand.php +++ b/system/src/Grav/Console/Cli/SandboxCommand.php @@ -15,7 +15,7 @@ class SandboxCommand extends ConsoleCommand /** * @var array */ - protected $directories = array( + protected $directories = [ '/backup', '/cache', '/logs', @@ -27,22 +27,22 @@ class SandboxCommand extends ConsoleCommand '/user/data', '/user/plugins', '/user/themes', - ); + ]; /** * @var array */ - protected $files = array( + protected $files = [ '/.dependencies', '/.htaccess', '/user/config/site.yaml', '/user/config/system.yaml', - ); + ]; /** * @var array */ - protected $mappings = array( + protected $mappings = [ '/.editorconfig' => '/.editorconfig', '/.gitignore' => '/.gitignore', '/CHANGELOG.md' => '/CHANGELOG.md', @@ -56,7 +56,7 @@ class SandboxCommand extends ConsoleCommand '/vendor' => '/vendor', '/webserver-configs' => '/webserver-configs', '/codeception.yml' => '/codeception.yml', - ); + ]; /** * @var string @@ -200,7 +200,7 @@ class SandboxCommand extends ConsoleCommand */ private function initFiles() { - $this->check($this->output); + $this->check(); $this->output->writeln(''); $this->output->writeln('File Initializing'); @@ -225,8 +225,6 @@ class SandboxCommand extends ConsoleCommand if (!$files_init) { $this->output->writeln(' Files already exist'); } - - } /** @@ -239,7 +237,7 @@ class SandboxCommand extends ConsoleCommand // get pages files and initialize if no pages exist $pages_dir = $this->destination . '/user/pages'; - $pages_files = array_diff(scandir($pages_dir), array('..', '.')); + $pages_files = array_diff(scandir($pages_dir), ['..', '.']); if (count($pages_files) == 0) { $destination = $this->source . '/user/pages'; @@ -269,7 +267,6 @@ class SandboxCommand extends ConsoleCommand $this->output->writeln(""); } - /** * */ @@ -295,6 +292,7 @@ class SandboxCommand extends ConsoleCommand $success = false; } } + if (!$success) { $this->output->writeln(''); $this->output->writeln('install should be run with --symlink|--s to symlink first'); diff --git a/system/src/Grav/Console/ConsoleCommand.php b/system/src/Grav/Console/ConsoleCommand.php index 349c77ac8..e75bc3537 100644 --- a/system/src/Grav/Console/ConsoleCommand.php +++ b/system/src/Grav/Console/ConsoleCommand.php @@ -3,7 +3,6 @@ namespace Grav\Console; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** diff --git a/system/src/Grav/Console/Gpm/InfoCommand.php b/system/src/Grav/Console/Gpm/InfoCommand.php index 99f8bd2e2..f52e66595 100644 --- a/system/src/Grav/Console/Gpm/InfoCommand.php +++ b/system/src/Grav/Console/Gpm/InfoCommand.php @@ -83,7 +83,7 @@ class InfoCommand extends ConsoleCommand $this->output->writeln("" . str_pad("Author", 12) . ": " . $foundPackage->author['name'] . ' <' . $foundPackage->author['email'] . '> ' . $packageURL); - foreach (array( + foreach ([ 'version', 'keywords', 'date', @@ -95,7 +95,7 @@ class InfoCommand extends ConsoleCommand 'bugs', 'zipball_url', 'license' - ) as $info) { + ] as $info) { if (isset($foundPackage->$info)) { $name = ucfirst($info); $data = $foundPackage->$info; diff --git a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php index 542878380..6178fb5ec 100644 --- a/system/src/Grav/Console/Gpm/SelfupgradeCommand.php +++ b/system/src/Grav/Console/Gpm/SelfupgradeCommand.php @@ -35,7 +35,7 @@ class SelfupgradeCommand extends ConsoleCommand /** * @var array */ - protected $types = array('plugins', 'themes'); + protected $types = ['plugins', 'themes']; /** * @var */ diff --git a/system/src/Grav/Console/Gpm/UpdateCommand.php b/system/src/Grav/Console/Gpm/UpdateCommand.php index 5ca795ea8..74bcd1be2 100644 --- a/system/src/Grav/Console/Gpm/UpdateCommand.php +++ b/system/src/Grav/Console/Gpm/UpdateCommand.php @@ -38,7 +38,7 @@ class UpdateCommand extends ConsoleCommand /** * @var array */ - protected $types = array('plugins', 'themes'); + protected $types = ['plugins', 'themes']; /** * @var GPM $gpm */ @@ -149,13 +149,13 @@ class UpdateCommand extends ConsoleCommand // finally update $install_command = $this->getApplication()->find('install'); - $args = new ArrayInput(array( + $args = new ArrayInput([ 'command' => 'install', 'package' => $slugs, '-f' => $this->input->getOption('force'), '-d' => $this->destination, '-y' => true - )); + ]); $command_exec = $install_command->run($args, $this->output); if ($command_exec != 0) { diff --git a/system/src/Grav/Console/Gpm/VersionCommand.php b/system/src/Grav/Console/Gpm/VersionCommand.php index 231645dcc..4b64586d0 100644 --- a/system/src/Grav/Console/Gpm/VersionCommand.php +++ b/system/src/Grav/Console/Gpm/VersionCommand.php @@ -70,7 +70,8 @@ class VersionCommand extends ConsoleCommand } } else { - if ($installed = $this->gpm->findPackage($package)) { + $installed = $this->gpm->findPackage($package); + if ($installed) { $name = $installed->name; $version = $installed->version; From 385c758c7783e5a0c2e3abaa73cf00e174dd1fa2 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 25 Feb 2016 12:09:08 +0100 Subject: [PATCH 34/41] dependencies_versions -> dependencies --- system/src/Grav/Console/Gpm/InstallCommand.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 220e910b3..91a0c763e 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -300,9 +300,8 @@ class InstallCommand extends ConsoleCommand $packageData = $this->gpm->findPackage($packageName); //Check for dependencies - if (isset($packageData->dependencies_versions)) { - - foreach ($packageData->dependencies_versions as $dependency) { + if (isset($packageData->dependencies)) { + foreach ($packageData->dependencies as $dependency) { $current_package_name = $dependency['name']; if (isset($dependency['version'])) { $current_package_version_information = $dependency['version']; From 7c61ed384a77348b95decde5c0a7998e88a0afd6 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 25 Feb 2016 12:57:45 +0100 Subject: [PATCH 35/41] If found, show the plugin dependent packages when uninstalling, and exit the procedure --- .../src/Grav/Console/Gpm/UninstallCommand.php | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/system/src/Grav/Console/Gpm/UninstallCommand.php b/system/src/Grav/Console/Gpm/UninstallCommand.php index dfe37e9ed..2d07242fa 100644 --- a/system/src/Grav/Console/Gpm/UninstallCommand.php +++ b/system/src/Grav/Console/Gpm/UninstallCommand.php @@ -57,6 +57,38 @@ class UninstallCommand extends ConsoleCommand ->setHelp('The uninstall command allows to uninstall plugins and themes'); } + /** + * Return the list of packages that have the passed one as dependency + * + * @param $package_slug The slug name of the package + * + * @return bool + */ + protected function getPackagesThatDependOnPackage($package_slug) + { + $plugins = $this->gpm->getInstalledPlugins(); + $themes = $this->gpm->getInstalledThemes(); + $packages = array_merge($plugins->toArray(), $themes->toArray()); + + $dependent_packages = []; + + foreach($packages as $package_name => $package) { + if (isset($package['dependencies'])) { + foreach($package['dependencies'] as $dependency) { + if (is_array($dependency)) { + $dependency = array_keys($dependency)[0]; + } + + if ($dependency == $package_slug) { + $dependent_packages[] = $package_name; + } + } + } + } + + return $dependent_packages; + } + /** * @return int|null|void */ @@ -97,6 +129,13 @@ class UninstallCommand extends ConsoleCommand foreach ($this->data as $slug => $package) { $this->output->writeln("Preparing to uninstall " . $package->name . " [v" . $package->version . "]"); + //check if there are packages that have this as a dependency. Abort and show list + $dependency_packages = $this->getPackagesThatDependOnPackage($slug); + if ($dependency_packages) { + $this->output->writeln("The installed packages " . implode(', ', $dependency_packages) . " have a dependency on this package. Please remove those first."); + $this->output->writeln(''); + exit; + } $this->output->write(" |- Checking destination... "); $checks = $this->checkDestination($slug, $package); From 072fa63067b96a63914ef662e9854a854872b44c Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 29 Feb 2016 16:14:21 +0100 Subject: [PATCH 36/41] Use the new repo versioning --- system/src/Grav/Common/GPM/Remote/Plugins.php | 2 +- system/src/Grav/Common/GPM/Remote/Themes.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/src/Grav/Common/GPM/Remote/Plugins.php b/system/src/Grav/Common/GPM/Remote/Plugins.php index 036fc0c2a..17b6a7f35 100644 --- a/system/src/Grav/Common/GPM/Remote/Plugins.php +++ b/system/src/Grav/Common/GPM/Remote/Plugins.php @@ -12,7 +12,7 @@ class Plugins extends AbstractPackageCollection */ protected $type = 'plugins'; - protected $repository = 'https://getgrav.org/downloads/plugins.json'; + protected $repository = 'https://getgrav.org/downloads/plugins.json?v=' . GRAV_VERSION; /** * Local Plugins Constructor diff --git a/system/src/Grav/Common/GPM/Remote/Themes.php b/system/src/Grav/Common/GPM/Remote/Themes.php index 43a5af54d..e5008dc87 100644 --- a/system/src/Grav/Common/GPM/Remote/Themes.php +++ b/system/src/Grav/Common/GPM/Remote/Themes.php @@ -12,7 +12,7 @@ class Themes extends AbstractPackageCollection */ protected $type = 'themes'; - protected $repository = 'https://getgrav.org/downloads/themes.json'; + protected $repository = 'https://getgrav.org/downloads/themes.json?v=' . GRAV_VERSION; /** * Local Themes Constructor From b1283004397641ce5b15aeecc83af666d666c64d Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 29 Feb 2016 16:15:43 +0100 Subject: [PATCH 37/41] Bump Grav version constant to 1.1.0-beta, to make use of the new repo versioning --- system/defines.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/defines.php b/system/defines.php index a56126901..7d1ce424a 100644 --- a/system/defines.php +++ b/system/defines.php @@ -2,7 +2,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '1.0.10'); +define('GRAV_VERSION', '1.1.0-beta'); define('DS', '/'); define('GRAV_PHP_MIN', '5.5.9'); From ff7d8a43911784a366083e6dda26142015e65d7a Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 29 Feb 2016 16:40:21 +0100 Subject: [PATCH 38/41] Rename dependencies_versions to dependencies in tests --- .../Grav/Console/Gpm/InstallCommandTest.php | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php index 96c524c2c..a9088ca11 100644 --- a/tests/unit/Grav/Console/Gpm/InstallCommandTest.php +++ b/tests/unit/Grav/Console/Gpm/InstallCommandTest.php @@ -56,7 +56,7 @@ class InstallCommandTest extends \Codeception\TestCase\Test ////////////////////////////////////////////////////////////////////////////////////////// $this->gpm->data = [ 'admin' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "grav", "version" => ">=1.0.10"], ["name" => "form", "version" => "~2.0"], ["name" => "login", "version" => ">=2.0"], @@ -65,13 +65,13 @@ class InstallCommandTest extends \Codeception\TestCase\Test ] ], 'test' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">=1.0"] ] ], 'grav', 'form' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">=3.2"] ] ] @@ -107,17 +107,17 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->gpm->data = [ 'admin' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">=4.0"], ] ], 'test' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">=1.0"] ] ], 'another' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">=3.2"] ] ] @@ -140,13 +140,13 @@ class InstallCommandTest extends \Codeception\TestCase\Test ////////////////////////////////////////////////////////////////////////////////////////// $this->gpm->data = [ 'admin' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "package1", "version" => ">=4.0.0-rc1"], ["name" => "package4", "version" => ">=3.2.0"], ] ], 'test' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "package1", "version" => ">=4.0.0-rc2"], ["name" => "package2", "version" => ">=3.2.0-alpha"], ["name" => "package3", "version" => ">=3.2.0-alpha.2"], @@ -154,7 +154,7 @@ class InstallCommandTest extends \Codeception\TestCase\Test ] ], 'another' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "package2", "version" => ">=3.2.0-beta.11"], ["name" => "package3", "version" => ">=3.2.0-alpha.1"], ["name" => "package4", "version" => ">=3.2.0-beta"], @@ -179,12 +179,12 @@ class InstallCommandTest extends \Codeception\TestCase\Test $this->gpm->data = [ 'admin' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">=4.0"], ] ], 'test' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => ">="] ] ], @@ -206,12 +206,12 @@ class InstallCommandTest extends \Codeception\TestCase\Test ////////////////////////////////////////////////////////////////////////////////////////// $this->gpm->data = [ 'admin' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => "~4.0"], ] ], 'test' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "errors", "version" => "~3.0"] ] ], @@ -232,7 +232,7 @@ class InstallCommandTest extends \Codeception\TestCase\Test ////////////////////////////////////////////////////////////////////////////////////////// $this->gpm->data = [ 'admin' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "grav", "version" => ">=1.0.10"], ["name" => "form", "version" => "~2.0"], ["name" => "login", "version" => ">=2.0"], @@ -241,13 +241,13 @@ class InstallCommandTest extends \Codeception\TestCase\Test ] ], 'login' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "antimatter", "version" => ">=1.0"] ] ], 'grav', 'antimatter' => (object)[ - 'dependencies_versions' => [ + 'dependencies' => [ ["name" => "something", "version" => ">=3.2"] ] ] From 991e4bde8f34853926ea1369a10b323103ba79d4 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Mon, 29 Feb 2016 20:48:15 +0100 Subject: [PATCH 39/41] Handle optionally uninstalling each dependency when uninstalling a package --- .../src/Grav/Console/Gpm/UninstallCommand.php | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/system/src/Grav/Console/Gpm/UninstallCommand.php b/system/src/Grav/Console/Gpm/UninstallCommand.php index 2d07242fa..0d067c060 100644 --- a/system/src/Grav/Console/Gpm/UninstallCommand.php +++ b/system/src/Grav/Console/Gpm/UninstallCommand.php @@ -129,14 +129,6 @@ class UninstallCommand extends ConsoleCommand foreach ($this->data as $slug => $package) { $this->output->writeln("Preparing to uninstall " . $package->name . " [v" . $package->version . "]"); - //check if there are packages that have this as a dependency. Abort and show list - $dependency_packages = $this->getPackagesThatDependOnPackage($slug); - if ($dependency_packages) { - $this->output->writeln("The installed packages " . implode(', ', $dependency_packages) . " have a dependency on this package. Please remove those first."); - $this->output->writeln(''); - exit; - } - $this->output->write(" |- Checking destination... "); $checks = $this->checkDestination($slug, $package); @@ -155,6 +147,7 @@ class UninstallCommand extends ConsoleCommand $this->output->writeln(''); } } + } // clear cache after successful upgrade @@ -170,6 +163,23 @@ class UninstallCommand extends ConsoleCommand */ private function uninstallPackage($slug, $package) { + //check if there are packages that have this as a dependency. Abort and show list + $dependency_packages = $this->getPackagesThatDependOnPackage($slug); + if ($dependency_packages) { + $this->output->writeln(''); + $this->output->writeln(''); + $this->output->writeln("Uninstallation failed."); + $this->output->writeln(''); + if (count($dependency_packages) > 1) { + $this->output->writeln("The installed packages " . implode(', ', $dependency_packages) . " depend on this package. Please remove those first."); + } else { + $this->output->writeln("The installed package " . implode(', ', $dependency_packages) . " depend on this package. Please remove it first."); + } + + $this->output->writeln(''); + exit; + } + $path = self::getGrav()['locator']->findResource($package->package_type . '://' .$slug); Installer::uninstall($path); $errorCode = Installer::lastErrorCode(); @@ -187,6 +197,35 @@ class UninstallCommand extends ConsoleCommand // extra white spaces to clear out the buffer properly $this->output->writeln(" |- Uninstalling package... ok "); + + if (isset($package->dependencies)) { + $questionHelper = $this->getHelper('question'); + + foreach($package->dependencies as $dependency) { + if (is_array($dependency)) { + $dependency = array_keys($dependency)[0]; + } + + $dependencyPackage = $this->gpm->findPackage($dependency); + $question = new ConfirmationQuestion(" | '- Delete dependency " . $dependency . " too? [y|N] ", false); + $answer = $questionHelper->ask($this->input, $this->output, $question); + + if ($answer) { + $this->output->writeln(" | '- You decided to delete " . $dependency . "."); + + $uninstall = $this->uninstallPackage($dependency, $dependencyPackage); + + if (!$uninstall) { + $this->output->writeln(" '- Uninstallation failed or aborted."); + $this->output->writeln(''); + } else { + $this->output->writeln(" '- Success! "); + $this->output->writeln(''); + } + } + } + } + return true; } From 0d77e310363d169b4d8a181a541885dd6b74e439 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 1 Mar 2016 11:33:21 +0100 Subject: [PATCH 40/41] Changing the month, the monthize() results changed. Take that into account for tests --- tests/unit/Grav/Common/InflectorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/Grav/Common/InflectorTest.php b/tests/unit/Grav/Common/InflectorTest.php index be6f68386..9caa3e810 100644 --- a/tests/unit/Grav/Common/InflectorTest.php +++ b/tests/unit/Grav/Common/InflectorTest.php @@ -138,9 +138,9 @@ class InflectorTest extends \Codeception\TestCase\Test public function testMonthize() { $this->assertSame(0, $this->inflector->monthize(10)); - $this->assertSame(1, $this->inflector->monthize(30)); + $this->assertSame(1, $this->inflector->monthize(33)); $this->assertSame(1, $this->inflector->monthize(41)); - $this->assertSame(11, $this->inflector->monthize(365)); + $this->assertSame(11, $this->inflector->monthize(364)); } } From cdef2e105dbd86d1f5fed266e5def15312286c95 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 1 Mar 2016 13:55:41 +0100 Subject: [PATCH 41/41] Fix error with self::getGrav() call --- system/src/Grav/Console/Gpm/InstallCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php index 91a0c763e..f8d93ae4d 100644 --- a/system/src/Grav/Console/Gpm/InstallCommand.php +++ b/system/src/Grav/Console/Gpm/InstallCommand.php @@ -5,6 +5,7 @@ use Grav\Common\Filesystem\Folder; use Grav\Common\GPM\GPM; use Grav\Common\GPM\Installer; use Grav\Common\GPM\Response; +use Grav\Common\Grav; use Grav\Common\Utils; use Grav\Console\ConsoleCommand; use Symfony\Component\Console\Input\InputArgument; @@ -255,7 +256,7 @@ class InstallCommand extends ConsoleCommand $dependencyVersion = $this->calculateVersionNumberFromDependencyVersion($dependencyVersion); // check the version, if an update is not strictly required mark as 'ignore' - $locator = self::getGrav()['locator']; + $locator = Grav::instance()['locator']; $blueprints_path = $locator->findResource('plugins://' . $dependencySlug . DS . 'blueprints.yaml'); $package_yaml = Yaml::parse(file_get_contents($blueprints_path)); $currentlyInstalledVersion = $package_yaml['version'];