Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions extensions/package-manager/src/Composer/ComposerAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,38 @@ public function run(InputInterface $input, ?Task $task = null, bool $safeMode =
// Move the temporary vendor directory to the real vendor directory.
if ($this->filesystem->isDirectory($temporaryVendorDir) && count($this->filesystem->allFiles($temporaryVendorDir))) {
$vendorDir = $this->paths->vendor;
if (file_exists($vendorDir)) {
$this->filesystem->deleteDirectory($vendorDir);
$previousVendorDir = $vendorDir.'-previous';

// Left over from a run that was interrupted before it could clean
// up after itself.
if ($this->filesystem->isDirectory($previousVendorDir)) {
$this->filesystem->deleteDirectory($previousVendorDir);
}

// Two renames, rather than deleting the live vendor directory and
// then moving the new one into place. Deleting first leaves the
// forum with no vendor directory for as long as it takes to remove
// and then move several hundred megabytes of packages, and this
// runs at the very end of a long job that can be killed by a
// worker timeout, a memory limit or a container restart. A process
// that dies inside that window leaves the site with no vendor
// directory at all, and a temp-vendor nobody thinks to look for.
// Renaming is effectively instantaneous on the same filesystem,
// and keeps the working tree until the new one is in place.
if ($this->filesystem->isDirectory($vendorDir)) {
$this->filesystem->moveDirectory($vendorDir, $previousVendorDir);
}
$this->filesystem->moveDirectory($temporaryVendorDir, $vendorDir);

if (! $this->filesystem->moveDirectory($temporaryVendorDir, $vendorDir)) {
// Put the working tree back rather than leave the site without
// one. The caller records this on the task, so the admin sees a
// failed update instead of a forum that has stopped booting.
$this->filesystem->moveDirectory($previousVendorDir, $vendorDir);

throw new \RuntimeException('Failed to move the new vendor directory into place.');
}

$this->filesystem->deleteDirectory($previousVendorDir);
}
Config::$defaultConfig['vendor-dir'] = $this->paths->vendor;
}
Expand Down