class FailureMarker
Handles failure marker file operation.
The failure marker is a file placed in the active directory while staged code is copied back into it, and then removed afterward. This allows us to know if a commit operation failed midway through, which could leave the site code base in an indeterminate state -- which, in the worst case scenario, might render Drupal being unable to boot.
@internal This is an internal part of Package Manager and may be changed or removed at any time without warning. External code should not interact with this class.
Hierarchy
- class \Drupal\package_manager\FailureMarker implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
Expanded class hierarchy of FailureMarker
6 files declare their use of FailureMarker
- ApiController.php in core/
modules/ package_manager/ tests/ modules/ package_manager_test_api/ src/ ApiController.php - FailureMarkerRequirementTest.php in core/
modules/ package_manager/ tests/ src/ Functional/ FailureMarkerRequirementTest.php - FailureMarkerTest.php in core/
modules/ package_manager/ tests/ src/ Kernel/ FailureMarkerTest.php - PackageManagerKernelTestBase.php in core/
modules/ package_manager/ tests/ src/ Kernel/ PackageManagerKernelTestBase.php - package_manager.install in core/
modules/ package_manager/ package_manager.install
File
-
core/
modules/ package_manager/ src/ FailureMarker.php, line 28
Namespace
Drupal\package_managerView source
final class FailureMarker implements EventSubscriberInterface {
public function __construct(PathLocator $pathLocator) {
}
/**
* Gets the marker file path.
*
* @return string
* The absolute path of the marker file.
*/
public function getPath() : string {
return $this->pathLocator
->getProjectRoot() . '/PACKAGE_MANAGER_FAILURE.yml';
}
/**
* Deletes the marker file.
*/
public function clear() : void {
unlink($this->getPath());
}
/**
* Writes data to marker file.
*
* @param \Drupal\package_manager\StageBase $stage
* The stage.
* @param \Drupal\Core\StringTranslation\TranslatableMarkup $message
* Failure message to be added.
* @param \Throwable|null $throwable
* (optional) The throwable that caused the failure.
*/
public function write(StageBase $stage, TranslatableMarkup $message, ?\Throwable $throwable = NULL) : void {
$data = [
'stage_class' => get_class($stage),
'stage_type' => $stage->getType(),
'stage_file' => (new \ReflectionObject($stage))->getFileName(),
'message' => (string) $message,
'throwable_class' => $throwable ? get_class($throwable) : FALSE,
'throwable_message' => $throwable?->getMessage() ?? 'Not available',
'throwable_backtrace' => $throwable?->getTraceAsString() ?? 'Not available.',
];
file_put_contents($this->getPath(), Yaml::dump($data));
}
/**
* Gets the data from the file if it exists.
*
* @return array|null
* The data from the file if it exists.
*
* @throws \Drupal\package_manager\Exception\StageFailureMarkerException
* Thrown if failure marker exists but cannot be decoded.
*/
private function getData() : ?array {
$path = $this->getPath();
if (file_exists($path)) {
$data = file_get_contents($path);
try {
return Yaml::parse($data);
} catch (ParseException $exception) {
throw new StageFailureMarkerException('Failure marker file exists but cannot be decoded.', $exception->getCode(), $exception);
}
}
return NULL;
}
/**
* Gets the message from the file if it exists.
*
* @param bool $include_backtrace
* Whether to include the backtrace in the message. Defaults to TRUE. May be
* set to FALSE in a context where it does not make sense to include, such
* as emails.
*
* @return string|null
* The message from the file if it exists, otherwise NULL.
*
* @throws \Drupal\package_manager\Exception\StageFailureMarkerException
* Thrown if failure marker exists but cannot be decoded.
*/
public function getMessage(bool $include_backtrace = TRUE) : ?string {
$data = $this->getData();
if ($data === NULL) {
return NULL;
}
$message = $data['message'];
if ($data['throwable_class']) {
$message .= sprintf(' Caused by %s, with this message: %s', $data['throwable_class'], $data['throwable_message']);
if ($include_backtrace) {
$message .= "\nBacktrace:\n" . $data['throwable_backtrace'];
}
}
return $message;
}
/**
* Asserts the failure file doesn't exist.
*
* @throws \Drupal\package_manager\Exception\StageFailureMarkerException
* Thrown if the marker file exists.
*/
public function assertNotExists() : void {
if ($message = $this->getMessage()) {
throw new StageFailureMarkerException($message);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() : array {
return [
CollectPathsToExcludeEvent::class => 'excludeMarkerFile',
];
}
/**
* Excludes the failure marker file from stage operations.
*
* @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent $event
* The event being handled.
*/
public function excludeMarkerFile(CollectPathsToExcludeEvent $event) : void {
$event->addPathsRelativeToProjectRoot([
$this->getPath(),
]);
}
}
Members
Title Sort descending | Modifiers | Object type | Summary |
---|---|---|---|
FailureMarker::assertNotExists | public | function | Asserts the failure file doesn't exist. |
FailureMarker::clear | public | function | Deletes the marker file. |
FailureMarker::excludeMarkerFile | public | function | Excludes the failure marker file from stage operations. |
FailureMarker::getData | private | function | Gets the data from the file if it exists. |
FailureMarker::getMessage | public | function | Gets the message from the file if it exists. |
FailureMarker::getPath | public | function | Gets the marker file path. |
FailureMarker::getSubscribedEvents | public static | function | |
FailureMarker::write | public | function | Writes data to marker file. |
FailureMarker::__construct | public | function |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.