1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-24 04:16:27 +02:00

202 lines
5.2 KiB
Go
Raw Normal View History

2017-04-14 15:39:32 -03:00
// Package fpm implements the Pipe interface providing FPM bindings.
2017-01-29 21:55:32 -02:00
package fpm
import (
2017-06-27 19:36:36 -03:00
"fmt"
"io/ioutil"
2017-12-26 22:13:58 -02:00
"os"
2017-01-29 21:55:32 -02:00
"os/exec"
"path/filepath"
2017-12-27 09:32:24 -02:00
"strings"
2017-01-29 21:55:32 -02:00
2017-06-22 00:09:14 -03:00
"github.com/apex/log"
2017-12-17 17:11:08 -02:00
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
2017-01-29 21:55:32 -02:00
"github.com/goreleaser/goreleaser/context"
2017-12-17 17:11:08 -02:00
"github.com/goreleaser/goreleaser/internal/artifact"
2017-08-27 13:18:23 -03:00
"github.com/goreleaser/goreleaser/internal/linux"
"github.com/goreleaser/goreleaser/internal/template"
2017-08-20 16:35:46 -03:00
"github.com/goreleaser/goreleaser/pipeline"
2017-01-29 21:55:32 -02:00
)
// ErrNoFPM is shown when fpm cannot be found in $PATH
var ErrNoFPM = errors.New("fpm not present in $PATH")
2017-12-27 09:58:42 -02:00
const (
defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
// path to gnu-tar on macOS when installed with homebrew
gnuTarPath = "/usr/local/opt/gnu-tar/libexec/gnubin"
)
2017-01-29 21:55:32 -02:00
// Pipe for fpm packaging
type Pipe struct{}
func (Pipe) String() string {
return "creating Linux packages with fpm"
}
// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
var fpm = &ctx.Config.FPM
if fpm.Bindir == "" {
fpm.Bindir = "/usr/local/bin"
}
if fpm.NameTemplate == "" {
fpm.NameTemplate = defaultNameTemplate
}
return nil
2017-01-29 21:55:32 -02:00
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
2017-01-29 22:01:26 -02:00
if len(ctx.Config.FPM.Formats) == 0 {
2017-08-20 16:35:46 -03:00
return pipeline.Skip("no output formats configured")
2017-01-29 22:01:26 -02:00
}
2017-01-30 07:53:05 -02:00
_, err := exec.LookPath("fpm")
if err != nil {
2017-01-29 21:55:32 -02:00
return ErrNoFPM
}
2017-09-14 21:19:56 -03:00
return doRun(ctx)
}
2017-01-29 22:33:08 -02:00
2017-09-14 21:19:56 -03:00
func doRun(ctx *context.Context) error {
var g errgroup.Group
sem := make(chan bool, ctx.Parallelism)
2017-01-29 21:55:32 -02:00
for _, format := range ctx.Config.FPM.Formats {
2017-12-17 17:11:08 -02:00
for platform, artifacts := range ctx.Artifacts.Filter(
artifact.And(
artifact.ByType(artifact.Binary),
artifact.ByGoos("linux"),
),
).GroupByPlatform() {
sem <- true
format := format
2017-12-17 17:11:08 -02:00
arch := linux.Arch(platform) // TODO: could probably pass artifact.Goarch here
artifacts := artifacts
g.Go(func() error {
defer func() {
<-sem
}()
return create(ctx, format, arch, artifacts)
})
2017-01-29 21:55:32 -02:00
}
}
return g.Wait()
2017-01-29 21:55:32 -02:00
}
2017-12-17 17:11:08 -02:00
func create(ctx *context.Context, format, arch string, binaries []artifact.Artifact) error {
name, err := template.Apply(
ctx.Config.FPM.NameTemplate,
template.NewFields(ctx, binaries[0], ctx.Config.FPM.Replacements),
)
2017-12-17 17:11:08 -02:00
if err != nil {
return err
}
var path = filepath.Join(ctx.Config.Dist, name)
var file = path + "." + format
2017-08-18 19:45:44 -03:00
var log = log.WithField("format", format).WithField("arch", arch)
dir, err := ioutil.TempDir("", "fpm")
if err != nil {
return err
}
log.WithField("file", file).WithField("workdir", dir).Info("creating fpm archive")
var options = basicOptions(ctx, dir, format, arch, file)
2017-09-14 21:19:56 -03:00
for _, binary := range binaries {
// This basically tells fpm to put the binary in the bindir, e.g. /usr/local/bin
2017-09-14 21:19:56 -03:00
// binary=/usr/local/bin/binary
log.WithField("path", binary.Path).
WithField("name", binary.Name).
Debug("added binary to fpm package")
options = append(options, fmt.Sprintf(
"%s=%s",
binary.Path,
filepath.Join(ctx.Config.FPM.Bindir, binary.Name),
2017-09-14 21:19:56 -03:00
))
}
for src, dest := range ctx.Config.FPM.Files {
log.WithField("src", src).
WithField("dest", dest).
Debug("added an extra file to the fpm package")
options = append(options, fmt.Sprintf(
"%s=%s",
src,
dest,
))
}
log.WithField("args", options).Debug("creating fpm package")
2017-12-26 22:13:58 -02:00
if out, err := cmd(options).CombinedOutput(); err != nil {
return errors.Wrap(err, string(out))
2017-09-14 21:19:56 -03:00
}
2017-12-17 17:11:08 -02:00
ctx.Artifacts.Add(artifact.Artifact{
Type: artifact.LinuxPackage,
Name: name + "." + format,
2017-12-17 17:11:08 -02:00
Path: file,
Goos: binaries[0].Goos,
Goarch: binaries[0].Goarch,
Goarm: binaries[0].Goarm,
})
2017-09-14 21:19:56 -03:00
return nil
}
2017-12-26 22:13:58 -02:00
func cmd(options []string) *exec.Cmd {
/* #nosec */
var cmd = exec.Command("fpm", options...)
cmd.Env = []string{fmt.Sprintf("PATH=%s:%s", gnuTarPath, os.Getenv("PATH"))}
2017-12-27 09:32:24 -02:00
for _, env := range os.Environ() {
if strings.HasPrefix(env, "PATH=") {
continue
}
cmd.Env = append(cmd.Env, env)
}
2017-12-26 22:13:58 -02:00
return cmd
}
func basicOptions(ctx *context.Context, workdir, format, arch, file string) []string {
2017-01-29 21:55:32 -02:00
var options = []string{
2017-02-01 15:40:27 -02:00
"--input-type", "dir",
"--output-type", format,
2017-07-01 22:42:10 -03:00
"--name", ctx.Config.ProjectName,
2017-02-01 15:40:27 -02:00
"--version", ctx.Version,
"--architecture", arch,
"--package", file,
2017-01-29 21:55:32 -02:00
"--force",
"--workdir", workdir,
}
if ctx.Debug {
options = append(options, "--debug")
2017-01-29 21:55:32 -02:00
}
2017-04-21 17:02:28 -03:00
if ctx.Config.FPM.Vendor != "" {
options = append(options, "--vendor", ctx.Config.FPM.Vendor)
}
2017-04-21 17:02:28 -03:00
if ctx.Config.FPM.Homepage != "" {
options = append(options, "--url", ctx.Config.FPM.Homepage)
}
2017-04-21 17:02:28 -03:00
if ctx.Config.FPM.Maintainer != "" {
options = append(options, "--maintainer", ctx.Config.FPM.Maintainer)
}
2017-04-21 17:02:28 -03:00
if ctx.Config.FPM.Description != "" {
options = append(options, "--description", ctx.Config.FPM.Description)
}
2017-04-21 17:02:28 -03:00
if ctx.Config.FPM.License != "" {
options = append(options, "--license", ctx.Config.FPM.License)
}
2017-01-29 22:33:08 -02:00
for _, dep := range ctx.Config.FPM.Dependencies {
2017-02-01 15:40:27 -02:00
options = append(options, "--depends", dep)
2017-01-29 21:55:32 -02:00
}
2017-02-01 15:40:27 -02:00
for _, conflict := range ctx.Config.FPM.Conflicts {
options = append(options, "--conflicts", conflict)
}
// FPM requires --rpm-os=linux if your rpm target is linux
2017-08-18 18:44:34 -03:00
if format == "rpm" {
options = append(options, "--rpm-os", "linux")
}
2017-09-14 21:19:56 -03:00
return options
2017-01-29 21:55:32 -02:00
}