Filesystem: added removeDirectoryAsync() and use it in ArchiveDownloader (#9618)
This turns half of the `rm -rf ...` executions during package installs async and therefore improves performancepull/9730/head
parent
980eef5b68
commit
a5fecc4720
|
@ -139,9 +139,11 @@ abstract class ArchiveDownloader extends FileDownloader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$filesystem->removeDirectory($temporaryDir);
|
$promise = $filesystem->removeDirectoryAsync($temporaryDir);
|
||||||
|
return $promise->then(function() use ($self, $package, $path, $temporaryDir) {
|
||||||
$self->removeCleanupPath($package, $temporaryDir);
|
$self->removeCleanupPath($package, $temporaryDir);
|
||||||
$self->removeCleanupPath($package, $path);
|
$self->removeCleanupPath($package, $path);
|
||||||
|
});
|
||||||
}, function ($e) use ($cleanup) {
|
}, function ($e) use ($cleanup) {
|
||||||
$cleanup();
|
$cleanup();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
namespace Composer\Util;
|
namespace Composer\Util;
|
||||||
|
|
||||||
|
use React\Promise\Promise;
|
||||||
use RecursiveDirectoryIterator;
|
use RecursiveDirectoryIterator;
|
||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
use Symfony\Component\Filesystem\Exception\IOException;
|
use Symfony\Component\Filesystem\Exception\IOException;
|
||||||
|
@ -96,6 +97,75 @@ class Filesystem
|
||||||
*/
|
*/
|
||||||
public function removeDirectory($directory)
|
public function removeDirectory($directory)
|
||||||
{
|
{
|
||||||
|
$edgeCaseResult = $this->removeEdgeCases($directory);
|
||||||
|
if ($edgeCaseResult !== null) {
|
||||||
|
return $edgeCaseResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform::isWindows()) {
|
||||||
|
$cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory)));
|
||||||
|
} else {
|
||||||
|
$cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->getProcess()->execute($cmd, $output) === 0;
|
||||||
|
|
||||||
|
// clear stat cache because external processes aren't tracked by the php stat cache
|
||||||
|
clearstatcache();
|
||||||
|
|
||||||
|
if ($result && !is_dir($directory)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->removeDirectoryPhp($directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively remove a directory asynchronously
|
||||||
|
*
|
||||||
|
* Uses the process component if proc_open is enabled on the PHP
|
||||||
|
* installation.
|
||||||
|
*
|
||||||
|
* @param string $directory
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function removeDirectoryAsync($directory)
|
||||||
|
{
|
||||||
|
$edgeCaseResult = $this->removeEdgeCases($directory);
|
||||||
|
if ($edgeCaseResult !== null) {
|
||||||
|
return \React\Promise\resolve($edgeCaseResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform::isWindows()) {
|
||||||
|
$cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory)));
|
||||||
|
} else {
|
||||||
|
$cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
$promise = $this->getProcess()->executeAsync($cmd);
|
||||||
|
|
||||||
|
$self = $this;
|
||||||
|
return $promise->then(function ($process) use ($directory, $self) {
|
||||||
|
// clear stat cache because external processes aren't tracked by the php stat cache
|
||||||
|
clearstatcache();
|
||||||
|
|
||||||
|
if ($process->isSuccessful()) {
|
||||||
|
if (!is_dir($directory)) {
|
||||||
|
return \React\Promise\resolve(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return \React\Promise\resolve($self->removeDirectoryPhp($directory));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $directory
|
||||||
|
*
|
||||||
|
* @return bool|null Returns null, when no edge case was hit. Otherwise a bool whether removal was successfull
|
||||||
|
*/
|
||||||
|
private function removeEdgeCases($directory) {
|
||||||
if ($this->isSymlinkedDirectory($directory)) {
|
if ($this->isSymlinkedDirectory($directory)) {
|
||||||
return $this->unlinkSymlinkedDirectory($directory);
|
return $this->unlinkSymlinkedDirectory($directory);
|
||||||
}
|
}
|
||||||
|
@ -120,22 +190,7 @@ class Filesystem
|
||||||
return $this->removeDirectoryPhp($directory);
|
return $this->removeDirectoryPhp($directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Platform::isWindows()) {
|
return null;
|
||||||
$cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory)));
|
|
||||||
} else {
|
|
||||||
$cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory));
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $this->getProcess()->execute($cmd, $output) === 0;
|
|
||||||
|
|
||||||
// clear stat cache because external processes aren't tracked by the php stat cache
|
|
||||||
clearstatcache();
|
|
||||||
|
|
||||||
if ($result && !is_dir($directory)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->removeDirectoryPhp($directory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue