1
1
mirror of https://github.com/goreleaser/nfpm synced 2024-11-18 23:14:12 +01:00
nfpm/nfpm.go
Carlos Alexandro Becker 33156b2b19
fix: rules tests, overridables (#66)
* fix: rules tests, overridables

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>

* doc: gogoc

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>

* fix: rpm template

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>

* fix: rpm template

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
2019-08-31 10:21:28 -03:00

194 lines
5.3 KiB
Go

// Package nfpm provides ways to package programs in some linux packaging
// formats.
package nfpm
import (
"fmt"
"io"
"os"
"strings"
"sync"
"github.com/imdario/mergo"
"gopkg.in/yaml.v2"
)
// nolint: gochecknoglobals
var (
packagers = map[string]Packager{}
lock sync.Mutex
)
// Register a new packager for the given format
func Register(format string, p Packager) {
lock.Lock()
packagers[format] = p
lock.Unlock()
}
// Get a packager for the given format
func Get(format string) (Packager, error) {
p, ok := packagers[format]
if !ok {
return nil, fmt.Errorf("no packager registered for the format %s", format)
}
return p, nil
}
// Parse decodes YAML data from an io.Reader into a configuration struct
func Parse(in io.Reader) (config Config, err error) {
dec := yaml.NewDecoder(in)
dec.SetStrict(true)
if err = dec.Decode(&config); err != nil {
return
}
config.Info.Version = os.ExpandEnv(config.Info.Version)
err = config.Validate()
return
}
// ParseFile decodes YAML data from a file path into a configuration struct
func ParseFile(path string) (config Config, err error) {
var file *os.File
file, err = os.Open(path) //nolint:gosec
if err != nil {
return
}
defer file.Close() // nolint: errcheck
return Parse(file)
}
// Packager represents any packager implementation
type Packager interface {
Package(info Info, w io.Writer) error
}
// Config contains the top level configuration for packages
type Config struct {
Info `yaml:",inline"`
Overrides map[string]Overridables `yaml:"overrides,omitempty"`
}
// Get returns the Info struct for the given packager format. Overrides
// for the given format are merged into the final struct
func (c *Config) Get(format string) (info Info, err error) {
// make a deep copy of info
if err = mergo.Merge(&info, c.Info); err != nil {
return
}
override, ok := c.Overrides[format]
if !ok {
// no overrides
return
}
err = mergo.Merge(&info.Overridables, override, mergo.WithOverride)
if err != nil {
return
}
return
}
// Validate ensures that the config is well typed
func (c *Config) Validate() error {
for format := range c.Overrides {
if _, err := Get(format); err != nil {
return err
}
}
return nil
}
// Info contains information about a single package
type Info struct {
Overridables `yaml:",inline"`
Name string `yaml:"name,omitempty"`
Arch string `yaml:"arch,omitempty"`
Platform string `yaml:"platform,omitempty"`
Epoch string `yaml:"epoch,omitempty"`
Version string `yaml:"version,omitempty"`
Section string `yaml:"section,omitempty"`
Priority string `yaml:"priority,omitempty"`
Maintainer string `yaml:"maintainer,omitempty"`
Description string `yaml:"description,omitempty"`
Vendor string `yaml:"vendor,omitempty"`
Homepage string `yaml:"homepage,omitempty"`
License string `yaml:"license,omitempty"`
Bindir string `yaml:"bindir,omitempty"`
}
// Overridables contain the field which are overridable in a package
type Overridables struct {
Replaces []string `yaml:"replaces,omitempty"`
Provides []string `yaml:"provides,omitempty"`
Depends []string `yaml:"depends,omitempty"`
Recommends []string `yaml:"recommends,omitempty"`
Suggests []string `yaml:"suggests,omitempty"`
Conflicts []string `yaml:"conflicts,omitempty"`
Files map[string]string `yaml:"files,omitempty"`
ConfigFiles map[string]string `yaml:"config_files,omitempty"`
EmptyFolders []string `yaml:"empty_folders,omitempty"`
Scripts Scripts `yaml:"scripts,omitempty"`
RPM RPM `yaml:"rpm,omitempty"`
Deb Deb `yaml:"deb,omitempty"`
}
// RPM is custom configs that are only available on RPM packages
type RPM struct {
Group string `yaml:"group,omitempty"`
Prefix string `yaml:"prefix,omitempty"`
Compression string `yaml:"compression,omitempty"`
Release string `yaml:"release,omitempty"`
}
// Deb is custom configs that are only available on deb packages
type Deb struct {
Scripts DebScripts `yaml:"scripts,omitempty"`
}
// DebScripts is scripts only available on deb packages
type DebScripts struct {
Rules string `yaml:"rules,omitempty"`
}
// Scripts contains information about maintainer scripts for packages
type Scripts struct {
PreInstall string `yaml:"preinstall,omitempty"`
PostInstall string `yaml:"postinstall,omitempty"`
PreRemove string `yaml:"preremove,omitempty"`
PostRemove string `yaml:"postremove,omitempty"`
}
// Validate the given Info and returns an error if it is invalid.
func Validate(info Info) error {
if info.Name == "" {
return fmt.Errorf("package name cannot be empty")
}
if info.Arch == "" {
return fmt.Errorf("package arch must be provided")
}
if info.Version == "" {
return fmt.Errorf("package version must be provided")
}
if len(info.Files)+len(info.ConfigFiles) == 0 {
return fmt.Errorf("no files were provided")
}
return nil
}
// WithDefaults set some sane defaults into the given Info
func WithDefaults(info Info) Info {
if info.Bindir == "" {
info.Bindir = "/usr/local/bin"
}
if info.Platform == "" {
info.Platform = "linux"
}
if info.Description == "" {
info.Description = "no description given"
}
info.Version = strings.TrimPrefix(info.Version, "v")
return info
}