1
1
mirror of https://github.com/goreleaser/nfpm synced 2024-11-18 19:04:07 +01:00
nfpm/rpm/rpm_test.go
Carlos Alexandro Becker 7d6a77bee6
test: fix arch tests
2023-05-24 02:42:13 +00:00

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
}