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

Win32: $self->which('cpansign') not working #681

Open
pryrt opened this issue Oct 14, 2024 · 0 comments
Open

Win32: $self->which('cpansign') not working #681

pryrt opened this issue Oct 14, 2024 · 0 comments

Comments

@pryrt
Copy link

pryrt commented Oct 14, 2024

Inspired by #679 to dig deeper into why it's not finding cpansign for me, even though it is in my path, I found something which is win32-specific. Since #679 used the $PATH nomenclature, I am going to assume that was found on a unix-like OS, not Win32, so I'll make this a separate issue.

Confirm cpansign in path:

C:\> where cpansign
C:\usr\local\apps\STRAWBERRY\perl\site\bin\cpansign
C:\usr\local\apps\STRAWBERRY\perl\site\bin\cpansign.bat

excerpt from cpanm --version:

cpanm (App::cpanminus) version 1.7047 (C:\USR\LOCAL\APPS\STRAWBERRY\PERL\SITE\BIN/cpanm.bat)
perl version 5.038000 (C:\USR\LOCAL\APPS\STRAWBERRY\PERL\BIN\perl.exe)

Diagnosis

setup_verify() includes the line $self->{cpansign} = $self->which('cpansign') ... and which() currently looks like:

sub which {
    my($self, $name) = @_;
    if (File::Spec->file_name_is_absolute($name)) {
        if (-x $name && !-d _) {
            return $name;
        }
    }
    my $exe_ext = $Config{_exe};
    for my $dir (File::Spec->path) {
        my $fullpath = File::Spec->catfile($dir, $name);
        if ((-x $fullpath || -x ($fullpath .= $exe_ext)) && !-d _) {
            if ($fullpath =~ /\s/) {
                $fullpath = $self->shell_quote($fullpath);
            }
            return $fullpath;
        }
    }
    return;
}

So it checks cpansign and cpansign.exe in each directory. But when cpansign (and similar scripts) are installed in Strawberry Perl on Win32, there are two copies of the file: cpansign with no extension, which is not executable on win32 so -x '.../cpansign' will return a false value; and cpansign.bat, which is executable but the which() never tests that extension.

In a trusting world, instead of just testing no-extension and $exe_ext, it would also split /;/, $ENV{PATHEXT} and test all of those extensions as well. But I understand the need for some caution in such things, so could I suggest:

sub which {
    my($self, $name) = @_;
    if (File::Spec->file_name_is_absolute($name)) {
        if (-x $name && !-d _) {
            return $name;
        }
    }
    my @exts = ('', $Config{_exe}, '.bat', '.cmd', '.ps1');
    for my $dir (File::Spec->path) {
        for my $ext (@exts) {
            my $fullpath = File::Spec->catfile($dir, $name.$ext);
            if ((-x $fullpath) && !-d _) {
                if ($fullpath =~ /\s/) {
                    $fullpath = $self->shell_quote($fullpath);
                }
                return $fullpath;
            }
        }
    }
    return;
}

When I modify my cpanm.bat to have that version of sub which, I am able to get cpanm --verify to work in my Strawberry Perl environment.

I suggested .cmd and .ps1 as well, because in theory Strawberry Perl or similar Win32 distribution might use one of the other common cmd.exe/powershell script extensions instead of .bat as the official script-install extension. But if even leaving that open for future changes or other distributions is too "generous" in what it accepts, then my suggestion would still work even with just my @exts = ('', $Config{_exe}, '.bat');

But if cpanm's which() is left-as-is, without testing at least the .bat extension, then cpanm --verify will never work on Strawberry Perl, even though a manual cpansign -v works just fine.

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

1 participant