1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-23 21:19:17 +02:00
goreleaser/pkg/archive/zip/zip_test.go
Ori Rawlings 19ab124f1b
fix: retain symlinks added to zip archives (#3585)
<!--

Hi, thanks for contributing!

Please make sure you read our CONTRIBUTING guide.

Also, add tests and the respective documentation changes as well.

-->


<!-- If applied, this commit will... -->

fixes #3584 

When following the reproduction steps in #3584 I now get the following
contents for the zip archive:
```
$ goreleaser --snapshot --skip-publish
...
$ (mkdir thezip && cd thezip && unzip ../dist/test_0.0.0-SNAPSHOT-none_darwin_amd64.zip) && ls -lR thezip
Archive:  ../dist/test_0.0.0-SNAPSHOT-none_darwin_amd64.zip
  inflating: a/x                     -> ../x 
  inflating: a/x2                    -> x 
  inflating: x                       
  inflating: test                    
finishing deferred symbolic links:
  a/x                    -> ../x
  a/x2                   -> x
total 1640
drwxr-xr-x  4 orawlings  staff     128 Nov 22 16:19 a
-rwxr-xr-x  1 orawlings  staff  833104 Nov 22 16:19 test
-rw-r--r--  1 orawlings  staff       2 Nov 22 15:32 x

thezip/a:
total 0
lrwxr-xr-x  1 orawlings  staff  4 Nov 22 16:19 x -> ../x
lrwxr-xr-x  1 orawlings  staff  1 Nov 22 16:19 x2 -> x
```

<!-- Why is this change being made? -->

I'm using goreleaser for a project that packages multiple binaries in
zip archives. We also include symlinks within the zip archives to give
some of the binaries an alternate (usually shorter) spelling so they are
easier to invoke on the command line.

This brings the zip archive behavior regarding symlinks in line with
tar.gz and tar archives.

<!-- # Provide links to any relevant tickets, URLs or other resources
-->
2022-11-29 22:05:18 -03:00

157 lines
3.8 KiB
Go

package zip
import (
"archive/zip"
"bytes"
"io"
"io/fs"
"os"
"path/filepath"
"testing"
"time"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/stretchr/testify/require"
)
func TestZipFile(t *testing.T) {
tmp := t.TempDir()
f, err := os.Create(filepath.Join(tmp, "test.zip"))
require.NoError(t, err)
defer f.Close() // nolint: errcheck
archive := New(f)
defer archive.Close() // nolint: errcheck
require.Error(t, archive.Add(config.File{
Source: "../testdata/nope.txt",
Destination: "nope.txt",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/foo.txt",
Destination: "foo.txt",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/sub1",
Destination: "sub1",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/sub1/bar.txt",
Destination: "sub1/bar.txt",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/sub1/executable",
Destination: "sub1/executable",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/sub1/sub2",
Destination: "sub1/sub2",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/sub1/sub2/subfoo.txt",
Destination: "sub1/sub2/subfoo.txt",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/regular.txt",
Destination: "regular.txt",
}))
require.NoError(t, archive.Add(config.File{
Source: "../testdata/link.txt",
Destination: "link.txt",
}))
require.NoError(t, archive.Close())
require.Error(t, archive.Add(config.File{
Source: "tar.go",
Destination: "tar.go",
}))
require.NoError(t, f.Close())
f, err = os.Open(f.Name())
require.NoError(t, err)
defer f.Close() // nolint: errcheck
info, err := f.Stat()
require.NoError(t, err)
require.Truef(t, info.Size() < 1000, "archived file should be smaller than %d", info.Size())
r, err := zip.NewReader(f, info.Size())
require.NoError(t, err)
paths := make([]string, len(r.File))
for i, zf := range r.File {
paths[i] = zf.Name
if zf.Name == "sub1/executable" {
ex := zf.Mode() | 0o111
require.Equal(t, zf.Mode().String(), ex.String())
}
if zf.Name == "link.txt" {
require.True(t, zf.FileInfo().Mode()&os.ModeSymlink != 0)
rc, err := zf.Open()
require.NoError(t, err)
var link bytes.Buffer
_, err = io.Copy(&link, rc)
require.NoError(t, err)
rc.Close()
require.Equal(t, link.String(), "regular.txt")
}
}
require.Equal(t, []string{
"foo.txt",
"sub1/bar.txt",
"sub1/executable",
"sub1/sub2/subfoo.txt",
"regular.txt",
"link.txt",
}, paths)
}
func TestZipFileInfo(t *testing.T) {
now := time.Now().Truncate(time.Second)
f, err := os.Create(filepath.Join(t.TempDir(), "test.zip"))
require.NoError(t, err)
defer f.Close() // nolint: errcheck
archive := New(f)
defer archive.Close() // nolint: errcheck
require.NoError(t, archive.Add(config.File{
Source: "../testdata/foo.txt",
Destination: "nope.txt",
Info: config.FileInfo{
Mode: 0o755,
Owner: "carlos",
Group: "root",
MTime: now,
},
}))
require.NoError(t, archive.Close())
require.NoError(t, f.Close())
f, err = os.Open(f.Name())
require.NoError(t, err)
defer f.Close() // nolint: errcheck
info, err := f.Stat()
require.NoError(t, err)
r, err := zip.NewReader(f, info.Size())
require.NoError(t, err)
require.Len(t, r.File, 1)
for _, next := range r.File {
require.Equal(t, "nope.txt", next.Name)
require.Equal(t, now.Unix(), next.Modified.Unix())
require.Equal(t, fs.FileMode(0o755), next.FileInfo().Mode())
}
}
func TestTarInvalidLink(t *testing.T) {
archive := New(io.Discard)
defer archive.Close() // nolint: errcheck
require.NoError(t, archive.Add(config.File{
Source: "../testdata/badlink.txt",
Destination: "badlink.txt",
}))
}