Commit 8c3fe9d5 authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3293417 by yash.rode, phenaproxima, tedbow, TravisCarden, rahul_,...

Issue #3293417 by yash.rode, phenaproxima, tedbow, TravisCarden, rahul_, bnjmnm: If an update failed to apply don't allow more use of the module
parent abca8e74
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ services:
      - '@tempstore.shared'
      - '@datetime.time'
      - '@PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface'
      - '@package_manager.failure_marker'
  automatic_updates.cron_updater:
    class: Drupal\automatic_updates\CronUpdater
    arguments:
@@ -45,6 +46,7 @@ services:
      - '@tempstore.shared'
      - '@datetime.time'
      - '@PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface'
      - '@package_manager.failure_marker'
  automatic_updates.staged_projects_validator:
    class: Drupal\automatic_updates\Validator\StagedProjectsValidator
    arguments:
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ services:
      - '@tempstore.shared'
      - '@datetime.time'
      - '@PhpTuf\ComposerStager\Infrastructure\Factory\Path\PathFactoryInterface'
      - '@package_manager.failure_marker'
  automatic_updates_extensions.validator.packages_installed_with_composer:
    class: Drupal\automatic_updates_extensions\Validator\PackagesInstalledWithComposerValidator
    arguments:
+2 −1
Original line number Diff line number Diff line
@@ -114,7 +114,8 @@ abstract class AutomaticUpdatesExtensionsKernelTestBase extends AutomaticUpdates
      $this->container->get('event_dispatcher'),
      $this->container->get('tempstore.shared'),
      $this->container->get('datetime.time'),
      new TestPathFactory()
      new TestPathFactory(),
      $this->container->get('package_manager.failure_marker')
    );
  }

+4 −0
Original line number Diff line number Diff line
@@ -45,6 +45,10 @@ services:
      - '%app.root%'
      - '@config.factory'
      - '@file_system'
  package_manager.failure_marker:
    class: Drupal\package_manager\FailureMarker
    arguments:
      - '@package_manager.path_locator'

  # Validators.
  package_manager.validator.composer_executable:
+87 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\package_manager;

use Drupal\Component\Serialization\Json;
use Drupal\package_manager\Exception\ApplyFailedException;

/**
 * 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 afterwards. 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 unbootable.
 */
final class FailureMarker {

  /**
   * The path locator service.
   *
   * @var \Drupal\package_manager\PathLocator
   */
  protected $pathLocator;

  /**
   * Constructs a FailureMarker object.
   *
   * @param \Drupal\package_manager\PathLocator $pathLocator
   *   The path locator service.
   */
  public function __construct(PathLocator $pathLocator) {
    $this->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.json';
  }

  /**
   * Deletes the marker file.
   */
  public function clear(): void {
    unlink($this->getPath());
  }

  /**
   * Writes data to marker file.
   *
   * @param \Drupal\package_manager\Stage $stage
   *   The stage.
   * @param string $message
   *   Failure message to be added.
   */
  public function write(Stage $stage, string $message): void {
    $data = [
      'stage_class' => get_class($stage),
      'stage_file' => (new \ReflectionObject($stage))->getFileName(),
      'message' => $message,
    ];
    file_put_contents($this->getPath(), Json::encode($data));
  }

  /**
   * Asserts the failure file doesn't exist.
   *
   * @throws \Drupal\package_manager\Exception\ApplyFailedException
   *   Thrown if the marker file exists.
   */
  public function assertNotExists(): void {
    $path = $this->getPath();

    if (file_exists($path)) {
      $data = file_get_contents($path);
      $data = Json::decode($data);

      throw new ApplyFailedException($data['message']);
    }
  }

}
Loading