/** * {@inheritDoc} */ public function initialize() { if (Filesystem::isLocalPath($this->url)) { $this->url = preg_replace('{[\\/]\\.git/?$}', '', $this->url); $this->repoDir = $this->url; $cacheUrl = realpath($this->url); } else { $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/'; GitUtil::cleanEnv(); $fs = new Filesystem(); $fs->ensureDirectoryExists(dirname($this->repoDir)); if (!is_writable(dirname($this->repoDir))) { throw new \RuntimeException('Can not clone ' . $this->url . ' to access package information. The "' . dirname($this->repoDir) . '" directory is not writable by the current user.'); } if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) { throw new \InvalidArgumentException('The source URL ' . $this->url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); } $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs); if (!$gitUtil->syncMirror($this->url, $this->repoDir)) { $this->io->writeError('<error>Failed to update ' . $this->url . ', package information from this repository may be outdated</error>'); } $cacheUrl = $this->url; } $this->getTags(); $this->getBranches(); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl)); }
private function guessGitVersion(array $packageConfig, $path) { GitUtil::cleanEnv(); $commit = null; $version = null; $prettyVersion = null; // try to fetch current version from git branch if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output, $path)) { $branches = array(); $isFeatureBranch = false; // find current branch and collect all branch names foreach ($this->process->splitLines($output) as $branch) { if ($branch && preg_match('{^(?:\\* ) *(\\(no branch\\)|\\(detached from \\S+\\)|\\S+) *([a-f0-9]+) .*$}', $branch, $match)) { if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') { $version = 'dev-' . $match[2]; $prettyVersion = $version; $isFeatureBranch = true; } else { $version = $this->versionParser->normalizeBranch($match[1]); $prettyVersion = 'dev-' . $match[1]; $isFeatureBranch = 0 === strpos($version, 'dev-'); if ('9999999-dev' === $version) { $version = $prettyVersion; } } if ($match[2]) { $commit = $match[2]; } } if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) { if (preg_match('{^(?:\\* )? *(\\S+) *([a-f0-9]+) .*$}', $branch, $match)) { $branches[] = $match[1]; } } } if ($isFeatureBranch) { // try to find the best (nearest) version branch to assume this feature's version $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path); $version = $result['version']; $prettyVersion = $result['pretty_version']; } } if (!$version) { $result = $this->versionFromGitTags($path); if ($result) { $version = $result['version']; $prettyVersion = $result['pretty_version']; } } if (!$commit) { $command = 'git log --pretty="%H" -n1 HEAD'; if (0 === $this->process->execute($command, $output, $path)) { $commit = trim($output) ?: null; } } return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion); }
protected function cleanChanges(PackageInterface $package, $path, $update) { GitUtil::cleanEnv(); $path = $this->normalizePath($path); if (!($changes = $this->getLocalChanges($package, $path))) { return; } if (!$this->io->isInteractive()) { $discardChanges = $this->config->get('discard-changes'); if (true === $discardChanges) { return $this->discardChanges($path); } if ('stash' === $discardChanges) { if (!$update) { return parent::cleanChanges($package, $path, $update); } return $this->stashChanges($path); } return parent::cleanChanges($package, $path, $update); } $changes = array_map(function ($elem) { return ' ' . $elem; }, preg_split('{\\s*\\r?\\n\\s*}', $changes)); $this->io->writeError(' <error>The package has modified files:</error>'); $this->io->writeError(array_slice($changes, 0, 10)); if (count($changes) > 10) { $this->io->writeError(' <info>' . count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>'); } while (true) { switch ($this->io->ask(' <info>Discard changes [y,n,v,' . ($update ? 's,' : '') . '?]?</info> ', '?')) { case 'y': $this->discardChanges($path); break 2; case 's': if (!$update) { goto help; } $this->stashChanges($path); break 2; case 'n': throw new \RuntimeException('Update aborted'); case 'v': $this->io->writeError($changes); break; case '?': default: help: $this->io->writeError(array(' y - discard changes and apply the ' . ($update ? 'update' : 'uninstall'), ' n - abort the ' . ($update ? 'update' : 'uninstall') . ' and let you manually clean things up', ' v - view modified files')); if ($update) { $this->io->writeError(' s - stash changes and try to reapply them after the update'); } $this->io->writeError(' ? - print help'); break; } } }
/** * {@inheritDoc} */ public function initialize() { if (static::isLocalUrl($this->url)) { $this->repoDir = str_replace('file://', '', $this->url); } else { $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/'; $util = new GitUtil(); $util->cleanEnv(); $fs = new Filesystem(); $fs->ensureDirectoryExists(dirname($this->repoDir)); if (!is_writable(dirname($this->repoDir))) { throw new \RuntimeException('Can not clone ' . $this->url . ' to access package information. The "' . dirname($this->repoDir) . '" directory is not writable by the current user.'); } if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) { throw new \InvalidArgumentException('The source URL ' . $this->url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); } // update the repo if it is a valid git repository if (is_dir($this->repoDir) && 0 === $this->process->execute('git remote', $output, $this->repoDir)) { if (0 !== $this->process->execute('git remote update --prune origin', $output, $this->repoDir)) { $this->io->write('<error>Failed to update ' . $this->url . ', package information from this repository may be outdated (' . $this->process->getErrorOutput() . ')</error>'); } } else { // clean up directory and do a fresh clone into it $fs->removeDirectory($this->repoDir); $command = sprintf('git clone --mirror %s %s', escapeshellarg($this->url), escapeshellarg($this->repoDir)); if (0 !== $this->process->execute($command, $output)) { $output = $this->process->getErrorOutput(); if (0 !== $this->process->execute('git --version', $ignoredOutput)) { throw new \RuntimeException('Failed to clone ' . $this->url . ', git was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()); } if ($this->io->isInteractive() && preg_match('{(https?://)([^/]+)(.*)$}i', $this->url, $match) && strpos($output, 'fatal: Authentication failed') !== false) { if ($this->io->hasAuthentication($match[2])) { $auth = $this->io->getAuthentication($match[2]); } else { $this->io->write($this->url . ' requires Authentication'); $auth = array('username' => $this->io->ask('Username: '******'password' => $this->io->askAndHideAnswer('Password: '******'username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . $match[3]; $command = sprintf('git clone --mirror %s %s', escapeshellarg($url), escapeshellarg($this->repoDir)); if (0 === $this->process->execute($command, $output)) { $this->io->setAuthentication($match[2], $auth['username'], $auth['password']); } else { $output = $this->process->getErrorOutput(); throw new \RuntimeException('Failed to clone ' . $this->url . ', could not read packages from it' . "\n\n" . $output); } } else { throw new \RuntimeException('Failed to clone ' . $this->url . ', could not read packages from it' . "\n\n" . $output); } } } } $this->getTags(); $this->getBranches(); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url)); }
private function guessGitVersion(array $packageConfig, $path) { GitUtil::cleanEnv(); // try to fetch current version from git tags if (0 === $this->process->execute('git describe --exact-match --tags', $output, $path)) { try { return $this->versionParser->normalize(trim($output)); } catch (\Exception $e) { } } // try to fetch current version from git branch if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output, $path)) { $branches = array(); $isFeatureBranch = false; $version = null; // find current branch and collect all branch names foreach ($this->process->splitLines($output) as $branch) { if ($branch && preg_match('{^(?:\\* ) *(\\(no branch\\)|\\(detached from \\S+\\)|\\S+) *([a-f0-9]+) .*$}', $branch, $match)) { if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') { $version = 'dev-' . $match[2]; $isFeatureBranch = true; } else { $version = $this->versionParser->normalizeBranch($match[1]); $isFeatureBranch = 0 === strpos($version, 'dev-'); if ('9999999-dev' === $version) { $version = 'dev-' . $match[1]; } } } if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) { if (preg_match('{^(?:\\* )? *(\\S+) *([a-f0-9]+) .*$}', $branch, $match)) { $branches[] = $match[1]; } } } if (!$isFeatureBranch) { return $version; } // try to find the best (nearest) version branch to assume this feature's version $version = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path); return $version; } }
/** * {@inheritDoc} */ public function initialize() { if (Filesystem::isLocalPath($this->url)) { $this->url = preg_replace('{[\\/]\\.git/?$}', '', $this->url); $this->repoDir = $this->url; $cacheUrl = realpath($this->url); } else { $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/'; GitUtil::cleanEnv(); $fs = new Filesystem(); $fs->ensureDirectoryExists(dirname($this->repoDir)); if (!is_writable(dirname($this->repoDir))) { throw new \RuntimeException('Can not clone ' . $this->url . ' to access package information. The "' . dirname($this->repoDir) . '" directory is not writable by the current user.'); } if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) { throw new \InvalidArgumentException('The source URL ' . $this->url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); } $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs); // update the repo if it is a valid git repository if (is_dir($this->repoDir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $this->repoDir) && trim($output) === '.') { try { $commandCallable = function ($url) { return sprintf('git remote set-url origin %s && git remote update --prune origin', ProcessExecutor::escape($url)); }; $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir); } catch (\Exception $e) { $this->io->writeError('<error>Failed to update ' . $this->url . ', package information from this repository may be outdated (' . $e->getMessage() . ')</error>'); } } else { // clean up directory and do a fresh clone into it $fs->removeDirectory($this->repoDir); $repoDir = $this->repoDir; $commandCallable = function ($url) use($repoDir) { return sprintf('git clone --mirror %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); }; $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir, true); } $cacheUrl = $this->url; } $this->getTags(); $this->getBranches(); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl)); }
public function initialize() { if (static::isLocalUrl($this->url)) { $this->repoDir = str_replace('file://', '', $this->url); } else { $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/'; $util = new GitUtil(); $util->cleanEnv(); $fs = new Filesystem(); $fs->ensureDirectoryExists(dirname($this->repoDir)); if (!is_writable(dirname($this->repoDir))) { throw new \RuntimeException('Can not clone ' . $this->url . ' to access package information. The "' . dirname($this->repoDir) . '" directory is not writable by the current user.'); } if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) { throw new \InvalidArgumentException('The source URL ' . $this->url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); } if (is_dir($this->repoDir) && 0 === $this->process->execute('git remote', $output, $this->repoDir)) { if (0 !== $this->process->execute('git remote update --prune origin', $output, $this->repoDir)) { $this->io->write('<error>Failed to update ' . $this->url . ', package information from this repository may be outdated (' . $this->process->getErrorOutput() . ')</error>'); } } else { $fs->removeDirectory($this->repoDir); $command = sprintf('git clone --mirror %s %s', escapeshellarg($this->url), escapeshellarg($this->repoDir)); if (0 !== $this->process->execute($command, $output)) { $output = $this->process->getErrorOutput(); if (0 !== $this->process->execute('git --version', $ignoredOutput)) { throw new \RuntimeException('Failed to clone ' . $this->url . ', git was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()); } throw new \RuntimeException('Failed to clone ' . $this->url . ', could not read packages from it' . "\n\n" . $output); } } } $this->getTags(); $this->getBranches(); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url)); }
private function guessGitVersion(array $config) { $util = new GitUtil(); $util->cleanEnv(); if (0 === $this->process->execute('git describe --exact-match --tags', $output)) { try { return $this->versionParser->normalize(trim($output)); } catch (\Exception $e) { } } if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output)) { $branches = array(); $isFeatureBranch = false; $version = null; foreach ($this->process->splitLines($output) as $branch) { if ($branch && preg_match('{^(?:\\* ) *(\\(no branch\\)|\\(detached from [a-f0-9]+\\)|\\S+) *([a-f0-9]+) .*$}', $branch, $match)) { if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') { $version = 'dev-' . $match[2]; $isFeatureBranch = true; } else { $version = $this->versionParser->normalizeBranch($match[1]); $isFeatureBranch = 0 === strpos($version, 'dev-'); if ('9999999-dev' === $version) { $version = 'dev-' . $match[1]; } } } if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) { if (preg_match('{^(?:\\* )? *(\\S+) *([a-f0-9]+) .*$}', $branch, $match)) { $branches[] = $match[1]; } } } if (!$isFeatureBranch) { return $version; } $version = $this->guessFeatureVersion($config, $version, $branches, 'git rev-list %candidate%..%branch%'); return $version; } }
/** * Returns the packages's datetime for its source reference. * * @param PackageInterface $package The package to scan. * @return string|null The formatted datetime or null if none was found. */ private function getPackageTime(PackageInterface $package) { if (!function_exists('proc_open')) { return null; } $path = realpath($this->installationManager->getInstallPath($package)); $sourceType = $package->getSourceType(); $datetime = null; if ($path && in_array($sourceType, array('git', 'hg'))) { $sourceRef = $package->getSourceReference() ?: $package->getDistReference(); switch ($sourceType) { case 'git': $util = new GitUtil(); $util->cleanEnv(); if (0 === $this->process->execute('git log -n1 --pretty=%ct ' . escapeshellarg($sourceRef), $output, $path) && preg_match('{^\\s*\\d+\\s*$}', $output)) { $datetime = new \DateTime('@' . trim($output), new \DateTimeZone('UTC')); } break; case 'hg': if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r ' . escapeshellarg($sourceRef), $output, $path) && preg_match('{^\\s*(\\d+)\\s*}', $output, $match)) { $datetime = new \DateTime('@' . $match[1], new \DateTimeZone('UTC')); } break; } } return $datetime ? $datetime->format('Y-m-d H:i:s') : null; }
protected function cleanEnv() { $util = new GitUtil(); $util->cleanEnv(); }
public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url) { GitUtil::cleanEnv(); $path = $this->normalizePath($path); if (!$this->isRepositoryCloned($path)) { //clone the multi repository if it was removed $this->io->write(' Multi-repository GIT directory not found. Cloning...'); $this->cloneRepository($initial, $path, $url); } parent::doUpdate($initial, $target, $path, $url); //copy file into required directory $this->copyFilesToDefaultPath($this->normalizePath($path)); }