Skip to content

Commit

Permalink
Update /examples for Drush 9 (drush-ops#2629)
Browse files Browse the repository at this point in the history
  • Loading branch information
weitzman authored Feb 20, 2017
1 parent 505179c commit 564c9f0
Show file tree
Hide file tree
Showing 17 changed files with 329 additions and 765 deletions.
8 changes: 4 additions & 4 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ Creating Custom Drush Commands

Creating a new Drush command is very easy. Follow these simple steps:

1. Copy the example commandfile at examples/SandwichCommands.php to mymodule/src/Drush/Commands/MyModuleCommands.php
1. Edit the namespace and classnames to match your file.
1. For next step, use the classes for the core Drush commands at /lib/Drush/Commands as inspiration and documention.
1. Rename and edit the makeMeASandwich method. Carefully add/edit/remove annotations above the method and put your logic inside the method.
1. Copy the example commandfile at lib/Drush/Commands/examples/Commands/SandwichCommands.php to mymodule/src/Drush/Commands/MyModuleCommands.php
1. Edit the namespace and classnames in your file to match the file's location.
1. Use the classes for the core Drush commands at /lib/Drush/Commands as inspiration and documentation.
1. Rename and edit the makeSandwich() method. Carefully add/edit/remove annotations above the method and put your logic inside the method.

Drush searches for commandfiles in the following locations:

Expand Down
12 changes: 5 additions & 7 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The _examples_ folder contains example files which you may copy and edit as needed. Read the documentation right in the file. If you see an opportunity to improve the file, please submit a pull request.
The _examples_ folder contains excellent example files which you may copy and edit as needed. Read the documentation right in the file. If you see an opportunity to improve the file, please submit a pull request.

* [drush.wrapper](https://raw.githubusercontent.com/drush-ops/drush/master/examples/drush.wrapper). A handy launcher script which calls the Drush located in vendor/bin/drush and can add options like --local, --root, etc.
* [example.aliases.drushrc.php](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.aliases.drushrc.php). Example site alias definitions.
Expand All @@ -10,9 +10,7 @@ The _examples_ folder contains example files which you may copy and edit as need
* [example.prompt.sh](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.prompt.sh). Displays Git repository and Drush alias status in your prompt.
* [git-bisect.example.sh](https://raw.githubusercontent.com/drush-ops/drush/master/examples/git-bisect.example.sh). Spelunking through Drush's git history with bisect.
* [helloworld.script](https://raw.githubusercontent.com/drush-ops/drush/master/examples/helloworld.script). An example Drush script.
* [pm_update.drush.inc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/pm_update.drush.inc). Restore sqlsrv driver after core update.
* [policy.drush.inc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/policy.drush.inc). A policy file can disallow prohibited commands/options etc.
* [sandwich.drush.inc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/sandwich.drush.inc). A fun example command inspired by a famous XKCD comic.
* [sync_via_http.drush.inc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/sync_via_http.drush.inc). sql-sync modification that transfers via http instead of rsync.
* [sync_enable.drush.inc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/sync_enable.drush.inc). Automatically enable modules after a sql-sync.
* [xkcd.drush.inc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/xkcd.drush.inc). A fun example command that browses XKCD comics.
* [PolicyCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/PolicyCommands.php). A policy file can disallow prohibited commands/options etc.
* [SandwichCommands](https://raw.githubusercontent.com/drush-ops/drush/master/lib/Drush/examples/Commands/SandwichCommands.php). A fun example command inspired by a famous XKCD comic.
* [SyncViaHttpCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/SyncViaHttpCommands.php). sql-sync modification that transfers via http instead of rsync.
* [XkcdCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/XkcdCommands.php). A fun example command that browses XKCD comics.
52 changes: 52 additions & 0 deletions examples/Commands/PolicyCommands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
namespace Drush\Commands;

use Consolidation\AnnotatedCommand\CommandData;
use Drush\Commands\DrushCommands;

/**
* Load this commandfile using the --include option - e.g. `drush --include=/path/to/drush/examples`
*/

class PolicyCommands extends DrushCommands {

/**
* Prevent catastrophic braino. Note that this file has to be local to the
* machine that intitiates the sql-sync command.
*
* hook validate sql-sync
*/
public function sqlSyncValidate(CommandData $commandData) {
if ($commandData->input()->getArgument('destination') == '@prod') {
throw new \Exception(dt('Per !file, you may never overwrite the production database.', ['!file' => __FILE__]));
}
}

/**
* Limit rsync operations to production site.
*
* hook validate core-rsync
*/
public function rsyncValidate(CommandData $commandData) {
if (preg_match("/^@prod/", $commandData->input()->getArgument('destination'))) {
throw new \Exception(dt('Per !file, you may never rsync to the production site.', ['!file' => __FILE__]));
}
}

/**
* Unauthorized may not execute updates.
*
* @hook validate updatedb
*/
public function validateUpdateDb(CommandData $commandData) {
if (!$commandData->input()->getOption('secret') == 'mysecret') {
throw new \Exception(dt('UpoateDb command requires a secret token per site policy.'));
}
}

/**
* @hook option updatedb
* @option secret A required token else user may not run updatedb command.
*/
public function optionsetUpdateDb() {}
}
120 changes: 120 additions & 0 deletions examples/Commands/SandwichCommands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
namespace Drush\Commands;

use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;

/**
* Run these commands using the --include option - e.g. `drush --include=/path/to/drush/examples mmas`
*/

class SandwichCommands extends DrushCommands {

/**
* Makes a delicious sandwich.
*
* @command make-me-a-sandwich
* @param $filling The type of the sandwich (turkey, cheese, etc.). Defaults to ascii.
* @option spreads A comma delimited list of spreads.
* @usage drush mmas turkey --spreads=ketchup,mustard
* Make a terrible-tasting sandwich that is lacking in pickles.
* @aliases mmas
* @bootstrap DRUSH_BOOTSTRAP_NONE
* @complete \SandwichCommands::complete
*/
public function makeSandwich($filling, $options = ['spreads' => NULL]) {
if ($spreads = _convert_csv_to_array('spreads')) {
$list = implode(' and ', $spreads);
$str_spreads = ' with just a dash of ' . $list;
}
$msg = dt('Okay. Enjoy this !filling sandwich!str_spreads.',
array('!filling' => $filling, '!str_spreads' => $str_spreads)
);
drush_print("\n" . $msg . "\n");
$this->printFile(__DIR__ . '/sandwich-nocolor.txt');
}

/**
* Show a table of information about available spreads.
*
* @command xkcd-spreads
* @aliases xspreads
* @bootstrap DRUSH_BOOTSTRAP_NONE
* @field-labels
* name: Name
* description: Description
* available: Num
* taste: Taste
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*/
public function spread($options = ['format' => 'table']) {
$data = array(
'ketchup' => array(
'name' => 'Ketchup',
'description' => 'Some say its a vegetable, but we know its a sweet spread.',
'available' => '7',
'taste' => 'sweet',
),
'mayonnaise' => array(
'name' => 'Mayonnaise',
'description' => 'A nice dairy-free spead.',
'available' => '12',
'taste' => 'creamy',
),
'mustard' => array(
'name' => 'Mustard',
'description' => 'Pardon me, but could you please pass that plastic yellow bottle?',
'available' => '8',
'taste' => 'tangy',
),
'pickles' => array(
'name' => 'Pickles',
'description' => 'A necessary part of any sandwich that does not taste terrible.',
'available' => '63',
'taste' => 'tasty',
),
);
return new RowsOfFields($data);
}

/**
* Commandfiles may also add topics. These will appear in
* the list of topics when `drush topic` is executed.
* To view the topic below, run `drush --include=/full/path/to/examples topic`
*/

/**
* Ruminations on the true meaning and philosophy of sandwiches.
*
* @command sandwich-exposition
* @hidden
* @topic
* @bootstrap DRUSH_BOOTSTRAP_NONE
*/
public function ruminate() {
self::printFile(__DIR__ . '/sandwich-topic.md');
}

/**
* @hook validate make-me-a-sandwich
*/
public function sandwichValidate(CommandData $commandData) {
$name = posix_getpwuid(posix_geteuid());
if ($name['name'] !== 'root') {
throw new \Exception(dt('What? Make your own sandwich.'));
}
}

/**
* Command argument complete callback.
*
* Provides argument values for shell completion.
*
* @return array
* Array of popular fillings.
*/
function complete() {
return array('values' => array('turkey', 'cheese', 'jelly', 'butter'));
}
}
92 changes: 92 additions & 0 deletions examples/Commands/SyncViaHttpCommands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
namespace Drush\Commands;


use Consolidation\AnnotatedCommand\CommandData;
use Drush\Commands\DrushCommands;

/**
* Load this commandfile using the --include option - e.g. `drush --include=/path/to/drush/examples`
*/

class SyncViaHttpCommands extends DrushCommands {

/**
* When a hook extends a command with additional options, it must
* implement declare those option(s) in a @hook option like this one. Doing so will add
* the option to the help text for the modified command, and will also
* allow the new option to be specified on the command line. Without
* this, Drush will fail with an error when a user attempts to use
* an unknown option.
*
* @hook option sql-sync
* @option http-sync Copy the database via http instead of rsync. Value is the url that the existing database dump can be found at.
* @option http-sync-user Username for the protected directory containing the sql dump.
* @option http-sync-password Password for the same directory.
*/
public function optionsetSqlSync() {}

/**
* During the pre hook, determine if the http-sync option has been
* specified. If it has been, then disable the normal ssh + rsync
* dump-and-transfer that sql-sync usually does, and transfer the
* database dump via an http download.
*
* @hook pre-command sql-sync
*/
public function preSqlSync(CommandData $commandData) {
$sql_dump_download_url = $commandData->input()->getOption('http-sync');
if (!empty($sql_dump_download_url)) {
$user = $commandData->input()->getOption('http-sync-user');
$password = $commandData->input()->getOption('http-sync-password');
$source_dump_file = $this->downloadFile($sql_dump_download_url, $user, $password);
$commandData->input()->setOption('target-dump', $source_dump_file);
$commandData->input()->setOption('no-dump', TRUE);
$commandData->input()->setOption('no-sync', TRUE);
}
}

/**
* Downloads a file.
*
* Optionally uses user authentication, using either wget or curl, as available.
*/
protected function downloadFile($url, $user = FALSE, $password = FALSE, $destination = FALSE, $overwrite = TRUE) {
static $use_wget;
if ($use_wget === NULL) {
$use_wget = drush_shell_exec('which wget');
}

$destination_tmp = drush_tempnam('download_file');
if ($use_wget) {
if ($user && $password) {
drush_shell_exec("wget -q --timeout=30 --user=%s --password=%s -O %s %s", $user, $password, $destination_tmp, $url);
}
else {
drush_shell_exec("wget -q --timeout=30 -O %s %s", $destination_tmp, $url);
}
}
else {
if ($user && $password) {
drush_shell_exec("curl -s -L --connect-timeout 30 --user %s:%s -o %s %s", $user, $password, $destination_tmp, $url);
}
else {
drush_shell_exec("curl -s -L --connect-timeout 30 -o %s %s", $destination_tmp, $url);
}
}
if (!drush_get_context('DRUSH_SIMULATE')) {
if (!drush_file_not_empty($destination_tmp) && $file = @file_get_contents($url)) {
@file_put_contents($destination_tmp, $file);
}
if (!drush_file_not_empty($destination_tmp)) {
// Download failed.
throw new \Exception(dt("The URL !url could not be downloaded.", array('!url' => $url)));
}
}
if ($destination) {
drush_move_dir($destination_tmp, $destination, $overwrite);
return $destination;
}
return $destination_tmp;
}
}
53 changes: 53 additions & 0 deletions examples/Commands/XkcdCommands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
namespace Drush\Commands;

/**
* Run these commands using the --include option - e.g. `drush --include=/path/to/drush/examples xkcd`
*/

class XkcdCommands extends DrushCommands {

/**
* Retrieve and display xkcd cartoons.
*
* @command xkcd-fetch
* @param $search Optional argument to retrieve the cartoons matching an index number, keyword search or "random". If omitted the latest cartoon will be retrieved.
* @option image-viewer Command to use to view images (e.g. xv, firefox). Defaults to "display" (from ImageMagick).
* @option google-custom-search-api-key Google Custom Search API Key, available from https://code.google.com/apis/console/. Default key limited to 100 queries/day globally.
* @usage drush xkcd
* Retrieve and display the latest cartoon.
* @usage drush xkcd sandwich
* Retrieve and display cartoons about sandwiches.
* @usage drush xkcd 123 --image-viewer=eog
* Retrieve and display cartoon #123 in eog.
* @usage drush xkcd random --image-viewer=firefox
* Retrieve and display a random cartoon in Firefox.
* @aliases @xkcd
*/
public function fetch($search = NULL, $options = ['image-viewer' => 'open', 'google-custom-search-api-key' => NULL]) {
if (empty($search)) {
drush_start_browser('http://xkcd.com');
}
elseif (is_numeric($search)) {
drush_start_browser('http://xkcd.com/' . $search);
}
elseif ($search == 'random') {
$xkcd_response = @json_decode(file_get_contents('http://xkcd.com/info.0.json'));
if (!empty($xkcd_response->num)) {
drush_start_browser('http://xkcd.com/' . rand(1, $xkcd_response->num));
}
}
else {
// This uses an API key with a limited number of searches per.
$search_response = @json_decode(file_get_contents('https://www.googleapis.com/customsearch/v1?key=' . drush_get_option('google-custom-search-api-key', 'AIzaSyDpE01VDNNT73s6CEeJRdSg5jukoG244ek') . '&cx=012652707207066138651:zudjtuwe28q&q=' . $search));
if (!empty($search_response->items)) {
foreach ($search_response->items as $item) {
drush_start_browser($item->link);
}
}
else {
throw new \Exception(dt('The search failed or produced no results.'));
}
}
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 564c9f0

Please sign in to comment.