Changeset View
Changeset View
Standalone View
Standalone View
src/symbols/PhutilSymbolLoader.php
| Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | final class PhutilSymbolLoader { | ||||
| private $type; | private $type; | ||||
| private $library; | private $library; | ||||
| private $base; | private $base; | ||||
| private $name; | private $name; | ||||
| private $concrete; | private $concrete; | ||||
| private $pathPrefix; | private $pathPrefix; | ||||
| private $suppressLoad; | private $suppressLoad; | ||||
| private $continueOnFailure; | |||||
| /** | /** | ||||
| * Select the type of symbol to load, either `class`, `function` or | * Select the type of symbol to load, either `class`, `function` or | ||||
| * `interface`. | * `interface`. | ||||
| * | * | ||||
| * @param string Type of symbol to load. | * @param string Type of symbol to load. | ||||
| * @return this | * @return this | ||||
| ▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | final class PhutilSymbolLoader { | ||||
| * | * | ||||
| * @task config | * @task config | ||||
| */ | */ | ||||
| public function setConcreteOnly($concrete) { | public function setConcreteOnly($concrete) { | ||||
| $this->concrete = $concrete; | $this->concrete = $concrete; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function setContinueOnFailure($continue) { | |||||
| $this->continueOnFailure = $continue; | |||||
| return $this; | |||||
| } | |||||
| /* -( Load )--------------------------------------------------------------- */ | /* -( Load )--------------------------------------------------------------- */ | ||||
| /** | /** | ||||
| * Execute the query and select matching symbols, then load them so they can | * Execute the query and select matching symbols, then load them so they can | ||||
| * be used. | * be used. | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | foreach ($libraries as $library) { | ||||
| 'library' => $library, | 'library' => $library, | ||||
| 'where' => $where, | 'where' => $where, | ||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (!$this->suppressLoad) { | if (!$this->suppressLoad) { | ||||
| // Loading a class may trigger the autoloader to load more classes | |||||
| // (usually, the parent class), so we need to keep track of whether we | |||||
| // are currently loading in "continue on failure" mode. Otherwise, we'll | |||||
| // fail anyway if we fail to load a parent class. | |||||
| // The driving use case for the "continue on failure" mode is to let | |||||
| // "arc liberate" run so it can rebuild the library map, even if you have | |||||
| // made changes to Workflow or Config classes which it must load before | |||||
| // it can operate. If we don't let it continue on failure, it is very | |||||
| // difficult to remove or move Workflows. | |||||
| static $continue_depth = 0; | |||||
| if ($this->continueOnFailure) { | |||||
| $continue_depth++; | |||||
| } | |||||
| $caught = null; | $caught = null; | ||||
| foreach ($symbols as $symbol) { | foreach ($symbols as $key => $symbol) { | ||||
| try { | try { | ||||
| $this->loadSymbol($symbol); | $this->loadSymbol($symbol); | ||||
| } catch (Exception $ex) { | } catch (Exception $ex) { | ||||
| // If we failed to load this symbol, remove it from the results. | |||||
| // Otherwise, we may fatal below when trying to reflect it. | |||||
| unset($symbols[$key]); | |||||
| $caught = $ex; | $caught = $ex; | ||||
| } | } | ||||
| } | } | ||||
| $should_continue = ($continue_depth > 0); | |||||
| if ($this->continueOnFailure) { | |||||
| $continue_depth--; | |||||
| } | |||||
| if ($caught) { | if ($caught) { | ||||
| // NOTE: We try to load everything even if we fail to load something, | // NOTE: We try to load everything even if we fail to load something, | ||||
| // primarily to make it possible to remove functions from a libphutil | // primarily to make it possible to remove functions from a libphutil | ||||
| // library without breaking library startup. | // library without breaking library startup. | ||||
| if ($should_continue) { | |||||
| // We may not have `pht()` yet. | |||||
| fprintf( | |||||
| STDERR, | |||||
| "%s: %s\n", | |||||
| 'IGNORING CLASS LOAD FAILURE', | |||||
| $caught->getMessage()); | |||||
| } else { | |||||
| throw $caught; | throw $caught; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if ($this->concrete) { | if ($this->concrete) { | ||||
| // Remove 'abstract' classes. | // Remove 'abstract' classes. | ||||
| foreach ($symbols as $key => $symbol) { | foreach ($symbols as $key => $symbol) { | ||||
| if ($symbol['type'] == 'class') { | if ($symbol['type'] == 'class') { | ||||
| $reflection = new ReflectionClass($symbol['name']); | $reflection = new ReflectionClass($symbol['name']); | ||||
| if ($reflection->isAbstract()) { | if ($reflection->isAbstract()) { | ||||
| ▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | private function loadSymbol(array $symbol_spec) { | ||||
| $bootloader->loadLibrarySource($lib_name, $where); | $bootloader->loadLibrarySource($lib_name, $where); | ||||
| // Check that we successfully loaded the symbol from wherever it was | // Check that we successfully loaded the symbol from wherever it was | ||||
| // supposed to be defined. | // supposed to be defined. | ||||
| $load_failed = null; | $load_failed = null; | ||||
| if ($is_function) { | if ($is_function) { | ||||
| if (!function_exists($name)) { | if (!function_exists($name)) { | ||||
| $load_failed = 'function'; | $load_failed = pht('function'); | ||||
| } | } | ||||
| } else { | } else { | ||||
| if (!class_exists($name, false) && !interface_exists($name, false)) { | if (!class_exists($name, false) && !interface_exists($name, false)) { | ||||
| $load_failed = 'class/interface'; | $load_failed = pht('class or interface'); | ||||
| } | } | ||||
| } | } | ||||
| if ($load_failed !== null) { | if ($load_failed !== null) { | ||||
| $lib_path = phutil_get_library_root($lib_name); | $lib_path = phutil_get_library_root($lib_name); | ||||
| throw new PhutilMissingSymbolException( | throw new PhutilMissingSymbolException( | ||||
| $name, | $name, | ||||
| $load_failed, | $load_failed, | ||||
| pht( | pht( | ||||
| 'The symbol map for library "%s" (at "%s") claims this symbol '. | "The symbol map for library '%s' (at '%s') claims this %s is ". | ||||
| '(of type "%s") is defined in "%s", but loading that source file '. | "defined in '%s', but loading that source file did not cause the ". | ||||
| 'did not cause the symbol to become defined.', | "%s to become defined.", | ||||
| $lib_name, | $lib_name, | ||||
| $lib_path, | $lib_path, | ||||
| $load_failed, | $load_failed, | ||||
| $where)); | $where, | ||||
| $load_failed)); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||