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

Latest changes have made unattended installation impossible #1914

Closed
1 task done
tegant opened this issue May 10, 2021 · 55 comments · Fixed by #1922
Closed
1 task done

Latest changes have made unattended installation impossible #1914

tegant opened this issue May 10, 2021 · 55 comments · Fixed by #1922
Assignees

Comments

@tegant
Copy link

tegant commented May 10, 2021

I love this project, but the latest changes have made the unattended installation of pyenv impossible.

I have a bash script that installs it unattended like this:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >>~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >>~/.bash_profile
echo 'eval "$(pyenv init -)"' >>~/.bash_profile
echo 'export PYTHONPATH=:"$HOME/tegant/app"' >>~/.bash_profile
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bash_profile
. ~/.bash_profile
pyenv install 3.9.4
pyenv virtualenv 3.9.4 venv
pyenv activate venv

But the latest version of pyenv doesn't allow eval "$(pyenv init -).
Now it's supposed to be done like echo 'eval "$(pyenv init --path)"' >>~/.profile. But the documentation doesn't quite explain that.

echo 'export PYENV_ROOT="$HOME/.pyenv"' >>~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >>~/.bash_profile
echo 'eval "$(pyenv init --path)"' >>~/.profile
echo 'export PYTHONPATH=:"$HOME/tegant/app"' >>~/.bash_profile
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bash_profile
. ~/.profile
. ~/.bash_profile
pyenv install 3.9.4
pyenv virtualenv 3.9.4 venv
pyenv activate venv

So when I try to activate the venv inside shell I get an error thrown:

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

Description

  • Platform information: Debian 10.9
  • [X ] OS architecture (e.g. amd64): AWS Ec2 t3.micro
  • [X ] pyenv version: 1.2.27-29-gfd3c891d
  • [X ] Python version: 3.9.4
  • [X ] C Compiler information: gcc (Debian 8.3.0-6) 8.3.0
@native-api native-api self-assigned this May 10, 2021
@native-api
Copy link
Member

native-api commented May 10, 2021

I understand the difficulties but don't quite see a way that's guaranteed to work reliably for an automated installation in all poasible cases.
Let's try to figure something out.


Here's the thing:

  • It all started with Shims directory appears multiple times in PATH #1649:
  • PATH manipulations must be done
    • in the login shell (to avoid executing them multiple times if nested shells are spawned), and
    • exactly in ~/.profile (so that they also have an effect on non-login shells in GUI sessions -- again, without executing multiple times if nested shells are spawned)

So we need to

  • run a few commands only in the login shell (both a regular shell and a GUI manager)
  • then a few commands in any interactive shell

The problem is:

  • In some distros, the stock ~/.profile sources ~/.bashrc at the start
    • so we can't just blindly append things to ~/.profile because they would be run too late
    • and we can't insert them automatically in a more intelligent way because its logic can be arbitrary

@native-api
Copy link
Member

My best idea so far is to recommend two different ways: for the case where ~./profile sources ~/.bashrc and for the case where it doesn't.

The first could e.g. append everything to ~/.bashrc but guard the login-only lines with login shell detection.

This however would break if the user's login shell is not Bash -- it would not execute anything!!

@tegant
Copy link
Author

tegant commented May 10, 2021

I understand you would like to enable this for all distributions. I can speak for Debian.

A fresh installed Debian doesn't come with ~/.bash_profile nor ~/.profile.
But it would read the former if it's there. I have never used the latter. I don't know if this would work.

Debian comes with ~/.bashrc though.

@tegant
Copy link
Author

tegant commented May 10, 2021

@native-api

Ok, based on your second comment. What would be the solution for Debian with Bash? I still can't figure this out.
Because doing echo 'eval "$(pyenv init --path)"' >>~/.bash_profile throws the same error.

@agoose77
Copy link

agoose77 commented May 10, 2021

This post explains the different uses of each file.

In your case, you want .profile to contain the $PATH manipulation, and .bashrc should call eval "$(pyenv init -)". .bash_profile should source the two in the correct order.

@tegant
Copy link
Author

tegant commented May 10, 2021

It's such a mess for something that was working perfectly. Sorry for the rant.

I have followed your advice and it still doesn't work. I think you have a typo and may have missed --path.

~/.bash_profile

source ~/.profile

~/.bashrc

...
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"

~/.profile

eval "$(pyenv init)" 
eval "$(pyenv virtualenv-init -)"
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

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

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

I'm getting the following error:

source ~/.bash_profile
# Add pyenv executable to PATH by adding
# the following to ~/.profile:

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"

# Load pyenv automatically by appending
# the following to ~/.bashrc:

eval "$(pyenv init -)"

# and the following to ~/.profile:

eval "$(pyenv init --path)"

# If your ~/.profile sources ~/.bashrc,
# the lines should be inserted before the part
# that does that.

# Make sure to restart your entire logon session
# for changes to ~/.profile to take effect.

@tegant
Copy link
Author

tegant commented May 10, 2021

I just noticed, I had missed the minus in there: eval "$(pyenv init -)"

Despite the correction, I'm now getting:

source ~/.bash_profile
WARNING: `pyenv init -` no longer sets PATH.
Run `pyenv init` to see the necessary changes to make to your configuration.

@agoose77
Copy link

agoose77 commented May 10, 2021

@tegant OK, I think there were some crossed wires on my part between what you want to do (solve this for Debian) vs what the pyenv project needs to be able to do.
A disclaimer: I use Ubuntu rather than Debian, so we might get something wrong first time around!

What the files do:

To clarify the purpose of the files:

  • .bashrc is for bash-shell-specific features (e.g. aliases, etc). It's sourced by bash for interactive-non-login shells.
  • .profile is for environment variables (predominantly). It is sourced by most(?) interactive login shells.

See this for more

What you need to do:

  1. Because the .profile file is sourced by more than just bash (and only once), you want to setup your PATH variable (and the other PYENV variables) here; i.e.
    export PYENV_ROOT="$HOME/.pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    eval "$(pyenv init --path)"
    If you happen to look at what pyenv init --path does, you'll notice that it just modifies PATH. You can therefore do that yourself:
    export PYENV_ROOT="$HOME/.pyenv"
    export PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
  2. In .bashrc you want only the shell-specific features; i.e.
    eval "$(pyenv init -)"

⚠️ Beware

When you modify the login configuration file e.g. .profile, your changes will not be reflected in your environment until you log-out-and-in. Alternatively, you can manually source the file, or SSH to localhost with ssh $USER@localhost. I'd recommend the latter approach, because if you have a broken configuration you can fix it more easily.

@tegant
Copy link
Author

tegant commented May 10, 2021

Thanks Agoose, I appreciate your help here. Really do. Sadly it is not working in a non-interactive way.

.bash_profile

source ~/.profile

~/.bashrc

...
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

~/.profile

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"

if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

This doesn't throw an error when ran manually:

source ~/.bash_profile

But we can no longer have this in our bash script to install it automatically like this:

git clone https://github.com/yyuu/pyenv.git ~/.pyenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'source ~/.profile' >>~/.bash_profile
echo 'eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"' >>~/.bashrc
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
source ~/.bash_profile
pyenv install 3.9.4
pyenv virtualenv 3.9.4 venv
pyenv activate venv

It all works until activation and then it fails.

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

This means we can no longer install our software automatically via scripts. It's a complete deal breaker for us.

@agoose77
Copy link

agoose77 commented May 10, 2021

@tegant at a high level, you definitely will be able to install things via scripts - the only thing that's changed here is pyenv now requires you to be more explicit about modifying PATH.

# Install pyenv
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

# Install pyenv-virtualenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bashrc

# Load new variables
# Assume that .profile contains `source $HOME/.bashrc`
source ~/.profile

# Pyenv
pyenv install 3.9.4
pyenv virtualenv 3.9.4 venv
pyenv activate venv

Incidentally, I hadn't seen the 1 i address syntax for sed before so TIL something new!

@tegant
Copy link
Author

tegant commented May 10, 2021

Incidentally, I hadn't seen the 1 i address syntax for sed before so TIL something new!

Glad, I could help. :-)

  1. Alrighty, I have removed everything from .bash_profile and removed the added lines to both .bashrc and .profile respectively.
  2. I exited the ssh session and came back via SSH to ensure the session is reset.
  3. I copy pasted all your code above into a script and ran it. The main difference is that you source .profile directly instead of .bash_profile, correct?
  4. Sadly I'm getting the same error. Screenshot attached as evidence. :-)

Screenshot 2021-05-10 at 16 18 57

Senui added a commit to BioDynaMo/biodynamo that referenced this issue May 10, 2021
@agoose77
Copy link

agoose77 commented May 10, 2021

You need to delete .bash_profile if you do not need it. Otherwise, it gets sourced in favour of .profile

Does your .profile source .bashrc? On my Ubuntu install, it does.

@tegant
Copy link
Author

tegant commented May 10, 2021

Yes,

Debian puts this by default into .profile

if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi
echo $BASH_VERSION
5.0.3(1)-release

So, yes, it is sourced from .profile. And in your code sample you are explicitly sourcing .profile, therefore .bashrc is sourced.

@tegant
Copy link
Author

tegant commented May 10, 2021

Guys, I think the best solution for now is simply

git clone --depth 1 --branch 1.2.27 https://github.com/yyuu/pyenv.git ~/.pyenv

This will solve everything. I really hope you consider the possibility of reverting #1649

Thanks

@agoose77
Copy link

@tegant I think you're being a little hasty. It's understandable that you're feeling frustrated about these changes, but really not much has changed. The reason you're having problems is because we need to understand why your configuration is different to the expected.

@agoose77
Copy link

Can you share your .profile and .bashrc files? Can you run env during your install process (at the bottom before pyenv virtualenv)?

@tegant
Copy link
Author

tegant commented May 10, 2021

I came across this issue at 10:00 this morning. It's now 17:44. I spent almost eight hours installing a virtualenv. haha My job is at risk. :-)

.bashrc

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar

# make less more friendly for non-text input files, see lesspipe(1)
#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;
esac

# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
        # We have color support; assume it's compliant with Ecma-48
        # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
        # a case would tend to support setf rather than setaf.)
        color_prompt=yes
    else
        color_prompt=
    fi
fi

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
    ;;
esac

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
    #alias dir='dir --color=auto'
    #alias vdir='vdir --color=auto'

    #alias grep='grep --color=auto'
    #alias fgrep='fgrep --color=auto'
    #alias egrep='egrep --color=auto'
fi

# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'

# some more ls aliases
#alias ll='ls -l'
#alias la='ls -A'
#alias l='ls -CF'

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

./profile

# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

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

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

There is no bash_profile on Debian by default.

@agoose77
Copy link

Could you also output the result of calling env before pyenv install?

@julianfortune
Copy link

julianfortune commented May 10, 2021

On Ubuntu, this is the fix that I came up with:

# Prepend the path modifications to the top of .profile (⚠️ overrites existing .profile)
(echo -e 'export PYENV_ROOT="$HOME/.pyenv"' \
         '\nexport PATH="$PYENV_ROOT/bin:$PATH"' \
         '\neval "$(pyenv init --path)"\n'; \
         cat /etc/skel/.profile) > ~/.profile

# Append shell initialization to the bottom of .bashrc
echo '"$(pyenv init -)"' >> .bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >> .bashrc

@native-api
Copy link
Member

I've made a PR with updated instructions for Bash and Zsh based on feedback: #1920.

Among other things, I've provided an alternative configuration for Bash that allows automatic installation.

Please review it and tell me:

  • If the instructions (both README and pyenv init) are clear
  • If they work for different distros
  • If there's a better way

@native-api
Copy link
Member

native-api commented May 11, 2021

The way I came up with turned out to be not enough.
Figured out 2 others but both have drawbacks.
See #1920 (review) .

@tegant
The most realistic automated way for Ubuntu I see as of now is:

echo -e 'if shopt -q login_shell; then'\
'\n  export PYENV_ROOT="$HOME/.pyenv"'\
'\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
'\n  eval "$(pyenv init --path)"'\
'\nfi' >>~/.bashrc

echo -e 'if [ -z "$BASH_VERSION" ]; then'\
'\n  export PYENV_ROOT="$HOME/.pyenv"'\
'\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
'\n  eval "$(pyenv init --path)"'\
'\nfi' >>~/.profile

echo 'eval "$(pyenv init -)"' >> ~/.bashrc

(then relogin)

@bersbersbers
Copy link

bersbersbers commented May 12, 2021

I would love to read (and understand) everything that's going on here, but I cannot due to lack of time (and in-depth Linux experience). Do know that this recent change has fixed something that was not broken ;)

Here's my problems which I believe I solved somehow, but maybe you guys can consider them for future "fixes":

  1. When sshing into my remote Linux system, .bashrc is called first (through /etc/profile, I believe, which the file itself says should not be modified), and then .bash_profile. So eval "$(pyenv init -)" will fail at least once (for two reasons: first because the path to pyenv is not in PATH; second, and worse, because PYENV_ROOT is not set yet).

  2. When a .bash_profile exists, bash does not load .profile apparently.

@agoose77
Copy link

@bersbersbers what distro are you running? /etc/profile shouldn't call $HOME/.bashrc

Usually it's .bash_profile which contains bash to source .profile and then .bashrc

@bersbersbers
Copy link

@bersbersbers what distro are you running? /etc/profile shouldn't call $HOME/.bashrc

This is on openSUSE Leap 15.2, see my /etc/profile.

Find test -r $HOME/.bashrc && . $HOME/.bashrc to see what I mean.

# /etc/profile for SUSE Linux
#
# PLEASE DO NOT CHANGE /etc/profile. There are chances that your changes
# will be lost during system upgrades. Instead use /etc/profile.local for
# your local settings, favourite global aliases, VISUAL and EDITOR
# variables, etc ...

#
# Check which shell is reading this file
#
norc=false
restricted=false
if test -f /proc/mounts ; then
  if ! is=$(readlink /proc/$$/exe 2>/dev/null) ; then
    case "$0" in
    *pcksh)	is=ksh	;;
    *bash)	is=bash	;;
    *)		is=sh	;;
    esac
  fi
  case "$is" in
    */bash)	is=bash
	while read -r -d $'\0' a ; do
	    case "$a" in
	    --norc)
		readonly norc=true ;;
	    --restricted)
		readonly restricted=true ;;
	    esac
	done < /proc/$$/cmdline
	case "$0" in
	sh|-sh|*/sh)
		is=sh	;;
	esac		;;
    */ash)	is=ash  ;;
    */dash)	is=ash  ;;
    */ksh)	is=ksh  ;;
    */ksh93)	is=ksh  ;;
    */pdksh)	is=ksh  ;;
    */mksh)	is=ksh  ;;
    */lksh)	is=ksh  ;;
    */*pcksh)	is=ksh  ;;
    */zsh)	is=zsh  ;;
    */*)	is=sh   ;;
  esac
  #
  # `r' in $- occurs *after* system files are parsed
  #
  for a in $SHELL ; do
    case "$a" in
      */r*sh)
        readonly restricted=true ;;
      -r*|-[!-]r*|-[!-][!-]r*)
        readonly restricted=true ;;
      --restricted)
        readonly restricted=true ;;
    esac
  done
  unset a
else
  is=sh
fi

#
# Call common progams from /bin or /usr/bin only
#
_path ()
{
    command -p ${1+"$@"}
}

#
# Initialize terminal
#
tty=`_path tty 2> /dev/null`
test $? -ne 0 && tty=""
if test -O "$tty" -a -n "$PS1"; then
    test -z "${TERM}"		&& { TERM=linux; export TERM; }
    test "${TERM}" = "unknown"	&& { TERM=linux; export TERM; }
    test "${TERM}" = "ibm327x"	&& { TERM=dumb;  export TERM; }
    if test "$(uname -m)" = "s390x" ; then
	if test "$tty" = "/dev/sclp_line0" -o "$tty" = "/dev/ttyS0" ; then
	    test "${TERM}" = "vt220" && { TERM=dumb;  export TERM; }
	fi
    fi
    case "$TERM" in
    screen.*)
	test -e /usr/share/terminfo/s/${TERM} || { TERM=screen;  export TERM; } ;;
    esac
    # Do not change settings on local line if connected to remote
    if test -z "$SSH_TTY" -a "${TERM}" != "dumb" ; then
	_path stty sane cr0 pass8 dec
	_path tset -I -Q
    fi
fi
unset TERMCAP

#
# Time until a complete key sequence must have arrived
#
#ESCDELAY=2000
#export ESCDELAY

#
# The user file-creation mask
#
# The global umask value is stored in /etc/login.defs and
# will be set by pam_umask.so (see "man pam_umask").
#umask 022

#
# Setup for gzip and (t)csh users
#
if test -z "$PROFILEREAD" ; then
    # GZIP=-9
    # export GZIP
    CSHEDIT=emacs
    export CSHEDIT
fi

#
# ksh/ash sometimes do not know
#
test -z "$UID"  && readonly  UID=`_path id -ur 2> /dev/null`
test -z "$EUID" && readonly EUID=`_path id -u  2> /dev/null`
test -z "$USER" && USER=`_path id -un 2> /dev/null`
test -z "$MAIL" && MAIL=/var/spool/mail/$USER
if test -x /bin/uname ; then
    test -z "$HOST" && HOST=`/bin/uname -n`
    test "$HOST" = "localhost" && HOST=`/bin/uname -n`
    test -z "$CPU"  &&  CPU=`/bin/uname -m`
fi
# Remark: /proc/sys/kernel/domainname and the program domainname
# its self will provide the NIS/YP domainname, see domainname(8).
if test -s /etc/HOSTNAME ; then
    test -z "$HOSTNAME" && HOSTNAME=`cat /etc/HOSTNAME`
else
    test -z "$HOSTNAME" && HOSTNAME=$HOST
fi
test -z "$LOGNAME"  && LOGNAME=$USER
case "$CPU" in
    i?86) HOSTTYPE=i386   ;;
    *)    HOSTTYPE=${CPU} ;;
esac
  OSTYPE=linux
MACHTYPE=${CPU}-suse-${OSTYPE}
# Do NOT export UID, EUID, USER, and LOGNAME
export MAIL HOST CPU HOSTNAME HOSTTYPE OSTYPE MACHTYPE

#
# You may use /etc/initscript, /etc/profile.local or the
# ulimit package instead to set up ulimits and your PATH.
#
# if test "$is" != "ash" -a ! -r /etc/initscript; then
#     ulimit -Sc 0		# don't create core files
#     ulimit -Sd $(ulimit -Hd)
#     ulimit -Ss $(ulimit -Hs)
#     ulimit -Sm $(ulimit -Hm)
# fi

#
# Make path more comfortable
#
# save current path setting, we might want to restore it
ORIG_PATH=$PATH
#
if test -z "$PROFILEREAD" ; then
    PATH=/usr/local/bin:/usr/bin:/bin
    if test "$HOME" != "/" ; then
	for dir in $HOME/bin/$CPU $HOME/bin ; do
	    test -d $dir && PATH=$dir:$PATH
	done
    fi
    if test "$UID" = 0 ; then
	test -d /opt/kde3/sbin  && PATH=/opt/kde3/sbin:$PATH
	PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH
    fi
    for dir in	/usr/X11/bin \
		/usr/X11R6/bin \
		/var/lib/dosemu \
		/usr/games \
		/opt/bin \
		/opt/kde3/bin \
		/opt/kde2/bin \
		/opt/kde/bin \
		/usr/openwin/bin \
		/opt/cross/bin
    do
	test -d $dir && PATH=$PATH:$dir
    done
    unset dir
    export PATH
fi

#
# Most bourn shell clones knows about this
#
if test -z "$PROFILEREAD" ; then
    HISTSIZE=1000
    export HISTSIZE
fi

#
# Set some environment variables for TeX/LaTeX (Not used due luatex)
#
#if test -n "$TEXINPUTS" ; then
#    TEXINPUTS=":$TEXINPUTS:$HOME/.TeX:/usr/share/doc/.TeX:/usr/doc/.TeX"
#else
#    TEXINPUTS=":$HOME/.TeX:/usr/share/doc/.TeX:/usr/doc/.TeX"
#fi
#export TEXINPUTS

#
# Configure the default pager on SUSE Linux
#
if test -z "$LESS" -a -x /usr/bin/less ; then
    LESS="-M -I -R"
    LESSOPEN="lessopen.sh %s"
    LESSCLOSE="lessclose.sh %s %s"
    LESS_ADVANCED_PREPROCESSOR="no"
    if test -s /etc/lesskey.bin ; then
	LESSKEY=/etc/lesskey.bin
    fi
    PAGER=less
    MORE=-sl
    export LESSOPEN LESSCLOSE LESS LESSKEY PAGER LESS_ADVANCED_PREPROCESSOR MORE
fi

#
# Minicom 
#
if test -z "$PROFILEREAD" ; then
    MINICOM="-c on"
    export MINICOM
fi

#
# Current manpath
#
if test -z "$PROFILEREAD" ; then
    tmp="$MANPATH"
    unset MANPATH
    if test -n "$tmp" ; then
	MANPATH="${tmp}:`test -x /usr/bin/manpath && /usr/bin/manpath -q`"
    else
	MANPATH="`test -x /usr/bin/manpath && /usr/bin/manpath -q`"
    fi
    unset tmp
    export MANPATH
fi

#
# Some applications do not handle the XAPPLRESDIR environment properly,
# when it contains more than one directory. More than one directory only
# makes sense if you have a client with /usr mounted via nfs and you want
# to configure applications machine dependent. Uncomment the lines below
# if you want this.
#
#XAPPLRESDIR="$XAPPLRESDIR:/var/X11R6/app-defaults:/usr/X11R6/lib/X11/app-defaults"
#export XAPPLRESDIR

#
# These settings are recommended for old motif applications
#
if test -z "$PROFILEREAD" ; then
    if [ -r /usr/share/X11/XKeysymDB ]; then
	export XKEYSYMDB=/usr/share/X11/XKeysymDB
    else
	export XKEYSYMDB=/usr/X11R6/lib/X11/XKeysymDB
    fi
    if [ -d /usr/share/X11/nls ]; then
	export XNLSPATH=/usr/share/X11/nls
    else
	export XNLSPATH=/usr/X11R6/lib/X11/nls
    fi

    #
    # Midnight Commander needs this to run in color mode
    #
    COLORTERM=1
    export COLORTERM
fi

#
# For RCS
#
#VERSION_CONTROL=numbered
#export VERSION_CONTROL

#
# Source profile.d files and UTF8 settings
#
# But do not source this if PROFILEREAD is already set to avoid
# overriding locale variables already present in the environment
#
if test -z "$PROFILEREAD" ; then
    test -r /etc/profile.d/sh.ssh && . /etc/profile.d/sh.ssh
fi

#
# Source profile extensions for certain packages, the super
# may disable some of them by setting the sticky bit.
#
if test -d /etc/profile.d -a -z "$PROFILEREAD" ; then
    for s in /etc/profile.d/*.sh ; do
	test -r $s -a ! -k $s && . $s
    done
    unset s
fi

if test "$is" != "ash" ; then
    #
    # And now let's see if there is a local profile
    # (for options defined by your sysadmin, not SUSE Linux)
    #
    test -s /etc/profile.local && . /etc/profile.local
fi

#
# Avoid overwriting user settings if called twice
#
if test -z "$PROFILEREAD" ; then
    readonly PROFILEREAD=true
    export PROFILEREAD
fi

#
# Standard ssh command does not do an login, therefore
# /etc/profile will be sourced by /etc/bash.bashrc
#
if test -z "$_SOURCED_FOR_SSH" -a "$norc" != true ; then
    #
    # System BASH specials, maybe also good for other shells
    # Note that ksh always reads /etc/ksh.kshrc
    #
    if test "$is" != ksh -a "$is" != zsh ; then
	_is_save=$is
	test -r /etc/bash.bashrc && . /etc/bash.bashrc
	is=$_is_save
	unset _is_save
    fi
    if test "$restricted" = true ; then
	readonly _HOMEBASHRC=true
    fi
    if test "$is" = "bash" -a -z "$_HOMEBASHRC" ; then
	# loop detection
	readonly _HOMEBASHRC=true
	test -r $HOME/.bashrc && . $HOME/.bashrc
    fi

    #
    # KSH specials
    #
    if test "$is" = "ksh" -a -r /etc/ksh.kshrc ; then
	if test "$restricted" = true ; then
	    readonly _HOMEKSHRC=true
	fi
	if test ! /etc/bash.bashrc -ef /etc/ksh.kshrc ; then
	    test -r /etc/bash.bashrc && . /etc/bash.bashrc
	fi
	if test -n "$ENV" -a "$ENV" != "\$HOME/.kshrc" -a "$ENV" != "$HOME/.kshrc" -a -z "$_HOMEKSHRC" ; then
	    # loop detection
	    readonly _HOMEKSHRC=true
	    test -r $HOME/.kshrc && . $HOME/.kshrc
	fi
    fi
fi
if test "$restricted" = true ; then
    PATH=/usr/lib/restricted/bin
    export PATH
fi

#
# An X session
#
case "$-" in
*i*)
    if test "$TERM" = "xterm" -a -O "$tty" -a -z "${SSH_TTY}" ; then
	echo "Directory: $PWD"
	# Last but not least
	date
    fi ;;
esac
unset ORIG_PATH
unset is

#
# End of /etc/profile
#

_SOURCED_FOR_SSH is set by this /etc/bash.bashrc, but apparently only when doing ssh user@host command or something like this.

# /etc/bash.bashrc for SUSE Linux
#
# PLEASE DO NOT CHANGE /etc/bash.bashrc There are chances that your changes
# will be lost during system upgrades.  Instead use /etc/bash.bashrc.local
# for bash or /etc/ksh.kshrc.local for ksh or /etc/zsh.zshrc.local for the
# zsh or /etc/ash.ashrc.local for the plain ash bourne shell  for your local
# settings, favourite global aliases, VISUAL and EDITOR variables, etc ...

#
# Check which shell is reading this file
# check if variables are read-only before setting them
# for example in a restricted shell
if unset noprofile 2>/dev/null ; then
  noprofile=false
fi
if unset restricted 2>/dev/null ; then
  restricted=false
fi
: ${_is_save:=unset}
if test -z "$is" ; then
 if test -f /proc/mounts ; then
  if ! is=$(readlink /proc/$$/exe 2>/dev/null) ; then
    case "$0" in
    *pcksh)	is=ksh	;;
    *bash)	is=bash	;;
    *)		is=sh	;;
    esac
  fi
  case "$is" in
    */bash)	is=bash
	while read -r -d $'\0' a ; do
	    case "$a" in
	    --noprofile)
		readonly noprofile=true ;;
	    --restricted)
		readonly restricted=true ;;
	    esac
	done < /proc/$$/cmdline
	case "$0" in
	sh|-sh|*/sh)
		is=sh	;;
	esac		;;
    */ash)	is=ash  ;;
    */dash)	is=ash  ;;
    */ksh)	is=ksh  ;;
    */ksh93)	is=ksh  ;;
    */pdksh)	is=ksh  ;;
    */mksh)	is=ksh  ;;
    */lksh)	is=ksh  ;;
    */*pcksh)	is=ksh  ;;
    */zsh)	is=zsh  ;;
    */*)	is=sh   ;;
  esac
  #
  # `r' in $- occurs *after* system files are parsed
  #
  for a in $SHELL ; do
    case "$a" in
      */r*sh)
        readonly restricted=true ;;
      -r*|-[!-]r*|-[!-][!-]r*)
        readonly restricted=true ;;
      --restricted)
        readonly restricted=true ;;
    esac
  done
  unset a
 else
  is=sh
 fi
fi

#
# Call common progams from /bin or /usr/bin only
#
_path ()
{
    if test -x /usr/bin/$1 ; then
	${1+"/usr/bin/$@"}
    elif test -x   /bin/$1 ; then
	${1+"/bin/$@"}
    fi
}


#
# ksh/ash sometimes do not know
#
test -z "$UID"  && readonly  UID=`_path id -ur 2> /dev/null`
test -z "$EUID" && readonly EUID=`_path id -u  2> /dev/null`

test -s /etc/profile.d/ls.bash && . /etc/profile.d/ls.bash

#
# Avoid trouble with Emacs shell mode
#
if test "$EMACS" = "t" ; then
    _path tset -I -Q
    _path stty cooked pass8 dec nl -echo
fi

#
# Set prompt and aliases to something useful for an interactive shell
#
case "$-" in
*i*)
    #
    # Set prompt to something useful
    #
    case "$is" in
    bash)
	# If COLUMNS are within the environment the shell should update
	# the winsize after each job otherwise the values are wrong
	case "$(declare -p COLUMNS 2> /dev/null)" in
	*-x*COLUMNS=*) shopt -s checkwinsize
	esac
	# Append history list instead of override
	shopt -s histappend
	# All commands of root will have a time stamp
	if test "$UID" -eq 0  ; then
	    HISTTIMEFORMAT=${HISTTIMEFORMAT:-"%F %H:%M:%S "}
	fi
	# Force a reset of the readline library
	unset TERMCAP
	#
	# Returns short path (last two directories)
	#
	spwd () {
	  ( IFS=/
	    set $PWD
	    if test $# -le 3 ; then
		echo "$PWD"
	    else
		eval echo \"..\${$(($#-1))}/\${$#}\"
	    fi ) ; }
	#
	# Set xterm prompt with short path (last 18 characters)
	#
	if _path tput hs 2>/dev/null || _path tput -T $TERM+sl hs 2>/dev/null || \
	   _path tput -T ${TERM%%[.-]*}+sl hs 2>/dev/null || \
	   [[ $TERM = *xterm* || $TERM = *gnome* || $TERM = *konsole* || $TERM = *xfce* ]]
	then
	    #
	    # Mirror prompt in terminal "status line", which for graphical
	    # terminals usually is the window title. KDE konsole in
	    # addition needs to have "%w" in the "tabs" setting, ymmv for
	    # other console emulators.
	    #
	    if [[ $TERM = *xterm* || $TERM = *gnome* || $TERM = *konsole* || $TERM = *xfce* ]]
	    then
		# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous
		_tsl=$(echo -en '\e]2;')
		_isl=$(echo -en '\e]1;')
		_fsl=$(echo -en '\007')
	    elif _path tput -T $TERM+sl tsl 2>/dev/null ; then
		_tsl=$(_path tput -T $TERM+sl tsl 2>/dev/null)
		_isl=''
		_fsl=$(_path tput -T $TERM+sl fsl 2>/dev/null)
	    elif _path tput -T ${TERM%%[.-]*}+sl tsl 2>/dev/null ; then
		_tsl=$(_path tput -T $TERM+sl tsl 2>/dev/null)
		_isl=''
		_fsl=$(_path tput -T $TERM+sl fsl 2>/dev/null)
	    else
		_tsl=$(_path tput tsl 2>/dev/null)
		_isl=''
		_fsl=$(_path tput fsl 2>/dev/null)
	    fi
	    _sc=$(tput sc 2>/dev/null)
	    _rc=$(tput rc 2>/dev/null)
	    if test -n "$_tsl" -a -n "$_isl" -a "$_fsl" ; then
		TS1="$_sc$_tsl%s@%s:%s$_fsl$_isl%s$_fsl$_rc"
	    elif test -n "$_tsl" -a "$_fsl" ; then
		TS1="$_sc$_tsl%s@%s:%s$_fsl$_rc"
	    fi
	    unset _isl _tsl _fsl _sc _rc
	    ppwd () {
		local dir
		local -i width
		test -n "$TS1" || return;
		dir="$(dirs +0)"
		let width=${#dir}-18
		test ${#dir} -le 18 || dir="...${dir#$(printf "%.*s" $width "$dir")}"
		if test ${#TS1} -gt 17 ; then
		    printf "$TS1" "$USER" "$HOST" "$dir" "$HOST"
		else
		    printf "$TS1" "$USER" "$HOST" "$dir"
		fi
	    }
	else
	    ppwd () { true; }
	fi
	# If set: do not follow sym links
	# set -P
	#
	# Other prompting for root
	if test "$UID" -eq 0  ; then
	    if test -n "$TERM" -a -t ; then
	    	_bred="$(_path tput bold 2> /dev/null; _path tput setaf 1 2> /dev/null)"
	    	_sgr0="$(_path tput sgr0 2> /dev/null)"
	    fi
	    # Colored root prompt (see bugzilla #144620)
	    if test -n "$_bred" -a -n "$_sgr0" ; then
		_u="\[$_bred\]\h"
		_p=" #\[$_sgr0\]"
	    else
		_u="\h"
		_p=" #"
	    fi
	    unset _bred _sgr0
	else
	    _u="\u@\h"
	    _p=">"
	fi
	if test -z "$EMACS" -a -z "$MC_SID" -a "$restricted" != true -a \
		-z "$STY" -a -n "$DISPLAY" -a ! -r $HOME/.bash.expert
	then
	    _t="\[\$(ppwd)\]"
	else
	    _t=""
	fi
	case "$(declare -p PS1 2> /dev/null)" in
	*-x*PS1=*)
	    ;;
	*)
	    # With full path on prompt
	    PS1="${_t}${_u}:\w${_p} "
#	    # With short path on prompt
#	    PS1="${_t}${_u}:\$(spwd)${_p} "
#	    # With physical path even if reached over sym link
#	    PS1="${_t}${_u}:\$(pwd -P)${_p} "
	    ;;
	esac
	unset _u _p _t
	;;
    ash)
	cd () {
	    local ret
	    command cd "$@"
	    ret=$?
	    PWD=$(pwd)
	    if test "$UID" = 0 ; then
		PS1="${HOST}:${PWD} # "
	    else
		PS1="${USER}@${HOST}:${PWD}> "
	    fi
	    return $ret
	}
	cd .
	;;
    ksh)
	# Some users of the ksh are not common with the usage of PS1.
	# This variable should not be exported, because normally only
	# interactive shells set this variable by default to ``$ ''.
	if test "${PS1-\$ }" = '$ ' -o "${PS1-\$ }" = '# ' ; then
	    if test "$UID" = 0 ; then
		PS1="${HOST}:"'${PWD}'" # "
	    else
		PS1="${USER}@${HOST}:"'${PWD}'"> "
	    fi
	fi
	;;
    zsh)
#	setopt chaselinks
	if test "$UID" = 0; then
	    PS1='%n@%m:%~ # '
	else
	    PS1='%n@%m:%~> '
	fi
	;;
    *)
	if test "$UID" = 0 ; then
	    PS1="${HOST}:"'${PWD}'" # "
	else
	    PS1="${USER}@${HOST}:"'${PWD}'"> "
	fi
	;;
    esac
    PS2='> '

    if test "$is" = "ash" ; then
	# The ash shell does not have an alias builtin in
	# therefore we use functions here. This is a seperate
	# file because other shells may run into trouble
	# if they parse this even if they do not expand.
	test -s /etc/profile.d/alias.ash && . /etc/profile.d/alias.ash
    else
	test -s /etc/profile.d/alias.bash && . /etc/profile.d/alias.bash
	test -s $HOME/.alias && . $HOME/.alias
    fi

    #
    # Expert mode: if we find $HOME/.bash.expert we skip our settings
    # used for interactive completion and read in the expert file.
    #
    if test "$is" = "bash" -a -r $HOME/.bash.expert ; then
	. $HOME/.bash.expert
    elif test "$is" = "bash" ; then
	# Complete builtin of the bash 2.0 and higher
	case "$BASH_VERSION" in
	[2-9].*)
	    if test -e /etc/bash_completion ; then
		. /etc/bash_completion
	    elif test -s /etc/profile.d/bash_completion.sh ; then
		. /etc/profile.d/bash_completion.sh
	    elif test -s /etc/profile.d/complete.bash ; then
		. /etc/profile.d/complete.bash
	    fi
	    # Do not source twice if already handled by bash-completion
	    if [[ -n $BASH_COMPLETION_COMPAT_DIR && $BASH_COMPLETION_COMPAT_DIR != /etc/bash_completion.d ]]; then
		for s in /etc/bash_completion.d/*.sh ; do
		    test -r $s && . $s
		done
	    fi
	    if test -e $HOME/.bash_completion ; then
		. $HOME/.bash_completion
	    fi
	    if test -f /etc/bash_command_not_found ; then
		. /etc/bash_command_not_found
	    fi
	    ;;
	*)  ;;
	esac
    fi

    # Do not save dupes and lines starting by space in the bash history file
    HISTCONTROL=ignoreboth
    if test "$is" = "ksh" ; then
	# Use a ksh specific history file and enable
    	# emacs line editor
    	: ${HISTFILE=$HOME/.kshrc_history}
    	: ${VISUAL=emacs}
	case $(set -o) in
	*multiline*) set -o multiline
	esac
    fi
    # command not found handler in zsh version
    if test "$is" = "zsh" ; then
	if test -f /etc/zsh_command_not_found ; then
	    . /etc/zsh_command_not_found
	fi
    fi
    ;;
esac

# Source /etc/profile.d/vte.sh, which improvies usage of VTE based terminals.
# It is vte.sh's responsibility to 'not load' when it's not applicable (not inside a VTE term)
# If you want to 'disable' this functionality, set the sticky bit on /etc/profile.d/vte.sh
if test -r /etc/profile.d/vte.sh -a ! -k /etc/profile.d/vte.sh; then
  . /etc/profile.d/vte.sh
fi

if test "$_is_save" = "unset" ; then
    #
    # Just in case the user excutes a command with ssh or sudo
    #
    if test \( -n "$SSH_CONNECTION" -o -n "$SUDO_COMMAND" \) -a -z "$PROFILEREAD" -a "$noprofile" != true ; then
	_is_save="$is"
	_SOURCED_FOR_SSH=true
	. /etc/profile > /dev/null 2>&1
	unset _SOURCED_FOR_SSH
	is="$_is_save"
	_is_save=unset
    fi
fi

#
# Set GPG_TTY for curses pinentry
# (see man gpg-agent and bnc#619295)
#
if test -t && type -p tty > /dev/null 2>&1 ; then
    GPG_TTY="`tty`"
    export GPG_TTY
fi

#
# And now let us see if there is e.g. a local bash.bashrc
# (for options defined by your sysadmin, not SUSE Linux)
#
case "$is" in
bash) test -s /etc/bash.bashrc.local && . /etc/bash.bashrc.local ;;
ksh)  test -s /etc/ksh.kshrc.local   && . /etc/ksh.kshrc.local ;;
zsh)  test -s /etc/zsh.zshrc.local   && . /etc/zsh.zshrc.local ;;
ash)  test -s /etc/ash.ashrc.local   && . /etc/ash.ashrc.local
esac
test -s /etc/sh.shrc.local && . /etc/sh.shrc.local

if test "$_is_save" = "unset" ; then
    unset is _is_save
fi

if test "$restricted" = true -a -z "$PROFILEREAD" ; then
    PATH=/usr/lib/restricted/bin
    export PATH
fi
#
# End of /etc/bash.bashrc
#

Even if my analysis not 100% correct - I certainly see this:

C:\Users\bers>ssh host
Last login: [...]
Have a lot of fun...
This is .bashrc
This is .bash_profile
This is .bashrc [this is me calling .bashrc from .bash_profile]

@agoose77
Copy link

@bersbersbers wow, OpenSUSE actually sources .bashrc for SSH shells/sudo. I find that very odd! It looks like it's intended to maintain the user environment for these cases. That's a bit ... disturbing!

@bersbersbers
Copy link

@agoose77 and I think it does that even for non-SSH shells (It's just that for some SSH shells it does not do that.), see here:

Note that the login shell also sources the configuration files listed under Table 15.2, “Bash Configuration Files for Non-Login Shells”.

https://doc.opensuse.org/documentation/leap/startup/html/book-opensuse-startup/cha-adm-shell.html#tab-adm-shell-config-loginshells

@native-api
Copy link
Member

Anyway, here's the PR with the auto-install option: #1922 (see the link there so see the rendered README).

@native-api
Copy link
Member

native-api commented May 13, 2021

Anyway, here's the PR with the auto-install option: #1922 (see the link there so see the rendered README).

Please check it out and tell if the option works and if there're any clarifications needed or anything
(e.g. it may be worth adding a brief explanation of how the code achieves the goal).

@bersbersbers
Copy link

bersbersbers commented May 14, 2021

I believe the easiest way would be to surround the ~/.bashrc part of config with a guard that would only run it if the profile part of config has already run:

if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; done

Yes, this is what I have been doing - specifically,

command -v pyenv > /dev/null && eval "$(pyenv init -)"

Wouldn't it make sense for you to add this in pyenv init instructions as well? As far as I can see, this makes sense in every case.

@tegant
Copy link
Author

tegant commented May 26, 2021

@native-api @agoose77

Apologies for the late reply. We had a release going out and had all hands full. I just had a few hours time to go through this and test the latest. Unfortunately it is not working.

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'export PYENV_ROOT="$HOME"/.pyenv' >>~/.bashrc
echo 'export PATH="$PYENV_ROOT"/bin:"$PATH"' >>~/.bashrc
echo 'eval "$(pyenv init -)"' >>~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bashrc
. ~/.profile
. ~/.bashrc
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

This leads to the same problem as before.
Based on the changes that native-api has proposed:

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv

echo -e 'if shopt -q login_shell; then' \
      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
      '\n eval "$(pyenv init --path)"' \
      '\nfi' >> ~/.bashrc
echo -e 'if [ -z "$BASH_VERSION" ]; then'\
      '\n  export PYENV_ROOT="$HOME/.pyenv"'\
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
      '\n  eval "$(pyenv init --path)"'\
      '\nfi' >>~/.profile
. ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

This actually makes it worse, because pyenv isn't in path.

test.sh: line 17: pyenv: command not found

Honestly guys, please don't get it the wrong way. You have "fixed" something that wasn't broken, and looking at the issues, it is causing so much trouble for everyone. The slogan of this project was a Simple Python version management. Sadly now it has become a guess game, what has to go in which environment file.

@agoose77
Copy link

agoose77 commented May 26, 2021

@tegant I don't speak for the project developers but;

Shell configuration is tricky, and needs to be done properly. In my experience, a lot of developers do not properly configure their shells, and so they can be easily broken / slow due to doing too much in the wrong place. Pyenv shouldn't do things the wrong way just because other people do.

For Debian, assuming you're using bash, then the scripts that you've posted expect .profile to source .bashrc, which is the default in Debian:

if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi

The -z "$BASH_VERSION" test should prevent the sourcing happening in .profile, unless you're using a non-bash shell (which won't source .bashrc. If you edit your .profile, then you need to make sure it still does this.

Clearly, it is not desirable that users have been impacted by a configuration change. However, this is free software; the authors of pyenv don't owe anyone anything. Whether you intended it to, your final remark comes across as a little entitled, which I don't think is fair.

@tegant
Copy link
Author

tegant commented May 26, 2021

@agoose77

My apologies, I didn't mean to cause any offend. I was hoping to leave it as a constructive feedback. If my previous post was misunderstood, I apologise again. We all have been there to fix a feature that was well intended, but caused headache at the end. Anyway let's focus on how we can automate this again. :-)

I have started off a fresh installation of Debian Buster 10 on AWS. Yes, I'm using Bash.

The default of ~/.profile is:

if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

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

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

There is no ~/.bash_profile that could interfere with ~/.profile.

So you are correct, ./profile is sourcing ./bashrc.

I'm not sure, If I understand this last bit correctly:

The -z "$BASH_VERSION" test should prevent the sourcing happening in .profile, unless you're using a non-bash shell (which won't source .bashrc. If you edit your .profile, then you need to make sure it still does this.

Since I'm using bash, you are saying I don't need to put anything into ~/.profile at all, correct?
So all I need to do is to add the following into ./bashrc

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'export PYENV_ROOT="$HOME"/.pyenv' >>~/.bashrc
echo 'export PATH="$PYENV_ROOT"/bin:"$PATH"' >>~/.bashrc
echo 'eval "$(pyenv init -)"' >>~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bashrc
. ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

This ends up like this:

Cloning into '/home/admin/.pyenv'...
remote: Enumerating objects: 19800, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (272/272), done.
remote: Total 19800 (delta 458), reused 602 (delta 397), pack-reused 19082
Receiving objects: 100% (19800/19800), 4.02 MiB | 2.50 MiB/s, done.
Resolving deltas: 100% (13389/13389), done.
Cloning into '/home/admin/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2072, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2072 (delta 1), reused 1 (delta 0), pack-reused 2064
Receiving objects: 100% (2072/2072), 586.87 KiB | 26.68 MiB/s, done.
Resolving deltas: 100% (1414/1414), done.
test.sh: line 10: pyenv: command not found

@tegant
Copy link
Author

tegant commented May 26, 2021

@agoose77 I have some more discovery here to share, if you don't mind, please.

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'export PYENV_ROOT="$HOME"/.pyenv' >>~/.bashrc
echo 'export PATH="$PYENV_ROOT"/bin:"$PATH"' >>~/.bashrc
echo 'eval "$(pyenv init -)"' >>~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bashrc

If I cut the script to only this part.
Exit the shell and SSH back to the server.
I can then continue as expected with the following.

pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

But this means Pyenv 2.0 can no longer be automated as it was possible before.
We can no longer have one bash script to install pyenv and activate the virtualenv and continue installing the requirements.txt etc. This is sadly a major downside of version 2.0

@agoose77
Copy link

@tegant the "automated installation" code that @native-api implemented is designed to work on "most" systems. If you know exactly how your system is configured, you can simplify it.

I'm not sure, If I understand this last bit correctly:

The -z "$BASH_VERSION" test should prevent the sourcing happening in .profile, unless you're using a non-bash shell (which won't source .bashrc. If you edit your .profile, then you need to make sure it still does this.

Since I'm using bash, you are saying I don't need to put anything into ~/.profile at all, correct?
So all I need to do is to add the following into ./bashrc

If you want to use the automated installer, the defaults should work. However, if you want to customise this yourself, you can "just" put this in your ~/.profile.

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"

How are you testing all of this? You need to make sure that you log out and log in after modifying either file in this case, because the .bashrc is testing for the login_shell option which is only set on login.

@native-api
Copy link
Member

@tegant You should be able to if you heed the instructions in the README. None of your snippets posted so far do that.

If something is unclear there, I'm all ears. I was specifically asking if anything's unclear when writing them.

@tegant
Copy link
Author

tegant commented May 26, 2021

Thanks guys for your feedback.

@agoose77
Correct. Whenever I want to retest something, I delete the new pyenv entries in ~/.bashrc and ~/.profile and do sudo rm -r ~/.pyenv/. Then I exit the shell. And ssh back to the server. This way I ensure that everything is reset.

Btw there is nothing customised in ~/.bashrc or ~/.profile. Since I had started off a fresh Debian installation. Hence there is nothing bespoke that could interfere with the pyenv installation.

@native-api Yes, I looked at your PR before I started testing today. Your branch is removed, some of those links return now 404. Hence it's a bit difficult to follow. However based on your commit, you have made only a change to the README.md, correct? Was there anything more? Sorry if I have missed it.

echo -e 'if shopt -q login_shell; then' \
      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
      '\n eval "$(pyenv init --path)"' \
      '\nfi' >> ~/.bashrc
echo -e 'if [ -z "$BASH_VERSION" ]; then'\
      '\n  export PYENV_ROOT="$HOME/.pyenv"'\
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
      '\n  eval "$(pyenv init --path)"'\
      '\nfi' >>~/.profile
. ~/.profile

I have tested this further above and posted the results. Sadly it doesn't work.
So the goal of automation is that the same bash script is able to pull, install, activate the virtualenv and install the requirements in one go, as it was possible until version pyenv 2.0.

I'm available to do further testing, if you need me. Please shout, happy to help.

@agoose77
Copy link

@tegant if you are getting a command not found error, then it suggests that either your SSH session is not considered a login shell, or you have made a mistake on the PATH. Perhaps add some echo statements to your .profile and .bashrc so that we can verify what is being executed.

@native-api
Copy link
Member

Yes, I looked at your PR before I started testing today.

The PR has been merged, so you should be looking at the master README.

@tegant
Copy link
Author

tegant commented May 26, 2021

Yes, I looked at your PR before I started testing today.

The PR has been merged, so you should be looking at the master README.

Correct. I have read through that: https://github.com/pyenv/pyenv/blob/master/README.md#basic-github-checkout
And executed what you have said. It doesn't work. Here is the result:

By executing this, I ensure that the three lines appear on top of ~/.profile, as you requested:

sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile

Then I pasted this into terminal:

echo -e 'if shopt -q login_shell; then' \
      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
      '\n eval "$(pyenv init --path)"' \
      '\nfi' >> ~/.bashrc
echo -e 'if [ -z "$BASH_VERSION" ]; then'\
      '\n  export PYENV_ROOT="$HOME/.pyenv"'\
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
      '\n  eval "$(pyenv init --path)"'\
      '\nfi' >>~/.profile

Then I sourced . ~/.profile

When activating the virtualenv, I get this:

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

Have you actually tried to run this as a bash script on your test server?
Here is the bash script for you to try and see for yourself:

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo -e 'if shopt -q login_shell; then' \
      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
      '\n eval "$(pyenv init --path)"' \
      '\nfi' >> ~/.bashrc
echo -e 'if [ -z "$BASH_VERSION" ]; then'\
      '\n  export PYENV_ROOT="$HOME/.pyenv"'\
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
      '\n  eval "$(pyenv init --path)"'\
      '\nfi' >>~/.profile
. ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

Thanks

@native-api
Copy link
Member

By executing this, I ensure that the three lines appear on top of ~/.profile, as you requested:

Then I pasted this into terminal:

These are 2 alternatives, you need to do either of them, not both.

Then, there's the next section about adding stuff into ~/.bashrc (it's technically optional but you probably want it; I don't know if pyenv-virtualenv requires it).

If you use pyenv-virtualenv, you also need to add pyenv-virtualenv's initialization command after Pyenv's, The pyenv activate command belongs to pyenv-virtualenv and requires that.

@tegant
Copy link
Author

tegant commented May 26, 2021

@native-api Thank you for your patience. I have adjusted the script based on your recommendation.

In summary:

  1. The path lines (including virtual-env) are added at the top of ~/.profile.
  2. Then the same path files are added to the bottom of ~/.bashrc
  3. ~/.profile is sourced.
  4. Pyenv and virtualend are successfully installed
  5. But activation fails.

See the new script:

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
sed -i '4 i\eval "$(pyenv virtualenv-init -)"' ~/.profile
echo -e 'if shopt -q login_shell; then' \
      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
      '\n  eval "$(pyenv init --path)"' \
      '\n  eval "$(pyenv virtualenv-init -)"' \
      '\nfi' >> ~/.bashrc
source ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

The result:

Cloning into '/home/admin/.pyenv'...
remote: Enumerating objects: 19800, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (238/238), done.
remote: Total 19800 (delta 457), reused 650 (delta 431), pack-reused 19082
Receiving objects: 100% (19800/19800), 4.02 MiB | 15.66 MiB/s, done.
Resolving deltas: 100% (13388/13388), done.
Cloning into '/home/admin/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2072, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2072 (delta 1), reused 1 (delta 0), pack-reused 2064
Receiving objects: 100% (2072/2072), 586.87 KiB | 26.68 MiB/s, done.
Resolving deltas: 100% (1414/1414), done.
Downloading Python-3.9.5.tar.xz...
-> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
Installing Python-3.9.5...
Installed Python-3.9.5 to /home/admin/.pyenv/versions/3.9.5

Looking in links: /tmp/tmp5yn508hj
Requirement already satisfied: setuptools in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (56.0.0)
Requirement already satisfied: pip in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (21.1.1)

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

@native-api
Copy link
Member

--- a.sh
+++ b.sh
@@ -5,13 +5,8 @@
 sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
 sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
 sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
-sed -i '4 i\eval "$(pyenv virtualenv-init -)"' ~/.profile
-echo -e 'if shopt -q login_shell; then' \
-      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
-      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
-      '\n  eval "$(pyenv init --path)"' \
-      '\n  eval "$(pyenv virtualenv-init -)"' \
-      '\nfi' >> ~/.bashrc
+echo 'eval "$(pyenv init -)"' ~/.bashrc
+echo 'eval "$(pyenv virtualenv-init -)"' ~/.bashrc
 source ~/.profile
 pyenv install 3.9.5
 pyenv virtualenv 3.9.5 venv

@tegant
Copy link
Author

tegant commented May 26, 2021

Thanks. I have tried it again.

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'eval "$(pyenv init -)"' ~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' ~/.bashrc
source ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

Result is:

Cloning into '/home/admin/.pyenv'...
remote: Enumerating objects: 19800, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (238/238), done.
remote: Total 19800 (delta 457), reused 650 (delta 431), pack-reused 19082
Receiving objects: 100% (19800/19800), 4.02 MiB | 25.57 MiB/s, done.
Resolving deltas: 100% (13388/13388), done.
Cloning into '/home/admin/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2072, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2072 (delta 1), reused 1 (delta 0), pack-reused 2064
Receiving objects: 100% (2072/2072), 586.87 KiB | 26.68 MiB/s, done.
Resolving deltas: 100% (1414/1414), done.
eval "$(pyenv init -)" /home/admin/.bashrc
eval "$(pyenv virtualenv-init -)" /home/admin/.bashrc
Downloading Python-3.9.5.tar.xz...
-> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
Installing Python-3.9.5...
Installed Python-3.9.5 to /home/admin/.pyenv/versions/3.9.5

Looking in links: /tmp/tmpqj95gvtd
Requirement already satisfied: setuptools in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (56.0.0)
Requirement already satisfied: pip in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (21.1.1)

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

@tegant
Copy link
Author

tegant commented May 26, 2021

Ah there is typo in your code above.

echo 'eval "$(pyenv virtualenv-init -)"' ~/.bashrc should be echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc

:-)

Let me try again

@agoose77
Copy link

@tegant you need to write the lines to the files

echo 'eval "$(pyenv init -)"' >> ~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc

@native-api
Copy link
Member

🤦

 sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
 sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
 sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
-sed -i '4 i\eval "$(pyenv virtualenv-init -)"' ~/.profile
-echo -e 'if shopt -q login_shell; then' \
-      '\n  export PYENV_ROOT="$HOME/.pyenv"' \
-      '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
-      '\n  eval "$(pyenv init --path)"' \
-      '\n  eval "$(pyenv virtualenv-init -)"' \
-      '\nfi' >> ~/.bashrc
+echo 'eval "$(pyenv init -)"' >>~/.bashrc
+echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bashrc
 source ~/.profile
 pyenv install 3.9.5
 pyenv virtualenv 3.9.5 venv

@tegant
Copy link
Author

tegant commented May 26, 2021

Alrighty. The new version:

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
source ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv

result:

Cloning into '/home/admin/.pyenv'...
remote: Enumerating objects: 19800, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (236/236), done.
remote: Total 19800 (delta 457), reused 652 (delta 433), pack-reused 19082
Receiving objects: 100% (19800/19800), 4.02 MiB | 14.10 MiB/s, done.
Resolving deltas: 100% (13387/13387), done.
Cloning into '/home/admin/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2072, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2072 (delta 1), reused 1 (delta 0), pack-reused 2064
Receiving objects: 100% (2072/2072), 586.87 KiB | 3.83 MiB/s, done.
Resolving deltas: 100% (1414/1414), done.
Downloading Python-3.9.5.tar.xz...
-> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
Installing Python-3.9.5...
Installed Python-3.9.5 to /home/admin/.pyenv/versions/3.9.5

Looking in links: /tmp/tmppmp2e67g
Requirement already satisfied: setuptools in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (56.0.0)
Requirement already satisfied: pip in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (21.1.1)

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

:-|

@native-api
Copy link
Member

native-api commented May 26, 2021

Looks like you have an uncommon configuration or something.

Please show a debug trace (it's going to be big so as a gist):

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
echo 'eval "$(pyenv init -)"' >>~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >>~/.bashrc
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -x
source ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv
set +x

@agoose77
Copy link

Can you dump the env at the end of this too? for ease-of-grepping :)

@tegant
Copy link
Author

tegant commented May 26, 2021

It's actually not that large, so I can paste it here:

Cloning into '/home/admin/.pyenv'...
remote: Enumerating objects: 19800, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (272/272), done.
remote: Total 19800 (delta 458), reused 602 (delta 397), pack-reused 19082
Receiving objects: 100% (19800/19800), 4.02 MiB | 1.11 MiB/s, done.
Resolving deltas: 100% (13389/13389), done.
Cloning into '/home/admin/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2072, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2072 (delta 1), reused 1 (delta 0), pack-reused 2064
Receiving objects: 100% (2072/2072), 586.87 KiB | 26.68 MiB/s, done.
Resolving deltas: 100% (1414/1414), done.
+(test.sh:12): source /home/admin/.profile
++(/home/admin/.profile:1): export PYENV_ROOT=/home/admin/.pyenv
++(/home/admin/.profile:1): PYENV_ROOT=/home/admin/.pyenv
++(/home/admin/.profile:2): export PATH=/home/admin/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
++(/home/admin/.profile:2): PATH=/home/admin/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
+++(/home/admin/.profile:3): pyenv init --path
++(/home/admin/.profile:3): eval 'export PATH="/home/admin/.pyenv/shims:${PATH}"'
+++(/home/admin/.profile:3): export PATH=/home/admin/.pyenv/shims:/home/admin/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
+++(/home/admin/.profile:3): PATH=/home/admin/.pyenv/shims:/home/admin/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
++(/home/admin/.profile:15): '[' -n '5.0.3(1)-release' ']'
++(/home/admin/.profile:17): '[' -f /home/admin/.bashrc ']'
++(/home/admin/.profile:18): . /home/admin/.bashrc
+++(/home/admin/.bashrc:6): case $- in
+++(/home/admin/.bashrc:8): return
++(/home/admin/.profile:23): '[' -d /home/admin/bin ']'
++(/home/admin/.profile:28): '[' -d /home/admin/.local/bin ']'
+(test.sh:13): pyenv install 3.9.5
Downloading Python-3.9.5.tar.xz...
-> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
Installing Python-3.9.5...
Installed Python-3.9.5 to /home/admin/.pyenv/versions/3.9.5

+(test.sh:14): pyenv virtualenv 3.9.5 venv
Looking in links: /tmp/tmp19vrnglo
Requirement already satisfied: setuptools in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (56.0.0)
Requirement already satisfied: pip in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (21.1.1)
+(test.sh:15): pyenv activate venv

Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.

Sure, how can I dump the env?

@tegant
Copy link
Author

tegant commented May 26, 2021

I think, I'm seeing the issue:

+++(/home/admin/.bashrc:6): case $- in
+++(/home/admin/.bashrc:8): return

I haven't put the code there. This comes by default with Debian Buster 10 (AWS / EC2).

I suppose I have to remove that section?

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

@tegant
Copy link
Author

tegant commented May 26, 2021

Great news, by inserting the lines at the top of ~/.bashrc, it will circumvent any return that may have been put in there, by the linux distribution. This has now worked for me:

#!/bin/bash
set -e
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
sed -i '1 i\export PYENV_ROOT="$HOME/.pyenv"' ~/.profile
sed -i '2 i\export PATH="$PYENV_ROOT/bin:$PATH"' ~/.profile
sed -i '3 i\eval "$(pyenv init --path)"' ~/.profile
sed -i '1 i\eval "$(pyenv init -)"' ~/.bashrc
sed -i '2 i\eval "$(pyenv virtualenv-init -)"' ~/.bashrc
source ~/.profile
pyenv install 3.9.5
pyenv virtualenv 3.9.5 venv
pyenv activate venv
pip install fastapi

Result:

Cloning into '/home/admin/.pyenv'...
remote: Enumerating objects: 19800, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (236/236), done.
remote: Total 19800 (delta 457), reused 652 (delta 433), pack-reused 19082
Receiving objects: 100% (19800/19800), 4.02 MiB | 6.93 MiB/s, done.
Resolving deltas: 100% (13387/13387), done.
Cloning into '/home/admin/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2072, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2072 (delta 1), reused 1 (delta 0), pack-reused 2064
Receiving objects: 100% (2072/2072), 586.87 KiB | 2.32 MiB/s, done.
Resolving deltas: 100% (1414/1414), done.
Downloading Python-3.9.5.tar.xz...
-> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
Installing Python-3.9.5...
Installed Python-3.9.5 to /home/admin/.pyenv/versions/3.9.5

Looking in links: /tmp/tmpaggklkbc
Requirement already satisfied: setuptools in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (56.0.0)
Requirement already satisfied: pip in /home/admin/.pyenv/versions/3.9.5/envs/venv/lib/python3.9/site-packages (21.1.1)
pyenv-virtualenv: prompt changing will be removed from future release. configure `export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
Collecting fastapi
  Downloading fastapi-0.65.1-py3-none-any.whl (50 kB)
     |████████████████████████████████| 50 kB 11.1 MB/s
Collecting starlette==0.14.2
  Downloading starlette-0.14.2-py3-none-any.whl (60 kB)
     |████████████████████████████████| 60 kB 13.3 MB/s
Collecting pydantic!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0,>=1.6.2
  Downloading pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl (11.3 MB)
     |████████████████████████████████| 11.3 MB 53.0 MB/s
Collecting typing-extensions>=3.7.4.3
  Downloading typing_extensions-3.10.0.0-py3-none-any.whl (26 kB)
Installing collected packages: typing-extensions, starlette, pydantic, fastapi
Successfully installed fastapi-0.65.1 pydantic-1.8.2 starlette-0.14.2 typing-extensions-3.10.0.0

So the key is inserting everything at the top.

Thank you so much for your help!!!

@native-api
Copy link
Member

native-api commented May 26, 2021

+++(/home/admin/.bashrc:6): case $- in
+++(/home/admin/.bashrc:8): return

Your shell is not interactive. Pyenv shell functions are only supposed to be installed into interactive shells.


If Pyenv-Virtualenv is supposed to install shell functions even into noninteractive shells (in which case, its documentation needs to be updated to clarify that), you need to put

if [ -n "$BASH_VERSION" ]; then case "$-" in *i*) ;; *) eval "$(pyenv init -)"; eval "$(pyenv virtualenv-init -)"; ;; esac; fi

into ~/.profile after other Pyenv initialization lines.


Alternatively, you can do without pyenv activate and source the activation script directly: source "$(pyenv prefix venv)/bin/activate".

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

Successfully merging a pull request may close this issue.

5 participants