Raku / App-Rakubrew

Raku environment manager
https://rakubrew.org/
Other
26 stars 13 forks source link

'Failed to extract archive.' on download | windows 10 #73

Closed scyleaf closed 7 months ago

scyleaf commented 1 year ago

I am just starting out with learning raku. I wanted to use rakubrew. I ran the installer and followed the instructions to set up the profiles for powershell, and cmd, and did init. Only thing I changed is to make the profiles use my $env:RAKUBREW_HOME and %RAKUBREW_HOME% respectively instead of hardcoding the path.

I tried several versions marked with D and all of them failed with 'Failed to extract archive'. However, I don't know how to debug the problem further.

patrickbkr commented 1 year ago

Thanks for reporting this! I'll see if I can reproduce. In the meantime you could manually download a release from rakudo.org, extract it to somewhere and use rakubrew register to make it known to Rakubrew.

patrickbkr commented 1 year ago

I have released a new version (v35) that should have better error reporting in your failure case. Can you update (using rakubrew self-upgrade), try again and post the error?

I failed to reproduce the error on a local Windows 10 machine. My current best guess is some anti-virus software or firewall blocking the download.

scyleaf commented 1 year ago

On rakubrew download moar 2023.02, output is:

Downloading https://rakudo.org/dl/rakudo/rakudo-moar-2023.02-01-win-x86_64-msvc.zip
Extracting
Failed to extract archive. Error: Inflation Error: data error

Edit: I only use Windows Defender and no other anti-virus.

PS: The rakubrew self-upgrade failed for me with this output:

Failed to call the downloaded rakubrew executable! Aborting update.

The executable that's in the update folder, appeared corrupted. I deleted it and tried again but I always got the same situation. I tried to check information about the bitness since windows refused to run it. MSVC's dumpbin didn't give me info and I ended up using sigcheck. This was the output:

        Verified:       Unsigned
        Link date:      22:14 17/03/1970
        Publisher:      n/a
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    2694

I ended up manually downloading the latest .exe from the link in the website and replacing my own with it.

PPS: I ran the commands from powershell in administrator mode.

patrickbkr commented 1 year ago

Can you upload a copy of that corrupted file somewhere?

scyleaf commented 1 year ago

Here is the archived exe: rakubrew.zip It happened when upgrading from v33 to v35 I think. I repeated the test again to make sure.

patrickbkr commented 1 year ago

I did a binary diff on that file. It seems like all CRLFs have been replaced by LF. The respective code in Rakubrew looks innocent. Do you have any idea if there is any component in your environment that could potentially cause a line ending conversion in downloaded data?

I have a growing suspicion: Somehow on your system HTTP::Tinyish fails to select HTTP::Tiny as download backend and thus falls back to its curl backend. I think that backend has a bug in that it doesn't set its output handle to binary mode, causing the CRLF -> LF conversion.

scyleaf commented 1 year ago

That's a substantial discovery.
When I initially searched about the Error: Inflation Error: data error the first things that came up had to do with ascii vs binary mode too.

I am not sure what you mean by environment in this context. My environment variables and Path especially are pretty messy because I have many paths added and you know how Windows is. However, I don't know how I could verify if this causes an issue. I haven't set anything up to intentionally replace line endings.

How should we proceed from here? I wasn't able to find any problem with that rakubrew code either, so it may be in one of the dependencies like you say. Perhaps I would be able to attach some raku debugger for rakubrew myself and try to step through it from there, line by line (and into HTTP::Tinyish etc). I wouldn't know how complex the setup would be but since you can't reproduce it on your system I can imagine it would be difficult for you. I wonder why HTTP::Tiny isn't selected though, since according to the docs it should have higher precedence than curl.

patrickbkr commented 1 year ago

@scyleaf It seems you are willing to invest some time to hunt this problem. Great! Here is what I'd do:

Rakubrew is packaged with PAR. That works by extracting all the sources and auxiliary files in a temporary directory and runs from there. The folder is in C:\Users\<your.user>\AppData\Local\Temp\par-<some number>\cache-<a4677100f46582b8d9b38f6d6d6ab0c89eaba557>. One can modify the files in there. Rerunning rakubrew will then use the changed files.

I'd add some debug code doing print STDERR "stuff\n"; to the following places (printing to STDERR is necessary as you won't see STDOUT printed things for annoying reasons):

inc/lib/HTTP/Tinyish.pm::_backend_for() - to see which backend is selected adapt the for loop:

    for my $backend ($self->backends) {
        print STDERR "trying $backend\n";
        $self->configure_backend($backend) or next;
        print STDERR "configure succeeded\n";
        if ($backend->supports($scheme)) {
            print STDERR "selected\n";
            return $backend->new(%$self);
        }
    }

inc/lib/HTTP/Tinyish/LWP.pm::request() (if that's the selected backend) - to see if the data LWP returns already has the lineendings replaced add the following before the return:

    print STDERR "LWP DATA ==================\n";
    my $data = $res->decoded_content(charset => 'none');
    {
        use bytes;
        if (length($data) > 200) {
            print STDERR "$_\n" for unpack("x118 H8", $data);
        }
    }

The above should print "0d0d0a24" on a correct rakubrew v35 executable and "0d0a2400" on a broken one.

Maybe also put a exit 1; in inc/lib/App/Rakubrew/Update.pm:92 to make sure it doesn't overwrite rakubrew.exe while updating.

Then either dig down into the download backend code if the data is already wrong, or dig up to inc/lib/App/Rakubrew/Update.pm if the data is still ok.

scyleaf commented 1 year ago

Thank you for this info! I did a little bit of digging but so far I was only able to determine that the curl backend always gets used. The reason being seems a little strange to me:

PS C:\> rakubrew self-upgrade
trying HTTP::Tinyish::LWP
configure succeeded
trying HTTP::Tinyish::HTTPTiny
HTTPTiny.pm configure: ok: 0 , reason: IO::Socket::SSL 1.42 must be installed for https support
Net::SSLeay 1.49 must be installed for https support
configure succeeded
trying HTTP::Tinyish::Curl
configure succeeded
selected for scheme https

Interestingly IO/Socket/SSL.pm is present under cache-a4677100f46582b8d9b38f6d6d6ab0c89eaba557/inc/lib.
So I am not sure what's happening at this point. I am running bare Rakudo instead of Rakudo Star but I would still think this module would be recognized from this cache directory, no?

patrickbkr commented 1 year ago

Thanks for persisting in hunting this bug!

The line responsible for that error is lib/HTTP/Tiny.pm:539. There it says:

eval {require IO::Socket::SSL; IO::Socket::SSL->VERSION(1.42)}

That line tries to load IO::Socket::SSL and then checks the version number. I bet the loading fails, but not because the module isn't found, but because compiling IO::Socket::SSL fails. During compiling all the BEGIN blocks and use statements are executed. I guess something in there errors. I'd sprinkle a few print STDERRs in the begin blocks of IO::Socket::SSL and Net::SSLeay.

In the mean time I'll try to fix HTTP::Tinyish::Curl.

2colours commented 1 year ago

The same error happens for me with the latest Rakubrew version, and actually I can't recall any time when Rakubrew actually worked for me on Windows... I was getting this error even a year ago.

patrickbkr commented 7 months ago

I finally managed to fix this. The windows builds did not include two DLL files needed for SSL to work. That caused HTTP::Tinyish to skip LWP and HTTP::Tiny and then choose Curl as backend. Which did the bad line ending conversion. The reason it did work on all the computers put my hands on: I had strawberry perl installed on all those machines. Rakubrew then found the missing DLLs in that installation.

I have now fixed both, the Curl issue and the missing DLL issue. All of that is available in the newly released version 38.