2 namespace Drush\Commands\core;
5 use Drush\Commands\DrushCommands;
6 use Drush\Exceptions\UserAbortException;
7 use Drush\Log\LogLevel;
9 use Robo\Contract\IOAwareInterface;
10 use Robo\Contract\BuilderAwareInterface;
12 class InitCommands extends DrushCommands implements BuilderAwareInterface, IOAwareInterface
17 * Enrich the bash startup file with bash aliases and a smart command prompt.
21 * @option $edit Open the new config file in an editor.
22 * @option $add-path Always add Drush to the $PATH in the user's .bashrc
23 * file, even if it is already in the $PATH. Use --no-add-path to skip
24 * updating .bashrc with the Drush $PATH. Default is to update .bashrc
25 * only if Drush is not already in the $PATH.
26 * @optionset_get_editor
27 * @aliases init,core-init
28 * @usage core-init --edit
29 * Enrich Bash and open drush config file in editor.
30 * @usage core-init --edit --bg
31 * Return to shell prompt as soon as the editor window opens
33 public function initializeDrush($options = ['edit' => false, 'add-path' => ''])
35 $home = Drush::config()->home();
36 $drush_config_dir = $home . "/.drush";
37 $drush_config_file = $drush_config_dir . "/drush.yml";
38 $drush_bashrc = $drush_config_dir . "/drush.bashrc";
39 $drush_prompt = $drush_config_dir . "/drush.prompt.sh";
40 $examples_dir = DRUSH_BASE_PATH . "/examples";
41 $example_configuration = $examples_dir . "/example.drush.yml";
42 $example_bashrc = $examples_dir . "/example.bashrc";
43 $example_prompt = $examples_dir . "/example.prompt.sh";
45 $collection = $this->collectionBuilder();
47 // Create a ~/.drush directory if it does not yet exist
48 $collection->taskFilesystemStack()->mkdir($drush_config_dir);
50 // If there is no ~/.drush/drush.yml, copy example there.
51 if (!is_file($drush_config_file)) {
52 $collection->taskWriteToFile($drush_config_file)->textFromFile($example_configuration);
55 // Decide whether we want to add our Bash commands to
56 // ~/.bashrc or ~/.bash_profile, and create a task to
57 // update it with includes of the various files we write,
58 // as needed. If it is, then we will add it to the collection.
59 $bashrc = $this->findBashrc($home);
60 $taskUpdateBashrc = $this->taskWriteToFile($bashrc)->append();
62 // List of Drush bash configuration files, and
63 // their source templates.
65 $drush_bashrc => $example_bashrc,
66 $drush_prompt => $example_prompt,
69 // Mapping from Drush bash configuration files
70 // to a description of what each one is.
71 $drushBashFileDescriptions = [
72 $drush_bashrc => 'Drush bash customizations',
73 $drush_prompt => 'Drush prompt customizations',
76 foreach ($drushBashFiles as $destFile => $sourceFile) {
77 // If the destination file does not exist, then
78 // copy the example file there.
79 if (!is_file($destFile)) {
80 $collection->taskWriteToFile($destFile)->textFromFile($sourceFile);
81 $description = $drushBashFileDescriptions[$destFile];
82 $collection->progressMessage('Copied {description} to {path}', ['description' => $description, 'path' => $destFile], LogLevel::OK);
83 $pattern = basename($destFile);
84 $taskUpdateBashrc->appendUnlessMatches("#$pattern#", "\n# Include $description.". $this->bashAddition($destFile));
88 // If Drush is not in the $PATH, then figure out which
89 // path to add so that Drush can be found globally.
90 $add_path = $options['add-path'];
91 if ((!drush_which("drush") || $add_path) && ($add_path !== false)) {
92 $drush_path = $this->findPathToDrush();
93 $drush_path = preg_replace("%^" . preg_quote($home) . "/%", '$HOME/', $drush_path);
94 $pattern = "$drush_path";
95 $taskUpdateBashrc->appendUnlessMatches("#$pattern#", "\n# Path to Drush, added by 'drush init'.\nexport PATH=\"\$PATH:$drush_path\"\n\n");
99 if ($taskUpdateBashrc->wouldChange()) {
100 if ($this->io()->confirm(dt("Modify !file to include Drush configuration files?", ['!file' => $bashrc]))) {
101 $collection->addTask($taskUpdateBashrc);
102 $collection->progressMessage('Updated bash configuration file {path}', ['path' => $bashrc], LogLevel::OK);
103 $collection->progressMessage('Start a new shell in order to experience the improvements (e.g. `{shell}`).', ['shell' => 'bash'], LogLevel::OK);
104 $openEditor = $options['edit'];
106 throw new UserAbortException();
109 $collection->progressMessage('No code added to {path}', ['path' => $bashrc]);
111 $result = $collection->run();
113 if ($result->wasSuccessful() && $openEditor) {
114 $exec = drush_get_editor();
115 drush_shell_exec_interactive($exec, $drush_config_file, $drush_config_file);
122 * Determine which .bashrc file is best to use on this platform.
124 protected function findBashrc($home)
126 # Set a default value in case nothing else exists.
127 $file = $home . '/.bashrc';
129 if (!empty($_ENV['SHELL']) && strstr($_ENV['SHELL'], 'zsh')) {
130 $file = $home . '/.zshrc';
131 } elseif (file_exists($home . '/.bash_profile')) {
132 $file = $home . '/.bash_profile';
133 } elseif (file_exists($home . '/.bashrc')) {
134 $file = $home . '/.bashrc';
135 } elseif (file_exists($home . '/.profile')) {
136 $file = $home . '/.profile';
137 } elseif (file_exists($home . '/.functions')) {
138 $file = $home . '/.functions';
145 * Determine where Drush is located, so that we can add
146 * that location to the $PATH.
148 protected function findPathToDrush()
150 // First test: is Drush inside a vendor directory?
151 // Does vendor/bin exist? If so, use that. We do
152 // not have a good way to locate the 'bin' directory
153 // if it has been relocated in the composer.json config
155 if ($vendor_pos = strpos(DRUSH_BASE_PATH, "/vendor/")) {
156 $vendor_dir = substr(DRUSH_BASE_PATH, 0, $vendor_pos + 7);
157 $vendor_bin = $vendor_dir . '/bin';
158 if (is_dir($vendor_bin)) {
163 // Fallback is to use the directory that Drush is in.
164 return DRUSH_BASE_PATH;
167 protected function bashAddition($file)
171 if [ -f "$file" ] ; then