gitee.com/mirrors_opencollective/goreleaser@v0.45.0/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/mattn/go-zglob"
    14  	"golang.org/x/sync/errgroup"
    15  
    16  	"github.com/goreleaser/archive"
    17  	"github.com/goreleaser/goreleaser/context"
    18  	"github.com/goreleaser/goreleaser/internal/artifact"
    19  	"github.com/goreleaser/goreleaser/internal/filenametemplate"
    20  )
    21  
    22  const (
    23  	defaultNameTemplate       = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    24  	defaultBinaryNameTemplate = "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    25  )
    26  
    27  // Pipe for archive
    28  type Pipe struct{}
    29  
    30  func (Pipe) String() string {
    31  	return "creating archives"
    32  }
    33  
    34  // Default sets the pipe defaults
    35  func (Pipe) Default(ctx *context.Context) error {
    36  	var archive = &ctx.Config.Archive
    37  	if archive.Format == "" {
    38  		archive.Format = "tar.gz"
    39  	}
    40  	if len(archive.Files) == 0 {
    41  		archive.Files = []string{
    42  			"licence*",
    43  			"LICENCE*",
    44  			"license*",
    45  			"LICENSE*",
    46  			"readme*",
    47  			"README*",
    48  			"changelog*",
    49  			"CHANGELOG*",
    50  		}
    51  	}
    52  	if archive.NameTemplate == "" {
    53  		if archive.Format == "binary" {
    54  			archive.NameTemplate = defaultBinaryNameTemplate
    55  		} else {
    56  			archive.NameTemplate = defaultNameTemplate
    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 ctx.Config.Archive.Format == "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  		if err = a.Add(wrap(ctx, f, folder), f); err != nil {
   103  			return fmt.Errorf("failed to add %s to the archive: %s", f, err.Error())
   104  		}
   105  	}
   106  	for _, binary := range binaries {
   107  		if err := a.Add(wrap(ctx, binary.Name, folder), binary.Path); err != nil {
   108  			return fmt.Errorf("failed to add %s -> %s to the archive: %s", binary.Path, binary.Name, err.Error())
   109  		}
   110  	}
   111  	ctx.Artifacts.Add(artifact.Artifact{
   112  		Type:   artifact.UploadableArchive,
   113  		Name:   folder + "." + format,
   114  		Path:   archivePath,
   115  		Goos:   binaries[0].Goos,
   116  		Goarch: binaries[0].Goarch,
   117  		Goarm:  binaries[0].Goarm,
   118  	})
   119  	return nil
   120  }
   121  
   122  func skip(ctx *context.Context, binaries []artifact.Artifact) error {
   123  	for _, binary := range binaries {
   124  		log.WithField("binary", binary.Name).Info("skip archiving")
   125  		var fields = filenametemplate.NewFields(ctx, ctx.Config.Archive.Replacements, binary)
   126  		name, err := filenametemplate.Apply(ctx.Config.Archive.NameTemplate, fields)
   127  		if err != nil {
   128  			return err
   129  		}
   130  		binary.Type = artifact.UploadableBinary
   131  		binary.Name = name + binary.Extra["Ext"]
   132  		ctx.Artifacts.Add(binary)
   133  	}
   134  	return nil
   135  }
   136  
   137  func findFiles(ctx *context.Context) (result []string, err error) {
   138  	for _, glob := range ctx.Config.Archive.Files {
   139  		files, err := zglob.Glob(glob)
   140  		if err != nil {
   141  			return result, fmt.Errorf("globbing failed for pattern %s: %s", glob, err.Error())
   142  		}
   143  		result = append(result, files...)
   144  	}
   145  	return
   146  }
   147  
   148  // Wrap archive files with folder if set in config.
   149  func wrap(ctx *context.Context, name, folder string) string {
   150  	if ctx.Config.Archive.WrapInDirectory {
   151  		return filepath.Join(folder, name)
   152  	}
   153  	return name
   154  }
   155  
   156  func packageFormat(ctx *context.Context, platform string) string {
   157  	for _, override := range ctx.Config.Archive.FormatOverrides {
   158  		if strings.HasPrefix(platform, override.Goos) {
   159  			return override.Format
   160  		}
   161  	}
   162  	return ctx.Config.Archive.Format
   163  }