1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-08 16:02:39 +01:00

[Wilds] Allow class loading to continue on failure

Ref T13098. I think I didn't turn this into an actual revision, but let
`ClassMapQuery` optionally continue if it encounters a class load failure.

If we don't allow this, it can become very difficult to modify or remove
some Arcanist classes since when you, say, remove a Workflow you can no
longer make it to "arc liberate" to update the map for the change.

This is currently used in roughly one place (in an upcoming diff) to let us
get through startup in Runtime and into the "liberate" workflow.
This commit is contained in:
epriestley 2018-09-19 06:22:25 -07:00
parent 412484022b
commit 23aaf85eaf
2 changed files with 51 additions and 2 deletions

View file

@ -45,6 +45,7 @@ final class PhutilClassMapQuery extends Phobject {
private $filterNull = false;
private $uniqueMethod;
private $sortMethod;
private $continueOnFailure;
// NOTE: If you add more configurable properties here, make sure that
// cache key construction in getCacheKey() is updated properly.
@ -162,6 +163,10 @@ final class PhutilClassMapQuery extends Phobject {
return $this;
}
public function setContinueOnFailure($continue) {
$this->continueOnFailure = $continue;
return $this;
}
/* -( Executing the Query )------------------------------------------------ */
@ -236,6 +241,7 @@ final class PhutilClassMapQuery extends Phobject {
$objects = id(new PhutilSymbolLoader())
->setAncestorClass($ancestor)
->setContinueOnFailure($this->continueOnFailure)
->loadObjects();
// Apply the "expand" mechanism, if it is configured.

View file

@ -49,6 +49,7 @@ final class PhutilSymbolLoader {
private $pathPrefix;
private $suppressLoad;
private $continueOnFailure;
/**
@ -148,6 +149,11 @@ final class PhutilSymbolLoader {
return $this;
}
public function setContinueOnFailure($continue) {
$this->continueOnFailure = $continue;
return $this;
}
/* -( Load )--------------------------------------------------------------- */
@ -250,19 +256,56 @@ final class PhutilSymbolLoader {
}
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;
foreach ($symbols as $symbol) {
foreach ($symbols as $key => $symbol) {
try {
$this->loadSymbol($symbol);
} 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;
}
}
$should_continue = ($continue_depth > 0);
if ($this->continueOnFailure) {
$continue_depth--;
}
if ($caught) {
// NOTE: We try to load everything even if we fail to load something,
// primarily to make it possible to remove functions from a libphutil
// library without breaking library startup.
throw $caught;
if ($should_continue) {
// We may not have `pht()` yet.
fprintf(
STDERR,
"%s: %s\n",
'IGNORING CLASS LOAD FAILURE',
$caught->getMessage());
} else {
throw $caught;
}
}
}