commands-1.x-dev/src/Commands/DrushCommands.php

src/Commands/DrushCommands.php
<?php

namespace Drupal\commands\Commands;

use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Component\Datetime\Time;
use Drupal\Core\Cache\Cache;
use Drupal\node\Entity\Node;
use Drupal\commands\Entity\Command;
use Drush\Commands\DrushCommands as DrushCommandsBase;
use Drush\Drush;
use Drush\Exceptions\CommandFailedException;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

/**
 * A Drush commandfile.
 *
 * In addition to this file, you need a drush.services.yml
 * in root of your module, and a composer.json file that provides the name
 * of the services file to use.
 *
 * See these files for an example of injecting Drupal services:
 *   - http://cgit.drupalcode.org/devel/tree/src/Commands/DevelCommands.php
 *   - http://cgit.drupalcode.org/devel/tree/drush.services.yml
 */
class DrushCommands extends DrushCommandsBase {


  /**
   * Run Command
   *
   * @param $id
   *   The ID of the command to run.
   * @param array $options
   *   An associative array of options whose values come from cli, aliases, config, etc.
   * @option force
   *   Force running the command again, regardless of exit state. (Not recommended. Will be replaced with "run-again".)
   * @usage command:run 123
   *   Enter the node ID of the command to run.
   *
   * @command command:run
   * @aliases t
   */
  public function commandRun($id, $options = [
    'force' => false,
  ]) {

    $command = Command::load($id);
    if (empty($command)) {
      throw new CommandFailedException(dt('No command found with that ID.'));
    }
    if (empty($command->state->value) || $command->state->value == Command::COMMAND_QUEUED || $options['force']) {
      $this->logger()->success(dt('Found Command in state:!state [!summary](!link) !command', [
        '!summary' => $command->label(),
        '!link' => $command->toUrl()->setAbsolute(true)->toString(),
        '!command' => $command->command->value,
        '!state' => $command->state->value,
      ]));

      if ($options['force']) {
        $this->logger()->warning(dt('The command is being run again because the "force" option was used.'));
      }

      $this->commandRunExecute($command);
    }
    elseif ($command->state->value == Command::COMMAND_PROCESSING) {
      $this->logger()->warning(dt('Command already running: !summary [!link].', [
        '!summary' => $command->label(),
        '!link' => $command->toUrl()->setAbsolute(true)->toString(),
      ]));
    }
    elseif ($command->state->value == Command::COMMAND_ERROR) {
      $this->logger()->warning(dt('Command already failed: !summary [!link].', [
        '!summary' => $command->label(),
        '!link' => $command->toUrl()->setAbsolute(true)->toString(),
      ]));
    }
    elseif ($command->state->value === Command::COMMAND_OK) {
      $this->logger()->warning(dt('Command already succeeded: !summary [!link].', [
        '!summary' => $command->label(),
        '!link' => $command->toUrl()->setAbsolute(true)->toString(),
      ]));
    }
    else {
      # @TODO: (maybe?) Print constant names too.
      throw new CommandFailedException(dt('Command state value is not found in Command. Possible states are: 0,1,2,3'));
    }
  }

  private function commandRunExecute(Command $command) {

    $this->logger()->info(dt('Command starting. Updated state. Command: @command', [
      '@command' => $command->command->value,
    ]));

    $command->set('state', Command::COMMAND_PROCESSING);
    $command->set('output', null);
    $command->set('executed', \Drupal::time()->getCurrentTime());

    // Unset values in case this command is being retried
    $command->set('finished', NULL);
    $command->set('duration', NULL);

    $command->setNewRevision();
    $command->save();

    // Turn off revisions for process run.
    $command->setNewRevision(FALSE);

    foreach ($command->command as $command_value) {

      # "exec" does not work for system commands like "cd". So instead, we call "sh".
      $args = ["/bin/sh", "-c", $command_value->value];
      $process = Drush::process($args);

      $process->setWorkingDirectory($command->working_directory->value ?? getcwd());

      try {
        $process->mustRun(function ($type, $buffer) use ($command){

          // Echo output to the same stream the process returned.
          if (Process::ERR === $type) {
            $this->stderr()->write($buffer);
          } else {
            $this->output()->write($buffer);
          }

          // @TODO: Use insert queries directly? Test performance.
          $command->get('output')->appendItem([
            'output' => $buffer,
            'stream' => $type == Process::OUT ? Process::STDOUT: Process::STDERR,
          ]);
          $command->save();
        });
        $command->set('state', Command::COMMAND_OK);
        $command->setNewRevision();
        $command->set('finished', \Drupal::time()->getCurrentTime());
        $command->save();
        $this->logger()->info(dt('Command ended in Success. Updated state.'));
      }
      catch (ProcessFailedException $exception) {
        $command->set('state', Command::COMMAND_ERROR);
        $command->setNewRevision();
        $command->set('finished', \Drupal::time()->getCurrentTime());
        $command->save();
        $this->logger()->info(dt('Command ended in Failure. Updated state.'));
        throw $exception;
      }
    }
  }


  /**
   * Run Commands as a daemon.
   *
   * @param array $options
   *   An associative array of options whose values come from cli, aliases, config, etc.
   * @option force
   *   Force running the command again, regardless of exit state. (Not recommended. Will be replaced with "run-again".)
   *
   * @command command:daemon
   * @aliases c:d
   */
  public function commandDaemon($options = [
    'sleep' => 1,
    'force' => false,
  ])
  {
    while (TRUE) {
      if (\Drupal::config('commands.settings')->get('daemon_enabled')) {
        $this->logger()->notice(dt('Checking for commands...'));
        $query = \Drupal::entityQuery('command');
        $query->condition('state', Command::COMMAND_QUEUED);
        $query->accessCheck(FALSE);

        $result = $query->execute();
        foreach ($result as $id) {
          $this->commandRun($id);
        }

        sleep($options['sleep']);
      }
      else {
        $this->logger()->notice(dt('Daemon is currently disabled.'));
        sleep($options['sleep']);
        continue;
      }
    }
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc