diff --git a/Gopkg.lock b/Gopkg.lock index e87db2f32..01d0f4082 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -123,16 +123,6 @@ packages = ["query"] revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a" -[[projects]] - name = "github.com/goreleaser/archive" - packages = [ - ".", - "tar", - "zip" - ] - revision = "9c6b0c177751034bab579499b81c69993ddfe563" - version = "v1.1.3" - [[projects]] name = "github.com/goreleaser/nfpm" packages = [ @@ -262,6 +252,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "f8fe5bd56d1929f1592ca556cb199eec1d49bbc99d1b1cd5796a9a2be7d6bb22" + inputs-digest = "c2930bf7f01a483d6510c5de94e117a16965ae17a44510c60e488da4778d77b9" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 643055f86..ef0b9817a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -1,7 +1,3 @@ -[[constraint]] - name = "github.com/goreleaser/archive" - version = "^1.0.0" - [[constraint]] branch = "master" name = "github.com/google/go-github" diff --git a/pipeline/archive/archive.go b/pipeline/archive/archive.go index c3e52901e..e6fe4b09f 100644 --- a/pipeline/archive/archive.go +++ b/pipeline/archive/archive.go @@ -11,13 +11,13 @@ import ( "github.com/apex/log" "github.com/campoy/unique" - "github.com/mattn/go-zglob" + zglob "github.com/mattn/go-zglob" "golang.org/x/sync/errgroup" - "github.com/goreleaser/archive" "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/tmpl" + "github.com/goreleaser/goreleaser/pkg/archive" ) const ( diff --git a/pkg/archive/archive.go b/pkg/archive/archive.go new file mode 100644 index 000000000..40a816938 --- /dev/null +++ b/pkg/archive/archive.go @@ -0,0 +1,27 @@ +// Package archive provides tar.gz and zip archiving +package archive + +import ( + "os" + + "path/filepath" + + "github.com/goreleaser/goreleaser/pkg/archive/tar" + "github.com/goreleaser/goreleaser/pkg/archive/zip" +) + +// Archive represents a compression archive files from disk can be written to. +type Archive interface { + Close() error + Add(name, path string) error +} + +// New archive +// If the exentions of the target file is .zip, the archive will be in the zip +// format, otherwise, it will be a tar.gz archive. +func New(file *os.File) Archive { + if filepath.Ext(file.Name()) == ".zip" { + return zip.New(file) + } + return tar.New(file) +} diff --git a/pkg/archive/archive_test.go b/pkg/archive/archive_test.go new file mode 100644 index 000000000..181ba4047 --- /dev/null +++ b/pkg/archive/archive_test.go @@ -0,0 +1,34 @@ +package archive + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestArchive(t *testing.T) { + var assert = assert.New(t) + folder, err := ioutil.TempDir("", "archivetest") + assert.NoError(err) + empty, err := os.Create(folder + "/empty.txt") + assert.NoError(err) + assert.NoError(os.Mkdir(folder+"/folder-inside", 0755)) + + for _, archive := range []Archive{ + newArchive(folder, "tar.gz", t), + newArchive(folder, "zip", t), + } { + assert.NoError(archive.Add("empty.txt", empty.Name())) + assert.NoError(archive.Add("empty.txt", folder+"/folder-inside")) + assert.Error(archive.Add("dont.txt", empty.Name()+"_nope")) + assert.NoError(archive.Close()) + } +} + +func newArchive(folder, format string, t *testing.T) Archive { + file, err := os.Create(folder + "/folder." + format) + assert.NoError(t, err) + return New(file) +} diff --git a/pkg/archive/tar/tar.go b/pkg/archive/tar/tar.go new file mode 100644 index 000000000..b88be4f65 --- /dev/null +++ b/pkg/archive/tar/tar.go @@ -0,0 +1,60 @@ +// Package tar implements the Archive interface providing tar.gz archiving +// and compression. +package tar + +import ( + "archive/tar" + "compress/gzip" + "io" + "os" +) + +// Archive as tar.gz +type Archive struct { + gw *gzip.Writer + tw *tar.Writer +} + +// Close all closeables +func (a Archive) Close() error { + if err := a.tw.Close(); err != nil { + return err + } + return a.gw.Close() +} + +// New tar.gz archive +func New(target io.Writer) Archive { + gw := gzip.NewWriter(target) + tw := tar.NewWriter(gw) + return Archive{ + gw: gw, + tw: tw, + } +} + +// Add file to the archive +func (a Archive) Add(name, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() // nolint: errcheck + info, err := file.Stat() + if err != nil { + return err + } + header, err := tar.FileInfoHeader(info, name) + if err != nil { + return err + } + header.Name = name + if err = a.tw.WriteHeader(header); err != nil { + return err + } + if info.IsDir() { + return nil + } + _, err = io.Copy(a.tw, file) + return err +} diff --git a/pkg/archive/tar/tar_test.go b/pkg/archive/tar/tar_test.go new file mode 100644 index 000000000..4d82c9f05 --- /dev/null +++ b/pkg/archive/tar/tar_test.go @@ -0,0 +1,66 @@ +package tar + +import ( + "archive/tar" + "compress/gzip" + "io" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTarGzFile(t *testing.T) { + var assert = assert.New(t) + tmp, err := ioutil.TempDir("", "") + assert.NoError(err) + f, err := os.Create(filepath.Join(tmp, "test.tar.gz")) + assert.NoError(err) + defer f.Close() // nolint: errcheck + archive := New(f) + + assert.Error(archive.Add("nope.txt", "../testdata/nope.txt")) + assert.NoError(archive.Add("foo.txt", "../testdata/foo.txt")) + assert.NoError(archive.Add("sub1", "../testdata/sub1")) + assert.NoError(archive.Add("sub1/bar.txt", "../testdata/sub1/bar.txt")) + assert.NoError(archive.Add("sub1/executable", "../testdata/sub1/executable")) + assert.NoError(archive.Add("sub1/sub2", "../testdata/sub1/sub2")) + assert.NoError(archive.Add("sub1/sub2/subfoo.txt", "../testdata/sub1/sub2/subfoo.txt")) + + assert.NoError(archive.Close()) + assert.Error(archive.Add("tar.go", "tar.go")) + assert.NoError(f.Close()) + + t.Log(f.Name()) + f, err = os.Open(f.Name()) + assert.NoError(err) + info, err := f.Stat() + assert.NoError(err) + assert.Truef(info.Size() < 500, "archived file should be smaller than %d", info.Size()) + gzf, err := gzip.NewReader(f) + assert.NoError(err) + var paths []string + r := tar.NewReader(gzf) + for { + next, err := r.Next() + if err == io.EOF { + break + } + assert.NoError(err) + paths = append(paths, next.Name) + t.Logf("%s: %v", next.Name, next.FileInfo().Mode()) + if next.Name == "sub1/executable" { + assert.Equal("-rwxrwxr-x", next.FileInfo().Mode().String()) + } + } + assert.Equal([]string{ + "foo.txt", + "sub1", + "sub1/bar.txt", + "sub1/executable", + "sub1/sub2", + "sub1/sub2/subfoo.txt", + }, paths) +} diff --git a/pkg/archive/testdata/foo.txt b/pkg/archive/testdata/foo.txt new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/pkg/archive/testdata/foo.txt @@ -0,0 +1 @@ +foo diff --git a/pkg/archive/testdata/sub1/bar.txt b/pkg/archive/testdata/sub1/bar.txt new file mode 100644 index 000000000..5716ca598 --- /dev/null +++ b/pkg/archive/testdata/sub1/bar.txt @@ -0,0 +1 @@ +bar diff --git a/pkg/archive/testdata/sub1/executable b/pkg/archive/testdata/sub1/executable new file mode 100755 index 000000000..e69de29bb diff --git a/pkg/archive/testdata/sub1/sub2/subfoo.txt b/pkg/archive/testdata/sub1/sub2/subfoo.txt new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/pkg/archive/testdata/sub1/sub2/subfoo.txt @@ -0,0 +1 @@ +sub diff --git a/pkg/archive/zip/zip.go b/pkg/archive/zip/zip.go new file mode 100644 index 000000000..67bddbfc5 --- /dev/null +++ b/pkg/archive/zip/zip.go @@ -0,0 +1,53 @@ +// Package zip implements the Archive interface providing zip archiving +// and compression. +package zip + +import ( + "archive/zip" + "io" + "os" +) + +// Archive zip struct +type Archive struct { + z *zip.Writer +} + +// Close all closeables +func (a Archive) Close() error { + return a.z.Close() +} + +// New zip archive +func New(target io.Writer) Archive { + return Archive{ + z: zip.NewWriter(target), + } +} + +// Add a file to the zip archive +func (a Archive) Add(name, path string) (err error) { + file, err := os.Open(path) + if err != nil { + return + } + defer file.Close() // nolint: errcheck + info, err := file.Stat() + if err != nil { + return + } + if info.IsDir() { + return + } + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + header.Name = name + w, err := a.z.CreateHeader(header) + if err != nil { + return err + } + _, err = io.Copy(w, file) + return err +} diff --git a/pkg/archive/zip/zip_test.go b/pkg/archive/zip/zip_test.go new file mode 100644 index 000000000..b0b2a8bba --- /dev/null +++ b/pkg/archive/zip/zip_test.go @@ -0,0 +1,58 @@ +package zip + +import ( + "archive/zip" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestZipFile(t *testing.T) { + var assert = assert.New(t) + tmp, err := ioutil.TempDir("", "") + assert.NoError(err) + f, err := os.Create(filepath.Join(tmp, "test.zip")) + assert.NoError(err) + fmt.Println(f.Name()) + defer f.Close() // nolint: errcheck + archive := New(f) + + assert.Error(archive.Add("nope.txt", "../testdata/nope.txt")) + assert.NoError(archive.Add("foo.txt", "../testdata/foo.txt")) + assert.NoError(archive.Add("sub1", "../testdata/sub1")) + assert.NoError(archive.Add("sub1/bar.txt", "../testdata/sub1/bar.txt")) + assert.NoError(archive.Add("sub1/executable", "../testdata/sub1/executable")) + assert.NoError(archive.Add("sub1/sub2", "../testdata/sub1/sub2")) + assert.NoError(archive.Add("sub1/sub2/subfoo.txt", "../testdata/sub1/sub2/subfoo.txt")) + + assert.NoError(archive.Close()) + assert.Error(archive.Add("tar.go", "tar.go")) + assert.NoError(f.Close()) + + t.Log(f.Name()) + f, err = os.Open(f.Name()) + assert.NoError(err) + info, err := f.Stat() + assert.NoError(err) + assert.Truef(info.Size() < 900, "archived file should be smaller than %d", info.Size()) + r, err := zip.NewReader(f, info.Size()) + assert.NoError(err) + var paths = make([]string, len(r.File)) + for i, zf := range r.File { + paths[i] = zf.Name + t.Logf("%s: %v", zf.Name, zf.Mode()) + if zf.Name == "sub1/executable" { + assert.Equal("-rwxrwxr-x", zf.Mode().String()) + } + } + assert.Equal([]string{ + "foo.txt", + "sub1/bar.txt", + "sub1/executable", + "sub1/sub2/subfoo.txt", + }, paths) +}