Merge pull request #1341 from beberlei/GH-1339
Fallback to PHP early if proc_open not allowed.pull/1349/head
commit
6f56568881
|
@ -288,7 +288,7 @@ class Locker
|
||||||
unset($spec['version_normalized']);
|
unset($spec['version_normalized']);
|
||||||
|
|
||||||
if ($package->isDev()) {
|
if ($package->isDev()) {
|
||||||
if ('git' === $package->getSourceType() && $path = $this->installationManager->getInstallPath($package)) {
|
if ('git' === $package->getSourceType() && $path = $this->installationManager->getInstallPath($package) && function_exists('proc_open')) {
|
||||||
$sourceRef = $package->getSourceReference() ?: $package->getDistReference();
|
$sourceRef = $package->getSourceReference() ?: $package->getDistReference();
|
||||||
$process = new ProcessExecutor();
|
$process = new ProcessExecutor();
|
||||||
if (0 === $process->execute('git log -n1 --pretty=%ct '.escapeshellarg($sourceRef), $output, $path)) {
|
if (0 === $process->execute('git log -n1 --pretty=%ct '.escapeshellarg($sourceRef), $output, $path)) {
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
namespace Composer\Util;
|
namespace Composer\Util;
|
||||||
|
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||||
|
@ -38,12 +41,25 @@ class Filesystem
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively remove a directory
|
||||||
|
*
|
||||||
|
* Uses the process component if proc_open is enabled on the PHP
|
||||||
|
* installation.
|
||||||
|
*
|
||||||
|
* @param string $directory
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function removeDirectory($directory)
|
public function removeDirectory($directory)
|
||||||
{
|
{
|
||||||
if (!is_dir($directory)) {
|
if (!is_dir($directory)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('proc_open')) {
|
||||||
|
return $this->removeDirectoryPhp($directory);
|
||||||
|
}
|
||||||
|
|
||||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
$cmd = sprintf('rmdir /S /Q %s', escapeshellarg(realpath($directory)));
|
$cmd = sprintf('rmdir /S /Q %s', escapeshellarg(realpath($directory)));
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,6 +74,32 @@ class Filesystem
|
||||||
return $result && !is_dir($directory);
|
return $result && !is_dir($directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively delete directory using PHP iterators.
|
||||||
|
*
|
||||||
|
* Uses a CHILD_FIRST RecursiveIteratorIterator to sort files
|
||||||
|
* before directories, creating a single non-recursive loop
|
||||||
|
* to delete files/directories in the correct order.
|
||||||
|
*
|
||||||
|
* @param string $directory
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function removeDirectoryPhp($directory)
|
||||||
|
{
|
||||||
|
$it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||||
|
$ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
|
||||||
|
|
||||||
|
foreach ($ri as $file) {
|
||||||
|
if ($file->isDir()) {
|
||||||
|
rmdir($file->getPathname());
|
||||||
|
} else {
|
||||||
|
unlink($file->getPathname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rmdir($directory);
|
||||||
|
}
|
||||||
|
|
||||||
public function ensureDirectoryExists($directory)
|
public function ensureDirectoryExists($directory)
|
||||||
{
|
{
|
||||||
if (!is_dir($directory)) {
|
if (!is_dir($directory)) {
|
||||||
|
@ -74,12 +116,46 @@ class Filesystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy then delete is a non-atomic version of {@link rename}.
|
||||||
|
*
|
||||||
|
* Some systems can't rename and also dont have proc_open,
|
||||||
|
* which requires this solution.
|
||||||
|
*
|
||||||
|
* @param string $source
|
||||||
|
* @param string $target
|
||||||
|
*/
|
||||||
|
public function copyThenRemove($source, $target)
|
||||||
|
{
|
||||||
|
$it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||||
|
$ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
|
||||||
|
|
||||||
|
if ( !file_exists($target)) {
|
||||||
|
mkdir($target, 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($ri as $file) {
|
||||||
|
$targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
|
||||||
|
if ($file->isDir()) {
|
||||||
|
mkdir($targetPath);
|
||||||
|
} else {
|
||||||
|
copy($file->getPathname(), $targetPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->removeDirectoryPhp($source);
|
||||||
|
}
|
||||||
|
|
||||||
public function rename($source, $target)
|
public function rename($source, $target)
|
||||||
{
|
{
|
||||||
if (true === @rename($source, $target)) {
|
if (true === @rename($source, $target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('proc_open')) {
|
||||||
|
return $this->copyThenRemove($source, $target);
|
||||||
|
}
|
||||||
|
|
||||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
// Try to copy & delete - this is a workaround for random "Access denied" errors.
|
// Try to copy & delete - this is a workaround for random "Access denied" errors.
|
||||||
$command = sprintf('xcopy %s %s /E /I /Q', escapeshellarg($source), escapeshellarg($target));
|
$command = sprintf('xcopy %s %s /E /I /Q', escapeshellarg($source), escapeshellarg($target));
|
||||||
|
|
|
@ -93,4 +93,19 @@ class FilesystemTest extends TestCase
|
||||||
array('C:/Temp', 'c:\Temp\test', "test"),
|
array('C:/Temp', 'c:\Temp\test', "test"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group GH-1339
|
||||||
|
*/
|
||||||
|
public function testRemoveDirectoryPhp()
|
||||||
|
{
|
||||||
|
$tmp = sys_get_temp_dir();
|
||||||
|
@mkdir($tmp . "/composer_testdir/level1/level2", 0777, true);
|
||||||
|
file_put_contents($tmp . "/composer_testdir/level1/level2/hello.txt", "hello world");
|
||||||
|
|
||||||
|
$fs = new Filesystem;
|
||||||
|
$this->assertTrue($fs->removeDirectoryPhp($tmp . "/composer_testdir"));
|
||||||
|
$this->assertFalse(file_exists($tmp . "/composer_testdir/level1/level2/hello.txt"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue