github.com/axxelg/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  }