github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/sourcearchive/source.go (about)

     1  // Package sourcearchive archives the source of the project using git-archive.
     2  package sourcearchive
     3  
     4  import (
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/caarlos0/log"
    10  	"github.com/goreleaser/goreleaser/internal/archivefiles"
    11  	"github.com/goreleaser/goreleaser/internal/artifact"
    12  	"github.com/goreleaser/goreleaser/internal/deprecate"
    13  	"github.com/goreleaser/goreleaser/internal/gio"
    14  	"github.com/goreleaser/goreleaser/internal/git"
    15  	"github.com/goreleaser/goreleaser/internal/tmpl"
    16  	"github.com/goreleaser/goreleaser/pkg/archive"
    17  	"github.com/goreleaser/goreleaser/pkg/context"
    18  )
    19  
    20  // Pipe for source archive.
    21  type Pipe struct{}
    22  
    23  func (Pipe) String() string {
    24  	return "creating source archive"
    25  }
    26  
    27  func (Pipe) Skip(ctx *context.Context) bool {
    28  	return !ctx.Config.Source.Enabled
    29  }
    30  
    31  // Run the pipe.
    32  func (Pipe) Run(ctx *context.Context) error {
    33  	format := ctx.Config.Source.Format
    34  	if format != "zip" && format != "tar" && format != "tgz" && format != "tar.gz" {
    35  		return fmt.Errorf("invalid source archive format: %s", format)
    36  	}
    37  	name, err := tmpl.New(ctx).Apply(ctx.Config.Source.NameTemplate)
    38  	if err != nil {
    39  		return err
    40  	}
    41  	filename := name + "." + format
    42  	path := filepath.Join(ctx.Config.Dist, filename)
    43  	log.WithField("file", filename).Info("creating source archive")
    44  	args := []string{
    45  		"archive",
    46  		"-o", path,
    47  	}
    48  
    49  	prefix := ""
    50  	if ctx.Config.Source.PrefixTemplate != "" {
    51  		pt, err := tmpl.New(ctx).Apply(ctx.Config.Source.PrefixTemplate)
    52  		if err != nil {
    53  			return err
    54  		}
    55  		prefix = pt
    56  		args = append(args, "--prefix", prefix)
    57  	}
    58  	args = append(args, ctx.Git.FullCommit)
    59  
    60  	if _, err := git.Clean(git.Run(ctx, args...)); err != nil {
    61  		return err
    62  	}
    63  
    64  	if len(ctx.Config.Source.Files) > 0 {
    65  		if err := appendExtraFilesToArchive(ctx, prefix, path, format); err != nil {
    66  			return err
    67  		}
    68  	}
    69  
    70  	ctx.Artifacts.Add(&artifact.Artifact{
    71  		Type: artifact.UploadableSourceArchive,
    72  		Name: filename,
    73  		Path: path,
    74  		Extra: map[string]interface{}{
    75  			artifact.ExtraFormat: format,
    76  		},
    77  	})
    78  	return err
    79  }
    80  
    81  func appendExtraFilesToArchive(ctx *context.Context, prefix, path, format string) error {
    82  	oldPath := path + ".bkp"
    83  	if err := gio.Copy(path, oldPath); err != nil {
    84  		return fmt.Errorf("failed make a backup of %q: %w", path, err)
    85  	}
    86  
    87  	// i could spend a lot of time trying to figure out how to append to a tar,
    88  	// tgz and zip file... but... this seems easy enough :)
    89  	of, err := os.Open(oldPath)
    90  	if err != nil {
    91  		return fmt.Errorf("could not open %q: %w", oldPath, err)
    92  	}
    93  	defer of.Close()
    94  
    95  	af, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0o644)
    96  	if err != nil {
    97  		return fmt.Errorf("could not open archive: %w", err)
    98  	}
    99  	defer af.Close() //nolint:errcheck
   100  
   101  	arch, err := archive.Copying(of, af, format)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	files, err := archivefiles.Eval(tmpl.New(ctx), ctx.Config.Source.Files)
   107  	if err != nil {
   108  		return err
   109  	}
   110  	for _, f := range files {
   111  		f.Destination = filepath.Join(prefix, f.Destination)
   112  		if err := arch.Add(f); err != nil {
   113  			return fmt.Errorf("could not add %q to archive: %w", f.Source, err)
   114  		}
   115  	}
   116  
   117  	if err := arch.Close(); err != nil {
   118  		return fmt.Errorf("could not close archive file: %w", err)
   119  	}
   120  	if err := af.Close(); err != nil {
   121  		return fmt.Errorf("could not close archive file: %w", err)
   122  	}
   123  	return nil
   124  }
   125  
   126  // Default sets the pipe defaults.
   127  func (Pipe) Default(ctx *context.Context) error {
   128  	archive := &ctx.Config.Source
   129  	if archive.Format == "" {
   130  		archive.Format = "tar.gz"
   131  	}
   132  
   133  	if archive.NameTemplate == "" {
   134  		archive.NameTemplate = "{{ .ProjectName }}-{{ .Version }}"
   135  	}
   136  
   137  	if archive.Enabled && archive.RLCP != "" {
   138  		deprecate.Notice(ctx, "source.rlcp")
   139  	}
   140  	return nil
   141  }