github.com/jonathanlloyd/goreleaser@v0.91.1/internal/pipe/nfpm/nfpm.go (about) 1 // Package nfpm implements the Pipe interface providing NFPM bindings. 2 package nfpm 3 4 import ( 5 "os" 6 "path/filepath" 7 8 "github.com/apex/log" 9 "github.com/goreleaser/nfpm" 10 "github.com/imdario/mergo" 11 "github.com/pkg/errors" 12 13 // blank imports here because the formats implementations need register 14 // themselves 15 _ "github.com/goreleaser/nfpm/deb" 16 _ "github.com/goreleaser/nfpm/rpm" 17 18 "github.com/goreleaser/goreleaser/internal/artifact" 19 "github.com/goreleaser/goreleaser/internal/linux" 20 "github.com/goreleaser/goreleaser/internal/pipe" 21 "github.com/goreleaser/goreleaser/internal/semerrgroup" 22 "github.com/goreleaser/goreleaser/internal/tmpl" 23 "github.com/goreleaser/goreleaser/pkg/config" 24 "github.com/goreleaser/goreleaser/pkg/context" 25 ) 26 27 const defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" 28 29 // Pipe for fpm packaging 30 type Pipe struct{} 31 32 func (Pipe) String() string { 33 return "creating Linux packages with nfpm" 34 } 35 36 // Default sets the pipe defaults 37 func (Pipe) Default(ctx *context.Context) error { 38 var fpm = &ctx.Config.NFPM 39 if fpm.Bindir == "" { 40 fpm.Bindir = "/usr/local/bin" 41 } 42 if fpm.NameTemplate == "" { 43 fpm.NameTemplate = defaultNameTemplate 44 } 45 if fpm.Files == nil { 46 fpm.Files = make(map[string]string) 47 } 48 return nil 49 } 50 51 // Run the pipe 52 func (Pipe) Run(ctx *context.Context) error { 53 if len(ctx.Config.NFPM.Formats) == 0 { 54 return pipe.Skip("no output formats configured") 55 } 56 return doRun(ctx) 57 } 58 59 func doRun(ctx *context.Context) error { 60 var linuxBinaries = ctx.Artifacts.Filter(artifact.And( 61 artifact.ByType(artifact.Binary), 62 artifact.ByGoos("linux"), 63 )).GroupByPlatform() 64 var g = semerrgroup.New(ctx.Parallelism) 65 for _, format := range ctx.Config.NFPM.Formats { 66 for platform, artifacts := range linuxBinaries { 67 format := format 68 arch := linux.Arch(platform) 69 artifacts := artifacts 70 g.Go(func() error { 71 return create(ctx, format, arch, artifacts) 72 }) 73 } 74 } 75 return g.Wait() 76 } 77 78 func mergeOverrides(ctx *context.Context, format string) (*config.NFPMOverridables, error) { 79 var overrided config.NFPMOverridables 80 if err := mergo.Merge(&overrided, ctx.Config.NFPM.NFPMOverridables); err != nil { 81 return nil, err 82 } 83 perFormat, ok := ctx.Config.NFPM.Overrides[format] 84 if ok { 85 err := mergo.Merge(&overrided, perFormat, mergo.WithOverride) 86 if err != nil { 87 return nil, err 88 } 89 } 90 return &overrided, nil 91 } 92 93 func create(ctx *context.Context, format, arch string, binaries []artifact.Artifact) error { 94 overrided, err := mergeOverrides(ctx, format) 95 if err != nil { 96 return err 97 } 98 name, err := tmpl.New(ctx). 99 WithArtifact(binaries[0], overrided.Replacements). 100 Apply(overrided.NameTemplate) 101 if err != nil { 102 return err 103 } 104 var files = map[string]string{} 105 for k, v := range overrided.Files { 106 files[k] = v 107 } 108 var log = log.WithField("package", name+"."+format) 109 for _, binary := range binaries { 110 src := binary.Path 111 dst := filepath.Join(ctx.Config.NFPM.Bindir, binary.Name) 112 log.WithField("src", src).WithField("dst", dst).Debug("adding binary to package") 113 files[src] = dst 114 } 115 log.WithField("files", files).Debug("all archive files") 116 117 var info = nfpm.Info{ 118 Arch: arch, 119 Platform: "linux", 120 Name: ctx.Config.ProjectName, 121 Version: ctx.Git.CurrentTag, 122 Section: "", 123 Priority: "", 124 Maintainer: ctx.Config.NFPM.Maintainer, 125 Description: ctx.Config.NFPM.Description, 126 Vendor: ctx.Config.NFPM.Vendor, 127 Homepage: ctx.Config.NFPM.Homepage, 128 License: ctx.Config.NFPM.License, 129 Bindir: ctx.Config.NFPM.Bindir, 130 Overridables: nfpm.Overridables{ 131 Conflicts: overrided.Conflicts, 132 Depends: overrided.Dependencies, 133 Recommends: overrided.Recommends, 134 Suggests: overrided.Suggests, 135 EmptyFolders: overrided.EmptyFolders, 136 Files: files, 137 ConfigFiles: overrided.ConfigFiles, 138 Scripts: nfpm.Scripts{ 139 PreInstall: overrided.Scripts.PreInstall, 140 PostInstall: overrided.Scripts.PostInstall, 141 PreRemove: overrided.Scripts.PreRemove, 142 PostRemove: overrided.Scripts.PostRemove, 143 }, 144 }, 145 } 146 147 if err = nfpm.Validate(info); err != nil { 148 return errors.Wrap(err, "invalid nfpm config") 149 } 150 151 packager, err := nfpm.Get(format) 152 if err != nil { 153 return err 154 } 155 156 var path = filepath.Join(ctx.Config.Dist, name+"."+format) 157 log.WithField("file", path).Info("creating") 158 w, err := os.Create(path) 159 if err != nil { 160 return err 161 } 162 defer w.Close() // nolint: errcheck 163 if err := packager.Package(nfpm.WithDefaults(info), w); err != nil { 164 return errors.Wrap(err, "nfpm failed") 165 } 166 if err := w.Close(); err != nil { 167 return errors.Wrap(err, "could not close package file") 168 } 169 ctx.Artifacts.Add(artifact.Artifact{ 170 Type: artifact.LinuxPackage, 171 Name: name + "." + format, 172 Path: path, 173 Goos: binaries[0].Goos, 174 Goarch: binaries[0].Goarch, 175 Goarm: binaries[0].Goarm, 176 }) 177 return nil 178 }