perlbrew 0.60 is broken in zsh of osx #302

Closed
Songmu opened this Issue Mar 18, 2013 · 16 comments
@Songmu

I installed perlbrew 0.60, but it doesn't work.

$PATH is broken and q{"} directory is created in $HOME and perlbrew
component is also created in the directory as bellow.

% echo $PATH
"/Users/Songmu/perl5/perlbrew/bin:/Users/Songmu/perl5/perlbrew/perls/perl-5.16.3/bin";:/Users/Songmu/bin:/Users/Songmu/perl5/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin

% tree ~/\"
/Users/Songmu/"
└── Users
    └── Songmu
        └── perl5
            └── perlbrew";
                ├── Config.pm
                ├── bin
                ├── build
                ├── dists
                │   └── perl-5.16.3.tar.bz2
                ├── etc
                │   ├── bashrc
                │   ├── csh_reinit
                │   ├── csh_set_path
                │   ├── csh_wrapper
                │   ├── cshrc
                │   └── perlbrew-completion.bash
                └── perls
9 directories, 8 files

It might be broken in this commit.

7e839e5

please take a look.

@aero

me too

Centos 5.9, bash

env. variables.

    $ env |grep PERLBREW
    PERLBREW_VERSION="0.60";
    PERLBREW_PERL="perl-5.16";
    PERLBREW_BASHRC_VERSION=0.60
    PERLBREW_ROOT="/home/aero/perl5/perlbrew";
    PERLBREW_HOME=/home/aero/.perlbrew
    PERLBREW_MANPATH="/home/aero/perl5/perlbrew/perls/perl-5.16/man";
    PERLBREW_PATH="/home/aero/perl5/perlbrew/bin:/home/aero/perl5/perlbrew/perls/perl-5.16/bin";

    $ echo $PATH
    "/home/aero/perl5/perlbrew/bin:/home/aero/perl5/perlbrew/perls/perl-5.16/bin";:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/aero/bin
$ tree '"'
"
`-- home
    `-- aero
        `-- perl5
            `-- perlbrew";
                |-- bin
                |-- build
                |-- dists
                |-- etc
                |   |-- bashrc
                |   |-- csh_reinit
                |   |-- csh_set_path
                |   |-- csh_wrapper
                |   |-- cshrc
                |   `-- perlbrew-completion.bash
                `-- perls
@autarch

I'm seeing similar problems with a semi-colon being appended to path names.

@rwstauner

ditto: bash

@rwstauner

i tried copying an old script over but couldn't get the 'init' command to work...
i had to remove my etc dir and do perlbrew init - > ~/perl5/perlbrew/etc/bashrc manually to get a working system again.

@Taeril

I tracked problem to __perlbrew_activate from commit 962f881 and reverted changes to that function to make perlbrew work.

@rjt-pl

Indeed, doesn't look like anything inherently OS or shell specific. My $PATH was similarly munged on Ubuntu 12.04 via bash.

@ilmari

Both bash and dash handle eval "$(${perlbrew_command} env)" correctly when perlbrew_command="comand perlbrew", so that's zsh not being compatible.

I can confirm the zsh behaviour reported in 962f881 with zsh 5.0.0 on Ubuntu.

@battlemidget

Same as ilmari, Ubuntu 12.10 running zsh 5.0.0

@djerius

I believe that I'm at least partially to blame for this.

7e839e5 was supposed to fix this code (in lib/App/perlbrew.pm):

   2099                 code="$(command perlbrew env $2)"
   2100                 exit_status="$?"
   2101                 if [[ $exit_status -eq 0 ]]
   2102                 then
   2103                     eval $code
   2104                     __perlbrew_set_path
   2105                 fi

which assigns the code to be evaluated to a variable and then eval's that variable. perlbrew env emitted code which looked like this:

export VAR1=value
unset VAR2

If you run this through the above code (for some versions of shells) you'll get the equivalent of

export VAR1=value unset VAR2

which does not unset VAR2. The "fix" was to output semi-colons after each command, e.g.

export VAR1=value;
unset VAR2;

which turns into

export VAR1=value; unset VAR2

And works. Unfortunately, it seems that the fix breaks any eval's which look like this:

   2060     if [[ -n "$PERLBREW_PERL" ]]; then
   2061         if [[ -z "$PERLBREW_LIB" ]]; then
   2062             $(eval $perlbrew_command env $PERLBREW_PERL)
   2063         else
   2064             $(eval $perlbrew_command env $PERLBREW_PERL@$PERLBREW_LIB)
   2065         fi
   2066     fi

where the results of the eval are interpolated directly into the command line to be run.

There's some subtlety about quoting that's going on. Here's an experiment:

% cat > setpath
export TPATH=1
unset TPATH

% cat > setpath-sc
export TPATH=1;
unset TPATH;

% echo $BASH_VERSION
4.1.5(1)-release

This is what happened prior to the above fix with the "two-stage" eval

% code=$(cat setpath) ; eval $code ; echo $TPATH
1
%

That fails. After the fix (simulated by setpath-sc), it works.

% code=$(cat setpath-sc) ; eval $code ; echo $TPATH

%

Interestingly, enclosing the code without semi-colons in double quotes works:

% code=$(cat setpath) ; eval "$code" ; echo $TPATH

%

Now for the bare eval. First with no semi-colons:

% $(eval cat setpath) ; echo $TPATH
1

That is wrong. It doesn't recognize the unset command.

Now with the extra semi-colons:

% $(eval cat setpath-sc) ; echo $TPATH
-bash: export: `TPATH;': not a valid identifier
1;

There are two errors; the obvious one about 'TPATH;', but also the the fact that TPATH is set to '1;', not '1'.

I think that the error arises because (at least in bash) by the time the shell performs command substitution, it is past the phase where it has split a line into multiple commands, so the semi-colons are treated as ordinary characters. Thus, the shell treats the input as

export TPATH='1;' unset 'TPATH;'

and sets TPATH to 1; and rightly complains that 'TPATH;' is not a valid variable name.

If you look at the examples in the comments above, there are a lot of excess semi-colons. Most likely due to this.

I think the most straightforward means of fixing this is to keep the semi-colons, and use either

code=$($perlbrew_command env) # or whatever is passed to perlbrew_command
eval $code

or, if not checking the return from $perlbrew_command, more simply

eval $($perlbrew_command env)

I'm not sure if this code works under all shells, however.

@gugod
Owner

@djerius What would break if we simply revert bf5d4c0 ?

IIRC this should work even if the env output contain "\n"

eval "$(perlbrew env xxx)"

Maybe we should use this in the bashrc instead.

@djerius djerius referenced this issue Mar 19, 2013
Closed

Develop #303

@djerius

That should do it. I just comitted some code which does essentially the above. it also creates a __perlbrew_set_env function to move the magic into a single location.

@Taeril

Commit 962f881 lost eval and that is problem. I was playing with eval to see if I got desired results - https://gist.github.com/Taeril/5194434 - and ended with insane double eval. I got what I wanted in bash and in zsh also for 'command ...' but I'm afraid to call it solution because it looks ugly.

@djerius I think that change with semicolons is irrelevant. I just changed only shell part directly in my bashrc with your proposed code and it worked for me in bash. In zsh 4.2.37 I had two problems.
First I had to add quotes:

local code="$($perlbrew_command env "$@")"

and it worked because I use just 'perlbrew' but when I changed perlbrew_command in __perlbrew_set_env to perlbrew_command='command perlbrew' zsh tried to run 'command perlbrew' so it's still an issue here.

@gugod
Owner

@djerius, I need to rework your patch a bit so that it worked for me (zsh4 / zsh5). This should be good to release and I'm testing it in various OS/shell. Let me know if the current develop branch is broken on your side and we'll figure out what to do. Thank you for the effort!

@jest

Any painless suggestions as for the upgrade path to 0.61? I'm stuck with 0.60 and self-upgrade doesn't work (installs into ").

@jest

OK, looks like this does the trick:

$PERLBREW_ROOT/bin/perlbrew self-upgrade
cd ~/\"$PERLBREW_ROOT\"\; && find . -type f -exec echo cp {} $PERLBREW_ROOT/{} \;
@gugod
Owner

@jest, redoing the instruction on http://www.perlbrew.pl should always work. self-upgrade is essentially doing just that.

Close this issue as 0.61 was released.

@gugod gugod closed this Mar 20, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment