forked from goreleaser/nfpm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nfpm.go
172 lines (154 loc) · 4.62 KB
/
nfpm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// 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"
)
// 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"`
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
}