|
@@ -20,9 +20,11 @@ use Packagist\WebBundle\Entity\Package;
|
|
use Packagist\WebBundle\Package\Updater;
|
|
use Packagist\WebBundle\Package\Updater;
|
|
use Packagist\WebBundle\Entity\Job;
|
|
use Packagist\WebBundle\Entity\Job;
|
|
use Packagist\WebBundle\Model\PackageManager;
|
|
use Packagist\WebBundle\Model\PackageManager;
|
|
|
|
+use Packagist\WebBundle\Model\DownloadManager;
|
|
use Seld\Signal\SignalHandler;
|
|
use Seld\Signal\SignalHandler;
|
|
use Composer\Factory;
|
|
use Composer\Factory;
|
|
use Composer\Downloader\TransportException;
|
|
use Composer\Downloader\TransportException;
|
|
|
|
+use Composer\Util\RemoteFilesystem;
|
|
|
|
|
|
class UpdaterWorker
|
|
class UpdaterWorker
|
|
{
|
|
{
|
|
@@ -33,6 +35,7 @@ class UpdaterWorker
|
|
/** @var Scheduler */
|
|
/** @var Scheduler */
|
|
private $scheduler;
|
|
private $scheduler;
|
|
private $packageManager;
|
|
private $packageManager;
|
|
|
|
+ private $downloadManager;
|
|
|
|
|
|
public function __construct(
|
|
public function __construct(
|
|
LoggerInterface $logger,
|
|
LoggerInterface $logger,
|
|
@@ -40,7 +43,8 @@ class UpdaterWorker
|
|
Updater $updater,
|
|
Updater $updater,
|
|
Locker $locker,
|
|
Locker $locker,
|
|
Scheduler $scheduler,
|
|
Scheduler $scheduler,
|
|
- PackageManager $packageManager
|
|
|
|
|
|
+ PackageManager $packageManager,
|
|
|
|
+ DownloadManager $downloadManager
|
|
) {
|
|
) {
|
|
$this->logger = $logger;
|
|
$this->logger = $logger;
|
|
$this->doctrine = $doctrine;
|
|
$this->doctrine = $doctrine;
|
|
@@ -48,6 +52,7 @@ class UpdaterWorker
|
|
$this->locker = $locker;
|
|
$this->locker = $locker;
|
|
$this->scheduler = $scheduler;
|
|
$this->scheduler = $scheduler;
|
|
$this->packageManager = $packageManager;
|
|
$this->packageManager = $packageManager;
|
|
|
|
+ $this->downloadManager = $downloadManager;
|
|
}
|
|
}
|
|
|
|
|
|
public function process(Job $job, SignalHandler $signal): array
|
|
public function process(Job $job, SignalHandler $signal): array
|
|
@@ -91,13 +96,23 @@ class UpdaterWorker
|
|
$repository->setLoader($loader);
|
|
$repository->setLoader($loader);
|
|
|
|
|
|
// perform the actual update (fetch and re-scan the repository's source)
|
|
// perform the actual update (fetch and re-scan the repository's source)
|
|
- $this->updater->update($io, $config, $package, $repository, $flags);
|
|
|
|
|
|
+ $package = $this->updater->update($io, $config, $package, $repository, $flags);
|
|
|
|
+
|
|
|
|
+ // github update downgraded to a git clone, this should not happen, so check through API whether the package still exists
|
|
|
|
+ if (preg_match('{[@/]github.com[:/]([^/]+/[^/]+?)(\.git)?$}i', $package->getRepository(), $match) && 0 === strpos($repository->getDriver()->getUrl(), 'git@')) {
|
|
|
|
+ if ($result = $this->checkForDeadGitHubPackage($package, $match, $io, $io->getOutput())) {
|
|
|
|
+ return $result;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
} catch (\Throwable $e) {
|
|
} catch (\Throwable $e) {
|
|
$output = $io->getOutput();
|
|
$output = $io->getOutput();
|
|
|
|
|
|
if (!$this->doctrine->getEntityManager()->isOpen()) {
|
|
if (!$this->doctrine->getEntityManager()->isOpen()) {
|
|
$this->doctrine->resetManager();
|
|
$this->doctrine->resetManager();
|
|
$package = $this->doctrine->getEntityManager()->getRepository(Package::class)->findOneById($package->getId());
|
|
$package = $this->doctrine->getEntityManager()->getRepository(Package::class)->findOneById($package->getId());
|
|
|
|
+ } else {
|
|
|
|
+ // reload the package just in case as Updater tends to merge it to a new instance
|
|
|
|
+ $package = $packageRepository->findOneById($id);
|
|
}
|
|
}
|
|
|
|
|
|
// invalid composer data somehow, notify the owner and then mark the job failed
|
|
// invalid composer data somehow, notify the owner and then mark the job failed
|
|
@@ -134,6 +149,13 @@ class UpdaterWorker
|
|
$found404 = true;
|
|
$found404 = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // github 404'ed, check through API whether the package still exists and delete if not
|
|
|
|
+ if ($found404 && preg_match('{[@/]github.com[:/]([^/]+/[^/]+?)(\.git)?$}i', $package->getRepository(), $match)) {
|
|
|
|
+ if ($result = $this->checkForDeadGitHubPackage($package, $match, $io, $output)) {
|
|
|
|
+ return $result;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
// detected a 404 so mark the package as gone and prevent updates for 1y
|
|
// detected a 404 so mark the package as gone and prevent updates for 1y
|
|
if ($found404) {
|
|
if ($found404) {
|
|
$package->setCrawledAt(new \DateTime('+1 year'));
|
|
$package->setCrawledAt(new \DateTime('+1 year'));
|
|
@@ -170,7 +192,7 @@ class UpdaterWorker
|
|
// unexpected error so mark the job errored
|
|
// unexpected error so mark the job errored
|
|
throw $e;
|
|
throw $e;
|
|
} finally {
|
|
} finally {
|
|
- $this->locker->unlockPackageUpdate($package->getId());
|
|
|
|
|
|
+ $this->locker->unlockPackageUpdate($id);
|
|
}
|
|
}
|
|
|
|
|
|
return [
|
|
return [
|
|
@@ -179,4 +201,35 @@ class UpdaterWorker
|
|
'details' => '<pre>'.$io->getOutput().'</pre>'
|
|
'details' => '<pre>'.$io->getOutput().'</pre>'
|
|
];
|
|
];
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ private function checkForDeadGitHubPackage(Package $package, $match, $io, $output)
|
|
|
|
+ {
|
|
|
|
+ $rfs = new RemoteFilesystem($io);
|
|
|
|
+ try {
|
|
|
|
+ $rfs->getContents('github.com', 'https://api.github.com/repos/'.$match[1], false, ['retry-auth-failure' => false]);
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
+ if ($e instanceof TransportException && $e->getStatusCode() === 404) {
|
|
|
|
+ try {
|
|
|
|
+ if (
|
|
|
|
+ // check composer repo is visible to make sure it's not github or something else glitching
|
|
|
|
+ $rfs->getContents('github.com', 'https://api.github.com/repos/composer/composer', false, ['retry-auth-failure' => false])
|
|
|
|
+ // remove packages with very low downloads and that are 404
|
|
|
|
+ && $this->downloadManager->getTotalDownloads($package) <= 100
|
|
|
|
+ ) {
|
|
|
|
+ $name = $package->getName();
|
|
|
|
+ $this->packageManager->deletePackage($package);
|
|
|
|
+
|
|
|
|
+ return [
|
|
|
|
+ 'status' => Job::STATUS_PACKAGE_DELETED,
|
|
|
|
+ 'message' => 'Update of '.$package->getName().' failed, package appears to be 404/gone and has been deleted',
|
|
|
|
+ 'details' => '<pre>'.$output.'</pre>',
|
|
|
|
+ 'exception' => $e,
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
+ // ignore failures here, we/github must be offline
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|