Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to most easily make vendor/bin/drush available as drush #5828

Open
gitressa opened this issue Dec 1, 2023 · 17 comments
Open

Document how to most easily make vendor/bin/drush available as drush #5828

gitressa opened this issue Dec 1, 2023 · 17 comments

Comments

@gitressa
Copy link
Contributor

gitressa commented Dec 1, 2023

Is your feature request related to a problem? Please describe.

The vast majority of Drupal sites use Drush on a Linux server. After installing Drush, you need to manually add it to the $PATH, or else you need to use vendor/bin/drush, which is not ideal.

Describe the solution you'd like

After installing Drush, it would be awesome if you could use the command drush, without any extra steps, but this is not possible, since the Drush folder needs to be added to the $PATH manually. But we could look for alternative solutions, or expand the documentation.

Additional context

drupal.org issue: https://www.drupal.org/project/ideas/issues/3405516

Possible solutions

Add in a Bash shell script file such as ~/.bashrc, and source it to take effect.

Using $PATH
Add Drush folder to $PATH (reset with source /etc/profile)

PATH=$PATH:./vendor/bin

If there's only one Drupal installation on the system, you can add the absolute path to the Drush folder, and now call drush from anywhere.

PATH=$PATH:/path/to/project/vendor/bin

Function with Git
Use Git with a function, to allow running drush inside sub-folders, shared by chx. May only work with absolute Drush path registered in $PATH (remove with unset -f drush).

function drush () {
  $(git rev-parse --show-toplevel)/vendor/bin/drush "$@"
}

Not recommended (alias)

alias drush='vendor/bin/drush': This may seem like a simple and good solution, but Drush will sometimes call itself via exec. When it does this, Drush expects that drush will be in the $PATH. If you use an alias, this redispatch might not work correctly.

@gitressa
Copy link
Contributor Author

gitressa commented Dec 2, 2023

It looks like better documentation is the best way forward, so adding some alternatives in the issue summary under "Possible solutions".

Alias vs. $PATH
What are the downsides to using an alias, as opposed to adding to $PATH? They share the same requirement, that they are to be used from the project root. As I see it, adding an alias is easier to deal with, and more immediately understandable.

But maybe there are good reasons to use $PATH instead?

@greg-1-anderson
Copy link
Member

greg-1-anderson commented Dec 3, 2023

Drush will sometimes call itself via exec. When it does this, Drush expects that drush will be in the $PATH. If you use an alias, this redispatch might not work correctly. In the past, Drush took some pains to look at $argv[0] and etc to try and call Drush with the same path and ini settings & etc as it was launched with; this code was simplified some time ago, with the stipulation that now, drush must be in the $PATH.

If you use an alias, perhaps it could find the drush it wants and then set a new PATH that includes its directory. I don't think I've seen any techniques try to do that, but in theory it might work.

@gitressa
Copy link
Contributor Author

gitressa commented Dec 3, 2023

Thanks for clarifying @greg-1-anderson, that's an important piece of the puzzle.

While updating the $PATH as part of calling an alias might work, the added complexity defeats the ease of using alias in the first place, I think ... but maybe it's doable?

I'll move using an alias out of the possible solutions, and add your explanation why it's probably not a great idea.

I suppose the function drush () solution have the same problem? Or maybe, if you both add the function and register the absolute path in $PATH, all bases are covered?

PATH=$PATH:/path/to/project/vendor/bin
function drush () {
  $(git rev-parse --show-toplevel)/vendor/bin/drush "$@"
}

This raises another question for me: Is it actually required to add the Drush folder to $PATH for those occasions where it calls itself via exec, even if you're using vendor/bin/drush?

@gitressa gitressa changed the title Allow using drush out of the box (not vendor/bin/drush) Document how to most easily make vendor/bin/drush available as drush Dec 3, 2023
@greg-1-anderson
Copy link
Member

greg-1-anderson commented Dec 3, 2023

My thought was to use a function, and add Drush to the PATH inside the body. Something like this:

PATH=$PATH:/path/to/project/vendor/bin
function drush () {
  DRUSH_BIN="$(git rev-parse --show-toplevel)/vendor/bin"
  PATH="$DRUSH_BIN:$PATH" "$DRUSH_BIN/drush" "$@"
}

Untested, but should work in concept.

@obriat
Copy link
Contributor

obriat commented Dec 4, 2023

Here's a git free function, could be useful on production servers where git could not be available :

drush() {
  cur_path=$(pwd)
  while [[ "$cur_path" != "" && ! -e "$cur_path/vendor/bin/drush" ]]; do
    cur_path="${cur_path%/*}"
  done

  if [ -e "$cur_path/vendor/bin/drush" ]; then
    eval "$cur_path/vendor/bin/drush $@"
  else
    echo "Could not found drush, maybe your not in a drupal folder or drush is not installed. See https://www.drupal.org/docs/develop/development-tools/drush"
  fi
}

@gitressa
Copy link
Contributor Author

gitressa commented Dec 4, 2023

Thanks @greg-1-anderson! though your suggestion is using the Git function, not alias ...

Also, do you know the answer to this question?

[...] Is it actually required to add the Drush folder to $PATH for those occasions where it calls itself via exec, even if you're using vendor/bin/drush?

And thanks @obriat! That seems to work well. Perhaps you can briefly describe how it works? Mostly this bit: cur_path="${cur_path%/*}"

@obriat
Copy link
Contributor

obriat commented Dec 4, 2023

Hi,
Sorry, this is stackoverflow copy/past :), after some research, it's called "pattern filtering", "/*" removes the rightist folder of the path string (just like .. while do).

Here's the explanation: https://stackoverflow.com/questions/10535985/how-to-remove-filename-prefix-with-a-posix-shell/25536935#25536935

But I don't know how to add the Drush folder to $PATH, specially without polluting the main $PATH and if eval is the best way to execute drush

@greg-1-anderson
Copy link
Member

@gitressa: As I mentioned in #5828 (comment), it is actually necessary to add Drush to the PATH.

Sorry for being indistinct about alias vs function. They are about the same, behavior-wise. Above, when I was talking about the limitations of aliases, I meant that these limitations also applied to functions. The main advantage of functions over aliases is that you can express them over multiple lines, so they are easier to read.

@obriat: See #5828 (comment) for an example of adding Drush to the PATH. I haven't tried this function, but it might work.

@obriat
Copy link
Contributor

obriat commented Dec 4, 2023

@greg-1-anderson I'm afraid that your proposition will add the drush path to the main $PATH each time it is executed and it could be worst if you have several projet on the same machine.

Here's a proposition that should leave the $PATH untouched (but I'm not a shell expert so there should be room for improvement):

drush() {
  PROJECT_PATH=$(pwd)
  while [[ "$PROJECT_PATH" != "" && ! -e "$PROJECT_PATH/vendor/bin/drush" ]]; do
    PROJECT_PATH="${PROJECT_PATH%/*}"
  done

  if [ -e "$PROJECT_PATH/vendor/bin/drush" ]; then
    SAVE_PATH=$PATH
    PATH="$PROJECT_PATH/vendor/bin/drush:$PATH"
    $PROJECT_PATH/vendor/bin/drush $@
    PATH="$SAVE_PATH"
  else
    echo "Could not found drush, maybe your not in a drupal folder or drush is not installed. See https://www.drupal.org/docs/develop/development-tools/drush"
  fi
}

BONUS:
This function should be added to the default #/.*shrc with a drush command (drush shell:alias (--disable), similar to drush completion). It should be auto-installed with a post-install composer script.

@gitressa
Copy link
Contributor Author

gitressa commented Dec 4, 2023

Thanks for confirming that it's always necessary to add Drush to the PATH @greg-1-anderson.

And thanks for experimenting with functions @obriat :)

Since development environments such as DDEV and Lando offer ddev drush or lando drush by default, it is not necessary to configure PATH doing work locally, on your own machine with these tools.

It then follows that the documentation is mostly needed for configuring servers, where in my opinion, there is for the most situations no need to work from anything else than the root of the project, to run git pull, drush config:import, drush updatedb, etc. From that follows that a simple PATH=$PATH:./vendor/binshould be the recommended solution, possibly using the full path to Drush, if there's only one installation on the system.

This is pretty much what is already documented on https://www.drush.org/latest/install/ under "2. Execution". I originally thought that maybe an alternative (and simple?) solution would be possible, which could be added to a "How to run simply drush"-documentation page -- but it doesn't seem like it, so far ...

@greg-1-anderson
Copy link
Member

@obriat You are correct; however, you can fix that problem by adding parenthesis to my original suggestion:

function drush () {
  (
    DRUSH_BIN="$(git rev-parse --show-toplevel)/vendor/bin"
    PATH="$DRUSH_BIN:$PATH" "$DRUSH_BIN/drush" "$@"
  )
}

I thought that the function isolated the PATH variable, since I didn't export it, but I was wrong. The parenthesis fork a subshell, which isolates the change to the PATH variable.

@obriat
Copy link
Contributor

obriat commented Dec 4, 2023

@gitressa Outside from "containered" dev tools, I've seen a lot of servers where more than one drupal site are running.
So IMHO, a 15 lines function that auto detect the correct drush to execute and doesn't depend on third party tools like git is a nice feature for sys admin (eg: editing settings.php and running drush cr)

@greg-1-anderson thanks for the tip, here's my new version (much longer but without git dependency):

drush() {
  (
   PROJECT_PATH=$(pwd)
    while [[ "$PROJECT_PATH" != "" && ! -e "$PROJECT_PATH/vendor/bin/drush" ]]; do
      PROJECT_PATH="${PROJECT_PATH%/*}"
    done

    if [ -e "$PROJECT_PATH/vendor/bin/drush" ]; then
      PATH="$PROJECT_PATH/vendor/bin/drush:$PATH" $PROJECT_PATH/vendor/bin/drush $@
    else
      echo "Could not found drush, maybe your not in a drupal folder or drush is not installed. See https://www.drupal.org/docs/develop/development-tools/drush"
    fi
  )
}

@gitressa
Copy link
Contributor Author

gitressa commented Dec 5, 2023

Sure @obriat, but if you're always running commands from the project root, I just can't see why it's needed ... Maybe you can expand with some more context, and clarify this?

@greg-1-anderson
Copy link
Member

Here's my really short version that makes git optional:

function drush () {
  (
    DRUSH_BIN="$(git rev-parse --show-toplevel 2>/dev/null || echo ".")/vendor/bin"
    PATH="$DRUSH_BIN:$PATH" "$DRUSH_BIN/drush" "$@"
  )
}

Works only at the project root if you don't have git, or anywhere in the git project if you do.

@hansfn
Copy link
Contributor

hansfn commented Dec 5, 2023

Just posting some (random) solutions that are worked on:

I think whatever solution we land on, it should be maintained here under "drush-ops". I think we should have something ready instead of too many options in the install instructions.

@obriat
Copy link
Contributor

obriat commented Dec 5, 2023

@gitressa As I said, as a sysadmin I had to do some tasks on random subfolders or files (cache settings,…) and run drush (cr mostly). So in this case it could be useful to have a command that does not depend on a specific location.

It’s this kind of “install and forget” setup that could bring a bit of magic that will make drush more easy to use, specially for people who are not Drupal specialists.

@dasginganinja
Copy link

I created dasginganinja/drush-launcher for a system-level drush wrapper.

There was a strong need for something in my $PATH. I didn't want a bunch of dependencies. We don't have git directories on production either. I wasn't a fan of the bash based profile solutions either. And, we have multiple installations on our systems. We like running Drush contextually, too.

I'm open to PRs and want to help push this issue further. I personally feel there is still a space for the drush launcher. If it was maintained by drush-ops, then that'd be best for the community. 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants