From 91fc635ca549b21a03d934b04c55fa58f29972a0 Mon Sep 17 00:00:00 2001 From: Mateusz Heleniak Date: Fri, 7 Sep 2012 20:25:07 +0200 Subject: [PATCH] better rename reliability on Windows - a workaround for random "Access denied" errors --- src/Composer/Downloader/ArchiveDownloader.php | 8 ++-- src/Composer/Util/Filesystem.php | 38 ++++++++++++++----- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index 216adfa90..9e1709699 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -52,9 +52,9 @@ abstract class ArchiveDownloader extends FileDownloader } else { // Rename the content directory to avoid error when moving up // a child folder with the same name - $temporaryName = md5(time().rand()); - $this->filesystem->rename($contentDir, $temporaryName); - $contentDir = $temporaryName; + $temporaryDir = sys_get_temp_dir().'/'.md5(time().rand()); + $this->filesystem->rename($contentDir, $temporaryDir); + $contentDir = $temporaryDir; foreach (array_merge(glob($contentDir . '/.*'), glob($contentDir . '/*')) as $file) { if (trim(basename($file), '.')) { @@ -62,7 +62,7 @@ abstract class ArchiveDownloader extends FileDownloader } } - rmdir($contentDir); + $this->filesystem->removeDirectory($contentDir); } } } catch (\Exception $e) { diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index af731b61b..fc5a590cf 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -25,6 +25,19 @@ class Filesystem $this->processExecutor = $executor ?: new ProcessExecutor(); } + public function remove($file) + { + if (is_dir($file)) { + return $this->removeDirectory($file); + } + + if (file_exists($file)) { + return unlink($file); + } + + return false; + } + public function removeDirectory($directory) { if (!is_dir($directory)) { @@ -63,21 +76,28 @@ class Filesystem public function rename($source, $target) { - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - rename($source, $target); - + if (true === @rename($source, $target)) { return; } - // We do not use PHP's "rename" function here since it does not support - // the case where $source, and $target are located on different partitions. - if (0 !== $this->processExecutor->execute('mv '.escapeshellarg($source).' '.escapeshellarg($target))) { - if (true === @rename($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)); + if (0 === $this->processExecutor->execute($command)) { + $this->remove($source); + + return; + } + } else { + // We do not use PHP's "rename" function here since it does not support + // the case where $source, and $target are located on different partitions. + $command = sprintf('mv %s %s', escapeshellarg($source), escapeshellarg($target)); + if (0 === $this->processExecutor->execute($command)) { return; } - - throw new \RuntimeException(sprintf('Could not rename "%s" to "%s".', $source, $target)); } + + throw new \RuntimeException(sprintf('Could not rename "%s" to "%s".', $source, $target)); } /**