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, $path);
|
||||
});
|
||||
}, function ($e) use ($cleanup) {
|
||||
$cleanup();
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Util;
|
||||
|
||||
use React\Promise\Promise;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
|
@ -96,6 +97,75 @@ class Filesystem
|
|||
*/
|
||||
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)) {
|
||||
return $this->unlinkSymlinkedDirectory($directory);
|
||||
}
|
||||
|
@ -120,22 +190,7 @@ class Filesystem
|
|||
return $this->removeDirectoryPhp($directory);
|
||||
}
|
||||
|
||||
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);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue