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 }