/** * Extract a ".ar" file into a given target directory * * @param string base * @param string ar * @param io.Folder target * @throws lang.IllegalStateException in case the target is not found * @throws lang.FormatException in case the .ar-file is not parseable */ protected function extract($base, $ar, Folder $target) { // Open a HTTP connection $url = new \peer\URL($base . $ar . '.ar'); $r = create(new HttpConnection($url))->get(); if (\peer\http\HttpConstants::STATUS_OK != $r->getStatusCode()) { throw new \lang\IllegalStateException(sprintf('Unexpected response %d:%s for %s', $r->getStatusCode(), $r->getMessage(), $url->getURL())); } $in = new BufferedInputStream($r->getInputStream()); do { // Seach for first section header, --[LENGTH]:[FILENAME]-- and parse it do { $line = $this->readLine($in); if (!$in->available()) { throw new \lang\FormatException('Cannot locate section header'); } } while (2 !== sscanf($line, '--%d:%[^:]--', $length, $filename)); // Calculate target file $file = new File($target, $filename); $folder = new Folder($file->getPath()); $folder->exists() || $folder->create(); \util\cmd\Console::writef(' >> [%-10s] %s (%.2f kB) [%s]%s', $ar, $filename, $length / 1024, str_repeat('.', self::PROGRESS_INDICATOR_WIDTH), str_repeat("", self::PROGRESS_INDICATOR_WIDTH + 1)); // Transfer length bytes into file $c = 0; $out = $file->getOutputStream(); $size = 0; while ($size < $length) { $chunk = $in->read(min(0x1000, $length - $size)); $size += strlen($chunk); $out->write($chunk); // Update progress $d = ceil($size / $length * self::PROGRESS_INDICATOR_WIDTH); if ($d == $c) { continue; } \util\cmd\Console::write(str_repeat('#', $d - $c)); $c = $d; } $out->close(); \util\cmd\Console::writeLine(); } while ($in->available() > 0); $in->close(); }
/** * Fetches this origin into a given target folder * * @param io.Folder $target */ public function fetchInto(Folder $target) { $r = $this->client->execute($this->release); if (200 !== $r->status()) { throw new \lang\IllegalArgumentException($r->message() . ': ' . $this->release->toString()); } $release = $r->data(); Console::writeLine('Release ', $release['version']['number'], ' published ', $release['published']); // Download files $pth = create(new File($target, 'class.pth'))->getOutputStream(); foreach ($release['files'] as $file) { $d = $this->client->execute(new RestRequest($file['link'])); $f = new File($target, $file['name']); Console::writeLine('>> ', $file['name']); $tran = new StreamTransfer($d->stream(), $f->getOutputStream()); $tran->transferAll(); $tran->close(); $ext = substr($file['name'], strrpos($file['name'], '.')); if ('.php' === $ext || '.xar' === $ext) { $pth->write($file['name'] . "\n"); } } $pth->close(); }
/** * Execute this action * * @param string[] $args command line args * @return int exit code */ public function perform($args) { if (empty($args)) { Console::$err->writeLine('*** Missing argument #1: Module name'); return 2; } sscanf($args[0], '%[^@]@%s', $name, $version); $module = Module::valueOf($name); $cwd = new Folder('.'); $base = new Folder($cwd, $module->vendor); // No version supplied -> check installation. If the module is already // installed, this is "xpi upgrade"'s job. If we have a version, the user // wants to install in parallel, so pass. if (null === $version) { $f = new File($base, $module->name . '.json'); if ($f->exists()) { Console::$err->writeLine('*** Not changing existing ', $module, '. Use "xpi upgrade"'); return 1; } } // Search for module $request = create(new RestRequest('/vendors/{vendor}/modules/{module}'))->withSegment('vendor', $module->vendor)->withSegment('module', $module->name); try { $info = $this->api->execute($request)->data(); uksort($info['releases'], function ($a, $b) { return version_compare($a, $b, '<'); }); } catch (RestException $e) { Console::$err->writeLine('*** Cannot find module ', $module, ': ', $e->getMessage()); return 3; } // Check newest version if (null === $version) { if (empty($info['releases'])) { Console::$err->writeLine('*** No releases yet for ', $module); return 1; } $version = key($info['releases']); $this->cat && $this->cat->info('Using latest release', $version); } else { if (':' === $version[0]) { $this->cat && $this->cat->info('Using development version', $version); } else { if (!isset($info['releases'][$version])) { Console::$err->writeLine('*** No such release ', $version, ' for ', $module, ', have ', $info['releases']); return 1; } $this->cat && $this->cat->info('Using version', $version); } } // Determine origin and target if (':' === $version[0]) { $branch = substr($version, 1); $target = new Folder($base, $module->name . '@' . $branch); $origin = new GitHubArchive($module->vendor, $module->name, $branch); } else { $target = new Folder($base, $module->name . '@' . $version); $origin = new XarRelease($this->api, $module->vendor, $module->name, $version); } if ($target->exists()) { Console::writeLine($module, ' already exists in ', $target); } else { Console::writeLine($module, ' -> ', $target); try { // Create and fetch into $target->create(0755); $origin->fetchInto($target); // Save module meta data unset($info['releases']); self::$json->encodeTo($info, create(new File($base, $module->name . '.json'))->getOutputStream()); } catch (\lang\Throwable $e) { Console::writeLine('*** ', $e); $target->unlink(); return 2; } } // Deselect any previously selected version foreach (new FilteredIOCollectionIterator(new FileCollection($cwd), new NameMatchesFilter('#^\\.' . $module->vendor . '\\.' . $module->name . '.*\\.pth#')) as $found) { $pth = new File($found->getURI()); Console::writeLine('Deselect ', $pth); $pth->unlink(); } // Rebuild paths based on .pth files found in newly selected $pth = new File('.' . $module->vendor . '.' . strtr($target->dirname, DIRECTORY_SEPARATOR, '.') . '.pth'); $out = $pth->getOutputStream(); $base = strtr(substr($target->getURI(), strlen($cwd->getURI())), DIRECTORY_SEPARATOR, '/'); Console::writeLine('Select ', $pth); foreach (new FilteredIOCollectionIterator(new FileCollection($target), new ExtensionEqualsFilter('.pth')) as $found) { $r = new StringReader($found->getInputStream()); while (null !== ($line = $r->readLine())) { if ('' === $line || '#' === $line[0]) { continue; } else { if ('!' === $line[0]) { $out->write('!' . $base . substr($line, 1) . "\n"); } else { $out->write($base . $line . "\n"); } } } } $out->close(); Console::writeLine('Done'); return 0; }
/** * Execute this action * * @param string[] $args command line args * @return int exit code */ public function perform($args) { if (empty($args)) { Console::$err->writeLine('*** Missing argument #1: Module name'); return 2; } sscanf($args[0], '%[^@]@%s', $name, $version); $module = Module::valueOf($name); $cwd = new Folder('.'); $vendor = new FileCollection(new Folder($cwd, $module->vendor)); $versions = new FilteredIOCollectionIterator($vendor, new NameMatchesFilter('#^' . $module->name . '@.+#')); if (null === $version) { // No version given: Remove all installed modules, and the module reference if (!$vendor->findElement($module->name . '.json')) { Console::writeLine($module, ' not installed'); return 1; } $this->removeAll($cwd, $versions); Console::writeLine('Removing module reference'); $vendor->removeElement($module->name . '.json'); } else { // Specific version given: Remove this version, if it's the last one, the // module reference, if not, select next possible one. if (!($coll = $vendor->findCollection($module->name . '@' . $version))) { Console::writeLine($module, ' not installed in version ', $version); return 1; } $active = $this->remove($cwd, $coll); if ($versions->hasNext()) { if ($active) { $next = $versions->next(); $pth = new File('.' . $module->vendor . '.' . basename($next->getURI()) . '.pth'); $out = $pth->getOutputStream(); $base = strtr(substr($next->getURI(), strlen($cwd->getURI())), DIRECTORY_SEPARATOR, '/'); Console::writeLine('Select ', $pth); foreach (new FilteredIOCollectionIterator($next, new ExtensionEqualsFilter('.pth')) as $found) { $r = new StringReader($found->getInputStream()); while (null !== ($line = $r->readLine())) { if ('' === $line || '#' === $line[0]) { continue; } else { if ('!' === $line[0]) { $out->write('!' . $base . substr($line, 1) . "\n"); } else { $out->write($base . $line . "\n"); } } } } } } else { Console::writeLine('Removing module reference'); $vendor->removeElement($module->name . '.json'); } } Console::writeLine('Done'); return 0; }
/** * Save properties to the file * * @deprecated Use store() method instead * @throws io.IOException if the property file could not be written */ public function save() { $fd = new File($this->_file); $this->store($fd->getOutputStream()); $fd->close(); }
/** * Fetches this origin into a given target folder * * @param io.Folder $target */ public function fetchInto(Folder $target) { $zip = $this->zipBallOf($this->url); $i = 0; with($iter = $zip->iterator()); $base = rtrim($iter->next()->getName() . '/', '/'); Console::write('Extracting (', $base, ') ['); while ($iter->hasNext()) { $entry = $iter->next(); $relative = str_replace($base, '', $entry->getName()); if ($entry->isDirectory()) { $folder = new Folder($target, $relative); $folder->exists() || $folder->create(0755); } else { $file = new File($target, $relative); $tran = new StreamTransfer($entry->getInputStream(), $file->getOutputStream()); $tran->transferAll(); $tran->close(); } $i++ % 10 || Console::write('.'); } $zip->close(); Console::writeLine(']'); }