diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 5e068ccff..940ab3f18 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -285,24 +285,24 @@ EOF; } } - file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile); - file_put_contents($targetDir.'/autoload_psr4.php', $psr4File); - file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile); + $this->filePutContentsIfModified($targetDir.'/autoload_namespaces.php', $namespacesFile); + $this->filePutContentsIfModified($targetDir.'/autoload_psr4.php', $psr4File); + $this->filePutContentsIfModified($targetDir.'/autoload_classmap.php', $classmapFile); $includePathFilePath = $targetDir.'/include_paths.php'; if ($includePathFileContents = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) { - file_put_contents($includePathFilePath, $includePathFileContents); + $this->filePutContentsIfModified($includePathFilePath, $includePathFileContents); } elseif (file_exists($includePathFilePath)) { unlink($includePathFilePath); } $includeFilesFilePath = $targetDir.'/autoload_files.php'; if ($includeFilesFileContents = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) { - file_put_contents($includeFilesFilePath, $includeFilesFileContents); + $this->filePutContentsIfModified($includeFilesFilePath, $includeFilesFileContents); } elseif (file_exists($includeFilesFilePath)) { unlink($includeFilesFilePath); } - file_put_contents($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath, $staticPhpVersion)); - file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix)); - file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $staticPhpVersion)); + $this->filePutContentsIfModified($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath, $staticPhpVersion)); + $this->filePutContentsIfModified($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix)); + $this->filePutContentsIfModified($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $staticPhpVersion)); $this->safeCopy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php'); $this->safeCopy(__DIR__.'/../../../LICENSE', $targetDir.'/LICENSE'); @@ -316,6 +316,16 @@ EOF; return count($classMap); } + private function filePutContentsIfModified($path, $content) + { + $currentContent = @file_get_contents($path); + if (!$currentContent || ($currentContent != $content)) { + return file_put_contents($path, $content); + } + + return 0; + } + private function addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist = null, $namespaceFilter = null, $autoloadType = null, array $classMap = array()) { foreach ($this->generateClassMap($dir, $blacklist, $namespaceFilter, $autoloadType) as $class => $path) { @@ -986,7 +996,6 @@ INITIALIZER; $sortedPackages = PackageSorter::sortPackages($packages); - $sortedPackageMap = array(); foreach ($sortedPackages as $package) { @@ -1005,11 +1014,42 @@ INITIALIZER; */ protected function safeCopy($source, $target) { - $source = fopen($source, 'r'); - $target = fopen($target, 'w+'); + if (!file_exists($target) || !file_exists($source) || !$this->filesAreEqual($source, $target)) { + $source = fopen($source, 'r'); + $target = fopen($target, 'w+'); - stream_copy_to_stream($source, $target); - fclose($source); - fclose($target); + stream_copy_to_stream($source, $target); + fclose($source); + fclose($target); + } + } + + /** + * compare 2 files + * https://stackoverflow.com/questions/3060125/can-i-use-file-get-contents-to-compare-two-files + */ + private function filesAreEqual($a, $b) + { + // Check if filesize is different + if (filesize($a) !== filesize($b)) { + return false; + } + + // Check if content is different + $ah = fopen($a, 'rb'); + $bh = fopen($b, 'rb'); + + $result = true; + while (!feof($ah)) { + if (fread($ah, 8192) != fread($bh, 8192)) { + $result = false; + break; + } + } + + fclose($ah); + fclose($bh); + + return $result; } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index c5ec5cc5d..71fa13d9b 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -311,13 +311,6 @@ class Installer foreach ($localRepo->getPackages() as $package) { $this->installationManager->ensureBinariesPresence($package); } - - $vendorDir = $this->config->get('vendor-dir'); - if (is_dir($vendorDir)) { - // suppress errors as this fails sometimes on OSX for no apparent reason - // see https://github.com/composer/composer/issues/4070#issuecomment-129792748 - @touch($vendorDir); - } } if ($this->runScripts) { @@ -631,6 +624,16 @@ class Installer $localRepo->write(); } + // see https://github.com/composer/composer/issues/2764 + if ($operations) { + $vendorDir = $this->config->get('vendor-dir'); + if (is_dir($vendorDir)) { + // suppress errors as this fails sometimes on OSX for no apparent reason + // see https://github.com/composer/composer/issues/4070#issuecomment-129792748 + @touch($vendorDir); + } + } + return array(0, $devPackages); } diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index f2d950004..89524df39 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -129,7 +129,7 @@ class JsonFile $retries = 3; while ($retries--) { try { - file_put_contents($this->path, static::encode($hash, $options). ($options & self::JSON_PRETTY_PRINT ? "\n" : '')); + $this->filePutContentsIfModified($this->path, static::encode($hash, $options). ($options & self::JSON_PRETTY_PRINT ? "\n" : '')); break; } catch (\Exception $e) { if ($retries) { @@ -142,6 +142,19 @@ class JsonFile } } + /** + * modify file properties only if content modified + */ + private function filePutContentsIfModified($path, $content) + { + $currentContent = @file_get_contents($path); + if (!$currentContent || ($currentContent != $content)) { + return file_put_contents($path, $content); + } + + return 0; + } + /** * Validates the schema of the current json file according to composer-schema.json rules *