Permalink
Browse files

Merge pull request #1341 from beberlei/GH-1339

Fallback to PHP early if proc_open not allowed.
  • Loading branch information...
2 parents 2719fb7 + fbf9a27 commit 6f56568881750e0009e7d827a97f72ac6ef2e4a0 @Seldaek Seldaek committed Nov 19, 2012
@@ -288,7 +288,7 @@ private function lockPackages(array $packages)
unset($spec['version_normalized']);
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();
$process = new ProcessExecutor();
if (0 === $process->execute('git log -n1 --pretty=%ct '.escapeshellarg($sourceRef), $output, $path)) {
@@ -12,6 +12,9 @@
namespace Composer\Util;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
@@ -38,12 +41,25 @@ public function remove($file)
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)
{
if (!is_dir($directory)) {
return true;
}
+ if (!function_exists('proc_open')) {
+ return $this->removeDirectoryPhp($directory);
+ }
+
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$cmd = sprintf('rmdir /S /Q %s', escapeshellarg(realpath($directory)));
} else {
@@ -58,6 +74,32 @@ public function removeDirectory($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)
{
if (!is_dir($directory)) {
@@ -74,12 +116,46 @@ public function ensureDirectoryExists($directory)
}
}
+ /**
+ * 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)
{
if (true === @rename($source, $target)) {
return;
}
+ if (!function_exists('proc_open')) {
+ return $this->copyThenRemove($source, $target);
+ }
+
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
// 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));
@@ -93,4 +93,19 @@ public function providePathCouples()
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"));
+ }
}
+

0 comments on commit 6f56568

Please sign in to comment.