Skip to content

Commit

Permalink
Merge remote-tracking branch 'github-composer/2.0' into solve-without…
Browse files Browse the repository at this point in the history
…-installed

* github-composer/2.0: (48 commits)
  Fix missing use/undefined var
  Split up steps on VCS downloaders to allow doing network operations before touching the filesystem on GitDownloader, fixes composer#7903
  Fix use statement
  Deduplicate findHeaderValue code
  Add install-path to the installed.json for every package, fixes composer#2174, closes composer#2424
  Remove unnecessary config from phpstan
  Make sure the directory exists and will not block installation later when downloading
  Avoid wiping the whole target package if download of the new one fails, refs composer#7929
  Only empty dir before actually installing packages, fixes composer#7929
  Improve output when installing packages
  Show best possible version in diagnose command
  Remove extra arg
  Allow path repos to point to their own source dir as install target, resulting in noop, fixes composer#8254
  Fix use of decodeJson
  Fix update mirrors to also update transport-options, fixes composer#7672
  Fix updating or URLs to include dist type and shasum, fixes composer#8216
  Fix origin computation
  Improve handling of non-standard ports for GitLab and GitHub installs, fixes composer#8173
  Load packages from the lock file for check-platform-reqs if no dependencies have been installed yet, fixes composer#8058
  Fix error_handler return type declaration
  ...
  • Loading branch information
naderman committed Sep 7, 2019
2 parents 06d11f2 + 607b487 commit f5e1825
Show file tree
Hide file tree
Showing 91 changed files with 1,565 additions and 516 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ matrix:
env:
- deps=high
- php: nightly
- php: 7.4snapshot
fast_finish: true
allow_failures:
- php: nightly
- php: 7.4snapshot

before_install:
# disable xdebug if available
Expand Down Expand Up @@ -62,7 +64,7 @@ script:
- ls -d tests/Composer/Test/* | grep -v TestCase.php | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml --colors=always {} || (echo -e "\e[41mFAILED\e[0m {}" && exit 1);'
# Run PHPStan
- if [[ $PHPSTAN == "1" ]]; then
composer require --dev phpstan/phpstan-shim:^0.11 --ignore-platform-reqs &&
bin/composer require --dev phpstan/phpstan-shim:^0.11 --ignore-platform-reqs &&
vendor/bin/phpstan.phar analyse src tests --configuration=phpstan/config.neon --autoload-file=phpstan/autoload.php;
fi

Expand Down
4 changes: 4 additions & 0 deletions doc/03-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ match the platform requirements of the installed packages. This can be used
to verify that a production server has all the extensions needed to run a
project after installing it for example.

Unlike update/install, this command will ignore config.platform settings and
check the real platform packages so you can be certain you have the required
platform dependencies.

## global

The global command allows you to run other commands like `install`, `remove`, `require`
Expand Down
13 changes: 13 additions & 0 deletions doc/articles/handling-private-packages-with-satis.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ Note that this will still need to pull and scan all of your VCS repositories
because any VCS repository might contain (on any branch) one of the selected
packages.

If you want to scan only the selected package and not all VCS repositories you need
to declare a *name* for all your package (this only work on VCS repositories type) :

```json
{
"repositories": [
{ "name": "company/privaterepo", "type": "vcs", "url": "https://github.com/mycompany/privaterepo" },
{ "name": "private/repo", "type": "vcs", "url": "http://svn.example.org/private/repo" },
{ "name": "mycompany/privaterepo2", "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" }
]
}
```

If you want to scan only a single repository and update all packages found in
it, pass the VCS repository URL as an optional argument:

Expand Down
1 change: 0 additions & 1 deletion phpstan/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ parameters:
- '~^Anonymous function has an unused use \$io\.$~'
- '~^Anonymous function has an unused use \$cache\.$~'
- '~^Anonymous function has an unused use \$path\.$~'
- '~^Anonymous function has an unused use \$fileName\.$~'

# ion cube is not installed
- '~^Function ioncube_loader_\w+ not found\.$~'
Expand Down
6 changes: 6 additions & 0 deletions src/Composer/Command/CheckPlatformReqsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ protected function configure()
<<<EOT
Checks that your PHP and extensions versions match the platform requirements of the installed packages.
Unlike update/install, this command will ignore config.platform settings and check the real platform packages so you can be certain you have the required platform dependencies.
<info>php composer.phar check-platform-reqs</info>
EOT
Expand All @@ -49,6 +51,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
$dependencies = $composer->getLocker()->getLockedRepository(!$input->getOption('no-dev'))->getPackages();
} else {
$dependencies = $composer->getRepositoryManager()->getLocalRepository()->getPackages();
// fallback to lockfile if installed repo is empty
if (!$dependencies) {
$dependencies = $composer->getLocker()->getLockedRepository(true)->getPackages();
}
$requires += $composer->getPackage()->getDevRequires();
}
foreach ($requires as $require => $link) {
Expand Down
6 changes: 3 additions & 3 deletions src/Composer/Command/DiagnoseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->outputResult($this->checkVersion($config));
}

$io->write(sprintf('Composer version: <comment>%s</comment>', Composer::VERSION));
$io->write(sprintf('Composer version: <comment>%s</comment>', Composer::getVersion()));

$platformOverrides = $config->get('platform') ?: array();
$platformRepo = new PlatformRepository(array(), $platformOverrides);
Expand Down Expand Up @@ -254,7 +254,7 @@ private function checkHttpProxy()

$protocol = extension_loaded('openssl') ? 'https' : 'http';
try {
$json = $this->httpDownloader->get($protocol . '://repo.packagist.org/packages.json')->parseJson();
$json = $this->httpDownloader->get($protocol . '://repo.packagist.org/packages.json')->decodeJson();
$hash = reset($json['provider-includes']);
$hash = $hash['sha256'];
$path = str_replace('%hash%', $hash, key($json['provider-includes']));
Expand Down Expand Up @@ -375,7 +375,7 @@ private function getGithubRateLimit($domain, $token = null)
}

$url = $domain === 'github.com' ? 'https://api.'.$domain.'/rate_limit' : 'https://'.$domain.'/api/rate_limit';
$data = $this->httpDownloader->get($url, array('retry-auth-failure' => false))->parseJson();
$data = $this->httpDownloader->get($url, array('retry-auth-failure' => false))->decodeJson();

return $data['resources']['core'];
}
Expand Down
22 changes: 17 additions & 5 deletions src/Composer/Command/InitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,25 @@ protected function interact(InputInterface $input, OutputInterface $output)
if ($repositories) {
$config = Factory::createConfig($io);
$repos = array(new PlatformRepository);
$createDefaultPackagistRepo = true;
foreach ($repositories as $repo) {
$repos[] = RepositoryFactory::fromString($io, $config, $repo);
$repoConfig = RepositoryFactory::configFromString($io, $config, $repo);
if (
(isset($repoConfig['packagist']) && $repoConfig === array('packagist' => false))
|| (isset($repoConfig['packagist.org']) && $repoConfig === array('packagist.org' => false))
) {
$createDefaultPackagistRepo = false;
continue;
}
$repos[] = RepositoryFactory::createRepo($io, $config, $repoConfig);
}

if ($createDefaultPackagistRepo) {
$repos[] = RepositoryFactory::createRepo($io, $config, array(
'type' => 'composer',
'url' => 'https://repo.packagist.org',
));
}
$repos[] = RepositoryFactory::createRepo($io, $config, array(
'type' => 'composer',
'url' => 'https://repo.packagist.org',
));

$this->repos = new CompositeRepository($repos);
unset($repos, $config, $repositories);
Expand Down
21 changes: 15 additions & 6 deletions src/Composer/Command/RequireCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\IO\IOInterface;
use Composer\Util\Silencer;

/**
* @author Jérémy Romey <jeremy@free-agent.fr>
Expand Down Expand Up @@ -103,11 +104,6 @@ protected function execute(InputInterface $input, OutputInterface $output)

return 1;
}
if (!is_writable($this->file)) {
$io->writeError('<error>'.$this->file.' is not writable.</error>');

return 1;
}

if (filesize($this->file) === 0) {
file_put_contents($this->file, "{\n}\n");
Expand All @@ -116,6 +112,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->json = new JsonFile($this->file);
$this->composerBackup = file_get_contents($this->json->getPath());

// check for writability by writing to the file as is_writable can not be trusted on network-mounts
// see https://github.com/composer/composer/issues/8231 and https://bugs.php.net/bug.php?id=68926
if (!is_writable($this->file) && !Silencer::call('file_put_contents', $this->file, $this->composerBackup)) {
$io->writeError('<error>'.$this->file.' is not writable.</error>');

return 1;
}

$composer = $this->getComposer(true, $input->getOption('no-plugins'));
$repos = $composer->getRepositoryManager()->getRepositories();

Expand All @@ -141,7 +145,12 @@ protected function execute(InputInterface $input, OutputInterface $output)

// validate requirements format
$versionParser = new VersionParser();
foreach ($requirements as $constraint) {
foreach ($requirements as $package => $constraint) {
if (strtolower($package) === $composer->getPackage()->getName()) {
$io->writeError(sprintf('<error>Root package \'%s\' cannot require itself in its composer.json</error>', $package));

return 1;
}
$versionParser->parseConstraints($constraint);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Composer/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,9 @@ public function getComposer($required = true, $disablePlugins = null)
public function resetComposer()
{
$this->composer = null;
if ($this->getIO() && method_exists($this->getIO(), 'resetAuthentications')) {
$this->getIO()->resetAuthentications();
}
}

/**
Expand Down
8 changes: 6 additions & 2 deletions src/Composer/DependencyResolver/RuleSetGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ protected function addRulesForPackage(PackageInterface $package, $ignorePlatform
}
}

protected function addConflictRules()
protected function addConflictRules($ignorePlatformReqs = false)
{
/** @var PackageInterface $package */
foreach ($this->addedPackages as $package) {
Expand All @@ -204,6 +204,10 @@ protected function addConflictRules()
continue;
}

if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
continue;
}

/** @var PackageInterface $possibleConflict */
foreach ($this->addedPackagesByNames[$link->getTarget()] as $possibleConflict) {
$conflictMatch = $this->pool->match($possibleConflict, $link->getTarget(), $link->getConstraint(), true);
Expand Down Expand Up @@ -305,7 +309,7 @@ public function getRulesFor(Request $request, $ignorePlatformReqs = false)

$this->addRulesForRequest($request, $ignorePlatformReqs);

$this->addConflictRules();
$this->addConflictRules($ignorePlatformReqs);

// Remove references to packages
$this->addedPackages = $this->addedPackagesByNames = null;
Expand Down
10 changes: 5 additions & 5 deletions src/Composer/Downloader/ArchiveDownloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ abstract class ArchiveDownloader extends FileDownloader
public function install(PackageInterface $package, $path, $output = true)
{
if ($output) {
$this->io->writeError(" - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
$this->io->writeError(" - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>): Extracting archive");
} else {
$this->io->writeError('Extracting archive', false);
}

$this->filesystem->emptyDirectory($path);

$temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
$fileName = $this->getFileName($package, $path);

if ($output) {
$this->io->writeError(' Extracting archive', true, IOInterface::VERBOSE);
}

try {
$this->filesystem->ensureDirectoryExists($temporaryDir);
try {
Expand Down
72 changes: 58 additions & 14 deletions src/Composer/Downloader/DownloadManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ public function getDownloaderType(DownloaderInterface $downloader)
/**
* Downloads package into target dir.
*
* @param PackageInterface $package package instance
* @param string $targetDir target dir
* @param PackageInterface $prevPackage previous package instance in case of updates
* @param PackageInterface $package package instance
* @param string $targetDir target dir
* @param PackageInterface|null $prevPackage previous package instance in case of updates
*
* @return PromiseInterface
* @throws \InvalidArgumentException if package have no urls to download from
Expand All @@ -182,7 +182,7 @@ public function download(PackageInterface $package, $targetDir, PackageInterface
$io = $this->io;
$self = $this;

$download = function ($retry = false) use (&$sources, $io, $package, $self, $targetDir, &$download) {
$download = function ($retry = false) use (&$sources, $io, $package, $self, $targetDir, &$download, $prevPackage) {
$source = array_shift($sources);
if ($retry) {
$io->writeError(' <warning>Now trying to download from ' . $source . '</warning>');
Expand Down Expand Up @@ -214,7 +214,7 @@ public function download(PackageInterface $package, $targetDir, PackageInterface
};

try {
$result = $downloader->download($package, $targetDir);
$result = $downloader->download($package, $targetDir, $prevPackage);
} catch (\Exception $e) {
return $handleError($e);
}
Expand All @@ -232,20 +232,39 @@ public function download(PackageInterface $package, $targetDir, PackageInterface
return $download();
}

/**
* Prepares an operation execution
*
* @param string $type one of install/update/uninstall
* @param PackageInterface $package package instance
* @param string $targetDir target dir
* @param PackageInterface|null $prevPackage previous package instance in case of updates
*
* @return PromiseInterface|null
*/
public function prepare($type, PackageInterface $package, $targetDir, PackageInterface $prevPackage = null)
{
$downloader = $this->getDownloaderForPackage($package);
if ($downloader) {
return $downloader->prepare($type, $package, $targetDir, $prevPackage);
}
}

/**
* Installs package into target dir.
*
* @param PackageInterface $package package instance
* @param string $targetDir target dir
*
* @return PromiseInterface|null
* @throws \InvalidArgumentException if package have no urls to download from
* @throws \RuntimeException
*/
public function install(PackageInterface $package, $targetDir)
{
$downloader = $this->getDownloaderForPackage($package);
if ($downloader) {
$downloader->install($package, $targetDir);
return $downloader->install($package, $targetDir);
}
}

Expand All @@ -256,6 +275,7 @@ public function install(PackageInterface $package, $targetDir)
* @param PackageInterface $target target package version
* @param string $targetDir target dir
*
* @return PromiseInterface|null
* @throws \InvalidArgumentException if initial package is not installed
*/
public function update(PackageInterface $initial, PackageInterface $target, $targetDir)
Expand All @@ -270,17 +290,14 @@ public function update(PackageInterface $initial, PackageInterface $target, $tar

// if we have a downloader present before, but not after, the package became a metapackage and its files should be removed
if (!$downloader) {
$initialDownloader->remove($initial, $targetDir);
return;
return $initialDownloader->remove($initial, $targetDir);
}

$initialType = $this->getDownloaderType($initialDownloader);
$targetType = $this->getDownloaderType($downloader);
if ($initialType === $targetType) {
try {
$downloader->update($initial, $target, $targetDir);

return;
return $downloader->update($initial, $target, $targetDir);
} catch (\RuntimeException $e) {
if (!$this->io->isInteractive()) {
throw $e;
Expand All @@ -294,21 +311,48 @@ public function update(PackageInterface $initial, PackageInterface $target, $tar

// if downloader type changed, or update failed and user asks for reinstall,
// we wipe the dir and do a new install instead of updating it
$initialDownloader->remove($initial, $targetDir);
$this->install($target, $targetDir);
$promise = $initialDownloader->remove($initial, $targetDir);
if ($promise) {
$self = $this;
return $promise->then(function ($res) use ($self, $target, $targetDir) {
return $self->install($target, $targetDir);
});
}

return $this->install($target, $targetDir);
}

/**
* Removes package from target dir.
*
* @param PackageInterface $package package instance
* @param string $targetDir target dir
*
* @return PromiseInterface|null
*/
public function remove(PackageInterface $package, $targetDir)
{
$downloader = $this->getDownloaderForPackage($package);
if ($downloader) {
$downloader->remove($package, $targetDir);
return $downloader->remove($package, $targetDir);
}
}

/**
* Cleans up a failed operation
*
* @param string $type one of install/update/uninstall
* @param PackageInterface $package package instance
* @param string $targetDir target dir
* @param PackageInterface|null $prevPackage previous package instance in case of updates
*
* @return PromiseInterface|null
*/
public function cleanup($type, PackageInterface $package, $targetDir, PackageInterface $prevPackage = null)
{
$downloader = $this->getDownloaderForPackage($package);
if ($downloader) {
return $downloader->cleanup($type, $package, $targetDir, $prevPackage);
}
}

Expand Down
Loading

0 comments on commit f5e1825

Please sign in to comment.