2018-02-05 02:53:22 +01:00
|
|
|
// Package deb implements nfpm.Packager providing .deb bindings.
|
2018-01-04 13:31:22 +01:00
|
|
|
package deb
|
|
|
|
|
|
|
|
import (
|
2018-01-10 00:03:01 +01:00
|
|
|
"archive/tar"
|
2018-01-04 13:31:22 +01:00
|
|
|
"bytes"
|
2018-06-02 20:22:21 +02:00
|
|
|
"crypto/md5" // nolint:gas
|
2022-05-30 15:34:45 +02:00
|
|
|
"crypto/sha1"
|
2020-09-19 22:06:07 +02:00
|
|
|
"errors"
|
2018-01-10 00:03:01 +01:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2018-01-04 13:31:22 +01:00
|
|
|
"os"
|
2018-06-02 20:22:21 +02:00
|
|
|
"path/filepath"
|
2018-01-10 00:03:01 +01:00
|
|
|
"strings"
|
2018-01-04 13:31:22 +01:00
|
|
|
"text/template"
|
2018-01-10 00:03:01 +01:00
|
|
|
"time"
|
2018-01-04 13:31:22 +01:00
|
|
|
|
2018-01-10 00:03:01 +01:00
|
|
|
"github.com/blakesmith/ar"
|
2022-08-10 05:46:47 +02:00
|
|
|
"github.com/goreleaser/chglog"
|
2020-12-23 14:25:57 +01:00
|
|
|
"github.com/goreleaser/nfpm/v2"
|
2021-11-13 03:07:18 +01:00
|
|
|
"github.com/goreleaser/nfpm/v2/deprecation"
|
2020-12-23 14:25:57 +01:00
|
|
|
"github.com/goreleaser/nfpm/v2/files"
|
|
|
|
"github.com/goreleaser/nfpm/v2/internal/sign"
|
2022-02-13 18:31:37 +01:00
|
|
|
gzip "github.com/klauspost/pgzip"
|
2021-10-12 19:42:00 +02:00
|
|
|
"github.com/ulikunitz/xz"
|
2018-01-04 13:31:22 +01:00
|
|
|
)
|
|
|
|
|
2020-12-15 17:47:00 +01:00
|
|
|
const packagerName = "deb"
|
|
|
|
|
2019-03-04 14:14:05 +01:00
|
|
|
// nolint: gochecknoinits
|
2018-02-12 16:50:25 +01:00
|
|
|
func init() {
|
2020-12-15 17:47:00 +01:00
|
|
|
nfpm.RegisterPackager(packagerName, Default)
|
2018-02-12 16:50:25 +01:00
|
|
|
}
|
2018-01-10 14:16:07 +01:00
|
|
|
|
2019-03-04 14:14:05 +01:00
|
|
|
// nolint: gochecknoglobals
|
2019-03-20 01:34:06 +01:00
|
|
|
var archToDebian = map[string]string{
|
2021-11-07 03:53:32 +01:00
|
|
|
"386": "i386",
|
2021-12-04 19:52:16 +01:00
|
|
|
"arm5": "armel",
|
|
|
|
"arm6": "armhf",
|
2021-11-07 03:53:32 +01:00
|
|
|
"arm7": "armhf",
|
|
|
|
"mipsle": "mipsel",
|
|
|
|
"mips64le": "mips64el",
|
|
|
|
"ppc64le": "ppc64el",
|
2021-11-14 01:19:11 +01:00
|
|
|
"s390": "s390x",
|
2018-03-21 22:07:35 +01:00
|
|
|
}
|
|
|
|
|
2021-11-06 18:04:50 +01:00
|
|
|
func ensureValidArch(info *nfpm.Info) *nfpm.Info {
|
|
|
|
if info.Deb.Arch != "" {
|
|
|
|
info.Arch = info.Deb.Arch
|
2021-11-07 03:53:32 +01:00
|
|
|
} else if arch, ok := archToDebian[info.Arch]; ok {
|
|
|
|
info.Arch = arch
|
2021-11-06 18:04:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return info
|
|
|
|
}
|
|
|
|
|
2020-11-27 03:17:14 +01:00
|
|
|
// Default deb packager.
|
2019-03-04 14:14:05 +01:00
|
|
|
// nolint: gochecknoglobals
|
2018-01-10 14:16:07 +01:00
|
|
|
var Default = &Deb{}
|
|
|
|
|
2020-05-13 21:24:06 +02:00
|
|
|
// Deb is a deb packager implementation.
|
2018-01-10 14:16:07 +01:00
|
|
|
type Deb struct{}
|
|
|
|
|
2020-07-09 15:16:04 +02:00
|
|
|
// ConventionalFileName returns a file name according
|
|
|
|
// to the conventions for debian packages. See:
|
|
|
|
// https://manpages.debian.org/buster/dpkg-dev/dpkg-name.1.en.html
|
|
|
|
func (*Deb) ConventionalFileName(info *nfpm.Info) string {
|
2021-11-06 18:04:50 +01:00
|
|
|
info = ensureValidArch(info)
|
2020-07-09 15:16:04 +02:00
|
|
|
|
2020-07-15 15:10:29 +02:00
|
|
|
version := info.Version
|
|
|
|
if info.Prerelease != "" {
|
|
|
|
version += "~" + info.Prerelease
|
|
|
|
}
|
|
|
|
|
2020-08-20 06:00:17 +02:00
|
|
|
if info.VersionMetadata != "" {
|
|
|
|
version += "+" + info.VersionMetadata
|
|
|
|
}
|
|
|
|
|
2021-10-10 19:44:47 +02:00
|
|
|
if info.Release != "" {
|
|
|
|
version += "-" + info.Release
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:16:04 +02:00
|
|
|
// package_version_architecture.package-type
|
2021-11-06 18:04:50 +01:00
|
|
|
return fmt.Sprintf("%s_%s_%s.deb", info.Name, version, info.Arch)
|
2020-07-09 15:16:04 +02:00
|
|
|
}
|
|
|
|
|
2022-10-15 19:54:36 +02:00
|
|
|
// ConventionalExtension returns the file name conventionally used for Deb packages
|
|
|
|
func (*Deb) ConventionalExtension() string {
|
|
|
|
return ".deb"
|
|
|
|
}
|
|
|
|
|
2020-09-19 22:06:07 +02:00
|
|
|
// ErrInvalidSignatureType happens if the signature type of a deb is not one of
|
|
|
|
// origin, maint or archive.
|
|
|
|
var ErrInvalidSignatureType = errors.New("invalid signature type")
|
|
|
|
|
2020-05-13 21:24:06 +02:00
|
|
|
// Package writes a new deb package to the given writer using the given info.
|
2021-10-11 14:50:43 +02:00
|
|
|
func (d *Deb) Package(info *nfpm.Info, deb io.Writer) (err error) { // nolint: funlen
|
2021-11-06 18:04:50 +01:00
|
|
|
info = ensureValidArch(info)
|
2020-12-15 17:47:00 +01:00
|
|
|
if err = info.Validate(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2021-10-11 14:50:43 +02:00
|
|
|
// Set up some deb specific defaults
|
|
|
|
d.SetPackagerDefaults(info)
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
dataTarball, md5sums, instSize, dataTarballName, err := createDataTarball(info)
|
2018-01-04 13:31:22 +01:00
|
|
|
if err != nil {
|
2018-01-10 00:03:01 +01:00
|
|
|
return err
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2018-02-25 18:56:29 +01:00
|
|
|
controlTarGz, err := createControl(instSize, md5sums, info)
|
2018-01-04 13:31:22 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
|
|
|
debianBinary := []byte("2.0\n")
|
|
|
|
|
2021-02-27 18:15:05 +01:00
|
|
|
w := ar.NewWriter(deb)
|
2018-01-10 00:03:01 +01:00
|
|
|
if err := w.WriteGlobalHeader(); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot write ar header to deb file: %w", err)
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
|
|
|
if err := addArFile(w, "debian-binary", debianBinary); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot pack debian-binary: %w", err)
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2018-02-25 18:56:29 +01:00
|
|
|
if err := addArFile(w, "control.tar.gz", controlTarGz); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot add control.tar.gz to deb: %w", err)
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
if err := addArFile(w, dataTarballName, dataTarball); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot add data.tar.gz to deb: %w", err)
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
|
|
|
if info.Deb.Signature.KeyFile != "" {
|
2022-06-12 04:32:07 +02:00
|
|
|
sig, sigType, err := doSign(info, debianBinary, controlTarGz, dataTarball)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
if err := addArFile(w, "_gpg"+sigType, sig); err != nil {
|
|
|
|
return &nfpm.ErrSigningFailure{
|
|
|
|
Err: fmt.Errorf("add signature to ar file: %w", err),
|
2022-05-30 15:34:45 +02:00
|
|
|
}
|
2022-06-12 04:32:07 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
return nil
|
|
|
|
}
|
2022-05-30 15:34:45 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
func doSign(info *nfpm.Info, debianBinary, controlTarGz, dataTarball []byte) ([]byte, string, error) {
|
|
|
|
switch info.Deb.Signature.Method {
|
|
|
|
case "dpkg-sig":
|
|
|
|
return dpkgSign(info, debianBinary, controlTarGz, dataTarball)
|
|
|
|
default:
|
|
|
|
return debSign(info, debianBinary, controlTarGz, dataTarball)
|
|
|
|
}
|
|
|
|
}
|
2022-05-30 15:34:45 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
func dpkgSign(info *nfpm.Info, debianBinary, controlTarGz, dataTarball []byte) ([]byte, string, error) {
|
|
|
|
sigType := "builder"
|
|
|
|
if info.Deb.Signature.Type != "" {
|
|
|
|
sigType = info.Deb.Signature.Type
|
|
|
|
}
|
2022-05-30 15:34:45 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
data, err := readDpkgSigData(info, debianBinary, controlTarGz, dataTarball)
|
|
|
|
if err != nil {
|
|
|
|
return nil, sigType, &nfpm.ErrSigningFailure{Err: err}
|
|
|
|
}
|
2022-05-30 15:34:45 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
sig, err := sign.PGPClearSignWithKeyID(data, info.Deb.Signature.KeyFile, info.Deb.Signature.KeyPassphrase, info.Deb.Signature.KeyID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, sigType, &nfpm.ErrSigningFailure{Err: err}
|
|
|
|
}
|
|
|
|
return sig, sigType, nil
|
|
|
|
}
|
2020-09-17 14:18:44 +02:00
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
func debSign(info *nfpm.Info, debianBinary, controlTarGz, dataTarball []byte) ([]byte, string, error) {
|
|
|
|
data := readDebsignData(debianBinary, controlTarGz, dataTarball)
|
|
|
|
|
|
|
|
sigType := "origin"
|
|
|
|
if info.Deb.Signature.Type != "" {
|
|
|
|
sigType = info.Deb.Signature.Type
|
|
|
|
}
|
|
|
|
|
|
|
|
if sigType != "origin" && sigType != "maint" && sigType != "archive" {
|
|
|
|
return nil, sigType, &nfpm.ErrSigningFailure{
|
|
|
|
Err: ErrInvalidSignatureType,
|
2020-09-17 14:18:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-12 04:32:07 +02:00
|
|
|
sig, err := sign.PGPArmoredDetachSignWithKeyID(data, info.Deb.Signature.KeyFile, info.Deb.Signature.KeyPassphrase, info.Deb.Signature.KeyID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, sigType, &nfpm.ErrSigningFailure{Err: err}
|
|
|
|
}
|
|
|
|
return sig, sigType, nil
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
|
|
|
|
2022-05-30 15:34:45 +02:00
|
|
|
func readDebsignData(debianBinary, controlTarGz, dataTarball []byte) io.Reader {
|
|
|
|
return io.MultiReader(bytes.NewReader(debianBinary), bytes.NewReader(controlTarGz),
|
|
|
|
bytes.NewReader(dataTarball))
|
|
|
|
}
|
|
|
|
|
|
|
|
// reference: https://manpages.debian.org/jessie/dpkg-sig/dpkg-sig.1.en.html
|
|
|
|
const dpkgSigTemplate = `
|
|
|
|
Hash: SHA1
|
|
|
|
|
|
|
|
Version: 4
|
|
|
|
Signer: {{ .Signer }}
|
|
|
|
Date: {{ .Date }}
|
|
|
|
Role: {{ .Role }}
|
|
|
|
Files:
|
|
|
|
{{range .Files}}{{ .Md5Sum }} {{ .Sha1Sum }} {{ .Size }} {{ .Name }}{{end}}
|
|
|
|
`
|
|
|
|
|
|
|
|
type dpkgSigData struct {
|
|
|
|
Signer string
|
|
|
|
Date time.Time
|
|
|
|
Role string
|
|
|
|
Files []dpkgSigFileLine
|
|
|
|
Info *nfpm.Info
|
|
|
|
}
|
|
|
|
type dpkgSigFileLine struct {
|
|
|
|
Md5Sum [16]byte
|
|
|
|
Sha1Sum [20]byte
|
|
|
|
Size int
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDpkgSigFileLine(name string, fileContent []byte) dpkgSigFileLine {
|
|
|
|
return dpkgSigFileLine{
|
|
|
|
Name: name,
|
|
|
|
Md5Sum: md5.Sum(fileContent),
|
|
|
|
Sha1Sum: sha1.Sum(fileContent),
|
|
|
|
Size: len(fileContent),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func readDpkgSigData(info *nfpm.Info, debianBinary, controlTarGz, dataTarball []byte) (io.Reader, error) {
|
|
|
|
data := dpkgSigData{
|
|
|
|
Signer: info.Deb.Signature.Signer,
|
|
|
|
Date: time.Now(),
|
|
|
|
Role: info.Deb.Signature.Type,
|
|
|
|
Files: []dpkgSigFileLine{
|
|
|
|
newDpkgSigFileLine("debian-binary", debianBinary),
|
|
|
|
newDpkgSigFileLine("control.tar.gz", controlTarGz),
|
|
|
|
newDpkgSigFileLine("data.tar.gz", dataTarball),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
temp, _ := template.New("dpkg-sig").Parse(dpkgSigTemplate)
|
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
err := temp.Execute(buf, data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("dpkg-sig template error: %w", err)
|
|
|
|
}
|
|
|
|
return buf, nil
|
|
|
|
}
|
|
|
|
|
2021-10-11 14:50:43 +02:00
|
|
|
func (*Deb) SetPackagerDefaults(info *nfpm.Info) {
|
|
|
|
// Priority should be set on all packages per:
|
|
|
|
// https://www.debian.org/doc/debian-policy/ch-archive.html#priorities
|
|
|
|
// "optional" seems to be the safe/sane default here
|
|
|
|
if info.Priority == "" {
|
|
|
|
info.Priority = "optional"
|
|
|
|
}
|
|
|
|
|
|
|
|
// The safe thing here feels like defaulting to something like below.
|
|
|
|
// That will prevent existing configs from breaking anyway... Wondering
|
|
|
|
// if in the long run we should be more strict about this and error when
|
|
|
|
// not set?
|
|
|
|
if info.Maintainer == "" {
|
2021-11-13 03:07:18 +01:00
|
|
|
deprecation.Println("Leaving the 'maintainer' field unset will not be allowed in a future version")
|
2021-10-11 14:50:43 +02:00
|
|
|
info.Maintainer = "Unset Maintainer <unset@localhost>"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-25 18:56:29 +01:00
|
|
|
func addArFile(w *ar.Writer, name string, body []byte) error {
|
2021-02-27 18:15:05 +01:00
|
|
|
header := ar.Header{
|
2020-12-09 19:28:30 +01:00
|
|
|
Name: files.ToNixPath(name),
|
2018-01-10 00:03:01 +01:00
|
|
|
Size: int64(len(body)),
|
2021-02-27 18:15:05 +01:00
|
|
|
Mode: 0o644,
|
2018-02-25 18:56:29 +01:00
|
|
|
ModTime: time.Now(),
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2018-01-10 00:03:01 +01:00
|
|
|
if err := w.WriteHeader(&header); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot write file header: %w", err)
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
|
|
|
_, err := w.Write(body)
|
2018-01-04 13:31:22 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
type nopCloser struct {
|
|
|
|
io.Writer
|
|
|
|
}
|
2018-02-16 02:58:37 +01:00
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
func (nopCloser) Close() error { return nil }
|
|
|
|
|
|
|
|
func createDataTarball(info *nfpm.Info) (dataTarBall, md5sums []byte,
|
2022-03-25 02:44:27 +01:00
|
|
|
instSize int64, name string, err error,
|
|
|
|
) {
|
2021-09-04 15:24:52 +02:00
|
|
|
var (
|
|
|
|
dataTarball bytes.Buffer
|
|
|
|
dataTarballWriteCloser io.WriteCloser
|
|
|
|
)
|
|
|
|
|
|
|
|
switch info.Deb.Compression {
|
|
|
|
case "", "gzip": // the default for now
|
|
|
|
dataTarballWriteCloser = gzip.NewWriter(&dataTarball)
|
|
|
|
name = "data.tar.gz"
|
|
|
|
case "xz":
|
|
|
|
dataTarballWriteCloser, err = xz.NewWriter(&dataTarball)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, 0, "", err
|
|
|
|
}
|
|
|
|
name = "data.tar.xz"
|
|
|
|
case "none":
|
|
|
|
dataTarballWriteCloser = nopCloser{Writer: &dataTarball}
|
|
|
|
name = "data.tar"
|
|
|
|
default:
|
|
|
|
return nil, nil, 0, "", fmt.Errorf("unknown compression algorithm: %s", info.Deb.Compression)
|
|
|
|
}
|
|
|
|
|
|
|
|
// the writer is properly closed later, this is just in case that we error out
|
|
|
|
defer dataTarballWriteCloser.Close() // nolint: errcheck
|
|
|
|
|
|
|
|
md5sums, instSize, err = fillDataTar(info, dataTarballWriteCloser)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, 0, "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := dataTarballWriteCloser.Close(); err != nil {
|
|
|
|
return nil, nil, 0, "", fmt.Errorf("closing data tarball: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return dataTarball.Bytes(), md5sums, instSize, name, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func fillDataTar(info *nfpm.Info, w io.Writer) (md5sums []byte, instSize int64, err error) {
|
|
|
|
out := tar.NewWriter(w)
|
|
|
|
|
|
|
|
// the writer is properly closed later, this is just in case that we have
|
2018-02-16 02:58:37 +01:00
|
|
|
// an error in another part of the code.
|
2021-09-04 15:24:52 +02:00
|
|
|
defer out.Close() // nolint: errcheck
|
2018-01-10 00:03:01 +01:00
|
|
|
|
2021-02-27 18:15:05 +01:00
|
|
|
created := map[string]bool{}
|
2018-05-17 02:14:35 +02:00
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
md5buf, instSize, err := createFilesInsideDataTar(info, out, created)
|
2018-05-17 02:14:35 +02:00
|
|
|
if err != nil {
|
2021-09-04 15:24:52 +02:00
|
|
|
return nil, 0, err
|
2018-05-17 01:59:24 +02:00
|
|
|
}
|
2018-02-25 19:17:55 +01:00
|
|
|
|
2018-05-17 02:14:35 +02:00
|
|
|
if err := out.Close(); err != nil {
|
2021-09-04 15:24:52 +02:00
|
|
|
return nil, 0, fmt.Errorf("closing data.tar.gz: %w", err)
|
2018-05-17 02:14:35 +02:00
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
return md5buf.Bytes(), instSize, nil
|
2018-05-17 02:14:35 +02:00
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
func createSymlinkInsideTar(file *files.Content, out *tar.Writer) error {
|
|
|
|
return newItemInsideTar(out, []byte{}, &tar.Header{
|
2020-12-15 17:47:00 +01:00
|
|
|
Name: normalizePath(file.Destination),
|
|
|
|
Linkname: file.Source,
|
|
|
|
Typeflag: tar.TypeSymlink,
|
|
|
|
ModTime: file.FileInfo.MTime,
|
|
|
|
Format: tar.FormatGNU,
|
|
|
|
})
|
2020-07-30 04:20:50 +02:00
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
func createFilesInsideDataTar(info *nfpm.Info, tw *tar.Writer,
|
2022-03-25 02:44:27 +01:00
|
|
|
created map[string]bool,
|
|
|
|
) (md5buf bytes.Buffer, instSize int64, err error) {
|
2021-11-12 02:58:59 +01:00
|
|
|
// create explicit directories first
|
|
|
|
for _, file := range info.Contents {
|
|
|
|
// at this point, we don't care about other types yet
|
|
|
|
if file.Type != "dir" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// only consider contents for this packager
|
|
|
|
if file.Packager != "" && file.Packager != packagerName {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-12-28 18:24:49 +01:00
|
|
|
if err := createTree(tw, file.Destination, created); err != nil {
|
|
|
|
return md5buf, 0, err
|
|
|
|
}
|
|
|
|
|
2021-12-01 15:38:15 +01:00
|
|
|
normalizedName := normalizePath(strings.Trim(file.Destination, "/")) + "/"
|
|
|
|
|
|
|
|
if created[normalizedName] {
|
|
|
|
return md5buf, 0, fmt.Errorf("duplicate directory: %q", normalizedName)
|
|
|
|
}
|
|
|
|
|
2021-11-12 02:58:59 +01:00
|
|
|
err = tw.WriteHeader(&tar.Header{
|
2021-12-01 15:38:15 +01:00
|
|
|
Name: normalizedName,
|
2021-11-12 02:58:59 +01:00
|
|
|
Mode: int64(file.FileInfo.Mode),
|
|
|
|
Typeflag: tar.TypeDir,
|
|
|
|
Format: tar.FormatGNU,
|
|
|
|
Uname: file.FileInfo.Owner,
|
|
|
|
Gname: file.FileInfo.Group,
|
|
|
|
ModTime: file.FileInfo.MTime,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return md5buf, 0, err
|
|
|
|
}
|
|
|
|
|
2021-12-01 15:38:15 +01:00
|
|
|
created[normalizedName] = true
|
2021-11-12 02:58:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// create files and implicit directories
|
2020-12-15 17:47:00 +01:00
|
|
|
for _, file := range info.Contents {
|
2021-11-12 02:58:59 +01:00
|
|
|
// only consider contents for this packager
|
2020-12-15 17:47:00 +01:00
|
|
|
if file.Packager != "" && file.Packager != packagerName {
|
|
|
|
continue
|
|
|
|
}
|
2021-11-12 02:58:59 +01:00
|
|
|
// create implicit directory structure below the current content
|
2020-12-15 17:47:00 +01:00
|
|
|
if err = createTree(tw, file.Destination, created); err != nil {
|
2020-05-14 14:46:46 +02:00
|
|
|
return md5buf, 0, err
|
|
|
|
}
|
2020-07-13 17:10:03 +02:00
|
|
|
|
|
|
|
var size int64 // declare early to avoid shadowing err
|
2020-12-15 17:47:00 +01:00
|
|
|
switch file.Type {
|
|
|
|
case "ghost":
|
2021-12-28 18:24:49 +01:00
|
|
|
// skip ghost files in deb
|
2020-12-15 17:47:00 +01:00
|
|
|
continue
|
2021-11-12 02:58:59 +01:00
|
|
|
case "dir":
|
|
|
|
// already handled above
|
|
|
|
continue
|
2020-12-15 17:47:00 +01:00
|
|
|
case "symlink":
|
2021-09-04 15:24:52 +02:00
|
|
|
err = createSymlinkInsideTar(file, tw)
|
2020-12-15 17:47:00 +01:00
|
|
|
default:
|
|
|
|
size, err = copyToTarAndDigest(file, tw, &md5buf)
|
|
|
|
}
|
2020-05-14 14:46:46 +02:00
|
|
|
if err != nil {
|
|
|
|
return md5buf, 0, err
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2020-05-14 14:46:46 +02:00
|
|
|
instSize += size
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2020-07-13 17:10:03 +02:00
|
|
|
|
2022-08-10 05:46:47 +02:00
|
|
|
if info.Changelog != "" {
|
2021-09-04 15:24:52 +02:00
|
|
|
size, err := createChangelogInsideDataTar(tw, &md5buf, created, info)
|
2020-07-13 17:10:03 +02:00
|
|
|
if err != nil {
|
|
|
|
return md5buf, 0, err
|
|
|
|
}
|
|
|
|
|
2020-08-24 21:34:28 +02:00
|
|
|
instSize += size
|
2020-07-13 17:10:03 +02:00
|
|
|
}
|
|
|
|
|
2018-05-17 02:14:35 +02:00
|
|
|
return md5buf, instSize, nil
|
|
|
|
}
|
2018-01-10 00:03:01 +01:00
|
|
|
|
2020-12-15 17:47:00 +01:00
|
|
|
func copyToTarAndDigest(file *files.Content, tw *tar.Writer, md5w io.Writer) (int64, error) {
|
2021-02-27 18:15:05 +01:00
|
|
|
tarFile, err := os.OpenFile(file.Source, os.O_RDONLY, 0o600) //nolint:gosec
|
2018-02-16 03:12:54 +01:00
|
|
|
if err != nil {
|
2020-12-15 17:47:00 +01:00
|
|
|
return 0, fmt.Errorf("could not add tarFile to the archive: %w", err)
|
2018-02-16 03:12:54 +01:00
|
|
|
}
|
|
|
|
// don't care if it errs while closing...
|
2020-12-15 17:47:00 +01:00
|
|
|
defer tarFile.Close() // nolint: errcheck,gosec
|
|
|
|
|
|
|
|
header, err := tar.FileInfoHeader(file, file.Source)
|
2018-02-16 03:12:54 +01:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2021-11-06 18:07:18 +01:00
|
|
|
|
|
|
|
// tar.FileInfoHeader only uses file.Mode().Perm() which masks the mode with
|
|
|
|
// 0o777 which we don't want because we want to be able to set the suid bit.
|
|
|
|
header.Mode = int64(file.Mode())
|
2020-12-15 17:47:00 +01:00
|
|
|
header.Format = tar.FormatGNU
|
|
|
|
header.Name = normalizePath(file.Destination)
|
2021-10-13 02:02:26 +02:00
|
|
|
header.Uname = file.FileInfo.Owner
|
|
|
|
header.Gname = file.FileInfo.Group
|
2020-12-15 17:47:00 +01:00
|
|
|
if err := tw.WriteHeader(header); err != nil {
|
|
|
|
return 0, fmt.Errorf("cannot write header of %s to data.tar.gz: %w", file.Source, err)
|
2018-02-16 03:12:54 +01:00
|
|
|
}
|
2021-02-27 18:15:05 +01:00
|
|
|
digest := md5.New() // nolint:gas
|
2020-12-15 17:47:00 +01:00
|
|
|
if _, err := io.Copy(tw, io.TeeReader(tarFile, digest)); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return 0, fmt.Errorf("failed to copy: %w", err)
|
2018-02-16 03:12:54 +01:00
|
|
|
}
|
2018-02-25 17:06:58 +01:00
|
|
|
if _, err := fmt.Fprintf(md5w, "%x %s\n", digest.Sum(nil), header.Name); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return 0, fmt.Errorf("failed to write md5: %w", err)
|
2018-02-16 03:12:54 +01:00
|
|
|
}
|
2020-12-15 17:47:00 +01:00
|
|
|
return file.Size(), nil
|
2018-02-16 03:12:54 +01:00
|
|
|
}
|
|
|
|
|
2022-08-10 05:46:47 +02:00
|
|
|
func createChangelogInsideDataTar(tarw *tar.Writer, md5w io.Writer,
|
|
|
|
created map[string]bool, info *nfpm.Info,
|
2022-03-25 02:44:27 +01:00
|
|
|
) (int64, error) {
|
2020-07-13 17:10:03 +02:00
|
|
|
var buf bytes.Buffer
|
2022-12-30 02:25:49 +01:00
|
|
|
out, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("could not create gzip writer: %w", err)
|
|
|
|
}
|
2020-07-13 17:10:03 +02:00
|
|
|
// the writers are properly closed later, this is just in case that we have
|
|
|
|
// an error in another part of the code.
|
|
|
|
defer out.Close() // nolint: errcheck
|
|
|
|
|
2022-08-10 05:46:47 +02:00
|
|
|
changelogContent, err := formatChangelog(info)
|
2020-07-13 17:10:03 +02:00
|
|
|
if err != nil {
|
2020-08-24 21:34:28 +02:00
|
|
|
return 0, err
|
2020-07-13 17:10:03 +02:00
|
|
|
}
|
|
|
|
|
2022-09-12 03:31:51 +02:00
|
|
|
if _, err = io.WriteString(out, changelogContent); err != nil {
|
2020-08-24 21:34:28 +02:00
|
|
|
return 0, err
|
2020-07-13 17:10:03 +02:00
|
|
|
}
|
|
|
|
|
2020-08-24 21:34:28 +02:00
|
|
|
if err = out.Close(); err != nil {
|
2022-12-30 02:25:49 +01:00
|
|
|
return 0, fmt.Errorf("closing changelog.Debian.gz: %w", err)
|
2020-07-13 17:10:03 +02:00
|
|
|
}
|
|
|
|
|
2020-08-24 21:34:28 +02:00
|
|
|
changelogData := buf.Bytes()
|
|
|
|
|
|
|
|
// https://www.debian.org/doc/manuals/developers-reference/pkgs.de.html#recording-changes-in-the-package
|
2022-12-30 02:25:49 +01:00
|
|
|
// https://lintian.debian.org/tags/debian-changelog-file-missing-or-wrong-name
|
|
|
|
changelogName := normalizePath(fmt.Sprintf("/usr/share/doc/%s/changelog.Debian.gz", info.Name))
|
2020-08-24 21:34:28 +02:00
|
|
|
if err = createTree(tarw, changelogName, created); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2021-02-27 18:15:05 +01:00
|
|
|
digest := md5.New() // nolint:gas
|
2020-08-24 21:34:28 +02:00
|
|
|
if _, err = digest.Write(changelogData); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = fmt.Fprintf(md5w, "%x %s\n", digest.Sum(nil), changelogName); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
if err = newFileInsideTar(tarw, changelogName, changelogData); err != nil {
|
2020-08-24 21:34:28 +02:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return int64(len(changelogData)), nil
|
2020-07-13 17:10:03 +02:00
|
|
|
}
|
|
|
|
|
2022-08-10 05:46:47 +02:00
|
|
|
func formatChangelog(info *nfpm.Info) (string, error) {
|
|
|
|
changelog, err := info.GetChangeLog()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
tpl, err := chglog.DebTemplate()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
formattedChangelog, err := chglog.FormatChangelog(changelog, tpl)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.TrimSpace(formattedChangelog) + "\n", nil
|
|
|
|
}
|
|
|
|
|
2020-07-27 18:22:06 +02:00
|
|
|
// nolint:funlen
|
2019-10-11 22:11:28 +02:00
|
|
|
func createControl(instSize int64, md5sums []byte, info *nfpm.Info) (controlTarGz []byte, err error) {
|
2018-01-10 00:03:01 +01:00
|
|
|
var buf bytes.Buffer
|
2021-02-27 18:15:05 +01:00
|
|
|
compress := gzip.NewWriter(&buf)
|
|
|
|
out := tar.NewWriter(compress)
|
2018-02-16 02:58:37 +01:00
|
|
|
// the writers are properly closed later, this is just in case that we have
|
|
|
|
// an error in another part of the code.
|
|
|
|
defer out.Close() // nolint: errcheck
|
|
|
|
defer compress.Close() // nolint: errcheck
|
2018-01-10 00:03:01 +01:00
|
|
|
|
|
|
|
var body bytes.Buffer
|
2020-07-13 17:10:03 +02:00
|
|
|
if err = writeControl(&body, controlData{
|
2018-01-10 00:03:01 +01:00
|
|
|
Info: info,
|
|
|
|
InstalledSize: instSize / 1024,
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2018-02-17 21:49:09 +01:00
|
|
|
|
2020-07-13 17:10:03 +02:00
|
|
|
filesToCreate := map[string][]byte{
|
2018-02-17 21:49:09 +01:00
|
|
|
"control": body.Bytes(),
|
|
|
|
"md5sums": md5sums,
|
|
|
|
"conffiles": conffiles(info),
|
2020-07-13 17:10:03 +02:00
|
|
|
}
|
|
|
|
|
2020-07-27 18:22:06 +02:00
|
|
|
triggers := createTriggers(info)
|
|
|
|
if len(triggers) > 0 {
|
|
|
|
filesToCreate["triggers"] = triggers
|
|
|
|
}
|
|
|
|
|
2020-07-13 17:10:03 +02:00
|
|
|
for name, content := range filesToCreate {
|
2021-09-04 15:24:52 +02:00
|
|
|
if err := newFileInsideTar(out, name, content); err != nil {
|
2018-02-17 21:49:09 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2018-02-17 21:49:09 +01:00
|
|
|
|
2020-11-03 13:44:59 +01:00
|
|
|
type fileAndMode struct {
|
|
|
|
fileName string
|
|
|
|
mode int64
|
|
|
|
}
|
|
|
|
|
2021-02-27 18:15:05 +01:00
|
|
|
specialFiles := map[string]*fileAndMode{}
|
2020-11-03 13:44:59 +01:00
|
|
|
specialFiles[info.Scripts.PreInstall] = &fileAndMode{
|
|
|
|
fileName: "preinst",
|
2021-02-27 18:15:05 +01:00
|
|
|
mode: 0o755,
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
|
|
|
specialFiles[info.Scripts.PostInstall] = &fileAndMode{
|
|
|
|
fileName: "postinst",
|
2021-02-27 18:15:05 +01:00
|
|
|
mode: 0o755,
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
|
|
|
specialFiles[info.Scripts.PreRemove] = &fileAndMode{
|
|
|
|
fileName: "prerm",
|
2021-02-27 18:15:05 +01:00
|
|
|
mode: 0o755,
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
|
|
|
specialFiles[info.Scripts.PostRemove] = &fileAndMode{
|
|
|
|
fileName: "postrm",
|
2021-02-27 18:15:05 +01:00
|
|
|
mode: 0o755,
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
|
|
|
specialFiles[info.Overridables.Deb.Scripts.Rules] = &fileAndMode{
|
|
|
|
fileName: "rules",
|
2021-02-27 18:15:05 +01:00
|
|
|
mode: 0o755,
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
|
|
|
specialFiles[info.Overridables.Deb.Scripts.Templates] = &fileAndMode{
|
|
|
|
fileName: "templates",
|
2021-02-27 18:15:05 +01:00
|
|
|
mode: 0o644,
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
2021-04-14 16:43:42 +02:00
|
|
|
specialFiles[info.Overridables.Deb.Scripts.Config] = &fileAndMode{
|
|
|
|
fileName: "config",
|
|
|
|
mode: 0o755,
|
|
|
|
}
|
2020-11-03 13:44:59 +01:00
|
|
|
|
|
|
|
for path, destMode := range specialFiles {
|
|
|
|
if path != "" {
|
2021-09-04 15:24:52 +02:00
|
|
|
if err := newFilePathInsideTar(out, path, destMode.fileName, destMode.mode); err != nil {
|
2018-04-08 20:43:09 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 21:49:09 +01:00
|
|
|
if err := out.Close(); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return nil, fmt.Errorf("closing control.tar.gz: %w", err)
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2018-02-17 21:49:09 +01:00
|
|
|
if err := compress.Close(); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return nil, fmt.Errorf("closing control.tar.gz: %w", err)
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2018-02-17 21:49:09 +01:00
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|
2018-01-10 00:03:01 +01:00
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
func newItemInsideTar(out *tar.Writer, content []byte, header *tar.Header) error {
|
2019-10-11 22:11:28 +02:00
|
|
|
if err := out.WriteHeader(header); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot write header of %s file to control.tar.gz: %w", header.Name, err)
|
2018-04-08 20:43:09 +02:00
|
|
|
}
|
|
|
|
if _, err := out.Write(content); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("cannot write %s file to control.tar.gz: %w", header.Name, err)
|
2018-04-08 20:43:09 +02:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
func newFileInsideTar(out *tar.Writer, name string, content []byte) error {
|
|
|
|
return newItemInsideTar(out, content, &tar.Header{
|
2020-08-24 21:34:28 +02:00
|
|
|
Name: normalizePath(name),
|
2018-02-17 21:49:09 +01:00
|
|
|
Size: int64(len(content)),
|
2021-02-27 18:15:05 +01:00
|
|
|
Mode: 0o644,
|
2018-02-25 18:56:29 +01:00
|
|
|
ModTime: time.Now(),
|
2018-01-10 00:03:01 +01:00
|
|
|
Typeflag: tar.TypeReg,
|
2018-02-25 18:56:29 +01:00
|
|
|
Format: tar.FormatGNU,
|
2018-04-08 20:43:09 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-04 15:24:52 +02:00
|
|
|
func newFilePathInsideTar(out *tar.Writer, path, dest string, mode int64) error {
|
2018-09-12 18:17:59 +02:00
|
|
|
file, err := os.Open(path) //nolint:gosec
|
2018-04-08 20:43:09 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2022-08-22 14:39:40 +02:00
|
|
|
content, err := io.ReadAll(file)
|
2018-04-08 20:43:09 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-01-10 00:03:01 +01:00
|
|
|
}
|
2021-09-04 15:24:52 +02:00
|
|
|
return newItemInsideTar(out, content, &tar.Header{
|
2020-08-24 21:34:28 +02:00
|
|
|
Name: normalizePath(dest),
|
2018-04-08 20:43:09 +02:00
|
|
|
Size: int64(len(content)),
|
2020-11-03 13:44:59 +01:00
|
|
|
Mode: mode,
|
2018-04-08 20:43:09 +02:00
|
|
|
ModTime: time.Now(),
|
|
|
|
Typeflag: tar.TypeReg,
|
|
|
|
Format: tar.FormatGNU,
|
|
|
|
})
|
2018-02-17 21:49:09 +01:00
|
|
|
}
|
2018-01-10 00:03:01 +01:00
|
|
|
|
2020-11-03 13:44:59 +01:00
|
|
|
// normalizePath returns a path separated by slashes, all relative path items
|
|
|
|
// resolved and relative to the current directory (so it starts with "./").
|
|
|
|
func normalizePath(src string) string {
|
2020-12-09 19:28:30 +01:00
|
|
|
return "." + files.ToNixPath(filepath.Join("/", src))
|
2020-11-03 13:44:59 +01:00
|
|
|
}
|
|
|
|
|
2018-02-25 21:29:24 +01:00
|
|
|
// this is needed because the data.tar.gz file should have the empty folders
|
|
|
|
// as well, so we walk through the dst and create all subfolders.
|
|
|
|
func createTree(tarw *tar.Writer, dst string, created map[string]bool) error {
|
|
|
|
for _, path := range pathsToCreate(dst) {
|
2020-08-24 21:34:28 +02:00
|
|
|
path = normalizePath(path) + "/"
|
|
|
|
|
2018-02-25 21:29:24 +01:00
|
|
|
if created[path] {
|
|
|
|
// skipping dir that was previously created inside the archive
|
|
|
|
// (eg: usr/)
|
|
|
|
continue
|
|
|
|
}
|
2021-12-01 15:38:15 +01:00
|
|
|
|
2018-02-25 21:29:24 +01:00
|
|
|
if err := tarw.WriteHeader(&tar.Header{
|
2020-08-24 21:34:28 +02:00
|
|
|
Name: path,
|
2021-02-27 18:15:05 +01:00
|
|
|
Mode: 0o755,
|
2018-02-25 21:29:24 +01:00
|
|
|
Typeflag: tar.TypeDir,
|
|
|
|
Format: tar.FormatGNU,
|
|
|
|
ModTime: time.Now(),
|
2021-12-01 15:38:15 +01:00
|
|
|
Uname: "root",
|
|
|
|
Gname: "root",
|
2018-02-25 21:29:24 +01:00
|
|
|
}); err != nil {
|
2020-09-19 22:06:07 +02:00
|
|
|
return fmt.Errorf("failed to create folder: %w", err)
|
2018-02-25 21:29:24 +01:00
|
|
|
}
|
|
|
|
created[path] = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func pathsToCreate(dst string) []string {
|
2021-02-27 18:15:05 +01:00
|
|
|
paths := []string{}
|
2021-11-12 02:58:59 +01:00
|
|
|
base := strings.Trim(dst, "/")
|
2018-02-25 21:29:24 +01:00
|
|
|
for {
|
|
|
|
base = filepath.Dir(base)
|
|
|
|
if base == "." {
|
|
|
|
break
|
|
|
|
}
|
2020-12-09 19:28:30 +01:00
|
|
|
paths = append(paths, files.ToNixPath(base))
|
2018-02-25 21:29:24 +01:00
|
|
|
}
|
|
|
|
// we don't really need to create those things in order apparently, but,
|
2018-05-17 01:59:24 +02:00
|
|
|
// it looks really weird if we don't.
|
2021-02-27 18:15:05 +01:00
|
|
|
result := []string{}
|
2018-02-25 21:29:24 +01:00
|
|
|
for i := len(paths) - 1; i >= 0; i-- {
|
|
|
|
result = append(result, paths[i])
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-10-11 22:11:28 +02:00
|
|
|
func conffiles(info *nfpm.Info) []byte {
|
2018-07-09 04:42:58 +02:00
|
|
|
// nolint: prealloc
|
2018-02-17 21:49:09 +01:00
|
|
|
var confs []string
|
2020-12-15 17:47:00 +01:00
|
|
|
for _, file := range info.Contents {
|
|
|
|
if file.Packager != "" && file.Packager != packagerName {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
switch file.Type {
|
|
|
|
case "config", "config|noreplace":
|
|
|
|
confs = append(confs, file.Destination)
|
|
|
|
}
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2018-02-17 21:49:09 +01:00
|
|
|
return []byte(strings.Join(confs, "\n") + "\n")
|
2018-01-04 13:31:22 +01:00
|
|
|
}
|
2018-02-25 21:29:24 +01:00
|
|
|
|
2020-07-27 18:22:06 +02:00
|
|
|
func createTriggers(info *nfpm.Info) []byte {
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
|
|
|
|
// https://man7.org/linux/man-pages/man5/deb-triggers.5.html
|
|
|
|
triggerEntries := []struct {
|
|
|
|
Directive string
|
|
|
|
TriggerNames *[]string
|
|
|
|
}{
|
|
|
|
{"interest", &info.Deb.Triggers.Interest},
|
|
|
|
{"interest-await", &info.Deb.Triggers.InterestAwait},
|
|
|
|
{"interest-noawait", &info.Deb.Triggers.InterestNoAwait},
|
|
|
|
{"activate", &info.Deb.Triggers.Activate},
|
|
|
|
{"activate-await", &info.Deb.Triggers.ActivateAwait},
|
|
|
|
{"activate-noawait", &info.Deb.Triggers.ActivateNoAwait},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, triggerEntry := range triggerEntries {
|
|
|
|
for _, triggerName := range *triggerEntry.TriggerNames {
|
|
|
|
fmt.Fprintf(&buffer, "%s %s\n", triggerEntry.Directive, triggerName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer.Bytes()
|
|
|
|
}
|
|
|
|
|
2019-03-04 14:14:05 +01:00
|
|
|
const controlTemplate = `
|
2019-03-03 23:40:31 +01:00
|
|
|
{{- /* Mandatory fields */ -}}
|
|
|
|
Package: {{.Info.Name}}
|
2019-10-10 03:11:58 +02:00
|
|
|
Version: {{ if .Info.Epoch}}{{ .Info.Epoch }}:{{ end }}{{.Info.Version}}
|
2020-02-18 14:49:10 +01:00
|
|
|
{{- if .Info.Prerelease}}~{{ .Info.Prerelease }}{{- end }}
|
2020-08-20 06:00:17 +02:00
|
|
|
{{- if .Info.VersionMetadata}}+{{ .Info.VersionMetadata }}{{- end }}
|
2022-04-22 20:25:37 +02:00
|
|
|
{{- if .Info.Release}}-{{ .Info.Release }}{{- end }}
|
2018-02-25 21:29:24 +01:00
|
|
|
Section: {{.Info.Section}}
|
|
|
|
Priority: {{.Info.Priority}}
|
2023-01-07 20:35:57 +01:00
|
|
|
Architecture: {{ if ne .Info.Platform "linux"}}{{ .Info.Platform }}-{{ end }}{{.Info.Arch}}
|
2019-03-03 23:40:31 +01:00
|
|
|
{{- /* Optional fields */ -}}
|
|
|
|
{{- if .Info.Maintainer}}
|
2018-02-25 21:29:24 +01:00
|
|
|
Maintainer: {{.Info.Maintainer}}
|
2019-03-03 23:40:31 +01:00
|
|
|
{{- end }}
|
2019-08-31 15:21:28 +02:00
|
|
|
Installed-Size: {{.InstalledSize}}
|
2018-03-10 18:41:41 +01:00
|
|
|
{{- with .Info.Replaces}}
|
|
|
|
Replaces: {{join .}}
|
|
|
|
{{- end }}
|
2023-01-24 02:44:22 +01:00
|
|
|
{{- with nonEmpty .Info.Provides}}
|
2018-03-10 18:41:41 +01:00
|
|
|
Provides: {{join .}}
|
|
|
|
{{- end }}
|
|
|
|
{{- with .Info.Depends}}
|
|
|
|
Depends: {{join .}}
|
|
|
|
{{- end }}
|
|
|
|
{{- with .Info.Recommends}}
|
|
|
|
Recommends: {{join .}}
|
|
|
|
{{- end }}
|
|
|
|
{{- with .Info.Suggests}}
|
|
|
|
Suggests: {{join .}}
|
|
|
|
{{- end }}
|
|
|
|
{{- with .Info.Conflicts}}
|
|
|
|
Conflicts: {{join .}}
|
|
|
|
{{- end }}
|
2020-09-01 21:27:29 +02:00
|
|
|
{{- with .Info.Deb.Breaks}}
|
|
|
|
Breaks: {{join .}}
|
|
|
|
{{- end }}
|
2019-03-03 23:40:31 +01:00
|
|
|
{{- if .Info.Homepage}}
|
2018-02-25 21:29:24 +01:00
|
|
|
Homepage: {{.Info.Homepage}}
|
2019-03-03 23:40:31 +01:00
|
|
|
{{- end }}
|
|
|
|
{{- /* Mandatory fields */}}
|
2020-02-18 14:15:42 +01:00
|
|
|
Description: {{multiline .Info.Description}}
|
2022-04-06 19:38:10 +02:00
|
|
|
{{- range $key, $value := .Info.Deb.Fields }}
|
|
|
|
{{- if $value }}
|
|
|
|
{{$key}}: {{$value}}
|
|
|
|
{{- end }}
|
|
|
|
{{- end }}
|
2018-02-25 21:29:24 +01:00
|
|
|
`
|
|
|
|
|
|
|
|
type controlData struct {
|
2019-10-11 22:11:28 +02:00
|
|
|
Info *nfpm.Info
|
2018-02-25 21:29:24 +01:00
|
|
|
InstalledSize int64
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeControl(w io.Writer, data controlData) error {
|
2021-02-27 18:15:05 +01:00
|
|
|
tmpl := template.New("control")
|
2018-02-25 21:29:24 +01:00
|
|
|
tmpl.Funcs(template.FuncMap{
|
|
|
|
"join": func(strs []string) string {
|
|
|
|
return strings.Trim(strings.Join(strs, ", "), " ")
|
|
|
|
},
|
2020-02-18 14:15:42 +01:00
|
|
|
"multiline": func(strs string) string {
|
2022-02-03 02:39:25 +01:00
|
|
|
ret := strings.ReplaceAll(strs, "\n", "\n ")
|
2020-02-18 14:15:42 +01:00
|
|
|
return strings.Trim(ret, " \n")
|
|
|
|
},
|
2023-01-24 02:44:22 +01:00
|
|
|
"nonEmpty": func(strs []string) []string {
|
|
|
|
var result []string
|
|
|
|
for _, s := range strs {
|
|
|
|
s := strings.TrimSpace(s)
|
|
|
|
if s == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
result = append(result, s)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
},
|
2018-02-25 21:29:24 +01:00
|
|
|
})
|
|
|
|
return template.Must(tmpl.Parse(controlTemplate)).Execute(w, data)
|
|
|
|
}
|