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

userpath append errors on Alpine linux: "No such file or directory: 'bash'" #60

Open
deronnax opened this issue Jul 23, 2024 · 1 comment

Comments

@deronnax
Copy link

Easily reproducible with docker:

$ docker run -it --rm alpine:3.20 sh -c "apk add -v py3-pip && pip install --break-system-package userpath && userpath append /opt/brew"

[...]
Traceback (most recent call last):
  File "/usr/bin/userpath", line 8, in <module>
    sys.exit(userpath())
             ^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/userpath/cli.py", line 122, in append
    elif up.in_new_path(location, shells=shells, all_shells=all_shells, home=home):
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/userpath/core.py", line 17, in in_new_path
    return interface.location_in_new_path(location, check=check)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/userpath/interface.py", line 116, in location_in_new_path
    new_path = get_flat_output(show_path_command)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/userpath/utils.py", line 33, in get_flat_output
    process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 1026, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.11/subprocess.py", line 1953, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'bash'

I think it's a bug but I don't know. Anyway, it makes fail pipx ensurepath on Alpine linux.

@matthewhughes934
Copy link

matthewhughes934 commented Aug 1, 2024

If you're looking for a workaround you can set the SHELL environment variable and userpath will pick that up (i.e. the added --env argument):

docker run --env 'SHELL=/bin/sh' -it --rm alpine:3.20 sh -c "apk add -v py3-pip && pip install --break-system-package userpath && userpath append /opt/brew"

this feels like a bug, the detect_shells function:

def detect_shell(cls):
will fail to detect the shell when:

  • There's no shell in the parent process name (e.g. a script invoked with Python)
  • The SHELL env var is not set

In this case it falls back to trying the default shells

DEFAULT_SHELLS = ('bash', 'sh')
which includes bash. Maybe these default should be reduced to just sh since that's defined in POSIX and is generally more likely to be available than bash

Another approach for unix systems might be to try pw_shell before falling back:

import os
import pwd

def shell_from_pwd():
    try:
        pw = pwd.getpwuid(os.getuid())
    except KeyError:
        return None
    else:
        return pw.pw_shell

Which should return /bin/sh on Alpine Linux

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

2 participants