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

fix: expand ~/bin in PATH and ensure consistency in subshells, for #6627 #6689

Merged
merged 5 commits into from
Nov 8, 2024

Conversation

stasadev
Copy link
Member

@stasadev stasadev commented Nov 5, 2024

The Issue

These comments:

And:

Inside the subshells, some strange things happen:

$ ddev ssh
stas@d11-web:/var/www/html$ echo $PATH
~/bin:/var/www/html/vendor/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/www/html/bin
stas@d11-web:/var/www/html$ bash
stas@d11-web:/var/www/html$ echo $PATH
~/bin:/var/www/html/vendor/bin:~/bin:/var/www/html/vendor/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/www/html/bin:/var/www/html/bin
stas@d11-web:/var/www/html$ bash
stas@d11-web:/var/www/html$ echo $PATH
~/bin:/var/www/html/vendor/bin:~/bin:/var/www/html/vendor/bin:~/bin:/var/www/html/vendor/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/www/html/bin:/var/www/html/bin:/var/www/html/bin

For:

How This PR Solves The Issue

  1. It turned out that when you pass PATH=~/bin:... as env, it doesn't understand what ~ means. This PR replaces ~ with $HOME.
  2. export PATH=... was added every time you go into the subshell, which led to more and more entries being added to the $PATH. I don't know if it affects anything, but it looks pretty weird, so I fixed it.

Manual Testing Instructions

  1. Using DDEV HEAD, install composer:

    ddev composer require composer/composer:v2.8.0 --dev
    

    Add this to .ddev/config.yaml:

    hooks:
        post-start:
            - exec: mkdir -p ~/bin && ln -sf /usr/local/bin/composer ~/bin/composer
    
    ddev restart
    ddev composer -V # should be the same as in /usr/local/bin/composer
    
  2. Try echo $PATH in subshells:

    ddev ssh
    echo $PATH
    bash
    echo $PATH
    bash
    echo $PATH
    

    It should be the same each time.

Automated Testing Overview

Release/Deployment Notes

@rfay
Copy link
Member

rfay commented Nov 5, 2024

Why was ~/bin/composer in use here anyway (in addition to vendor/bin/composer and /usr/local/bin/composer)?

@stasadev
Copy link
Member Author

stasadev commented Nov 5, 2024

Why was ~/bin/composer in use here anyway (in addition to vendor/bin/composer and /usr/local/bin/composer)?

It's the first item in the $PATH, I guess we should respect it, and let people to do such overrides for composer:

@rfay
Copy link
Member

rfay commented Nov 5, 2024

Sorry, my question is not whether it should work, but why we would have used it as a composer instance. As we've seen with the ddev binary, having it in multiple places can only lead to confusion. So I was asking why we would ever put composer in ~/bin to begin with.

@stasadev
Copy link
Member Author

stasadev commented Nov 5, 2024

why we would ever put composer in ~/bin to begin with.

To use a different composer, as @deviantintegral said in #6688 (comment) what if people have composer/composer in their composer.json, but they use it for a different purpose.

Even though I don't use it this way, I see a problem here as well, for example, after installing it, you can't uninstall it in the usual way because it can't uninstall itself:

ddev composer require composer/composer:v2.8.0 --dev
ddev composer remove composer/composer --dev # throws error

Copy link
Member

@rfay rfay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor suggestions.

I generally don't think we should add every workaround for every obscure case we encounter to the docs, because they get cluttered. I usually point to Stack Overflow for cases like that.

@@ -95,7 +95,13 @@ Composer version for the web container and the [`ddev composer`](../usage/comman
| :octicons-file-directory-16: project | `2` | Can be `2`, `1`, or empty (`""`) for latest major version at container build time.<br><br>Can also be a minor version like `2.2` for the latest release of that branch, an explicit version like `1.0.22`, or a keyword like `stable`, `preview` or `snapshot`. See Composer documentation.

!!!note "If your `composer.json` requires `composer/composer` that version will be used instead"
If your project `composer.json` includes `composer/composer`, then the version specified there will normally be used instead of any version specified by `composer_version`, since `vendor/bin/composer` will come first in the in-container `$PATH`.
If your project `composer.json` includes `composer/composer`, then the version specified there will normally be used instead of any version specified by `composer_version`, since `vendor/bin/composer` will come first in the in-container `$PATH`. However, if you prefer to use the version specified by `composer_version`, add the following hook to your `.ddev/config.yaml`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a very unusual workaround. Why would people not want to use the version they specify in their composer.json?

I worry that adding too much detail in places like this just makes it so people can't make it through the docs, or find the right thing when they need it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would people not want to use the version they specify in their composer.json?

It's less about matching the version, and more about issues upgrading composer itself since PHP can't reload classes it's already loaded: composer/composer#11672

I wonder if this should also be improved upstream. Perhaps composer should never install vendor/bin/composer, or if it needs to it should be something like vendor/bin/composer.internal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry that adding too much detail in places like this just makes it so people can't make it through the docs, or find the right thing when they need it.

I think if people use Composer in such an advanced way, they'll know how to change something in $PATH.
I'll remove this example from the docs because it's unlikely to be found.

path, _, err := app.Exec(&ExecOpts{
Cmd: "echo $PATH",
Cmd: `echo $PATH | sed "s|~|$HOME|g"`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if homedir.Expand() could be used successfully here. Probably not, since this is in the context of the container. But transformations like this are notoriously fragile.

(I don't understand what homedir.Expand() replaces the ~ with. It it's $HOME, it's good, I don't think it is.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is not only about Composer binary override, but also if in the future we have some commands that will work just like ddev composer with PATH.

This entry in PATH=~/bin should really be PATH=$HOME/bin, then we don't need these ugly workarounds.

I'll also look into the PATH problem with subshells while I'm here:

@stasadev stasadev force-pushed the 20241105_stasadev_composer_bin branch from 411afd0 to e754818 Compare November 6, 2024 21:33
@stasadev stasadev changed the title fix: respect ~/bin for composer commands, for #6627 fix: expand ~/bin in PATH and ensure consistency in subshells, for #6627 Nov 6, 2024
@github-actions github-actions bot added the dependencies Pull requests that update a dependency file label Nov 6, 2024
@stasadev
Copy link
Member Author

stasadev commented Nov 6, 2024

Side note: when you have ~/bin inside a container with:

hooks:
    post-start:
        - exec: mkdir -p ~/bin

and run

ddev ssh
echo $PATH
/home/stas/bin:/home/stas/bin:/var/www/html/vendor/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/www/html/bin

It has a second entry for $HOME/bin, that's because of this Debian default:

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi

It doesn't check if $HOME/bin is already here.

I decided not to change/fix it.
When you run ddev composer, $PATH has only one $HOME/bin entry, and the second entry only appears inside the container (with ddev ssh).

export PATH="~/bin:$PATH:/var/www/html/bin"
case ":$PATH:" in
*":$HOME/bin:"*) ;;
*) PATH="$HOME/bin:$PATH" ;;
Copy link
Member Author

@stasadev stasadev Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the fix is to write $HOME/bin instead of ~/bin just like Debian does.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs a comment explaining what it's doing.

But it's great, and an excellent solution.

@rfay rfay force-pushed the 20241105_stasadev_composer_bin branch from 2c506da to 10ef45e Compare November 7, 2024 00:59
@rfay
Copy link
Member

rfay commented Nov 7, 2024

Rebased for colima/lima problem

Copy link
Member

@rfay rfay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor suggestions just to make sure future readers can grok what's going on.

Comment on lines 2 to 9
case ":$PATH:" in
*":${DDEV_COMPOSER_ROOT:-/var/www/html}/vendor/bin:"*) ;;
*) PATH="${DDEV_COMPOSER_ROOT:-/var/www/html}/vendor/bin:$PATH" ;;
esac
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a fine solution, but it's really, really cryptic. Please add a comment to both places explaining what it does.

export PATH="~/bin:$PATH:/var/www/html/bin"
case ":$PATH:" in
*":$HOME/bin:"*) ;;
*) PATH="$HOME/bin:$PATH" ;;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs a comment explaining what it's doing.

But it's great, and an excellent solution.

@stasadev
Copy link
Member Author

stasadev commented Nov 8, 2024

Comments added (without a new image rebuild).

Copy link
Member

@rfay rfay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@rfay rfay force-pushed the 20241105_stasadev_composer_bin branch from f3a56f2 to 7f481cc Compare November 8, 2024 20:12
@rfay
Copy link
Member

rfay commented Nov 8, 2024

Rebased, fixed versionconstants, needs image push. Could you push the ddev-webserver image or give me perms on your fork?

@rfay rfay merged commit 62bf39b into ddev:master Nov 8, 2024
4 of 9 checks passed
@rfay rfay deleted the 20241105_stasadev_composer_bin branch November 8, 2024 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix dependencies Pull requests that update a dependency file
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants