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