github.com/droot/goreleaser@v0.66.2-0.20180420030140-c2db5fb17157/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, binaries) 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, filepath.Base(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 func skip(ctx *context.Context, binaries []artifact.Artifact) error { 125 for _, binary := range binaries { 126 log.WithField("binary", binary.Name).Info("skip archiving") 127 var fields = filenametemplate.NewFields(ctx, ctx.Config.Archive.Replacements, binary) 128 name, err := filenametemplate.Apply(ctx.Config.Archive.NameTemplate, fields) 129 if err != nil { 130 return err 131 } 132 binary.Type = artifact.UploadableBinary 133 binary.Name = name + binary.Extra["Ext"] 134 ctx.Artifacts.Add(binary) 135 } 136 return nil 137 } 138 139 func findFiles(ctx *context.Context, binaries []artifact.Artifact) (result []string, err error) { 140 for _, globTmpl := range ctx.Config.Archive.Files { 141 var glob string 142 glob, err = filenametemplate.Apply( 143 globTmpl, 144 filenametemplate.NewFields(ctx, nil, binaries...), 145 ) 146 if err != nil { 147 return 148 } 149 log.Debugf("adding glob %s \n", glob) 150 files, err := zglob.Glob(glob) 151 if err != nil { 152 return result, fmt.Errorf("globbing failed for pattern %s: %s", glob, err.Error()) 153 } 154 result = append(result, files...) 155 } 156 // remove duplicates 157 unique.Slice(&result, func(i, j int) bool { 158 return strings.Compare(result[i], result[j]) < 0 159 }) 160 return 161 } 162 163 // Wrap archive files with folder if set in config. 164 func wrap(ctx *context.Context, name, folder string) string { 165 if ctx.Config.Archive.WrapInDirectory { 166 return filepath.Join(folder, ctx.Config.Archive.WrapInDirectoryPath, name) 167 } 168 return name 169 } 170 171 func packageFormat(ctx *context.Context, platform string) string { 172 for _, override := range ctx.Config.Archive.FormatOverrides { 173 if strings.HasPrefix(platform, override.Goos) { 174 return override.Format 175 } 176 } 177 return ctx.Config.Archive.Format 178 }