github.phpd.cn/goreleaser/goreleaser@v0.92.0/internal/pipe/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 zglob "github.com/mattn/go-zglob" 15 "golang.org/x/sync/errgroup" 16 17 "github.com/goreleaser/goreleaser/internal/artifact" 18 "github.com/goreleaser/goreleaser/internal/tmpl" 19 "github.com/goreleaser/goreleaser/pkg/archive" 20 "github.com/goreleaser/goreleaser/pkg/context" 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 "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 group, artifacts := range filtered.GroupByPlatform() { 67 log.Debugf("group %s has %d binaries", group, len(artifacts)) 68 artifacts := artifacts 69 g.Go(func() error { 70 if packageFormat(ctx, artifacts[0].Goos) == "binary" { 71 return skip(ctx, artifacts) 72 } 73 return create(ctx, artifacts) 74 }) 75 } 76 return g.Wait() 77 } 78 79 func create(ctx *context.Context, binaries []artifact.Artifact) error { 80 var format = packageFormat(ctx, binaries[0].Goos) 81 folder, err := tmpl.New(ctx). 82 WithArtifact(binaries[0], ctx.Config.Archive.Replacements). 83 Apply(ctx.Config.Archive.NameTemplate) 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 var log = log.WithField("archive", archivePath) 94 log.Info("creating") 95 var a = archive.New(archiveFile) 96 defer a.Close() // nolint: errcheck 97 98 files, err := findFiles(ctx) 99 if err != nil { 100 return fmt.Errorf("failed to find files to archive: %s", err.Error()) 101 } 102 for _, f := range files { 103 log.Debugf("adding %s", f) 104 if err = a.Add(wrap(ctx, f, folder), f); err != nil { 105 return fmt.Errorf("failed to add %s to the archive: %s", f, err.Error()) 106 } 107 } 108 for _, binary := range binaries { 109 var bin = wrap(ctx, binary.Name, folder) 110 log.Debugf("adding %s", bin) 111 if err := a.Add(bin, binary.Path); err != nil { 112 return fmt.Errorf("failed to add %s -> %s to the archive: %s", binary.Path, binary.Name, err.Error()) 113 } 114 } 115 ctx.Artifacts.Add(artifact.Artifact{ 116 Type: artifact.UploadableArchive, 117 Name: folder + "." + format, 118 Path: archivePath, 119 Goos: binaries[0].Goos, 120 Goarch: binaries[0].Goarch, 121 Goarm: binaries[0].Goarm, 122 }) 123 return nil 124 } 125 126 func skip(ctx *context.Context, binaries []artifact.Artifact) error { 127 for _, binary := range binaries { 128 log.WithField("binary", binary.Name).Info("skip archiving") 129 name, err := tmpl.New(ctx). 130 WithArtifact(binary, ctx.Config.Archive.Replacements). 131 Apply(ctx.Config.Archive.NameTemplate) 132 if err != nil { 133 return err 134 } 135 binary.Type = artifact.UploadableBinary 136 binary.Name = name + binary.Extra["Ext"] 137 ctx.Artifacts.Add(binary) 138 } 139 return nil 140 } 141 142 func findFiles(ctx *context.Context) (result []string, err error) { 143 for _, glob := range ctx.Config.Archive.Files { 144 files, err := zglob.Glob(glob) 145 if err != nil { 146 return result, fmt.Errorf("globbing failed for pattern %s: %s", glob, err.Error()) 147 } 148 result = append(result, files...) 149 } 150 // remove duplicates 151 unique.Slice(&result, func(i, j int) bool { 152 return strings.Compare(result[i], result[j]) < 0 153 }) 154 return 155 } 156 157 // Wrap archive files with folder if set in config. 158 func wrap(ctx *context.Context, name, folder string) string { 159 if ctx.Config.Archive.WrapInDirectory { 160 return filepath.Join(folder, name) 161 } 162 return name 163 } 164 165 func packageFormat(ctx *context.Context, platform string) string { 166 for _, override := range ctx.Config.Archive.FormatOverrides { 167 if strings.HasPrefix(platform, override.Goos) { 168 return override.Format 169 } 170 } 171 return ctx.Config.Archive.Format 172 }