+++ /dev/null
-<?php
-
-namespace Drupal\Driver;
-
-use Drupal\Component\Utility\Random;
-use Drupal\Driver\Exception\BootstrapException;
-
-use Symfony\Component\Process\Process;
-
-/**
- * Implements DriverInterface.
- */
-class DrushDriver extends BaseDriver {
- /**
- * Store a drush alias for tests requiring shell access.
- *
- * @var string
- */
- public $alias;
-
- /**
- * Stores the root path to a Drupal installation.
- *
- * This is an alternative to using drush aliases.
- *
- * @var string
- */
- public $root;
-
- /**
- * Store the path to drush binary.
- *
- * @var string
- */
- public $binary;
-
- /**
- * Track bootstrapping.
- */
- private $bootstrapped = FALSE;
-
- /**
- * Random generator.
- *
- * @var \Drupal\Component\Utility\Random
- */
- private $random;
-
- /**
- * Global arguments or options for drush commands.
- *
- * @var string
- */
- private $arguments = '';
-
- /**
- * Set drush alias or root path.
- *
- * @param string $alias
- * A drush alias.
- * @param string $root_path
- * The root path of the Drupal install. This is an alternative to using
- * aliases.
- * @param string $binary
- * The path to the drush binary.
- * @param \Drupal\Component\Utility\Random $random
- * Random generator.
- *
- * @throws \Drupal\Driver\Exception\BootstrapException
- * Thrown when a required parameter is missing.
- */
- public function __construct($alias = NULL, $root_path = NULL, $binary = 'drush', Random $random = NULL) {
- if (!empty($alias)) {
- // Trim off the '@' symbol if it has been added.
- $alias = ltrim($alias, '@');
-
- $this->alias = $alias;
- }
- elseif (!empty($root_path)) {
- $this->root = realpath($root_path);
- }
- else {
- throw new BootstrapException('A drush alias or root path is required.');
- }
-
- $this->binary = $binary;
-
- if (!isset($random)) {
- $random = new Random();
- }
- $this->random = $random;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRandom() {
- return $this->random;
- }
-
- /**
- * {@inheritdoc}
- */
- public function bootstrap() {
- // Check that the given alias works.
- // @todo check that this is a functioning alias.
- // See http://drupal.org/node/1615450
- if (!isset($this->alias) && !isset($this->root)) {
- throw new BootstrapException('A drush alias or root path is required.');
- }
- $this->bootstrapped = TRUE;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isBootstrapped() {
- return $this->bootstrapped;
- }
-
- /**
- * {@inheritdoc}
- */
- public function userCreate(\stdClass $user) {
- $arguments = array(
- sprintf('"%s"', $user->name),
- );
- $options = array(
- 'password' => $user->pass,
- 'mail' => $user->mail,
- );
- $this->drush('user-create', $arguments, $options);
- if (isset($user->roles) && is_array($user->roles)) {
- foreach ($user->roles as $role) {
- $this->userAddRole($user, $role);
- }
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function userDelete(\stdClass $user) {
- $arguments = array(sprintf('"%s"', $user->name));
- $options = array(
- 'yes' => NULL,
- 'delete-content' => NULL,
- );
- $this->drush('user-cancel', $arguments, $options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function userAddRole(\stdClass $user, $role) {
- $arguments = array(
- sprintf('"%s"', $role),
- sprintf('"%s"', $user->name),
- );
- $this->drush('user-add-role', $arguments);
- }
-
- /**
- * {@inheritdoc}
- */
- public function fetchWatchdog($count = 10, $type = NULL, $severity = NULL) {
- $options = array(
- 'count' => $count,
- 'type' => $type,
- 'severity' => $severity,
- );
- return $this->drush('watchdog-show', array(), $options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function clearCache($type = 'all') {
- $type = array($type);
- return $this->drush('cache-clear', $type, array());
- }
-
- /**
- * {@inheritdoc}
- */
- public function clearStaticCaches() {
- // The drush driver does each operation as a separate request;
- // therefore, 'clearStaticCaches' can be a no-op.
- }
-
- /**
- * Decodes JSON object returned by Drush.
- *
- * It will clean up any junk that may have appeared before or after the
- * JSON object. This can happen with remote Drush aliases.
- *
- * @param string $output
- * The output from Drush.
- * @return object
- * The decoded JSON object.
- */
- protected function decodeJsonObject($output) {
- // Remove anything before the first '{'.
- $output = preg_replace('/^[^\{]*/', '', $output);
- // Remove anything after the last '}'.
- $output = preg_replace('/[^\}]*$/s', '', $output);
- return json_decode($output);
- }
-
- /**
- * {@inheritdoc}
- */
- public function createNode($node) {
- $result = $this->drush('behat', array('create-node', escapeshellarg(json_encode($node))), array());
- return $this->decodeJsonObject($result);
- }
-
- /**
- * {@inheritdoc}
- */
- public function nodeDelete($node) {
- $this->drush('behat', array('delete-node', escapeshellarg(json_encode($node))), array());
- }
-
- /**
- * {@inheritdoc}
- */
- public function createTerm(\stdClass $term) {
- $result = $this->drush('behat', array('create-term', escapeshellarg(json_encode($term))), array());
- return $this->decodeJsonObject($result);
- }
-
- /**
- * {@inheritdoc}
- */
- public function termDelete(\stdClass $term) {
- $this->drush('behat', array('delete-term', escapeshellarg(json_encode($term))), array());
- }
-
- /**
- * {@inheritdoc}
- */
- public function isField($entity_type, $field_name) {
- // If the Behat Drush Endpoint is not installed on the site-under-test,
- // then the drush() method will throw an exception. In this instance, we
- // want to treat all potential fields as non-fields. This allows the
- // Drush Driver to work with certain built-in Drush capabilities (e.g.
- // creating users) even if the Behat Drush Endpoint is not available.
- try {
- $result = $this->drush('behat', array('is-field', escapeshellarg(json_encode(array($entity_type, $field_name)))), array());
- return strpos($result, "true\n") !== FALSE;
- }
- catch (\Exception $e) {
- return FALSE;
- }
- }
-
- /**
- * Sets common drush arguments or options.
- *
- * @param string $arguments
- * Global arguments to add to every drush command.
- */
- public function setArguments($arguments) {
- $this->arguments = $arguments;
- }
-
- /**
- * Get common drush arguments.
- */
- public function getArguments() {
- return $this->arguments;
- }
-
- /**
- * Parse arguments into a string.
- *
- * @param array $arguments
- * An array of argument/option names to values.
- *
- * @return string
- * The parsed arguments.
- */
- protected static function parseArguments(array $arguments) {
- $string = '';
- foreach ($arguments as $name => $value) {
- if (is_null($value)) {
- $string .= ' --' . $name;
- }
- else {
- $string .= ' --' . $name . '=' . $value;
- }
- }
- return $string;
- }
-
- /**
- * Execute a drush command.
- */
- public function drush($command, array $arguments = array(), array $options = array()) {
- $arguments = implode(' ', $arguments);
-
- // Disable colored output from drush.
- $options['nocolor'] = TRUE;
- $string_options = $this->parseArguments($options);
-
- $alias = isset($this->alias) ? "@{$this->alias}" : '--root=' . $this->root;
-
- // Add any global arguments.
- $global = $this->getArguments();
-
- $process = new Process("{$this->binary} {$alias} {$string_options} {$global} {$command} {$arguments}");
- $process->setTimeout(3600);
- $process->run();
-
- if (!$process->isSuccessful()) {
- throw new \RuntimeException($process->getErrorOutput());
- }
-
- // Some drush commands write to standard error output (for example enable
- // use drush_log which default to _drush_print_log) instead of returning a
- // string (drush status use drush_print_pipe).
- if (!$process->getOutput()) {
- return $process->getErrorOutput();
- }
- else {
- return $process->getOutput();
- }
-
- }
-
- /**
- * {@inheritdoc}
- */
- public function processBatch() {
- // Do nothing. Drush should internally handle any needs for processing
- // batch ops.
- }
-
- /**
- * {@inheritdoc}
- */
- public function runCron() {
- $this->drush('cron');
- }
-
- /**
- * Run Drush commands dynamically from a DrupalContext.
- */
- public function __call($name, $arguments) {
- return $this->drush($name, $arguments);
- }
-
-}