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 }