2017-04-14 15:39:32 -03:00
|
|
|
// Package archive implements the pipe interface with the intent of
|
|
|
|
// archiving and compressing the binaries, readme, and other artifacts. It
|
|
|
|
// also provides an Archive interface which represents an archiving format.
|
2017-01-14 19:47:15 -02:00
|
|
|
package archive
|
2016-12-28 22:23:39 -02:00
|
|
|
|
2016-12-28 22:53:56 -02:00
|
|
|
import (
|
2017-09-09 11:10:08 +02:00
|
|
|
"fmt"
|
2016-12-29 18:10:11 -02:00
|
|
|
"os"
|
2017-07-13 20:22:10 -03:00
|
|
|
"path/filepath"
|
2017-12-17 18:01:58 -02:00
|
|
|
"strings"
|
2018-11-11 12:11:03 -02:00
|
|
|
"sync"
|
2016-12-29 18:10:11 -02:00
|
|
|
|
2017-06-22 00:09:14 -03:00
|
|
|
"github.com/apex/log"
|
2018-01-21 12:59:15 -02:00
|
|
|
"github.com/campoy/unique"
|
2019-12-29 15:02:15 -03:00
|
|
|
"github.com/mattn/go-zglob"
|
2020-03-04 00:52:43 -03:00
|
|
|
"github.com/pkg/errors"
|
2019-12-29 15:02:15 -03:00
|
|
|
|
2017-12-17 15:50:09 -02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/artifact"
|
2019-05-07 07:18:35 -03:00
|
|
|
"github.com/goreleaser/goreleaser/internal/ids"
|
2019-04-16 10:19:15 -03:00
|
|
|
"github.com/goreleaser/goreleaser/internal/semerrgroup"
|
2018-07-08 20:47:30 -07:00
|
|
|
"github.com/goreleaser/goreleaser/internal/tmpl"
|
2018-08-05 10:23:39 -03:00
|
|
|
"github.com/goreleaser/goreleaser/pkg/archive"
|
2019-04-16 10:19:15 -03:00
|
|
|
archivelib "github.com/goreleaser/goreleaser/pkg/archive"
|
2018-11-13 13:48:16 -02:00
|
|
|
"github.com/goreleaser/goreleaser/pkg/config"
|
2018-08-14 23:50:20 -03:00
|
|
|
"github.com/goreleaser/goreleaser/pkg/context"
|
2016-12-28 22:53:56 -02:00
|
|
|
)
|
2016-12-28 22:23:39 -02:00
|
|
|
|
2017-12-26 21:19:58 -02:00
|
|
|
const (
|
2020-02-05 22:08:18 -03:00
|
|
|
defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
|
|
|
|
defaultBinaryNameTemplate = "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
|
2017-12-26 21:19:58 -02:00
|
|
|
)
|
2017-12-18 21:32:31 -02:00
|
|
|
|
2018-11-11 18:17:44 -02:00
|
|
|
// nolint: gochecknoglobals
|
|
|
|
var lock sync.Mutex
|
|
|
|
|
2017-01-14 19:47:15 -02:00
|
|
|
// Pipe for archive
|
2018-11-11 18:17:44 -02:00
|
|
|
type Pipe struct{}
|
2016-12-30 09:27:35 -02:00
|
|
|
|
2017-12-02 19:53:19 -02:00
|
|
|
func (Pipe) String() string {
|
2018-10-26 14:27:41 -06:00
|
|
|
return "archives"
|
2016-12-30 09:27:35 -02:00
|
|
|
}
|
|
|
|
|
2017-12-02 19:53:19 -02:00
|
|
|
// Default sets the pipe defaults
|
|
|
|
func (Pipe) Default(ctx *context.Context) error {
|
2019-07-27 10:55:56 -03:00
|
|
|
var ids = ids.New("archives")
|
2019-04-16 10:19:15 -03:00
|
|
|
if len(ctx.Config.Archives) == 0 {
|
2019-12-29 15:02:15 -03:00
|
|
|
ctx.Config.Archives = append(ctx.Config.Archives, config.Archive{})
|
2017-12-02 19:53:19 -02:00
|
|
|
}
|
2019-04-16 10:19:15 -03:00
|
|
|
for i := range ctx.Config.Archives {
|
|
|
|
var archive = &ctx.Config.Archives[i]
|
|
|
|
if archive.Format == "" {
|
|
|
|
archive.Format = "tar.gz"
|
|
|
|
}
|
|
|
|
if archive.ID == "" {
|
|
|
|
archive.ID = "default"
|
|
|
|
}
|
|
|
|
if len(archive.Files) == 0 {
|
|
|
|
archive.Files = []string{
|
|
|
|
"licence*",
|
|
|
|
"LICENCE*",
|
|
|
|
"license*",
|
|
|
|
"LICENSE*",
|
|
|
|
"readme*",
|
|
|
|
"README*",
|
|
|
|
"changelog*",
|
|
|
|
"CHANGELOG*",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if archive.NameTemplate == "" {
|
|
|
|
archive.NameTemplate = defaultNameTemplate
|
|
|
|
if archive.Format == "binary" {
|
|
|
|
archive.NameTemplate = defaultBinaryNameTemplate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(archive.Builds) == 0 {
|
|
|
|
for _, build := range ctx.Config.Builds {
|
|
|
|
archive.Builds = append(archive.Builds, build.ID)
|
|
|
|
}
|
|
|
|
}
|
2019-05-07 07:18:35 -03:00
|
|
|
ids.Inc(archive.ID)
|
2017-12-26 21:19:58 -02:00
|
|
|
}
|
2019-05-07 07:18:35 -03:00
|
|
|
return ids.Validate()
|
2017-12-02 19:53:19 -02:00
|
|
|
}
|
|
|
|
|
2017-12-26 21:19:58 -02:00
|
|
|
// Run the pipe
|
2018-11-11 18:17:44 -02:00
|
|
|
func (Pipe) Run(ctx *context.Context) error {
|
2019-04-16 10:19:15 -03:00
|
|
|
var g = semerrgroup.New(ctx.Parallelism)
|
|
|
|
for _, archive := range ctx.Config.Archives {
|
|
|
|
archive := archive
|
|
|
|
var filtered = ctx.Artifacts.Filter(
|
|
|
|
artifact.And(
|
|
|
|
artifact.ByType(artifact.Binary),
|
|
|
|
artifact.ByIDs(archive.Builds...),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
for group, artifacts := range filtered.GroupByPlatform() {
|
|
|
|
log.Debugf("group %s has %d binaries", group, len(artifacts))
|
|
|
|
artifacts := artifacts
|
|
|
|
g.Go(func() error {
|
|
|
|
if packageFormat(archive, artifacts[0].Goos) == "binary" {
|
|
|
|
return skip(ctx, archive, artifacts)
|
|
|
|
}
|
|
|
|
return create(ctx, archive, artifacts)
|
|
|
|
})
|
|
|
|
}
|
2017-12-26 21:19:58 -02:00
|
|
|
}
|
|
|
|
return g.Wait()
|
|
|
|
}
|
|
|
|
|
2019-08-12 17:44:48 -03:00
|
|
|
func create(ctx *context.Context, archive config.Archive, binaries []*artifact.Artifact) error {
|
2019-04-16 10:19:15 -03:00
|
|
|
var format = packageFormat(archive, binaries[0].Goos)
|
2018-07-08 20:47:30 -07:00
|
|
|
folder, err := tmpl.New(ctx).
|
2019-04-16 10:19:15 -03:00
|
|
|
WithArtifact(binaries[0], archive.Replacements).
|
|
|
|
Apply(archive.NameTemplate)
|
2017-12-17 15:50:09 -02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
archivePath := filepath.Join(ctx.Config.Dist, folder+"."+format)
|
2018-11-11 18:17:44 -02:00
|
|
|
lock.Lock()
|
2020-03-28 15:40:16 -03:00
|
|
|
if err := os.MkdirAll(filepath.Dir(archivePath), 0755|os.ModeDir); err != nil {
|
|
|
|
lock.Unlock()
|
|
|
|
return err
|
|
|
|
}
|
2018-11-13 13:48:16 -02:00
|
|
|
if _, err = os.Stat(archivePath); !os.IsNotExist(err) {
|
2018-11-11 18:17:44 -02:00
|
|
|
lock.Unlock()
|
2018-11-11 12:11:03 -02:00
|
|
|
return fmt.Errorf("archive named %s already exists. Check your archive name template", archivePath)
|
|
|
|
}
|
2017-12-17 15:50:09 -02:00
|
|
|
archiveFile, err := os.Create(archivePath)
|
|
|
|
if err != nil {
|
2018-11-11 18:17:44 -02:00
|
|
|
lock.Unlock()
|
2017-12-17 15:50:09 -02:00
|
|
|
return fmt.Errorf("failed to create directory %s: %s", archivePath, err.Error())
|
|
|
|
}
|
2018-11-11 18:17:44 -02:00
|
|
|
lock.Unlock()
|
2017-12-17 23:04:29 -02:00
|
|
|
defer archiveFile.Close() // nolint: errcheck
|
2018-11-13 13:48:16 -02:00
|
|
|
|
2018-10-10 12:49:50 -03:00
|
|
|
var log = log.WithField("archive", archivePath)
|
2018-10-26 16:31:06 -06:00
|
|
|
log.Info("creating")
|
2018-11-13 13:48:16 -02:00
|
|
|
|
2020-03-04 00:52:43 -03:00
|
|
|
template := tmpl.New(ctx).
|
|
|
|
WithArtifact(binaries[0], archive.Replacements)
|
|
|
|
wrap, err := template.
|
2019-04-16 10:19:15 -03:00
|
|
|
Apply(wrapFolder(archive))
|
2018-11-13 13:48:16 -02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-11-07 14:15:51 -02:00
|
|
|
}
|
2018-11-13 13:48:16 -02:00
|
|
|
|
2019-04-16 10:19:15 -03:00
|
|
|
var a = NewEnhancedArchive(archivelib.New(archiveFile), wrap)
|
2017-12-17 23:04:29 -02:00
|
|
|
defer a.Close() // nolint: errcheck
|
2017-12-17 15:50:09 -02:00
|
|
|
|
2020-03-04 00:52:43 -03:00
|
|
|
files, err := findFiles(template, archive)
|
2017-12-17 15:50:09 -02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to find files to archive: %s", err.Error())
|
|
|
|
}
|
|
|
|
for _, f := range files {
|
2018-11-07 14:15:51 -02:00
|
|
|
if err = a.Add(f, f); err != nil {
|
2017-12-17 15:50:09 -02:00
|
|
|
return fmt.Errorf("failed to add %s to the archive: %s", f, err.Error())
|
2017-07-13 19:46:48 -03:00
|
|
|
}
|
2017-12-17 15:50:09 -02:00
|
|
|
}
|
2017-12-29 11:47:13 -02:00
|
|
|
for _, binary := range binaries {
|
2018-11-07 14:15:51 -02:00
|
|
|
if err := a.Add(binary.Name, binary.Path); err != nil {
|
2017-12-17 15:50:09 -02:00
|
|
|
return fmt.Errorf("failed to add %s -> %s to the archive: %s", binary.Path, binary.Name, err.Error())
|
2017-07-13 19:46:48 -03:00
|
|
|
}
|
2017-05-11 00:05:51 -03:00
|
|
|
}
|
2019-08-12 17:44:48 -03:00
|
|
|
ctx.Artifacts.Add(&artifact.Artifact{
|
2017-12-17 16:46:45 -02:00
|
|
|
Type: artifact.UploadableArchive,
|
2017-12-17 15:50:09 -02:00
|
|
|
Name: folder + "." + format,
|
|
|
|
Path: archivePath,
|
2017-12-29 11:47:13 -02:00
|
|
|
Goos: binaries[0].Goos,
|
|
|
|
Goarch: binaries[0].Goarch,
|
|
|
|
Goarm: binaries[0].Goarm,
|
2020-02-05 22:08:18 -03:00
|
|
|
Gomips: binaries[0].Gomips,
|
2019-01-01 14:40:17 -02:00
|
|
|
Extra: map[string]interface{}{
|
|
|
|
"Builds": binaries,
|
2019-04-16 10:19:15 -03:00
|
|
|
"ID": archive.ID,
|
2019-06-10 10:35:19 -03:00
|
|
|
"Format": archive.Format,
|
2019-01-01 14:40:17 -02:00
|
|
|
},
|
2017-12-17 15:50:09 -02:00
|
|
|
})
|
2017-01-14 12:51:09 -02:00
|
|
|
return nil
|
2016-12-28 22:53:56 -02:00
|
|
|
}
|
|
|
|
|
2018-11-13 13:48:16 -02:00
|
|
|
func wrapFolder(a config.Archive) string {
|
|
|
|
switch a.WrapInDirectory {
|
|
|
|
case "true":
|
|
|
|
return a.NameTemplate
|
|
|
|
case "false":
|
|
|
|
return ""
|
|
|
|
default:
|
|
|
|
return a.WrapInDirectory
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-12 17:44:48 -03:00
|
|
|
func skip(ctx *context.Context, archive config.Archive, binaries []*artifact.Artifact) error {
|
2017-12-29 11:47:13 -02:00
|
|
|
for _, binary := range binaries {
|
|
|
|
log.WithField("binary", binary.Name).Info("skip archiving")
|
2018-07-08 20:47:30 -07:00
|
|
|
name, err := tmpl.New(ctx).
|
2019-04-16 10:19:15 -03:00
|
|
|
WithArtifact(binary, archive.Replacements).
|
|
|
|
Apply(archive.NameTemplate)
|
2017-12-17 18:01:58 -02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-08-12 17:44:48 -03:00
|
|
|
ctx.Artifacts.Add(&artifact.Artifact{
|
2019-01-01 14:40:17 -02:00
|
|
|
Type: artifact.UploadableBinary,
|
|
|
|
Name: name + binary.ExtraOr("Ext", "").(string),
|
|
|
|
Path: binary.Path,
|
|
|
|
Goos: binary.Goos,
|
|
|
|
Goarch: binary.Goarch,
|
|
|
|
Goarm: binary.Goarm,
|
2020-02-05 22:08:18 -03:00
|
|
|
Gomips: binary.Gomips,
|
2019-01-01 14:40:17 -02:00
|
|
|
Extra: map[string]interface{}{
|
2019-08-12 17:44:48 -03:00
|
|
|
"Builds": []*artifact.Artifact{binary},
|
2019-04-16 10:19:15 -03:00
|
|
|
"ID": archive.ID,
|
2019-06-10 10:35:19 -03:00
|
|
|
"Format": archive.Format,
|
2019-01-01 14:40:17 -02:00
|
|
|
},
|
|
|
|
})
|
2017-07-03 00:57:39 -03:00
|
|
|
}
|
2017-06-05 16:38:59 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-04 00:52:43 -03:00
|
|
|
func findFiles(template *tmpl.Template, archive config.Archive) (result []string, err error) {
|
2019-04-16 10:19:15 -03:00
|
|
|
for _, glob := range archive.Files {
|
2020-03-04 00:52:43 -03:00
|
|
|
replaced, err := template.Apply(glob)
|
|
|
|
if err != nil {
|
|
|
|
return result, errors.Wrapf(err, "failed to apply template %s", glob)
|
|
|
|
}
|
|
|
|
files, err := zglob.Glob(replaced)
|
2017-05-11 00:05:51 -03:00
|
|
|
if err != nil {
|
2020-03-04 00:52:43 -03:00
|
|
|
return result, errors.Wrapf(err, "globbing failed for pattern %s", glob)
|
2017-05-11 00:05:51 -03:00
|
|
|
}
|
|
|
|
result = append(result, files...)
|
|
|
|
}
|
2018-01-21 12:59:15 -02:00
|
|
|
// remove duplicates
|
|
|
|
unique.Slice(&result, func(i, j int) bool {
|
|
|
|
return strings.Compare(result[i], result[j]) < 0
|
|
|
|
})
|
2017-05-11 00:05:51 -03:00
|
|
|
return
|
|
|
|
}
|
2017-10-02 18:43:03 +02:00
|
|
|
|
2019-04-16 10:19:15 -03:00
|
|
|
func packageFormat(archive config.Archive, platform string) string {
|
|
|
|
for _, override := range archive.FormatOverrides {
|
2017-12-18 21:15:32 -02:00
|
|
|
if strings.HasPrefix(platform, override.Goos) {
|
|
|
|
return override.Format
|
|
|
|
}
|
|
|
|
}
|
2019-04-16 10:19:15 -03:00
|
|
|
return archive.Format
|
2017-12-18 21:15:32 -02:00
|
|
|
}
|
2018-11-07 14:15:51 -02:00
|
|
|
|
2018-11-11 19:02:45 -02:00
|
|
|
// NewEnhancedArchive enhances a pre-existing archive.Archive instance
|
|
|
|
// with this pipe specifics.
|
|
|
|
func NewEnhancedArchive(a archive.Archive, wrap string) archive.Archive {
|
|
|
|
return EnhancedArchive{
|
|
|
|
a: a,
|
|
|
|
wrap: wrap,
|
|
|
|
files: map[string]string{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 14:15:51 -02:00
|
|
|
// EnhancedArchive is an archive.Archive implementation which decorates an
|
|
|
|
// archive.Archive adding wrap directory support, logging and windows
|
|
|
|
// backslash fixes.
|
|
|
|
type EnhancedArchive struct {
|
2018-11-11 19:02:45 -02:00
|
|
|
a archive.Archive
|
|
|
|
wrap string
|
|
|
|
files map[string]string
|
2018-11-07 14:15:51 -02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add adds a file
|
|
|
|
func (d EnhancedArchive) Add(name, path string) error {
|
|
|
|
name = strings.Replace(filepath.Join(d.wrap, name), "\\", "/", -1)
|
|
|
|
log.Debugf("adding file: %s as %s", path, name)
|
2018-11-11 19:02:45 -02:00
|
|
|
if _, ok := d.files[name]; ok {
|
|
|
|
return fmt.Errorf("file %s already exists in the archive", name)
|
|
|
|
}
|
|
|
|
d.files[name] = path
|
2018-11-07 14:15:51 -02:00
|
|
|
return d.a.Add(name, path)
|
|
|
|
}
|
|
|
|
|
2018-11-11 19:02:45 -02:00
|
|
|
// Close closes the underlying archive
|
2018-11-07 14:15:51 -02:00
|
|
|
func (d EnhancedArchive) Close() error {
|
|
|
|
return d.a.Close()
|
|
|
|
}
|