marcosnils / bin

Effortless binary manager
MIT License
685 stars 46 forks source link

Support bzip2ed binaries like restic #117

Closed korpa closed 2 years ago

korpa commented 2 years ago

From the discussion in #81

I tried to install restic (https://github.com/restic/restic/releases/tag/v0.12.1) which is a bzip2ed binary. But I get following error:

$ bin install github.com/restic/restic 
   • Getting latest release for restic/restic
   • Starting download of https://github.com/restic/restic/releases/download/v0.12.1/restic_0.12.1_linux_amd64.bz2
5.92 MiB / 5.92 MiB [------------------------------------------------------------------------------------------------------] 100.00% 102.02 MiB p/s 0s
   ⨯ command failed            error=Error installing binary: open /home/user/bin: file exists

So I wonder if bzip2ed binaries are not supported at the moment?

$ bin --version
bin version 0.10.0
commit: 9aa08f233b1233d649d515a3c147ef6f238003ed
built at: 2021-11-30T18:06:27Z
built by: goreleaser

[snip]

marcosnils commented 6 minutes ago

Just found what's happening. bin has support for .tar.bz2 files, but not just .bz2 files.

Definitely an "feature" we need to address. Mind adding that please?

korpa commented 2 years ago

The issue is within processBz2. It always returns an empty name:

func (f *Filter) processBz2(name string, r io.Reader) (string, io.Reader, error) {
    br := bzip2.NewReader(r)

    return "", br, nil
}

Compared with processGz which returns a name:

// processGz receives a tar.gz file and returns the
// correct file for bin to download
func (f *Filter) processGz(name string, r io.Reader) (string, io.Reader, error) {
    gr, err := gzip.NewReader(r)
    if err != nil {
        return "", nil, err
    }

    return gr.Name, gr, nil
}

Problem is now, that bzip2 library is very limited compared to gzip library:

It does not implement the the Header struct. Therefore we don't get back the name without .bz2 extension.

Just for testing I added following bad hack:

func (f *Filter) processBz2(name string, r io.Reader) (string, io.Reader, error) {
    br := bzip2.NewReader(r)

    name = strings.Replace(name, ".bz2", "", -1)

    return name, br, nil
}

Voilà, it works:

go run main.go install github.com/restic/restic
   • Getting latest release for restic/restic
   • Starting download of https://github.com/restic/restic/releases/download/v0.12.1/restic_0.12.1_linux_amd64.bz2
5.92 MiB / 5.92 MiB [-------------------------------------------------------------------------------------------------------] 100.00% 17.34 MiB p/s 1s
   • Copying for restic@v0.12.1 into /home/user/bin/restic
   • Done installing restic v0.12.1

What do you think. Should we implement the replacing in the filename on our own or ask the go team to implement that in the bzip2 lib?

marcosnils commented 2 years ago

Should we implement the replacing in the filename on our own or ask the go team to implement that in the bzip2 lib?

bz2 works differently than gzip, that's why you don't have a header struct with the name. Seems like your fix should be the correct thing to do. Let me do a quick test and we can merge it.