2019-10-09 21:30:17 +02:00
|
|
|
// Package rpm implements nfpm.Packager providing .rpm bindings using
|
|
|
|
// google/rpmpack.
|
2018-02-03 20:42:56 +01:00
|
|
|
package rpm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2019-11-05 03:56:18 +01:00
|
|
|
"strings"
|
2019-10-30 21:56:34 +01:00
|
|
|
"time"
|
2018-02-03 20:42:56 +01:00
|
|
|
|
2019-09-10 20:01:43 +02:00
|
|
|
"github.com/google/rpmpack"
|
2019-10-11 22:11:28 +02:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
2018-02-05 02:53:22 +01:00
|
|
|
"github.com/goreleaser/nfpm"
|
2018-03-11 16:59:12 +01:00
|
|
|
"github.com/goreleaser/nfpm/glob"
|
2018-02-03 20:42:56 +01:00
|
|
|
)
|
|
|
|
|
2019-03-04 14:14:05 +01:00
|
|
|
// nolint: gochecknoinits
|
2018-02-12 16:50:25 +01:00
|
|
|
func init() {
|
|
|
|
nfpm.Register("rpm", Default)
|
|
|
|
}
|
2018-02-03 20:42:56 +01:00
|
|
|
|
2019-08-30 03:05:25 +02:00
|
|
|
// Default RPM packager
|
2019-03-04 14:14:05 +01:00
|
|
|
// nolint: gochecknoglobals
|
2018-02-03 20:42:56 +01:00
|
|
|
var Default = &RPM{}
|
|
|
|
|
|
|
|
// RPM is a RPM packager implementation
|
|
|
|
type RPM struct{}
|
|
|
|
|
2019-03-20 01:48:14 +01:00
|
|
|
// nolint: gochecknoglobals
|
2019-03-20 01:34:06 +01:00
|
|
|
var archToRPM = map[string]string{
|
|
|
|
"amd64": "x86_64",
|
|
|
|
"386": "i386",
|
2019-06-28 19:14:45 +02:00
|
|
|
"arm64": "aarch64",
|
2019-03-20 00:47:02 +01:00
|
|
|
}
|
|
|
|
|
2019-10-11 22:11:28 +02:00
|
|
|
func ensureValidArch(info *nfpm.Info) *nfpm.Info {
|
2019-03-20 01:34:06 +01:00
|
|
|
arch, ok := archToRPM[info.Arch]
|
|
|
|
if ok {
|
|
|
|
info.Arch = arch
|
|
|
|
}
|
2019-06-28 19:14:45 +02:00
|
|
|
return info
|
|
|
|
}
|
|
|
|
|
|
|
|
// Package writes a new RPM package to the given writer using the given info
|
2019-10-11 22:11:28 +02:00
|
|
|
func (*RPM) Package(info *nfpm.Info, w io.Writer) error {
|
2019-10-09 21:10:05 +02:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
meta *rpmpack.RPMMetaData
|
|
|
|
rpm *rpmpack.RPM
|
|
|
|
)
|
2019-06-28 19:14:45 +02:00
|
|
|
info = ensureValidArch(info)
|
2019-10-09 21:10:05 +02:00
|
|
|
if err = nfpm.Validate(info); err != nil {
|
2018-03-28 01:36:02 +02:00
|
|
|
return err
|
2018-02-03 20:42:56 +01:00
|
|
|
}
|
|
|
|
|
2019-10-09 21:10:05 +02:00
|
|
|
if meta, err = buildRPMMeta(info); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if rpm, err = rpmpack.NewRPM(*meta); err != nil {
|
2019-09-10 20:01:43 +02:00
|
|
|
return err
|
2018-02-18 22:41:32 +01:00
|
|
|
}
|
2018-03-06 01:02:26 +01:00
|
|
|
|
2019-10-09 21:10:05 +02:00
|
|
|
addEmptyDirsRPM(info, rpm)
|
2019-09-10 20:01:43 +02:00
|
|
|
if err = createFilesInsideRPM(info, rpm); err != nil {
|
|
|
|
return err
|
2018-02-18 22:41:32 +01:00
|
|
|
}
|
|
|
|
|
2019-09-10 20:01:43 +02:00
|
|
|
if err = addScriptFiles(info, rpm); err != nil {
|
2018-02-18 22:41:32 +01:00
|
|
|
return err
|
|
|
|
}
|
2018-04-08 23:37:25 +02:00
|
|
|
|
2019-09-10 20:01:43 +02:00
|
|
|
if err = rpm.Write(w); err != nil {
|
2018-04-08 23:37:25 +02:00
|
|
|
return err
|
2018-02-18 22:41:32 +01:00
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
|
2018-02-18 21:13:47 +01:00
|
|
|
return nil
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
|
|
|
|
2019-10-11 22:11:28 +02:00
|
|
|
func buildRPMMeta(info *nfpm.Info) (*rpmpack.RPMMetaData, error) {
|
2019-10-09 21:10:05 +02:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
provides,
|
|
|
|
depends,
|
|
|
|
replaces,
|
|
|
|
suggests,
|
|
|
|
conflicts rpmpack.Relations
|
|
|
|
)
|
|
|
|
if provides, err = toRelation(info.Provides); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if depends, err = toRelation(info.Depends); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if replaces, err = toRelation(info.Replaces); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if suggests, err = toRelation(info.Suggests); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if conflicts, err = toRelation(info.Conflicts); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &rpmpack.RPMMetaData{
|
|
|
|
Name: info.Name,
|
2019-11-05 03:56:18 +01:00
|
|
|
Summary: strings.Split(info.Description, "\n")[0],
|
2019-10-09 21:10:05 +02:00
|
|
|
Description: info.Description,
|
2019-10-10 03:11:58 +02:00
|
|
|
Version: info.Version,
|
2019-10-22 05:55:29 +02:00
|
|
|
Release: defaultTo(info.Release, "1"),
|
2019-10-09 21:10:05 +02:00
|
|
|
Arch: info.Arch,
|
|
|
|
OS: info.Platform,
|
|
|
|
Licence: info.License,
|
|
|
|
URL: info.Homepage,
|
|
|
|
Vendor: info.Vendor,
|
|
|
|
Packager: info.Maintainer,
|
2019-11-05 03:56:18 +01:00
|
|
|
Group: defaultTo(info.RPM.Group, "Development/Tools"),
|
2019-10-09 21:10:05 +02:00
|
|
|
Provides: provides,
|
|
|
|
Requires: depends,
|
|
|
|
Obsoletes: replaces,
|
|
|
|
Suggests: suggests,
|
|
|
|
Conflicts: conflicts,
|
|
|
|
Compressor: info.RPM.Compression,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-10-22 05:55:29 +02:00
|
|
|
func defaultTo(in, def string) string {
|
|
|
|
if in == "" {
|
|
|
|
return def
|
|
|
|
}
|
|
|
|
return in
|
|
|
|
}
|
|
|
|
|
2019-10-09 21:10:05 +02:00
|
|
|
func toRelation(items []string) (rpmpack.Relations, error) {
|
|
|
|
relations := make(rpmpack.Relations, 0)
|
|
|
|
for idx := range items {
|
|
|
|
if err := relations.Set(items[idx]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return relations, nil
|
|
|
|
}
|
|
|
|
|
2019-10-11 22:11:28 +02:00
|
|
|
func addScriptFiles(info *nfpm.Info, rpm *rpmpack.RPM) error {
|
2019-09-10 20:01:43 +02:00
|
|
|
if info.Scripts.PreInstall != "" {
|
|
|
|
data, err := ioutil.ReadFile(info.Scripts.PreInstall)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-04-08 23:37:25 +02:00
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
rpm.AddPrein(string(data))
|
2018-04-08 23:37:25 +02:00
|
|
|
}
|
|
|
|
|
2019-09-10 20:01:43 +02:00
|
|
|
if info.Scripts.PreRemove != "" {
|
|
|
|
data, err := ioutil.ReadFile(info.Scripts.PreRemove)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
rpm.AddPreun(string(data))
|
2018-02-16 02:58:37 +01:00
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
|
|
|
|
if info.Scripts.PostInstall != "" {
|
|
|
|
data, err := ioutil.ReadFile(info.Scripts.PostInstall)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
rpm.AddPostin(string(data))
|
2018-02-16 02:58:37 +01:00
|
|
|
}
|
|
|
|
|
2019-09-10 20:01:43 +02:00
|
|
|
if info.Scripts.PostRemove != "" {
|
2019-10-09 21:10:05 +02:00
|
|
|
data, err := ioutil.ReadFile(info.Scripts.PostRemove)
|
2019-09-10 20:01:43 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
rpm.AddPostun(string(data))
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
|
2018-02-06 03:28:30 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-10-11 22:11:28 +02:00
|
|
|
func addEmptyDirsRPM(info *nfpm.Info, rpm *rpmpack.RPM) {
|
2019-10-09 21:10:05 +02:00
|
|
|
for _, dir := range info.EmptyFolders {
|
|
|
|
rpm.AddFile(
|
|
|
|
rpmpack.RPMFile{
|
2019-10-30 21:56:34 +01:00
|
|
|
Name: dir,
|
|
|
|
Mode: uint(040755),
|
|
|
|
MTime: uint32(time.Now().Unix()),
|
2019-10-22 05:56:11 +02:00
|
|
|
},
|
|
|
|
)
|
2019-10-09 21:10:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-11 22:11:28 +02:00
|
|
|
func createFilesInsideRPM(info *nfpm.Info, rpm *rpmpack.RPM) error {
|
|
|
|
copyFunc := func(files map[string]string, config bool) error {
|
2018-03-11 16:59:12 +01:00
|
|
|
for srcglob, dstroot := range files {
|
|
|
|
globbed, err := glob.Glob(srcglob, dstroot)
|
2018-03-10 22:26:45 +01:00
|
|
|
if err != nil {
|
2018-02-16 03:12:54 +01:00
|
|
|
return err
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
2018-03-10 22:26:45 +01:00
|
|
|
for src, dst := range globbed {
|
2019-10-09 21:10:05 +02:00
|
|
|
err := copyToRPM(rpm, src, dst, config)
|
2019-09-10 20:01:43 +02:00
|
|
|
if err != nil {
|
2018-03-10 22:26:45 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
2019-10-09 21:10:05 +02:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2019-10-11 22:11:28 +02:00
|
|
|
err := copyFunc(info.Files, false)
|
2019-10-09 21:10:05 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-11 22:11:28 +02:00
|
|
|
err = copyFunc(info.ConfigFiles, true)
|
2019-10-09 21:10:05 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
2018-02-16 02:58:37 +01:00
|
|
|
return nil
|
2018-02-06 03:28:30 +01:00
|
|
|
}
|
|
|
|
|
2019-10-09 21:10:05 +02:00
|
|
|
func copyToRPM(rpm *rpmpack.RPM, src, dst string, config bool) error {
|
2019-09-10 20:01:43 +02:00
|
|
|
file, err := os.OpenFile(src, os.O_RDONLY, 0600) //nolint:gosec
|
2018-02-16 03:12:54 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not add file to the archive")
|
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
// don't care if it errs while closing...
|
2018-02-16 03:12:54 +01:00
|
|
|
defer file.Close() // nolint: errcheck
|
|
|
|
info, err := file.Stat()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info.IsDir() {
|
2019-09-10 20:01:43 +02:00
|
|
|
// TODO: this should probably return an error
|
2018-02-16 03:12:54 +01:00
|
|
|
return nil
|
|
|
|
}
|
2019-09-10 20:01:43 +02:00
|
|
|
data, err := ioutil.ReadAll(file)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-02-16 03:12:54 +01:00
|
|
|
}
|
2018-02-03 20:42:56 +01:00
|
|
|
|
2019-10-09 21:10:05 +02:00
|
|
|
rpmFile := rpmpack.RPMFile{
|
2019-10-30 21:56:34 +01:00
|
|
|
Name: dst,
|
|
|
|
Body: data,
|
|
|
|
Mode: uint(info.Mode()),
|
|
|
|
MTime: uint32(info.ModTime().Unix()),
|
2019-10-09 21:10:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if config {
|
|
|
|
rpmFile.Type = rpmpack.ConfigFile
|
|
|
|
}
|
|
|
|
|
|
|
|
rpm.AddFile(rpmFile)
|
2018-02-03 20:42:56 +01:00
|
|
|
|
2019-09-10 20:01:43 +02:00
|
|
|
return nil
|
|
|
|
}
|