public function testRange() { $tests = [['1.2.3', '1.2.3', true], ['1.2.3', '1.2.3-0', false], ['>1.2.3', '1.2.5', true], ['>1.2.3', '1.2.2', false], ['<1.2.3', '1.2.0', true], ['<1.2.3', '1.2.5', false], ['1.2.3 - 2.3.4', '1.2.0', false], ['1.2.3 - 2.3.4', '1.2.3', true], ['1.2.3 - 2.3.4', '1.4.1', true], ['1.2.3 - 2.3.4', '2.2.0', true], ['1.2.3 - 2.3.4', '2.3.5', false], ['~1.2.3', '1.2.2', false], ['~1.2.3', '1.2.3-0', true], ['~1.2.3', '1.2.8', true], ['~1.2.3', '1.3.0-0', false], ['^1.2.3', '1.2.2', false], ['^1.2.3', '1.2.3-0', true], ['^1.2.3', '1.4.0', true], ['^1.2.3', '2.0.0-0', false], ['^1.2.3', '2.0.0-beta', false], ['^0.0.2', '0.0.1', false], ['^0.0.2', '0.0.2', true], ['^0.0.2', '0.0.3', false], ['~1.2', '1.1.5', false], ['~1.2', '1.2.0-0', true], ['~1.2', '1.3.0-0', false], ['^1.2', '1.1.9', false], ['^1.2', '1.2.0-0', true], ['^1.2', '1.9.9', true], ['^1.2', '2.0.0-0', false], ['1.2.x', '1.1.9', false], ['1.2.x', '1.2.0-0', true], ['1.2.x', '1.2.5', true], ['1.2.x', '1.3.0-0', false], ['1.2.*', '1.1.9', false], ['1.2.*', '1.2.0-0', true], ['1.2.*', '1.2.5', true], ['1.2.*', '1.3.0-0', false], ['1.2', '1.1.9', false], ['1.2', '1.2.0-0', true], ['1.2', '1.2.5', true], ['1.2', '1.3.0-0', false], ['~1', '0.9.9', false], ['~1', '1.0.0-0', true], ['~1', '1.4.5', true], ['~1', '2.0.0-0', false], ['^1', '0.9.9', false], ['^1', '1.0.0-0', true], ['^1', '1.4.5', true], ['^1', '2.0.0-0', false], ['1.x', '0.9.9', false], ['1.x', '1.0.0-0', true], ['1.x', '1.4.5', true], ['1.x', '2.0.0-0', false], ['1.*', '0.9.9', false], ['1.*', '1.0.0-0', true], ['1.*', '1.4.5', true], ['1.*', '2.0.0-0', false], ['1', '0.9.9', false], ['1', '1.0.0-0', true], ['1', '1.4.5', true], ['1', '2.0.0-0', false]]; foreach ($tests as $t) { $v = new \Gini\Version($t[1]); if ($t[2]) { $this->assertTrue($v->satisfies($t[0]), $t[1] . ' should satisfy ' . $t[0]); } else { $this->assertFalse($v->satisfies($t[0]), $t[1] . ' should not satisfy ' . $t[0]); } } }
public function actionInstall($argv) { count($argv) > 0 || APP_ID != 'gini' or die("Usage: gini index install <module> <version>\n\n"); if (!class_exists('\\Sabre\\DAV\\Client')) { self::_loadGiniComposer(); } list($options, $headers) = self::_davOptionsAndHeaders(); $client = new \Sabre\DAV\Client($options); $installedModules = []; $installModule = function ($module, $versionRange, $targetDir, $isApp = false) use(&$installModule, &$installedModules, &$client, &$options, &$headers) { if (isset($installedModules[$module])) { $info = $installedModules[$module]; $v = new \Gini\Version($info->version); // if installed version is incorrect, abort the operation. if (!$v->satisfies($versionRange)) { die("Conflict detected on {$module}! Installed: {$v->fullVersion} Expecting: {$versionRange}\n"); } } else { // try to see if we've already got it somewhere if (isset(\Gini\Core::$MODULE_INFO[$module])) { $info = \Gini\Core::$MODULE_INFO[$module]; $v = new \Gini\Version($info->version); if ($v->satisfies($versionRange)) { $matched = $v; } } // fetch index.json echo "Fetching catalog of {$module}...\n"; while (true) { $response = $client->request('GET', $module . '/index.json', null, $headers); if ($response['statusCode'] == 401 && isset($response['headers']['www-authenticate'])) { // Authentication required // prompt user/password and try again if (!isset($options['userName'])) { list($options, $headers) = self::_davOptionsAndHeaders(true); $client = new \Sabre\DAV\Client($options); continue; } $matched or die("Access denied for fetch catalog of {$module} .\n"); $response = null; } elseif ($response['statusCode'] < 200 || $response['statusCode'] > 206) { $matched or die('Error: ' . $response['statusCode'] . "\n"); $response = null; } break; } if ($response) { $indexInfo = (array) json_decode($response['body'], true); // find latest match version foreach ($indexInfo as $version => $foo) { $v = new \Gini\Version($version); if ($v->satisfies($versionRange)) { if ($matched) { if ($matched->compare($v) > 0) { continue; } } $matched = $v; } } } if (!$matched) { die("Failed to locate required version!\n"); } if (!$info || $matched->fullVersion != $info->version) { $version = $matched->fullVersion; $info = (object) $indexInfo[$version]; $tarPath = "{$module}/{$version}.tgz"; echo "Downloading {$module} from {$tarPath}...\n"; while (true) { $response = $client->request('GET', $tarPath, null, $headers); if ($response['statusCode'] == 401 && isset($response['headers']['www-authenticate'])) { // Authentication required // prompt user/password and try again if (!isset($options['userName'])) { list($options, $headers) = self::_davOptionsAndHeaders(true); $client = new \Sabre\DAV\Client($options); continue; } die("Access denied for fetch catalog of {$module}.\n"); } if ($response['statusCode'] < 200 || $response['statusCode'] > 206) { die('Error: ' . $response['statusCode'] . "\n"); } break; } if ($isApp) { $modulePath = $targetDir; } else { $modulePath = "{$targetDir}/modules/{$module}"; } if (is_dir($modulePath) && file_exists($modulePath)) { \Gini\File::removeDir($modulePath); } \Gini\File::ensureDir($modulePath); echo "Extracting {$module}...\n"; $ph = popen('tar -zx -C ' . escapeshellcmd($modulePath), 'w'); if (is_resource($ph)) { fwrite($ph, $response['body']); pclose($ph); } } else { $version = $info->version; echo "Found local copy of {$module}/{$version}.\n"; } $installedModules[$module] = $info; echo "\n"; } if ($info) { foreach ((array) $info->dependencies as $m => $r) { if ($m == 'gini') { continue; } $installModule($m, $r, $targetDir, false); } } }; if (count($argv) > 0) { // e.g. gini install xxx $module = $argv[0]; if (count($argv) > 1) { $versionRange = $argv[1]; } else { $versionRange = readline('Please provide a version constraint for the ' . $module . ' requirement:'); } $installModule($module, $versionRange, $_SERVER['PWD'] . "/{$module}", true); } else { // run: gini install, then you should be in module directory if (APP_ID != 'gini') { // try to install its dependencies $app = \Gini\Core::moduleInfo(APP_ID); $installedModules[APP_ID] = $app; $installModule(APP_ID, $app->version, APP_PATH, true); } } }