github.com/szyn/goreleaser@v0.76.1-0.20180517112710-333da09a1297/pipeline/archive/archive.go (about)

     1  // Package archive implements the pipe interface with the intent of
     2  // archiving and compressing the binaries, readme, and other artifacts. It
     3  // also provides an Archive interface which represents an archiving format.
     4  package archive
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/apex/log"
    13  	"github.com/campoy/unique"
    14  	"github.com/mattn/go-zglob"
    15  	"golang.org/x/sync/errgroup"
    16  
    17  	"github.com/goreleaser/archive"
    18  	"github.com/goreleaser/goreleaser/context"
    19  	"github.com/goreleaser/goreleaser/internal/artifact"
    20  	"github.com/goreleaser/goreleaser/internal/filenametemplate"
    21  )
    22  
    23  const (
    24  	defaultNameTemplate       = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    25  	defaultBinaryNameTemplate = "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    26  )
    27  
    28  // Pipe for archive
    29  type Pipe struct{}
    30  
    31  func (Pipe) String() string {
    32  	return "creating archives"
    33  }
    34  
    35  // Default sets the pipe defaults
    36  func (Pipe) Default(ctx *context.Context) error {
    37  	var archive = &ctx.Config.Archive
    38  	if archive.Format == "" {
    39  		archive.Format = "tar.gz"
    40  	}
    41  	if len(archive.Files) == 0 {
    42  		archive.Files = []string{
    43  			"licence*",
    44  			"LICENCE*",
    45  			"license*",
    46  			"LICENSE*",
    47  			"readme*",
    48  			"README*",
    49  			"changelog*",
    50  			"CHANGELOG*",
    51  		}
    52  	}
    53  	if archive.NameTemplate == "" {
    54  		archive.NameTemplate = defaultNameTemplate
    55  		if archive.Format == "binary" {
    56  			archive.NameTemplate = defaultBinaryNameTemplate
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  // Run the pipe
    63  func (Pipe) Run(ctx *context.Context) error {
    64  	var g errgroup.Group
    65  	var filtered = ctx.Artifacts.Filter(artifact.ByType(artifact.Binary))
    66  	for _, artifacts := range filtered.GroupByPlatform() {
    67  		artifacts := artifacts
    68  		g.Go(func() error {
    69  			if packageFormat(ctx, artifacts[0].Goos) == "binary" {
    70  				return skip(ctx, artifacts)
    71  			}
    72  			return create(ctx, artifacts)
    73  		})
    74  	}
    75  	return g.Wait()
    76  }
    77  
    78  func create(ctx *context.Context, binaries []artifact.Artifact) error {
    79  	var format = packageFormat(ctx, binaries[0].Goos)
    80  	folder, err := filenametemplate.Apply(
    81  		ctx.Config.Archive.NameTemplate,
    82  		filenametemplate.NewFields(ctx, ctx.Config.Archive.Replacements, binaries...),
    83  	)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	archivePath := filepath.Join(ctx.Config.Dist, folder+"."+format)
    88  	archiveFile, err := os.Create(archivePath)
    89  	if err != nil {
    90  		return fmt.Errorf("failed to create directory %s: %s", archivePath, err.Error())
    91  	}
    92  	defer archiveFile.Close() // nolint: errcheck
    93  	log.WithField("archive", archivePath).Info("creating")
    94  	var a = archive.New(archiveFile)
    95  	defer a.Close() // nolint: errcheck
    96  
    97  	files, err := findFiles(ctx)
    98  	if err != nil {
    99  		return fmt.Errorf("failed to find files to archive: %s", err.Error())
   100  	}
   101  	for _, f := range files {
   102  		log.Debugf("adding %s", f)
   103  		if err = a.Add(wrap(ctx, f, folder), f); err != nil {
   104  			return fmt.Errorf("failed to add %s to the archive: %s", f, err.Error())
   105  		}
   106  	}
   107  	for _, binary := range binaries {
   108  		var bin = wrap(ctx, binary.Name, folder)
   109  		log.Debugf("adding %s", bin)
   110  		if err := a.Add(bin, binary.Path); err != nil {
   111  			return fmt.Errorf("failed to add %s -> %s to the archive: %s", binary.Path, binary.Name, err.Error())
   112  		}
   113  	}
   114  	ctx.Artifacts.Add(artifact.Artifact{
   115  		Type:   artifact.UploadableArchive,
   116  		Name:   folder + "." + format,
   117  		Path:   archivePath,
   118  		Goos:   binaries[0].Goos,
   119  		Goarch: binaries[0].Goarch,
   120  		Goarm:  binaries[0].Goarm,
   121  	})
   122  	return nil
   123  }
   124  
   125  func skip(ctx *context.Context, binaries []artifact.Artifact) error {
   126  	for _, binary := range binaries {
   127  		log.WithField("binary", binary.Name).Info("skip archiving")
   128  		var fields = filenametemplate.NewFields(ctx, ctx.Config.Archive.Replacements, binary)
   129  		name, err := filenametemplate.Apply(ctx.Config.Archive.NameTemplate, fields)
   130  		if err != nil {
   131  			return err
   132  		}
   133  		binary.Type = artifact.UploadableBinary
   134  		binary.Name = name + binary.Extra["Ext"]
   135  		ctx.Artifacts.Add(binary)
   136  	}
   137  	return nil
   138  }
   139  
   140  func findFiles(ctx *context.Context) (result []string, err error) {
   141  	for _, glob := range ctx.Config.Archive.Files {
   142  		files, err := zglob.Glob(glob)
   143  		if err != nil {
   144  			return result, fmt.Errorf("globbing failed for pattern %s: %s", glob, err.Error())
   145  		}
   146  		result = append(result, files...)
   147  	}
   148  	// remove duplicates
   149  	unique.Slice(&result, func(i, j int) bool {
   150  		return strings.Compare(result[i], result[j]) < 0
   151  	})
   152  	return
   153  }
   154  
   155  // Wrap archive files with folder if set in config.
   156  func wrap(ctx *context.Context, name, folder string) string {
   157  	if ctx.Config.Archive.WrapInDirectory {
   158  		return filepath.Join(folder, name)
   159  	}
   160  	return name
   161  }
   162  
   163  func packageFormat(ctx *context.Context, platform string) string {
   164  	for _, override := range ctx.Config.Archive.FormatOverrides {
   165  		if strings.HasPrefix(platform, override.Goos) {
   166  			return override.Format
   167  		}
   168  	}
   169  	return ctx.Config.Archive.Format
   170  }