Commit dcabfebd authored by moshe weitzman's avatar moshe weitzman

Port devel to Drush9

parent cc2d495f
services:
develgenerate.command:
class: Drupal\devel_generate\Commands\DevelGenerateCommands
arguments: ['@plugin.manager.develgenerate']
tags:
- { name: drush.command }
<?php
namespace Unish;
if (class_exists('Unish\CommandUnishTestCase')) {
/**
* Tests for devel_generate drush commands.
*
* @group devel_generate
*/
class DevelGenerateUnishTest extends CommandUnishTestCase {
/**
* {@inheritdoc}
*/
public function setUp() {
if (UNISH_DRUPAL_MAJOR_VERSION < 8) {
$this->markTestSkipped('Devel Generate Tests only available on D8+.');
}
if (!$this->getSites()) {
$this->setUpDrupal(1, TRUE, UNISH_DRUPAL_MAJOR_VERSION, 'standard');
// Symlink the devel module into the sandbox.
$devel_directory = dirname(dirname(__DIR__));
symlink($devel_directory, $this->webroot() . '/modules/devel');
// Enable the devel_generate modules.
$this->drush('pm-enable', ['devel_generate'], $this->getOptions());
}
}
/**
* Tests devel generate terms.
*/
public function testDevelGenerateTerms() {
$this->drush('pm-enable', ['taxonomy'], $this->getOptions());
$this->drush('generate-terms', [], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Please provide a vocabulary machine name.', $this->getErrorOutput());
$this->drush('generate-terms', ['unknown'], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Invalid vocabulary name: unknown', $this->getErrorOutput());
$this->drush('generate-terms', ['tags', 'NaN'], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Invalid number of terms: NaN', $this->getErrorOutput());
$eval_term_count = "return \\Drupal::entityQuery('taxonomy_term')->count()->execute();";
$eval_options = $this->getOptions() + ['format' => 'string'];
$this->drush('generate-terms', ['tags'], $this->getOptions());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
$this->drush('php-eval', [$eval_term_count], $eval_options);
$this->assertEquals(10, $this->getOutput());
$this->drush('generate-terms', ['tags', '1'], $this->getOptions());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
$this->drush('php-eval', [$eval_term_count], $eval_options);
$this->assertEquals(11, $this->getOutput());
$this->drush('generate-terms', ['tags', '1'], $this->getOptions(TRUE));
$this->assertContains('Deleted existing terms.', $this->getErrorOutput());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
$this->drush('php-eval', [$eval_term_count], $eval_options);
$this->assertEquals(1, $this->getOutput());
$this->drush('gent', ['tags', '1'], $this->getOptions());
$this->assertContains('Created the following new terms:', $this->getErrorOutput());
}
/**
* Tests devel generate contents.
*/
public function testDevelGenerateContents() {
$this->drush('pm-enable', ['node'], $this->getOptions());
$eval_content_count = "return \\Drupal::entityQuery('node')->count()->execute();";
$eval_options = $this->getOptions() + ['format' => 'string'];
// Try to generate 10 content of type "page" or "article"
$this->drush('generate-content', [10], $this->getOptions(), NULL, NULL, static::EXIT_SUCCESS);
$this->assertContains('Finished creating 10 nodes', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(10, $this->getOutput());
// Try to generate 1 content of type "page" or "article"
$this->drush('generate-content', [1], $this->getOptions(), NULL, NULL, static::EXIT_SUCCESS);
$this->assertContains('1 node created.', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(11, $this->getOutput());
// Try to generate 5 content of type "page" or "article", removing all
// previous contents.
$this->drush('generate-content', [5], $this->getOptions(TRUE), NULL, NULL, static::EXIT_SUCCESS);
$this->assertContains('Finished creating 5 nodes', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
// Try to generate other 5 content with "crappy" type. Output should
// remains 5.
$generate_content_wrong_ct = $this->getOptions(TRUE) + ['types' => 'crappy'];
$this->drush('generate-content', [5], $generate_content_wrong_ct, NULL, NULL, static::EXIT_ERROR);
$this->assertContains('One or more content types have been entered that don', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
// Try to generate other 5 content with empty types. Output should
// remains 5.
$generate_content_no_types = $this->getOptions(TRUE) + ['types' => ''];
$this->drush('generate-content', [5], $generate_content_no_types, NULL, NULL, static::EXIT_ERROR);
$this->assertContains('No content types available', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
// Try to generate other 5 content without any types. Output should
// remains 5.
$generate_content_no_types = $this->getOptions(TRUE) + ['types' => NULL];
$this->drush('generate-content', [5], $generate_content_no_types, NULL, NULL, static::EXIT_ERROR);
$this->assertContains('Wrong syntax or no content type selected. The correct syntax uses', $this->getErrorOutput());
$this->drush('php-eval', [$eval_content_count], $eval_options);
$this->assertEquals(5, $this->getOutput());
}
/**
* Default drush options.
*
* @param bool $kill
* Whether add kill option.
*
* @return array
* An array containing the default options for drush commands.
*/
protected function getOptions($kill = FALSE) {
$options = [
'yes' => NULL,
'root' => $this->webroot(),
'uri' => key($this->getSites()),
];
if($kill) {
$options['kill'] = NULL;
}
return $options;
}
}
}
......@@ -2,7 +2,7 @@
/**
* @file
* Generate content, taxonomy, menu, and users via drush framework.
* Integration with Drush8. Drush9 commands are in src/Commands.
*/
use Drupal\devel_generate\DevelGenerateBaseInterface;
use Drupal\devel_generate\DevelGeneratePluginManager;
......
<?php
namespace Drupal\devel_generate\Commands;
use Consolidation\AnnotatedCommand\CommandData;
use Drupal\devel_generate\DevelGenerateBaseInterface;
use Drush\Commands\DrushCommands;
/**
* For commands that are parts of modules, Drush expects to find commandfiles in
* __MODULE__/src/Commands, and the namespace is Drupal/__MODULE__/Commands.
*/
class DevelGenerateCommands extends DrushCommands {
/**
* @var DevelGenerateBaseInterface $manager
*/
protected $manager;
/**
* The plugin instance.
*
* @var DevelGenerateBaseInterface $instance
*/
protected $pluginInstance;
/**
* The Generate plugin parameters.
*
* @var array $parameters
*/
protected $parameters;
/**
* DevelGenerateCommands constructor.
* @param $manager
*/
public function __construct($manager) {
parent::__construct();
$this->setManager($manager);
}
/**
* @return \Drupal\devel_generate\DevelGenerateBaseInterface
*/
public function getManager() {
return $this->manager;
}
/**
* @param \Drupal\devel_generate\DevelGenerateBaseInterface $manager
*/
public function setManager($manager) {
$this->manager = $manager;
}
/**
* @return mixed
*/
public function getPluginInstance() {
return $this->pluginInstance;
}
/**
* @param mixed $pluginInstance
*/
public function setPluginInstance($pluginInstance) {
$this->pluginInstance = $pluginInstance;
}
/**
* @return array
*/
public function getParameters() {
return $this->parameters;
}
/**
* @param array $parameters
*/
public function setParameters($parameters) {
$this->parameters = $parameters;
}
/**
* Create users.
*
* @command generate-users
* @pluginId user
* @param $num Number of users to generate.
* @option kill Delete all users before generating new ones.
* @option roles A comma delimited list of role IDs for new users. Don't specify 'authenticated'.
* @option pass Specify a password to be set for all generated users.
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases genu
*/
public function users($num = 50, $options = ['kill' => FALSE, 'roles' => '']) {
// @todo pass $options to the plugins.
$this->generate();
}
/**
* Create terms in specified vocabulary.
*
* @command generate-terms
* @pluginId term
* @param $machine_name Vocabulary machine name into which new terms will be inserted.
* @param $num Number of terms to generate.
* @option kill Delete all terms before generating new ones.
* @option feedback An integer representing interval for insertion rate logging.
* @validate-entity-load taxonomy_vocabulary machine_name
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases gent
*/
public function terms($machine_name, $num = 50, $options = ['feedback' => 1000]) {
$this->generate();
}
/**
* Create vocabularies.
*
* @command generate-vocabs
* @pluginId vocabulary
* @param $num Number of vocabularies to generate.
* @option kill Delete all vocabs before generating new ones.
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases genv
* @validate-module-enabled taxonomy
*/
public function vocabs($num = 1, $options = ['kill' => FALSE]) {
$this->generate();
}
/**
* Create menus.
*
* @command generate-menus
* @pluginId menu
* @param $number_menus Number of menus to generate.
* @param $number_links Number of links to generate.
* @param $max_depth Max link depth.
* @param $max_width Max width of first level of links.
* @option kill Delete all content before generating new content.
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases genm
*/
public function menus($number_menus = 2, $number_links = 50, $max_depth = 3, $max_width = 8, $options = ['kill' => FALSE]) {
$this->generate();
}
/**
* Create content.
*
* @command generate-content
* @pluginId content
* @param $num Number of nodes to generate.
* @param $max_comments Maximum number of comments to generate.
* @option kill Delete all content before generating new content.
* @option types A comma delimited list of content types to create. Defaults to page,article.
* @option feedback An integer representing interval for insertion rate logging.
* @option skip-fields A comma delimited list of fields to omit when generating random values
* @option languages A comma-separated list of language codes
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases genc
* @validate-module-enabled node
*/
public function content($num = 50, $max_comments = 0, $options = ['kill' => FALSE, 'types' => 'page,article', 'feedback' => 1000]) {
$this->generate();
}
/**
* @hook validate
* @param \Consolidation\AnnotatedCommand\CommandData $commandData
* @return \Consolidation\AnnotatedCommand\CommandError|null
*/
public function validate(CommandData $commandData) {
$manager = $this->getManager();
$args = $commandData->input()->getArguments();
$commandName = array_shift($args);
/** @var DevelGenerateBaseInterface $instance */
$instance = $manager->createInstance($commandData->annotationData()->get('pluginId'), array());
$this->setPluginInstance($instance);
$parameters = $instance->validateDrushParams($args);
$this->setParameters($parameters);
}
public function generate() {
$instance = $this->getPluginInstance();
$instance->generate($this->getParameters());
}
}
\ No newline at end of file
......@@ -492,7 +492,7 @@ class ContentDevelGenerate extends DevelGenerateBase implements ContainerFactory
}
/**
* Retrive 50 uids from the database.
* Retrieve 50 uids from the database.
*/
protected function getUsers() {
$users = array();
......
services:
devel.command:
class: Drupal\devel\Commands\DevelCommands
tags:
- { name: drush.command }
......@@ -2,7 +2,8 @@
/**
* @file
* Drush integration for the devel module.
* This file is only used by Drush8. Drush9 discovers its commands via tagged
* service(s) in devel.services.yml. Also see classes in src/Commands.
*/
use Drupal\Component\Uuid\Php;
......@@ -160,6 +161,7 @@ function drush_devel_fn_event($event = NULL) {
drush_log(dt('No implementations.'), 'ok');
}
}
/**
* Command handler. Show source code of specified function or method.
*/
......
<?php
/**
* @file
* Generate PhpStorm metadata file.
*/
/**
* Implements of hook_drush_command().
*/
function phpstorm_drush_command() {
$items = array();
$items['phpstorm-metadata'] = array(
'description' => 'Save the PhpStorm Metadata file to Drupal root.',
'core' => array('8+'),
'aliases' => array('phpm'),
'category' => 'devel',
);
return $items;
}
/**
* Implements hook_drush_help_alter().
*/
function phpstorm_drush_help_alter(&$command) {
if ($command['command'] == 'cache-rebuild') {
$command['options']['storm'] = 'Write a new PHPstorm metadata file to Drupal root.';
}
}
/*
* Implements drush_hook_post_COMMAND().
*/
function drush_phpstorm_post_cache_rebuild() {
if (drush_get_option('storm')) {
drush_invoke_process('@self', 'phpstorm-metadata');
}
}
/**
* Generate PhpStorm Metadata file.
*
* @see http://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata
*/
function drush_phpstorm_metadata() {
$container = \Drupal::getContainer();
$reflectedClass = new ReflectionClass($container);
$map = array();
// Map for all services of the container.
// @see \Symfony\Component\DependencyInjection\Container::getServiceIds().
foreach ($reflectedClass->getMethods() as $method) {
if (preg_match('/^get(.+)Service$/', $method->name, $match)) {
$id = strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($match[1], '_', '.')));
$service = \Drupal::service($id);
if (is_object($service)) {
$map["\\Drupal::service('')"][$id] = '\\' . get_class($service);
}
}
}
// Entity Manager - getStorage
foreach (\Drupal::entityTypeManager()->getDefinitions() as $type => $definition) {
$class = Drupal::entityTypeManager()->getStorage($type);
$map["\\Drupal::entityManager()->getStorage('')"][$type] = '\\' . get_class($class);
$map["\\Drupal::entityTypeManager()->getStorage('')"][$type] = '\\' . get_class($class);
}
$content = _drush_phpstorm_metadata_phpstorm_metadata_template($map);
file_put_contents(DRUPAL_ROOT . '/.phpstorm.meta.php', $content);
}
function _drush_phpstorm_metadata_phpstorm_metadata_template($data) {
$file = '<?php
namespace PHPSTORM_META {
/** @noinspection PhpUnusedLocalVariableInspection */
/** @noinspection PhpIllegalArrayKeyTypeInspection */
$STATIC_METHOD_TYPES = [
';
foreach ($data as $method => $map) {
$file .= "\n";
$file .= " {$method} => [\n";
foreach ($map as $argument => $class) {
$file .= " '{$argument}' instanceof {$class},\n";
}
$file .= " ],";
$file .= "\n";
}
$file .= '
];
}
';
return $file;
}
<?php
namespace Drupal\devel\Commands;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Component\Uuid\Php;
use Drush\Commands\DrushCommands;
use Drush\Exceptions\UserAbortException;
/**
* For commands that are parts of modules, Drush expects to find commandfiles in
* __MODULE__/src/Commands, and the namespace is Drupal/__MODULE__/Commands.
*/
class DevelCommands extends DrushCommands {
/**
* Uninstall, and Install a list of modules.
* @command devel-reinstall
* @param $modules A comma-separated list of module names.
* @aliases dre
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @allow-additional-options pm-uninstall,pm-enable
*/
public function reinstall($projects) {
$projects = _convert_csv_to_array($projects);
// This is faster than 3 separate bootstraps.
$args = array_merge(array('pm-uninstall'), $projects);
// @todo. Use $application dispatch instead of drush_invoke().
call_user_func_array('drush_invoke', $args);
$args = array_merge(array('pm-enable'), $projects);
call_user_func_array('drush_invoke', $args);
}
/**
* List implementations of a given hook and optionally edit one.
*
* @command devel-hook
* @param $hook The name of the hook to explore.
* @usage devel-hook cron
* List implementations of hook_cron().
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases fnh,fn-hook,hook
*/
function hook($hook) {
// Get implementations in the .install files as well.
include_once './core/includes/install.inc';
drupal_load_updates();
if ($hook_implementations = \Drupal::moduleHandler()->getImplementations($hook)) {
if ($choice = drush_choice(array_combine($hook_implementations, $hook_implementations), 'Enter the number of the hook implementation you wish to view.')) {
$info= $this->codeLocate($choice . "_$hook");
$exec = drush_get_editor();
drush_shell_exec_interactive($exec, $info['file']);
}
}
else {
$this->logger()->success(dt('No implementations.'));
}
}
/**
* List implementations of a given event and optionally edit one.
*
* @command devel-event
* @param $event The name of the event to explore. If omitted, a list of events is shown.
* @usage devel-event
* Pick a Kernel event, then pick an implementation, and then view its source code.
* @usage devel-event kernel.terminate
* Pick a terminate subscribers and view its source code.
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @aliases fne,fn-event,event
*/
function event($event) {
$dispatcher = \Drupal::service('event_dispatcher');
if (empty($event)) {
// @todo Expand this list and move to interact().
$events = array('kernel.controller', 'kernel.exception', 'kernel.request', 'kernel.response', 'kernel.terminate', 'kernel.view');
$events = array_combine($events, $events);
if (!$event = drush_choice($events, 'Enter the event you wish to explore.')) {
throw new UserAbortException();
}
}
if ($implementations = $dispatcher->getListeners($event)) {
foreach ($implementations as $implementation) {
$callable = get_class($implementation[0]) . '::' . $implementation[1];
$choices[$callable] = $callable;
}
if ($choice = drush_choice($choices, 'Enter the number of the implementation you wish to view.')) {
$info= $this->codeLocate($choice);
$exec = drush_get_editor();
drush_shell_exec_interactive($exec, $info['file']);
}
}
else {
$this->logger()->success(dt('No implementations.'));
}
}
/**
* List available tokens.
*
* @command devel-token
* @aliases token
* @field-labels
* group: Group
* token: Token
* name: Name
* @default-fields group,token,name
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*/
public function token($options = ['format' => 'table']) {
$all = \Drupal::token()->getInfo();
foreach ($all['tokens'] as $group => $tokens) {
foreach ($tokens as $key => $token) {
$rows[] = [
'group' => $group,
'token' => $key,
'name' => $token['name'],
];
}
}
return new RowsOfFields($rows);
}
/**
* Generate a UUID.
*
* @command devel-uuid
* @aliases uuid
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @usage drush devel-uuid
* Outputs a Universally Unique Identifier.
*
* @return string
*/
public function uuid() {
$uuid = new Php();
return $uuid->generate();
}
/**
* Get source code line for specified function or method.
*/
function codeLocate($function_name) {
// Get implementations in the .install files as well.
include_once './core/includes/install.inc';
drupal_load_updates();
if (strpos($function_name, '::') === FALSE) {
if (!function_exists($function_name)) {
throw new \Exception(dt('Function not found'));
}
$reflect = new \ReflectionFunction($function_name);
}
else {
list($class, $method) = explode('::', $function_name);
if (!method_exists($class, $method)) {
throw new \Exception(dt('Method not found'));
}
$reflect = new \ReflectionMethod($class, $method);
}
return array('file' => $reflect->getFileName(), 'startline' => $reflect->getStartLine(), 'endline' => $reflect->getEndLine());
}
/**
* Get a list of available container services.
*
* @command devel-services
* @param $prefix A prefix to filter the service list by.
* @aliases devel-container-services,dcs
* @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL
* @usage drush devel-services
* Gets a list of all available container services
* @usage drush dcs plugin.manager
* Get all services containing "plugin.manager"
*
* @return array
*/
public function services($prefix = NULL, $options = ['format' => 'yaml']) {
$container = \Drupal::getContainer();
// Get a list of all available service IDs.
$services = $container->getServiceIds();
// If there is a prefix, try to find matches.
if (isset($prefix)) {
$services = preg_grep("/$prefix/", $services);
}
if (empty($services)) {
throw new \Exception(dt('No container services found.'));
}
sort($services);
return $services;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment