1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8namespace Tiki\Composer; 9 10use Composer\Script\Event; 11use Composer\Util\FileSystem; 12use Symfony\Component\Finder\Finder; 13 14/** 15 * After Migrate the vendors to vendors_bundled, we should clean the vendor folder 16 * We don't want to that by deleting all files in the vendor folder, instead we will try 17 * to do sensitive decisions about what to delete 18 * 19 * All the process is skipped exists a file called "do_not_clean.txt" in the vendor folder 20 * 21 * Class CleanVendorAfterVendorBundledMigration 22 * @package Tiki\Composer 23 */ 24class CleanVendorAfterVendorBundledMigration 25{ 26 27 // To calculate the md5 hash for the old vendor folder, on a linux server, you can use (inside the old vendor folder): 28 // 29 // $ STRING=$(ls -d */* | grep -v "^composer/" | grep -v "^bin/" | LC_COLLATE=C sort -fu | tr '\n' ':' | sed 's/:$//') 30 // $ echo -n $STRING | md5sum 31 // 32 const PRE_MIGRATION_OLD_VENDOR_FOLDER_MD5_HASH = '6997e3dc0e3ad453ab8ea9798653a0fa'; // version 17 before change 33 const VENDOR_FOLDER_MD5_HASH_16_X = '40473ceff65c1045ccd10ebd5e5e3110'; // version 16.3 34 const VENDOR_FOLDER_MD5_HASH_15_X = '273278571219f62e2d658e510684d763'; // version 15.6 35 const VENDOR_FOLDER_MD5_HASH_14_X = 'fbf3913809c5575aee178a1c2437a48a'; // version 14.4 36 const VENDOR_FOLDER_MD5_HASH_13_X = '507a38862ece4a36a6787850e7e732be'; // version 13.2 37 const VENDOR_FOLDER_MD5_HASH_12_X = '466948d920571e4065b5ddde9b0d72da'; // version 12.13 38 39 /** 40 * @param Event $event 41 */ 42 public static function cleanLinks(Event $event) 43 { 44 self::cleanBinLinks(); 45 } 46 47 /** 48 * @param Event $event 49 */ 50 public static function clean(Event $event) 51 { 52 53 /* 54 * 0) Make sure old bin links are removed so they can be created by composer 55 * 1) If a file called do_not_clean.txt exists in the vendor folder stop 56 * 2) If there is a vendor/autoload.php, check the hash of the folder structure, if different from at the time 57 * of the vendor_bundle migration, ignore 58 * 2.1) Even if the hash do not match, check if 3 of the tiki bundled packages are installed, if that is the 59 * case warn the user as it might be a problem and disable autoload 60 * 3) If we arrive here, clean all folders and autoload.php in the old (pre migration) vendor folder 61 */ 62 63 $io = $event->getIO(); 64 $fs = new FileSystem(); 65 66 $rootFolder = realpath(__DIR__ . '/../../../../'); 67 $oldVendorFolder = realpath($rootFolder . '/vendor'); 68 69 // 0) Make sure we can install known bin files (they might be still linked to the old vendor folder 70 self::cleanBinLinks(); 71 72 // if we cant find the vendor dir no sense in progressing 73 if ($oldVendorFolder === false || ! is_dir($oldVendorFolder)) { 74 return; 75 } 76 77 // 1) If a file called do_not_clean.txt exists in the vendor folder stop 78 if (file_exists($oldVendorFolder . '/do_not_clean.txt')) { 79 $io->write(''); 80 $io->write('File vendor/do_not_clean.txt is present, no attempt to clean the vendor folder will be done!'); 81 $io->write(''); 82 83 return; 84 } 85 86 // 2) If there is a vendor/autoload.php, check the hash of the folder structure, if different from at the time 87 // of the vendor_bundle migration, ignore 88 if (file_exists($oldVendorFolder . '/autoload.php')) { 89 $finder = new Finder(); 90 $finder->in($oldVendorFolder)->exclude(['composer', 'bin'])->depth(2); 91 92 $packages = []; 93 foreach ($finder as $file) { 94 $packages[] = $file->getRelativePath(); 95 } 96 97 $packages = array_unique($packages); 98 natcasesort($packages); 99 $packagesString = implode(':', array_values($packages)); 100 101 $md5checksum = md5($packagesString); 102 103 if (! in_array( 104 $md5checksum, 105 [ 106 self::PRE_MIGRATION_OLD_VENDOR_FOLDER_MD5_HASH, 107 self::VENDOR_FOLDER_MD5_HASH_16_X, 108 self::VENDOR_FOLDER_MD5_HASH_15_X, 109 self::VENDOR_FOLDER_MD5_HASH_14_X, 110 self::VENDOR_FOLDER_MD5_HASH_13_X, 111 self::VENDOR_FOLDER_MD5_HASH_12_X, 112 ] 113 )) { 114 // * 2.1) Even if the hash do not match, check if 3 of the tiki bundled packages are installed, if that is the 115 // case warn the user as it might be a problem and disable autoload 116 if ((file_exists($oldVendorFolder . '/zendframework/zend-config/src/Config.php') //ZF2 117 || file_exists($oldVendorFolder . '/bombayworks/zendframework1/library/Zend/Config.php')) //ZF1 118 && (file_exists($oldVendorFolder . '/smarty/smarty/libs/Smarty.class.php') //Smarty 119 || file_exists($oldVendorFolder . '/smarty/smarty/distribution/libs/Smarty.class.php')) //Smarty 120 && file_exists($oldVendorFolder . '/adodb/adodb/adodb.inc.php') //Adodb 121 ) { 122 rename($oldVendorFolder . '/autoload.php', $oldVendorFolder . '/autoload-disabled.php'); 123 self::cleanTemplates($rootFolder, $fs); 124 125 $message = <<<'EOD' 126Your vendor folder contains multiple packages that were normally bundled with Tiki. Since version 17 those libraries 127were migrated from the folder "vendor" to the folder "vendor_bundled". 128 129It looks like your instance still has these libraries in the vendor folder, to avoid issues your "vendor/autoload.php" 130was renamed to "vendor/autoload-disabled.php". 131 132If you are sure that you want to use the libraries in addition to the ones bundled with tiki, please rename 133"vendor/autoload-disabled.php" back to "vendor/autoload.php" and place a file with the name "do_not_clean.txt" in the vendor folder. 134 135Tiki will not load your "vendor/autoload.php" when is detected as being a stale folder unless a file called 136"vendor/do_not_clean.txt" exists. A "vendor/do_not_clean.txt" will prevent, in future runs of composer, the automatic disabling of 137"vendor/autoload.php". 138 139Most probably you did not add your own custom libraries in addition to the ones bundled with tiki, so you can empty your "vendor" directory 140with: "rm -rf vendor/*". 141If you have your own custom libraries, you should remove all the other ones from the "vendor" directory. 142EOD; 143 144 file_put_contents($oldVendorFolder . '/autoload-disabled-README.txt', $message . "\n"); 145 146 $io->write(''); 147 $io->write('!!!! Warning !!!!'); 148 $io->write(''); 149 $io->write($message); 150 $io->write(''); 151 $io->write('A copy of this information was written also into "vendor/autoload-disabled-README.txt"'); 152 $io->write(''); 153 } 154 return; 155 } 156 } elseif (file_exists($oldVendorFolder . '/autoload-disabled.php')) { 157 // we already disabled autoload, in previous runs, do nothing. 158 return; 159 } 160 161 // 3) If we arrive here, clean all folders and autoload.php in the old (pre migration) vendor folder 162 163 $fs->remove($oldVendorFolder . '/autoload.php'); 164 165 $vendorDirsCleaned = false; 166 $vendorDirs = glob($oldVendorFolder . '/*', GLOB_ONLYDIR); 167 foreach ($vendorDirs as $dir) { 168 if (is_dir($dir)) { 169 $fs->remove($dir); 170 $vendorDirsCleaned = true; 171 } 172 } 173 174 if ($vendorDirsCleaned) { 175 self::cleanTemplates($rootFolder, $fs); 176 } 177 } 178 179 /** 180 * Cleans links from the bin folder to the legacy vendor folder 181 */ 182 protected static function cleanBinLinks() 183 { 184 $fs = new FileSystem(); 185 186 $rootFolder = realpath(__DIR__ . '/../../../../'); 187 $oldVendorFolder = realpath($rootFolder . '/vendor'); 188 189 // 0) Make sure we can install known bin files (they might be still linked to the old vendor folder 190 $binFiles = ['lessc', 'minifycss', 'minifyjs', 'dbunit', 'phpunit']; 191 192 foreach ($binFiles as $file) { 193 $filePath = $rootFolder . '/bin/' . $file; 194 if (is_link($filePath)) { 195 $linkDestination = readlink($filePath); 196 $fileRealPath = realpath($filePath); 197 if (strncmp($linkDestination, '../vendor/', strlen('../vendor/')) === 0 // relative link to vendor folder 198 || $filePath === false // target don't exists, so link is broken 199 || strncmp( 200 $fileRealPath, 201 $oldVendorFolder, 202 strlen($oldVendorFolder) 203 ) === 0 // still pointing to old vendor folder 204 ) { 205 $fs->unlink($filePath); 206 } 207 } 208 } 209 } 210 211 /** 212 * Clean templates, if there was a change to the vendors 213 * @param string $rootFolder 214 * @param FileSystem $fs 215 */ 216 protected static function cleanTemplates($rootFolder, $fs) 217 { 218 // there are some cached templates that will stop tiki to work after the migration 219 $loopDirs = array_merge( 220 [$rootFolder . '/temp/templates_c'], 221 glob($rootFolder . '/temp/templates_c/*', GLOB_ONLYDIR) 222 ); 223 foreach ($loopDirs as $dir) { 224 $cachedTemplates = glob($dir . '/*.tpl.php'); 225 foreach ($cachedTemplates as $template) { 226 $fs->remove($template); 227 } 228 } 229 } 230} 231