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