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  }