Open gitressa opened 11 months ago
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?
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.
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
?
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.
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
}
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 viaexec
, even if you're usingvendor/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%/*}"
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
@gitressa: As I mentioned in https://github.com/drush-ops/drush/issues/5828#issuecomment-1837320691, 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 https://github.com/drush-ops/drush/issues/5828#issuecomment-1837478344 for an example of adding Drush to the PATH. I haven't tried this function, but it might work.
@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.
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/bin
should 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 ...
@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.
@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
)
}
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?
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.
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.
@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.
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. 💯
When Drush calls itself via exec
, how does it resolve PHP binary and parameters?
For example on a shared webhosting when I have different PHP versions available (and eventually two sites using different PHP versions, like production 8.2 and test 8.3) I must call Drush via php drush
. Furthermore, PHP memory limit defaults sometimes are too low for Drush commands like pm:install
or config:import
. Therefore I always use an alias like
alias php='/usr/local/php83/bin/php -d memory_limit=-1'
alias drush='/usr/local/php83/bin/php -d memory_limit=-1 vendor/bin/drush'
Of course using $PATH would work to determine the correct locations for PHP and Drush binaries. But how can the Parameter -d memory_limit=-1
be passed to the sub-call via exec?
Both of those needs (PATH and custom php.ini) are mentioned briefly in the Note at https://www.drush.org/13.x/install/
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 usevendor/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
, andsource
it to take effect.Using
$PATH
Add Drush folder to$PATH
(reset withsource /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 withunset -f drush
).Not recommended (
alias
)alias drush='vendor/bin/drush'
: This may seem like a simple and good solution, but Drush will sometimes call itself viaexec
. When it does this, Drush expects thatdrush
will be in the$PATH
. If you use an alias, this redispatch might not work correctly.