mirror of
https://github.com/goreleaser/nfpm
synced 2024-11-18 19:04:07 +01:00
998 lines
25 KiB
Go
998 lines
25 KiB
Go
package rpm
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
|
"github.com/caarlos0/go-rpmutils"
|
|
"github.com/caarlos0/go-rpmutils/cpio"
|
|
"github.com/goreleaser/chglog"
|
|
"github.com/goreleaser/nfpm/v2"
|
|
"github.com/goreleaser/nfpm/v2/files"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func exampleInfo() *nfpm.Info {
|
|
return nfpm.WithDefaults(&nfpm.Info{
|
|
Name: "foo",
|
|
Arch: "amd64",
|
|
Description: "Foo does things",
|
|
Priority: "extra",
|
|
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
|
Version: "1.0.0",
|
|
Section: "default",
|
|
Homepage: "http://carlosbecker.com",
|
|
Vendor: "nope",
|
|
License: "MIT",
|
|
Overridables: nfpm.Overridables{
|
|
Depends: []string{
|
|
"bash",
|
|
},
|
|
Recommends: []string{
|
|
"git",
|
|
},
|
|
Suggests: []string{
|
|
"bash",
|
|
},
|
|
Replaces: []string{
|
|
"svn",
|
|
},
|
|
Provides: []string{
|
|
"bzr",
|
|
},
|
|
Conflicts: []string{
|
|
"zsh",
|
|
},
|
|
Contents: []*files.Content{
|
|
{
|
|
Source: "../testdata/fake",
|
|
Destination: "/usr/bin/fake",
|
|
},
|
|
{
|
|
Source: "../testdata/whatever.conf",
|
|
Destination: "/etc/fake/fake.conf",
|
|
Type: files.TypeConfig,
|
|
},
|
|
{
|
|
Destination: "/var/log/whatever",
|
|
Type: files.TypeDir,
|
|
},
|
|
{
|
|
Destination: "/usr/share/whatever",
|
|
Type: files.TypeDir,
|
|
},
|
|
},
|
|
Scripts: nfpm.Scripts{
|
|
PreInstall: "../testdata/scripts/preinstall.sh",
|
|
PostInstall: "../testdata/scripts/postinstall.sh",
|
|
PreRemove: "../testdata/scripts/preremove.sh",
|
|
PostRemove: "../testdata/scripts/postremove.sh",
|
|
},
|
|
RPM: nfpm.RPM{
|
|
Scripts: nfpm.RPMScripts{
|
|
PreTrans: "../testdata/scripts/pretrans.sh",
|
|
PostTrans: "../testdata/scripts/posttrans.sh",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestConventionalExtension(t *testing.T) {
|
|
require.Equal(t, ".rpm", Default.ConventionalExtension())
|
|
}
|
|
|
|
func TestRPM(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
require.NoError(t, err)
|
|
require.NoError(t, Default.Package(exampleInfo(), f))
|
|
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
os, err := rpm.Header.GetString(rpmutils.OS)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "linux", os)
|
|
|
|
arch, err := rpm.Header.GetString(rpmutils.ARCH)
|
|
require.NoError(t, err)
|
|
require.Equal(t, archToRPM["amd64"], arch)
|
|
|
|
version, err := rpm.Header.GetString(rpmutils.VERSION)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0", version)
|
|
|
|
release, err := rpm.Header.GetString(rpmutils.RELEASE)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1", release)
|
|
|
|
epoch, err := rpm.Header.Get(rpmutils.EPOCH)
|
|
require.NoError(t, err)
|
|
epochUint32, ok := epoch.([]uint32)
|
|
require.True(t, ok)
|
|
require.Len(t, epochUint32, 1)
|
|
require.Equal(t, uint32(0), epochUint32[0])
|
|
|
|
group, err := rpm.Header.GetString(rpmutils.GROUP)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "", group)
|
|
|
|
summary, err := rpm.Header.GetString(rpmutils.SUMMARY)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Foo does things", summary)
|
|
|
|
description, err := rpm.Header.GetString(rpmutils.DESCRIPTION)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Foo does things", description)
|
|
}
|
|
|
|
func TestRPMPlatform(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test*.rpm")
|
|
require.NoError(t, err)
|
|
info := exampleInfo()
|
|
info.Platform = "darwin"
|
|
require.NoError(t, Default.Package(info, f))
|
|
}
|
|
|
|
func TestRPMGroup(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
require.NoError(t, err)
|
|
info := exampleInfo()
|
|
info.RPM.Group = "Unspecified"
|
|
require.NoError(t, Default.Package(info, f))
|
|
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
group, err := rpm.Header.GetString(rpmutils.GROUP)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Unspecified", group)
|
|
}
|
|
|
|
func TestRPMCompression(t *testing.T) {
|
|
for _, compressor := range []string{"gzip", "lzma", "xz", "zstd"} {
|
|
for _, level := range []int{-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9} {
|
|
compLevel := fmt.Sprintf("%v:%v", compressor, level)
|
|
if strings.HasPrefix(compLevel, "xz:") {
|
|
compLevel = "xz"
|
|
}
|
|
if strings.HasPrefix(compLevel, "lzma:") {
|
|
compLevel = "lzma"
|
|
}
|
|
t.Run(compLevel, func(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
require.NoError(t, err)
|
|
|
|
info := exampleInfo()
|
|
info.RPM.Compression = compLevel
|
|
|
|
require.NoError(t, Default.Package(info, f))
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
rpmCompressor, err := rpm.Header.GetString(rpmutils.PAYLOADCOMPRESSOR)
|
|
require.NoError(t, err)
|
|
require.Equal(t, compressor, rpmCompressor)
|
|
})
|
|
if compLevel == "xz" || compLevel == "lzma" {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRPMSummary(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
require.NoError(t, err)
|
|
|
|
customSummary := "This is my custom summary"
|
|
info := exampleInfo()
|
|
info.RPM.Group = "Unspecified"
|
|
info.RPM.Summary = customSummary
|
|
|
|
require.NoError(t, Default.Package(info, f))
|
|
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
summary, err := rpm.Header.GetString(rpmutils.SUMMARY)
|
|
require.NoError(t, err)
|
|
require.Equal(t, customSummary, summary)
|
|
}
|
|
|
|
func TestRPMPackager(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
require.NoError(t, err)
|
|
|
|
customPackager := "GoReleaser <staff@goreleaser.com>"
|
|
info := exampleInfo()
|
|
info.RPM.Group = "Unspecified"
|
|
info.RPM.Packager = customPackager
|
|
|
|
require.NoError(t, Default.Package(info, f))
|
|
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
packager, err := rpm.Header.GetString(rpmutils.PACKAGER)
|
|
require.NoError(t, err)
|
|
require.Equal(t, customPackager, packager)
|
|
}
|
|
|
|
func TestWithRPMTags(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
require.NoError(t, err)
|
|
|
|
info := exampleInfo()
|
|
info.Release = "3"
|
|
info.Epoch = "42"
|
|
info.RPM = nfpm.RPM{
|
|
Group: "default",
|
|
}
|
|
info.Description = "first line\nsecond line\nthird line"
|
|
require.NoError(t, Default.Package(info, f))
|
|
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
version, err := rpm.Header.GetString(rpmutils.VERSION)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0", version)
|
|
|
|
release, err := rpm.Header.GetString(rpmutils.RELEASE)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "3", release)
|
|
|
|
epoch, err := rpm.Header.Get(rpmutils.EPOCH)
|
|
require.NoError(t, err)
|
|
epochUint32, ok := epoch.([]uint32)
|
|
require.Len(t, epochUint32, 1)
|
|
require.True(t, ok)
|
|
require.Equal(t, uint32(42), epochUint32[0])
|
|
|
|
group, err := rpm.Header.GetString(rpmutils.GROUP)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "default", group)
|
|
|
|
summary, err := rpm.Header.GetString(rpmutils.SUMMARY)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "first line", summary)
|
|
|
|
description, err := rpm.Header.GetString(rpmutils.DESCRIPTION)
|
|
require.NoError(t, err)
|
|
require.Equal(t, info.Description, description)
|
|
}
|
|
|
|
func TestRPMVersion(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Version = "1.0.0" //nolint:golint,goconst
|
|
meta, err := buildRPMMeta(info)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0", meta.Version)
|
|
require.Equal(t, "1", meta.Release)
|
|
}
|
|
|
|
func TestRPMVersionWithRelease(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Version = "1.0.0" //nolint:golint,goconst
|
|
info.Release = "2"
|
|
meta, err := buildRPMMeta(info)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0", meta.Version)
|
|
require.Equal(t, "2", meta.Release)
|
|
}
|
|
|
|
func TestRPMVersionWithPrerelease(t *testing.T) {
|
|
// https://fedoraproject.org/wiki/Package_Versioning_Examples#Complex_versioning_examples
|
|
info := exampleInfo()
|
|
|
|
info.Version = "1.0.0"
|
|
info.Prerelease = "rc1" // nolint:goconst
|
|
meta, err := buildRPMMeta(info)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0~rc1", meta.Version)
|
|
require.Equal(t, "1", meta.Release)
|
|
|
|
info.Version = "1.0.0~rc1"
|
|
info.Prerelease = ""
|
|
meta, err = buildRPMMeta(info)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0~rc1", meta.Version)
|
|
require.Equal(t, "1", meta.Release)
|
|
}
|
|
|
|
func TestRPMVersionWithReleaseAndPrerelease(t *testing.T) {
|
|
// https://fedoraproject.org/wiki/Package_Versioning_Examples#Complex_versioning_examples
|
|
info := exampleInfo()
|
|
|
|
info.Version = "1.0.0"
|
|
info.Release = "0.2"
|
|
info.Prerelease = "rc1"
|
|
meta, err := buildRPMMeta(info)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0~rc1", meta.Version)
|
|
require.Equal(t, "0.2", meta.Release)
|
|
|
|
info.Version = "1.0.0~rc1"
|
|
info.Release = "0.2"
|
|
info.Prerelease = ""
|
|
meta, err = buildRPMMeta(info)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0~rc1", meta.Version)
|
|
require.Equal(t, "0.2", meta.Release)
|
|
}
|
|
|
|
func TestRPMVersionWithVersionMetadata(t *testing.T) {
|
|
// https://fedoraproject.org/wiki/Package_Versioning_Examples#Complex_versioning_examples
|
|
info := exampleInfo()
|
|
|
|
info.Version = "1.0.0+meta"
|
|
info.VersionMetadata = ""
|
|
meta, err := buildRPMMeta(nfpm.WithDefaults(info))
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0+meta", meta.Version)
|
|
|
|
info.Version = "1.0.0"
|
|
info.VersionMetadata = "meta"
|
|
meta, err = buildRPMMeta(nfpm.WithDefaults(info))
|
|
require.NoError(t, err)
|
|
require.Equal(t, "1.0.0+meta", meta.Version)
|
|
}
|
|
|
|
func TestWithInvalidEpoch(t *testing.T) {
|
|
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
|
defer func() {
|
|
_ = f.Close()
|
|
err = os.Remove(f.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
info := exampleInfo()
|
|
info.Release = "3"
|
|
info.Epoch = "-1"
|
|
info.RPM = nfpm.RPM{
|
|
Group: "default",
|
|
}
|
|
info.Description = "first line\nsecond line\nthird line"
|
|
require.Error(t, Default.Package(info, f))
|
|
}
|
|
|
|
func TestRPMScripts(t *testing.T) {
|
|
info := exampleInfo()
|
|
f, err := os.CreateTemp(t.TempDir(), fmt.Sprintf("%s-%s-*.rpm", info.Name, info.Version))
|
|
require.NoError(t, err)
|
|
err = Default.Package(info, f)
|
|
require.NoError(t, err)
|
|
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
f.Close()
|
|
file.Close()
|
|
err = os.Remove(file.Name())
|
|
require.NoError(t, err)
|
|
}()
|
|
rpm, err := rpmutils.ReadRpm(file)
|
|
require.NoError(t, err)
|
|
|
|
data, err := rpm.Header.GetString(rpmutils.PREIN)
|
|
require.NoError(t, err)
|
|
require.Equal(t, `#!/bin/bash
|
|
|
|
echo "Preinstall" > /dev/null
|
|
`, data, "Preinstall script does not match")
|
|
|
|
data, err = rpm.Header.GetString(rpmutils.PREUN)
|
|
require.NoError(t, err)
|
|
require.Equal(t, `#!/bin/bash
|
|
|
|
echo "Preremove" > /dev/null
|
|
`, data, "Preremove script does not match")
|
|
|
|
data, err = rpm.Header.GetString(rpmutils.POSTIN)
|
|
require.NoError(t, err)
|
|
require.Equal(t, `#!/bin/bash
|
|
|
|
echo "Postinstall" > /dev/null
|
|
`, data, "Postinstall script does not match")
|
|
|
|
data, err = rpm.Header.GetString(rpmutils.POSTUN)
|
|
require.NoError(t, err)
|
|
require.Equal(t, `#!/bin/bash
|
|
|
|
echo "Postremove" > /dev/null
|
|
`, data, "Postremove script does not match")
|
|
|
|
rpmPreTransTag := 1151
|
|
data, err = rpm.Header.GetString(rpmPreTransTag)
|
|
require.NoError(t, err)
|
|
require.Equal(t, `#!/bin/bash
|
|
|
|
echo "Pretrans" > /dev/null
|
|
`, data, "Pretrans script does not match")
|
|
|
|
rpmPostTransTag := 1152
|
|
data, err = rpm.Header.GetString(rpmPostTransTag)
|
|
require.NoError(t, err)
|
|
require.Equal(t, `#!/bin/bash
|
|
|
|
echo "Posttrans" > /dev/null
|
|
`, data, "Posttrans script does not match")
|
|
}
|
|
|
|
func TestRPMFileDoesNotExist(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Contents = []*files.Content{
|
|
{
|
|
Source: "../testdata/fake",
|
|
Destination: "/usr/bin/fake",
|
|
},
|
|
{
|
|
Source: "../testdata/whatever.confzzz",
|
|
Destination: "/etc/fake/fake.conf",
|
|
Type: files.TypeConfig,
|
|
},
|
|
}
|
|
abs, err := filepath.Abs("../testdata/whatever.confzzz")
|
|
require.NoError(t, err)
|
|
err = Default.Package(info, io.Discard)
|
|
require.EqualError(t, err, fmt.Sprintf("matching \"%s\": file does not exist", filepath.ToSlash(abs)))
|
|
}
|
|
|
|
func TestArches(t *testing.T) {
|
|
for k := range archToRPM {
|
|
t.Run(k, func(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Arch = k
|
|
info = ensureValidArch(info)
|
|
require.Equal(t, archToRPM[k], info.Arch)
|
|
})
|
|
}
|
|
|
|
t.Run("override", func(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.RPM.Arch = "foo64"
|
|
info = ensureValidArch(info)
|
|
require.Equal(t, "foo64", info.Arch)
|
|
})
|
|
}
|
|
|
|
func TestConfigNoReplace(t *testing.T) {
|
|
var (
|
|
buildConfigFile = "../testdata/whatever.conf"
|
|
packageConfigFile = "/etc/fake/fake.conf"
|
|
)
|
|
|
|
info := &nfpm.Info{
|
|
Name: "symlink-in-files",
|
|
Arch: "amd64",
|
|
Description: "This package's config references a file via symlink.",
|
|
Version: "1.0.0",
|
|
Maintainer: "maintainer",
|
|
Overridables: nfpm.Overridables{
|
|
Contents: []*files.Content{
|
|
{
|
|
Source: buildConfigFile,
|
|
Destination: packageConfigFile,
|
|
Type: files.TypeConfigNoReplace,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
expectedConfigContent, err := os.ReadFile(buildConfigFile)
|
|
require.NoError(t, err)
|
|
|
|
packageConfigContent, err := extractFileFromRpm(rpmFileBuffer.Bytes(), packageConfigFile)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expectedConfigContent, packageConfigContent)
|
|
}
|
|
|
|
func TestRPMConventionalFileName(t *testing.T) {
|
|
info := &nfpm.Info{
|
|
Name: "testpkg",
|
|
Arch: "noarch",
|
|
Maintainer: "maintainer",
|
|
}
|
|
|
|
testCases := []struct {
|
|
Version string
|
|
Release string
|
|
Prerelease string
|
|
Expected string
|
|
Metadata string
|
|
}{
|
|
{
|
|
Version: "1.2.3", Release: "", Prerelease: "", Metadata: "",
|
|
Expected: fmt.Sprintf("%s-1.2.3.%s.rpm", info.Name, info.Arch),
|
|
},
|
|
{
|
|
Version: "1.2.3", Release: "4", Prerelease: "", Metadata: "",
|
|
Expected: fmt.Sprintf("%s-1.2.3-4.%s.rpm", info.Name, info.Arch),
|
|
},
|
|
{
|
|
Version: "1.2.3", Release: "4", Prerelease: "5", Metadata: "",
|
|
Expected: fmt.Sprintf("%s-1.2.3~5-4.%s.rpm", info.Name, info.Arch),
|
|
},
|
|
{
|
|
Version: "1.2.3", Release: "", Prerelease: "5", Metadata: "",
|
|
Expected: fmt.Sprintf("%s-1.2.3~5.%s.rpm", info.Name, info.Arch),
|
|
},
|
|
{
|
|
Version: "1.2.3", Release: "1", Prerelease: "5", Metadata: "git",
|
|
Expected: fmt.Sprintf("%s-1.2.3~5+git-1.%s.rpm", info.Name, info.Arch),
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
info.Version = testCase.Version
|
|
info.Release = testCase.Release
|
|
info.Prerelease = testCase.Prerelease
|
|
info.VersionMetadata = testCase.Metadata
|
|
|
|
require.Equal(t, testCase.Expected, Default.ConventionalFileName(info))
|
|
}
|
|
}
|
|
|
|
func TestRPMChangelog(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Changelog = "../testdata/changelog.yaml"
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
rpm, err := rpmutils.ReadRpm(bytes.NewReader(rpmFileBuffer.Bytes()))
|
|
require.NoError(t, err)
|
|
|
|
changelog, err := chglog.Parse(info.Changelog)
|
|
require.NoError(t, err)
|
|
|
|
_times, err := rpm.Header.Get(tagChangelogTime)
|
|
require.NoError(t, err)
|
|
times, ok := _times.([]uint32)
|
|
require.True(t, ok)
|
|
require.Equal(t, len(changelog), len(times))
|
|
|
|
_titles, err := rpm.Header.Get(tagChangelogName)
|
|
require.NoError(t, err)
|
|
titles, ok := _titles.([]string)
|
|
require.True(t, ok)
|
|
require.Equal(t, len(changelog), len(titles))
|
|
|
|
_notes, err := rpm.Header.Get(tagChangelogText)
|
|
require.NoError(t, err)
|
|
allNotes, ok := _notes.([]string)
|
|
require.True(t, ok)
|
|
require.Equal(t, len(changelog), len(allNotes))
|
|
|
|
for i, entry := range changelog {
|
|
timestamp := time.Unix(int64(times[i]), 0).UTC()
|
|
title := titles[i]
|
|
notes := strings.Split(allNotes[i], "\n")
|
|
|
|
require.Equal(t, entry.Date, timestamp)
|
|
require.True(t, strings.Contains(title, entry.Packager))
|
|
require.True(t, strings.Contains(title, entry.Semver))
|
|
require.Equal(t, len(entry.Changes), len(notes))
|
|
|
|
for j, change := range entry.Changes {
|
|
require.True(t, strings.Contains(notes[j], change.Note))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRPMNoChangelogTagsWithoutChangelogConfigured(t *testing.T) {
|
|
info := exampleInfo()
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
rpm, err := rpmutils.ReadRpm(bytes.NewReader(rpmFileBuffer.Bytes()))
|
|
require.NoError(t, err)
|
|
|
|
_, err = rpm.Header.Get(tagChangelogTime)
|
|
require.Error(t, err)
|
|
|
|
_, err = rpm.Header.Get(tagChangelogName)
|
|
require.Error(t, err)
|
|
|
|
_, err = rpm.Header.Get(tagChangelogText)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestSymlink(t *testing.T) {
|
|
var (
|
|
configFilePath = "/usr/share/doc/fake/fake.txt"
|
|
symlink = "/path/to/symlink"
|
|
symlinkTarget = configFilePath
|
|
)
|
|
|
|
info := &nfpm.Info{
|
|
Name: "symlink-in-files",
|
|
Arch: "amd64",
|
|
Description: "This package's config references a file via symlink.",
|
|
Version: "1.0.0",
|
|
Maintainer: "maintainer",
|
|
Overridables: nfpm.Overridables{
|
|
Contents: []*files.Content{
|
|
{
|
|
Source: "../testdata/whatever.conf",
|
|
Destination: configFilePath,
|
|
},
|
|
{
|
|
Source: symlinkTarget,
|
|
Destination: symlink,
|
|
Type: files.TypeSymlink,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
packagedSymlinkHeader, err := extractFileHeaderFromRpm(rpmFileBuffer.Bytes(), symlink)
|
|
require.NoError(t, err)
|
|
|
|
packagedSymlink, err := extractFileFromRpm(rpmFileBuffer.Bytes(), symlink)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, symlink, packagedSymlinkHeader.Filename())
|
|
require.Equal(t, cpio.S_ISLNK, packagedSymlinkHeader.Mode())
|
|
require.Equal(t, symlinkTarget, string(packagedSymlink))
|
|
}
|
|
|
|
func TestRPMSignature(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.RPM.Signature.KeyFile = "../internal/sign/testdata/privkey.asc"
|
|
info.RPM.Signature.KeyPassphrase = "hunter2"
|
|
|
|
pubkeyFileContent, err := os.ReadFile("../internal/sign/testdata/pubkey.gpg")
|
|
require.NoError(t, err)
|
|
|
|
keyring, err := openpgp.ReadKeyRing(bytes.NewReader(pubkeyFileContent))
|
|
require.NoError(t, err)
|
|
require.NotNil(t, keyring, "cannot verify sigs with an empty keyring")
|
|
|
|
var rpmBuffer bytes.Buffer
|
|
err = Default.Package(info, &rpmBuffer)
|
|
require.NoError(t, err)
|
|
|
|
_, sigs, err := rpmutils.Verify(bytes.NewReader(rpmBuffer.Bytes()), keyring)
|
|
require.NoError(t, err)
|
|
require.Len(t, sigs, 2)
|
|
}
|
|
|
|
func TestRPMSignatureError(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.RPM.Signature.KeyFile = "../internal/sign/testdata/privkey.asc"
|
|
info.RPM.Signature.KeyPassphrase = "wrongpass"
|
|
|
|
var rpmBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmBuffer)
|
|
require.Error(t, err)
|
|
|
|
var expectedError *nfpm.ErrSigningFailure
|
|
require.True(t, errors.As(err, &expectedError))
|
|
}
|
|
|
|
func TestRPMGhostFiles(t *testing.T) {
|
|
filename := "/usr/lib/casper.a"
|
|
|
|
info := &nfpm.Info{
|
|
Name: "rpm-ghost",
|
|
Arch: "amd64",
|
|
Description: "This RPM contains ghost files.",
|
|
Version: "1.0.0",
|
|
Maintainer: "maintainer",
|
|
Overridables: nfpm.Overridables{
|
|
Contents: []*files.Content{
|
|
{
|
|
Destination: filename,
|
|
Type: files.TypeRPMGhost,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
headerFiles, err := extraFileInfoSliceFromRpm(rpmFileBuffer.Bytes())
|
|
require.NoError(t, err)
|
|
|
|
type headerFileInfo struct {
|
|
Name string
|
|
Size int64
|
|
Mode int
|
|
}
|
|
expected := []headerFileInfo{
|
|
{filename, 0, cpio.S_ISREG | 0o644},
|
|
}
|
|
actual := make([]headerFileInfo, 0)
|
|
for _, fileInfo := range headerFiles {
|
|
actual = append(actual, headerFileInfo{fileInfo.Name(), fileInfo.Size(), fileInfo.Mode()})
|
|
}
|
|
require.Equal(t, expected, actual)
|
|
|
|
_, err = extractFileHeaderFromRpm(rpmFileBuffer.Bytes(), filename)
|
|
require.Error(t, err)
|
|
|
|
_, err = extractFileFromRpm(rpmFileBuffer.Bytes(), filename)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestDisableGlobbing(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.DisableGlobbing = true
|
|
info.Contents = []*files.Content{
|
|
{
|
|
Source: "../testdata/{file}[",
|
|
Destination: "/test/{file}[",
|
|
},
|
|
}
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
expectedContent, err := os.ReadFile("../testdata/{file}[")
|
|
require.NoError(t, err)
|
|
|
|
actualContent, err := extractFileFromRpm(rpmFileBuffer.Bytes(), "/test/{file}[")
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expectedContent, actualContent)
|
|
}
|
|
|
|
func TestDirectories(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Contents = []*files.Content{
|
|
{
|
|
Source: "../testdata/whatever.conf",
|
|
Destination: "/etc/foo/file",
|
|
},
|
|
{
|
|
Source: "../testdata/whatever.conf",
|
|
Destination: "/etc/bar/file",
|
|
},
|
|
{
|
|
Destination: "/etc/bar",
|
|
Type: files.TypeDir,
|
|
},
|
|
{
|
|
Destination: "/etc/baz",
|
|
Type: files.TypeDir,
|
|
FileInfo: &files.ContentFileInfo{
|
|
Owner: "test",
|
|
Mode: 0o700,
|
|
},
|
|
},
|
|
{
|
|
Destination: "/usr/lib/something/somethingelse",
|
|
Type: files.TypeDir,
|
|
},
|
|
}
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []string{
|
|
"/etc/bar",
|
|
"/etc/bar/file",
|
|
"/etc/baz",
|
|
"/etc/foo/file",
|
|
"/usr/lib/something/somethingelse",
|
|
}, getTree(t, rpmFileBuffer.Bytes()))
|
|
|
|
// the directory /etc/foo should not be implicitly created as that
|
|
// implies ownership of /etc/foo which should always be implicit
|
|
_, err = extractFileHeaderFromRpm(rpmFileBuffer.Bytes(), "/etc/foo")
|
|
require.Equal(t, err, os.ErrNotExist)
|
|
|
|
// claiming explicit ownership of /etc/bar which already contains a file
|
|
h, err := extractFileHeaderFromRpm(rpmFileBuffer.Bytes(), "/etc/bar")
|
|
require.NoError(t, err)
|
|
require.NotEqual(t, h.Mode()&int(tagDirectory), 0)
|
|
|
|
// creating an empty folder (which also implies ownership)
|
|
h, err = extractFileHeaderFromRpm(rpmFileBuffer.Bytes(), "/etc/baz")
|
|
require.NoError(t, err)
|
|
require.Equal(t, h.Mode(), int(tagDirectory|0o700))
|
|
}
|
|
|
|
func TestGlob(t *testing.T) {
|
|
require.NoError(t, Default.Package(nfpm.WithDefaults(&nfpm.Info{
|
|
Name: "nfpm-repro",
|
|
Version: "1.0.0",
|
|
Maintainer: "asdfasdf",
|
|
|
|
Overridables: nfpm.Overridables{
|
|
Contents: files.Contents{
|
|
{
|
|
Destination: "/usr/share/nfpm-repro",
|
|
Source: "../files/*",
|
|
},
|
|
},
|
|
},
|
|
}), io.Discard))
|
|
}
|
|
|
|
func TestIgnoreUnrelatedFiles(t *testing.T) {
|
|
info := exampleInfo()
|
|
info.Contents = files.Contents{
|
|
{
|
|
Source: "../testdata/fake",
|
|
Destination: "/some/file",
|
|
Type: files.TypeDebChangelog,
|
|
},
|
|
}
|
|
|
|
var rpmFileBuffer bytes.Buffer
|
|
err := Default.Package(info, &rpmFileBuffer)
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, getTree(t, rpmFileBuffer.Bytes()), 0)
|
|
}
|
|
|
|
func extractFileFromRpm(rpm []byte, filename string) ([]byte, error) {
|
|
rpmFile, err := rpmutils.ReadRpm(bytes.NewReader(rpm))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pr, err := rpmFile.PayloadReader()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for {
|
|
hdr, err := pr.Next()
|
|
if errors.Is(err, io.EOF) {
|
|
break // End of archive
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if hdr.Filename() != filename {
|
|
continue
|
|
}
|
|
|
|
fileContents, err := io.ReadAll(pr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return fileContents, nil
|
|
}
|
|
|
|
return nil, os.ErrNotExist
|
|
}
|
|
|
|
func extraFileInfoSliceFromRpm(rpm []byte) ([]rpmutils.FileInfo, error) {
|
|
rpmFile, err := rpmutils.ReadRpm(bytes.NewReader(rpm))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rpmFile.Header.GetFiles()
|
|
}
|
|
|
|
func getTree(tb testing.TB, rpm []byte) []string {
|
|
tb.Helper()
|
|
|
|
rpmFile, err := rpmutils.ReadRpm(bytes.NewReader(rpm))
|
|
require.NoError(tb, err)
|
|
pr, err := rpmFile.PayloadReader()
|
|
require.NoError(tb, err)
|
|
|
|
var tree []string
|
|
for {
|
|
hdr, err := pr.Next()
|
|
if errors.Is(err, io.EOF) {
|
|
break // End of archive
|
|
}
|
|
require.NoError(tb, err)
|
|
tree = append(tree, hdr.Filename())
|
|
}
|
|
|
|
return tree
|
|
}
|
|
|
|
func extractFileHeaderFromRpm(rpm []byte, filename string) (*cpio.Cpio_newc_header, error) {
|
|
rpmFile, err := rpmutils.ReadRpm(bytes.NewReader(rpm))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pr, err := rpmFile.PayloadReader()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for {
|
|
hdr, err := pr.Next()
|
|
if errors.Is(err, io.EOF) {
|
|
break // End of archive
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if hdr.Filename() != filename {
|
|
continue
|
|
}
|
|
|
|
return hdr, nil
|
|
}
|
|
|
|
return nil, os.ErrNotExist
|
|
}
|