[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 abstract class PhabricatorSQLPatchList { 4 5 abstract function getNamespace(); 6 abstract function getPatches(); 7 8 /** 9 * Examine a directory for `.php` and `.sql` files and build patch 10 * specifications for them. 11 */ 12 protected function buildPatchesFromDirectory($directory) { 13 $patch_list = Filesystem::listDirectory( 14 $directory, 15 $include_hidden = false); 16 17 sort($patch_list); 18 $patches = array(); 19 20 foreach ($patch_list as $patch) { 21 $matches = null; 22 if (!preg_match('/\.(sql|php)$/', $patch, $matches)) { 23 throw new Exception( 24 pht( 25 'Unknown patch "%s" in "%s", expected ".php" or ".sql" suffix.', 26 $patch, 27 $directory)); 28 } 29 30 $patches[$patch] = array( 31 'type' => $matches[1], 32 'name' => rtrim($directory, '/').'/'.$patch, 33 ); 34 } 35 36 return $patches; 37 } 38 39 final public static function buildAllPatches() { 40 $patch_lists = id(new PhutilSymbolLoader()) 41 ->setAncestorClass('PhabricatorSQLPatchList') 42 ->setConcreteOnly(true) 43 ->selectAndLoadSymbols(); 44 45 $specs = array(); 46 $seen_namespaces = array(); 47 48 foreach ($patch_lists as $patch_class) { 49 $patch_class = $patch_class['name']; 50 $patch_list = newv($patch_class, array()); 51 52 $namespace = $patch_list->getNamespace(); 53 if (isset($seen_namespaces[$namespace])) { 54 $prior = $seen_namespaces[$namespace]; 55 throw new Exception( 56 "PatchList '{$patch_class}' has the same namespace, '{$namespace}', ". 57 "as another patch list class, '{$prior}'. Each patch list MUST have ". 58 "a unique namespace."); 59 } 60 61 $last_key = null; 62 foreach ($patch_list->getPatches() as $key => $patch) { 63 if (!is_array($patch)) { 64 throw new Exception( 65 "PatchList '{$patch_class}' has a patch '{$key}' which is not ". 66 "an array."); 67 } 68 69 $valid = array( 70 'type' => true, 71 'name' => true, 72 'after' => true, 73 'legacy' => true, 74 'dead' => true, 75 ); 76 77 foreach ($patch as $pkey => $pval) { 78 if (empty($valid[$pkey])) { 79 throw new Exception( 80 "PatchList '{$patch_class}' has a patch, '{$key}', with an ". 81 "unknown property, '{$pkey}'. Patches must have only valid ". 82 "keys: ".implode(', ', array_keys($valid)).'.'); 83 } 84 } 85 86 if (is_numeric($key)) { 87 throw new Exception( 88 "PatchList '{$patch_class}' has a patch with a numeric key, ". 89 "'{$key}'. Patches must use string keys."); 90 } 91 92 if (strpos($key, ':') !== false) { 93 throw new Exception( 94 "PatchList '{$patch_class}' has a patch with a colon in the ". 95 "key name, '{$key}'. Patch keys may not contain colons."); 96 } 97 98 $full_key = "{$namespace}:{$key}"; 99 100 if (isset($specs[$full_key])) { 101 throw new Exception( 102 "PatchList '{$patch_class}' has a patch '{$key}' which ". 103 "duplicates an existing patch key."); 104 } 105 106 $patch['key'] = $key; 107 $patch['fullKey'] = $full_key; 108 $patch['dead'] = (bool)idx($patch, 'dead', false); 109 110 if (isset($patch['legacy'])) { 111 if ($namespace != 'phabricator') { 112 throw new Exception( 113 "Only patches in the 'phabricator' namespace may contain ". 114 "'legacy' keys."); 115 } 116 } else { 117 $patch['legacy'] = false; 118 } 119 120 if (!array_key_exists('after', $patch)) { 121 if ($last_key === null) { 122 throw new Exception( 123 "Patch '{$full_key}' is missing key 'after', and is the first ". 124 "patch in the patch list '{$patch_class}', so its application ". 125 "order can not be determined implicitly. The first patch in a ". 126 "patch list must list the patch or patches it depends on ". 127 "explicitly."); 128 } else { 129 $patch['after'] = array($last_key); 130 } 131 } 132 $last_key = $full_key; 133 134 foreach ($patch['after'] as $after_key => $after) { 135 if (strpos($after, ':') === false) { 136 $patch['after'][$after_key] = $namespace.':'.$after; 137 } 138 } 139 140 $type = idx($patch, 'type'); 141 if (!$type) { 142 throw new Exception( 143 "Patch '{$namespace}:{$key}' is missing key 'type'. Every patch ". 144 "must have a type."); 145 } 146 147 switch ($type) { 148 case 'db': 149 case 'sql': 150 case 'php': 151 break; 152 default: 153 throw new Exception( 154 "Patch '{$namespace}:{$key}' has unknown patch type '{$type}'."); 155 } 156 157 $specs[$full_key] = $patch; 158 } 159 } 160 161 foreach ($specs as $key => $patch) { 162 foreach ($patch['after'] as $after) { 163 if (empty($specs[$after])) { 164 throw new Exception( 165 "Patch '{$key}' references nonexistent dependency, '{$after}'. ". 166 "Patches may only depend on patches which actually exist."); 167 } 168 } 169 } 170 171 $patches = array(); 172 foreach ($specs as $full_key => $spec) { 173 $patches[$full_key] = new PhabricatorStoragePatch($spec); 174 } 175 176 // TODO: Detect cycles? 177 178 return $patches; 179 } 180 181 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |