Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func TestRPMSpecific(t *testing.T) {
"release",
"directories",
"verify",
"postrequires",
}
for _, name := range testNames {
for _, arch := range formatArchs[format] {
Expand Down
8 changes: 8 additions & 0 deletions nfpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ func (c *Config) expandEnvVars() {
c.Overrides[or].Recommends = c.expandEnvVarsStringSlice(c.Overrides[or].Recommends)
c.Overrides[or].Provides = c.expandEnvVarsStringSlice(c.Overrides[or].Provides)
c.Overrides[or].Suggests = c.expandEnvVarsStringSlice(c.Overrides[or].Suggests)
c.Overrides[or].RPM.Requires.Post = c.expandEnvVarsStringSlice(c.Overrides[or].RPM.Requires.Post)
c.Overrides[or].Contents = c.expandEnvVarsContents(c.Overrides[or].Contents)
}
c.Conflicts = c.expandEnvVarsStringSlice(c.Conflicts)
Expand All @@ -228,6 +229,7 @@ func (c *Config) expandEnvVars() {
c.Recommends = c.expandEnvVarsStringSlice(c.Recommends)
c.Provides = c.expandEnvVarsStringSlice(c.Provides)
c.Suggests = c.expandEnvVarsStringSlice(c.Suggests)
c.RPM.Requires.Post = c.expandEnvVarsStringSlice(c.RPM.Requires.Post)
c.Contents = c.expandEnvVarsContents(c.Contents)

// Basic metadata fields
Expand Down Expand Up @@ -392,6 +394,7 @@ type RPM struct {
Arch string `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"title=architecture in rpm nomenclature"`
BuildHost string `yaml:"buildhost,omitempty" json:"buildhost,omitempty" jsonschema:"title=host name of the build environment, default=os.Hostname()"`
Scripts RPMScripts `yaml:"scripts,omitempty" json:"scripts,omitempty" jsonschema:"title=rpm-specific scripts"`
Requires RPMRequires `yaml:"requires,omitempty" json:"requires,omitempty" jsonschema:"title=rpm-specific requires"`
Group string `yaml:"group,omitempty" json:"group,omitempty" jsonschema:"title=package group,example=Unspecified"`
Summary string `yaml:"summary,omitempty" json:"summary,omitempty" jsonschema:"title=package summary"`
Compression string `yaml:"compression,omitempty" json:"compression,omitempty" jsonschema:"title=compression algorithm to be used,enum=gzip,enum=lzma,enum=xz,enum=zstd,default=gzip:-1"`
Expand All @@ -407,6 +410,11 @@ type RPMScripts struct {
Verify string `yaml:"verify,omitempty" json:"verify,omitempty" jsonschema:"title=verify script"`
}

// RPMRequires represents qualified RPM Requires dependencies.
type RPMRequires struct {
Post []string `yaml:"post,omitempty" json:"post,omitempty" jsonschema:"title=post requires directive,example=nfpm"`
}

type PackageSignature struct {
// PGP secret key, can be ASCII-armored
KeyFile string `yaml:"key_file,omitempty" json:"key_file,omitempty" jsonschema:"title=key file,example=key.gpg"`
Expand Down
19 changes: 19 additions & 0 deletions rpm/rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const (
tagChangelogText = 1082
// https://github.com/rpm-software-management/rpm/blob/master/include/rpm/rpmtag.h#L183
tagSourcePackage = 1106
// RPMSENSE_SCRIPT_POST marks a dependency as Requires(post).
// https://github.com/rpm-software-management/rpm/blob/master/include/rpm/rpmds.h
rpmSenseScriptPost = 1 << 10

// Symbolic link
tagLink = 0o120000
Expand Down Expand Up @@ -248,6 +251,9 @@ func buildRPMMeta(info *nfpm.Info) (*rpmpack.RPMMetaData, error) {
if depends, err = toRelation(info.Depends); err != nil {
return nil, err
}
if err = addPostRequires(&depends, info.RPM.Requires.Post); err != nil {
return nil, err
}
if recommends, err = toRelation(info.Recommends); err != nil {
return nil, err
}
Expand Down Expand Up @@ -328,6 +334,19 @@ func toRelation(items []string) (rpmpack.Relations, error) {
return relations, nil
}

func addPostRequires(relations *rpmpack.Relations, items []string) error {
for idx := range items {
relation, err := rpmpack.NewRelation(items[idx])
if err != nil {
return err
}
relation.Sense |= rpmSenseScriptPost
*relations = append(*relations, relation)
}

return nil
}

func addScriptFiles(info *nfpm.Info, rpm *rpmpack.RPM) error {
if info.RPM.Scripts.PreTrans != "" {
data, err := os.ReadFile(info.RPM.Scripts.PreTrans)
Expand Down
50 changes: 50 additions & 0 deletions rpm/rpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import (
"github.com/stretchr/testify/require"
)

const (
tagRequireFlags = 1048
tagRequireName = 1049
tagRequireVersion = 1050
)

func exampleInfo() *nfpm.Info {
return setDefaults(nfpm.WithDefaults(&nfpm.Info{
Name: "foo",
Expand Down Expand Up @@ -154,6 +160,50 @@ func TestRPM(t *testing.T) {
require.Equal(t, "Foo does things", description)
}

func TestRPMPostRequires(t *testing.T) {
info := exampleInfo()
info.RPM.Requires.Post = []string{"systemd", "coreutils >= 9.0"}

var buf bytes.Buffer
err := DefaultRPM.Package(info, &buf)
require.NoError(t, err)

rpm, err := rpmutils.ReadRpm(&buf)
require.NoError(t, err)

namesRaw, err := rpm.Header.Get(tagRequireName)
require.NoError(t, err)
names, ok := namesRaw.([]string)
require.True(t, ok)
versionsRaw, err := rpm.Header.Get(tagRequireVersion)
require.NoError(t, err)
versions, ok := versionsRaw.([]string)
require.True(t, ok)
flagsRaw, err := rpm.Header.Get(tagRequireFlags)
require.NoError(t, err)
flags, ok := flagsRaw.([]uint32)
require.True(t, ok)

requireRPMRequire(t, names, versions, flags, "systemd", "", rpmSenseScriptPost)
requireRPMRequire(t, names, versions, flags, "coreutils", "9.0", rpmSenseScriptPost|4|8)
}

func requireRPMRequire(
t *testing.T,
names, versions []string,
flags []uint32,
name, version string,
flag uint32,
) {
t.Helper()
for idx := range names {
if names[idx] == name && versions[idx] == version && flags[idx] == flag {
return
}
}
require.Failf(t, "RPM require not found", "name=%s version=%s flag=%d", name, version, flag)
}

func TestRPMRiscv64(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "test-riscv.rpm")
require.NoError(t, err)
Expand Down
6 changes: 6 additions & 0 deletions testdata/acceptance/rpm.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,9 @@ FROM min AS verify
RUN rpm -V foo
RUN rm /tmp/postinstall-proof
RUN ! rpm -V foo

# ---- postrequires test ----
FROM min AS postrequires
RUN rpm -qp --qf '[%{REQUIRENAME} %{REQUIREFLAGS} %{REQUIREVERSION}\n]' /tmp/foo.rpm
RUN rpm -qp --qf '[%{REQUIRENAME} %{REQUIREFLAGS} %{REQUIREVERSION}\n]' /tmp/foo.rpm | grep -E '^bash 1024 ?$'
RUN rpm -qp --qf '[%{REQUIRENAME} %{REQUIREFLAGS} %{REQUIREVERSION}\n]' /tmp/foo.rpm | grep -E '^coreutils 1036 9\.0$'
20 changes: 20 additions & 0 deletions testdata/acceptance/rpm.postrequires.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: "foo"
arch: "${BUILD_ARCH}"
platform: "linux"
version: "v1.2.3"
maintainer: "Foo Bar"
release: "4"
description: |
Foo bar
Multiple lines
vendor: "foobar"
homepage: "https://foobar.org"
license: "MIT"
contents:
- src: ./testdata/fake
dst: /usr/bin/fake
rpm:
requires:
post:
- bash
- coreutils >= 9.0
6 changes: 6 additions & 0 deletions www/content/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ rpm:
# The verify script runs when verifying packages using `rpm -V`.
verify: ./scripts/verify.sh

# RPM specific qualified Requires dependencies.
requires:
# Adds `Requires(post): systemd`.
post:
- systemd

# The package group. This option is deprecated by most distros
# but required by old distros like CentOS 5 / EL 5 and earlier.
group: Unspecified
Expand Down
20 changes: 20 additions & 0 deletions www/static/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,10 @@
"$ref": "#/$defs/RPMScripts",
"title": "rpm-specific scripts"
},
"requires": {
"$ref": "#/$defs/RPMRequires",
"title": "rpm-specific requires"
},
"group": {
"type": "string",
"title": "package group",
Expand Down Expand Up @@ -1015,6 +1019,22 @@
"additionalProperties": false,
"type": "object"
},
"RPMRequires": {
"properties": {
"post": {
"items": {
"type": "string",
"examples": [
"nfpm"
]
},
"type": "array",
"title": "post requires directive"
}
},
"additionalProperties": false,
"type": "object"
},
"RPMScripts": {
"properties": {
"pretrans": {
Expand Down
Loading