diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index 86be2d7db..0b91056c7 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -194,6 +194,7 @@ class Compiler $content = str_replace('@package_version@', $this->version, $content); $content = str_replace('@package_branch_alias_version@', $this->branchAliasVersion, $content); $content = str_replace('@release_date@', $this->versionDate->format('Y-m-d H:i:s'), $content); + $content = preg_replace('{SOURCE_VERSION = \'[^\']+\';}', 'SOURCE_VERSION = \'\';', $content); } $phar->addFromString($path, $content); diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index c1a61545c..b5bbb0a0b 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -29,10 +29,46 @@ use Composer\Package\Archiver\ArchiveManager; */ class Composer { + /* + * Examples of the following constants in the various configurations they can be in + * + * releases (phar): + * const VERSION = '1.8.2'; + * const BRANCH_ALIAS_VERSION = ''; + * const RELEASE_DATE = '2019-01-29 15:00:53'; + * const SOURCE_VERSION = ''; + * + * snapshot builds (phar): + * const VERSION = 'd3873a05650e168251067d9648845c220c50e2d7'; + * const BRANCH_ALIAS_VERSION = '1.9-dev'; + * const RELEASE_DATE = '2019-02-20 07:43:56'; + * const SOURCE_VERSION = ''; + * + * source (git clone): + * const VERSION = '@package_version@'; + * const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; + * const RELEASE_DATE = '@release_date@'; + * const SOURCE_VERSION = '1.8-dev+source'; + */ const VERSION = '@package_version@'; const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@'; const RELEASE_DATE = '@release_date@'; - const SOURCE_VERSION = '2.0-source'; + const SOURCE_VERSION = '2.0-dev+source'; + + public static function getVersion() + { + // no replacement done, this must be a source checkout + if (self::VERSION === '@package_version'.'@') { + return self::SOURCE_VERSION; + } + + // we have a branch alias and version is a commit id, this must be a snapshot build + if (self::BRANCH_ALIAS_VERSION !== '' && preg_match('{^[a-f0-9]{40}$}', self::VERSION)) { + return self::BRANCH_ALIAS_VERSION.'+'.self::VERSION; + } + + return self::VERSION; + } /** * @var Package\RootPackageInterface diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 64a32b46f..a91f96f0d 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -91,7 +91,7 @@ class Application extends BaseApplication $this->io = new NullIO(); - parent::__construct('Composer', Composer::VERSION); + parent::__construct('Composer', Composer::getVersion()); } /** @@ -190,7 +190,7 @@ class Application extends BaseApplication if (!$isProxyCommand) { $io->writeError(sprintf( 'Running %s (%s) with %s on %s', - Composer::VERSION, + Composer::getVersion(), Composer::RELEASE_DATE, defined('HHVM_VERSION') ? 'HHVM '.HHVM_VERSION : 'PHP '.PHP_VERSION, function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknown OS' @@ -440,7 +440,7 @@ class Application extends BaseApplication */ public function getLongVersion() { - if (Composer::BRANCH_ALIAS_VERSION) { + if (Composer::BRANCH_ALIAS_VERSION && Composer::BRANCH_ALIAS_VERSION !== '@package_branch_alias_version'.'@') { return sprintf( '%s version %s (%s) %s', $this->getName(), diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php index aa8abc5c9..2d069fdbc 100644 --- a/src/Composer/Downloader/PathDownloader.php +++ b/src/Composer/Downloader/PathDownloader.php @@ -189,24 +189,21 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter } /** - * Returns true if junctions can be safely used on Windows + * Returns true if junctions can be created and safely used on Windows * * A PHP bug makes junction detection fragile, leading to possible data loss * when removing a package. See https://bugs.php.net/bug.php?id=77552 * * For safety we require a minimum version of Windows 7, so we can call the - * system rmdir which can detect junctions and not delete target content. + * system rmdir which will preserve target content if given a junction. + * + * The PHP bug was fixed in 7.2.16 and 7.3.3 (requires at least Windows 7). * * @return bool */ private function safeJunctions() { - // Bug fixed in 7.3.3 and 7.2.16 - if (PHP_VERSION_ID >= 70303 || (PHP_VERSION_ID >= 70216 && PHP_VERSION_ID < 70300)) { - return true; - } - - // Windows 7 is version 6.1 + // We need to call mklink, and rmdir on Windows 7 (version 6.1) return function_exists('proc_open') && (PHP_WINDOWS_VERSION_MAJOR > 6 || (PHP_WINDOWS_VERSION_MAJOR === 6 && PHP_WINDOWS_VERSION_MINOR >= 1)); diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index f12c85b85..e835e221b 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -19,6 +19,7 @@ use Composer\Package\Version\VersionParser; use Composer\Json\JsonFile; use Composer\Cache; use Composer\Config; +use Composer\Composer; use Composer\Factory; use Composer\IO\IOInterface; use Composer\Util\HttpDownloader; @@ -961,12 +962,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - if (!empty($data['warning'])) { - $this->io->writeError('Warning from '.$this->url.': '.$data['warning'].''); - } - if (!empty($data['info'])) { - $this->io->writeError('Info from '.$this->url.': '.$data['info'].''); - } + $this->outputWarnings($data); if ($cacheKey) { if ($storeLastModifiedTime) { @@ -1040,12 +1036,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - if (!empty($data['warning'])) { - $this->io->writeError('Warning from '.$this->url.': '.$data['warning'].''); - } - if (!empty($data['info'])) { - $this->io->writeError('Info from '.$this->url.': '.$data['info'].''); - } + $this->outputWarnings($data); $lastModifiedDate = $response->getHeader('last-modified'); $response->collect(); @@ -1110,12 +1101,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - if (!empty($data['warning'])) { - $io->writeError('Warning from '.$url.': '.$data['warning'].''); - } - if (!empty($data['info'])) { - $io->writeError('Info from '.$url.': '.$data['info'].''); - } + $this->outputWarnings($data); $lastModifiedDate = $response->getHeader('last-modified'); $response->collect(); @@ -1175,4 +1161,24 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito // wipe rootData as it is fully consumed at this point and this saves some memory $this->rootData = true; } + + private function outputWarnings($data) + { + foreach (array('warning', 'info') as $type) { + if (empty($data[$type])) { + continue; + } + + if (!empty($data[$type . '-versions'])) { + $versionParser = new VersionParser(); + $constraint = $versionParser->parseConstraints($data[$type . '-versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + } + + $this->io->writeError('<'.$type.'>'.ucfirst($type).' from '.$this->url.': '.$data[$type].''); + } + } } diff --git a/src/Composer/Repository/FilesystemRepository.php b/src/Composer/Repository/FilesystemRepository.php index bde55aad3..204aa095d 100644 --- a/src/Composer/Repository/FilesystemRepository.php +++ b/src/Composer/Repository/FilesystemRepository.php @@ -51,6 +51,11 @@ class FilesystemRepository extends WritableArrayRepository try { $packages = $this->file->read(); + // forward compatibility for composer v2 installed.json + if (isset($packages['packages'])) { + $packages = $packages['packages']; + } + if (!is_array($packages)) { throw new \UnexpectedValueException('Could not parse package list from the repository'); } diff --git a/src/Composer/Repository/Vcs/BitbucketDriver.php b/src/Composer/Repository/Vcs/BitbucketDriver.php index bde4fc1b7..6405d3bb3 100644 --- a/src/Composer/Repository/Vcs/BitbucketDriver.php +++ b/src/Composer/Repository/Vcs/BitbucketDriver.php @@ -125,50 +125,52 @@ abstract class BitbucketDriver extends VcsDriver $composer = $this->getBaseComposerInformation($identifier); - // specials for bitbucket - if (!isset($composer['support']['source'])) { - $label = array_search( - $identifier, - $this->getTags() - ) ?: array_search( - $identifier, - $this->getBranches() - ) ?: $identifier; + if ($composer) { + // specials for bitbucket + if (!isset($composer['support']['source'])) { + $label = array_search( + $identifier, + $this->getTags() + ) ?: array_search( + $identifier, + $this->getBranches() + ) ?: $identifier; - if (array_key_exists($label, $tags = $this->getTags())) { - $hash = $tags[$label]; - } elseif (array_key_exists($label, $branches = $this->getBranches())) { - $hash = $branches[$label]; + if (array_key_exists($label, $tags = $this->getTags())) { + $hash = $tags[$label]; + } elseif (array_key_exists($label, $branches = $this->getBranches())) { + $hash = $branches[$label]; + } + + if (! isset($hash)) { + $composer['support']['source'] = sprintf( + 'https://%s/%s/%s/src', + $this->originUrl, + $this->owner, + $this->repository + ); + } else { + $composer['support']['source'] = sprintf( + 'https://%s/%s/%s/src/%s/?at=%s', + $this->originUrl, + $this->owner, + $this->repository, + $hash, + $label + ); + } } - - if (! isset($hash)) { - $composer['support']['source'] = sprintf( - 'https://%s/%s/%s/src', + if (!isset($composer['support']['issues']) && $this->hasIssues) { + $composer['support']['issues'] = sprintf( + 'https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository ); - } else { - $composer['support']['source'] = sprintf( - 'https://%s/%s/%s/src/%s/?at=%s', - $this->originUrl, - $this->owner, - $this->repository, - $hash, - $label - ); } - } - if (!isset($composer['support']['issues']) && $this->hasIssues) { - $composer['support']['issues'] = sprintf( - 'https://%s/%s/%s/issues', - $this->originUrl, - $this->owner, - $this->repository - ); - } - if (!isset($composer['homepage'])) { - $composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website; + if (!isset($composer['homepage'])) { + $composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website; + } } $this->infoCache[$identifier] = $composer; diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 0a166c7b0..ee6456a89 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -154,8 +154,8 @@ class GitHubDriver extends VcsDriver } $composer = $this->getBaseComposerInformation($identifier); - if ($composer) { + if ($composer) { // specials for github if (!isset($composer['support']['source'])) { $label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier; diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index f39c6dd38..09291a908 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -164,7 +164,7 @@ final class StreamContextFactory if (!isset($options['http']['header']) || false === stripos(implode('', $options['http']['header']), 'user-agent')) { $options['http']['header'][] = sprintf( 'User-Agent: Composer/%s (%s; %s; %s; %s%s)', - Composer::VERSION === '@package_version@' ? Composer::SOURCE_VERSION : Composer::VERSION, + Composer::getVersion(), function_exists('php_uname') ? php_uname('s') : 'Unknown', function_exists('php_uname') ? php_uname('r') : 'Unknown', $phpVersion,