mirror of
https://github.com/goreleaser/nfpm
synced 2024-11-19 03:25:08 +01:00
172 lines
4.6 KiB
Go
172 lines
4.6 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"
|
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
)
|
|
|
|
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"`
|
|
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"`
|
|
}
|
|
|
|
// 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
|
|
}
|