Skip to content

Commit 64b788a

Browse files
teddelincaarlos0Copilot
authored
feat: add Requires(Post) for RPMS (#1085)
* feat: add Requires(Post) for RPMS https://rpm-software-management.github.io/rpm/manual/spec.html section Dependencies * test: add acceptance test Signed-off-by: Carlos Alexandro Becker <[email protected]> --------- Signed-off-by: Carlos Alexandro Becker <[email protected]> Co-authored-by: Carlos Alexandro Becker <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 1bd2fed commit 64b788a

8 files changed

Lines changed: 130 additions & 0 deletions

File tree

acceptance_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ func TestRPMSpecific(t *testing.T) {
202202
"release",
203203
"directories",
204204
"verify",
205+
"postrequires",
205206
}
206207
for _, name := range testNames {
207208
for _, arch := range formatArchs[format] {

nfpm.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ func (c *Config) expandEnvVars() {
220220
c.Overrides[or].Recommends = c.expandEnvVarsStringSlice(c.Overrides[or].Recommends)
221221
c.Overrides[or].Provides = c.expandEnvVarsStringSlice(c.Overrides[or].Provides)
222222
c.Overrides[or].Suggests = c.expandEnvVarsStringSlice(c.Overrides[or].Suggests)
223+
c.Overrides[or].RPM.Requires.Post = c.expandEnvVarsStringSlice(c.Overrides[or].RPM.Requires.Post)
223224
c.Overrides[or].Contents = c.expandEnvVarsContents(c.Overrides[or].Contents)
224225
}
225226
c.Conflicts = c.expandEnvVarsStringSlice(c.Conflicts)
@@ -228,6 +229,7 @@ func (c *Config) expandEnvVars() {
228229
c.Recommends = c.expandEnvVarsStringSlice(c.Recommends)
229230
c.Provides = c.expandEnvVarsStringSlice(c.Provides)
230231
c.Suggests = c.expandEnvVarsStringSlice(c.Suggests)
232+
c.RPM.Requires.Post = c.expandEnvVarsStringSlice(c.RPM.Requires.Post)
231233
c.Contents = c.expandEnvVarsContents(c.Contents)
232234

233235
// Basic metadata fields
@@ -392,6 +394,7 @@ type RPM struct {
392394
Arch string `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"title=architecture in rpm nomenclature"`
393395
BuildHost string `yaml:"buildhost,omitempty" json:"buildhost,omitempty" jsonschema:"title=host name of the build environment, default=os.Hostname()"`
394396
Scripts RPMScripts `yaml:"scripts,omitempty" json:"scripts,omitempty" jsonschema:"title=rpm-specific scripts"`
397+
Requires RPMRequires `yaml:"requires,omitempty" json:"requires,omitempty" jsonschema:"title=rpm-specific requires"`
395398
Group string `yaml:"group,omitempty" json:"group,omitempty" jsonschema:"title=package group,example=Unspecified"`
396399
Summary string `yaml:"summary,omitempty" json:"summary,omitempty" jsonschema:"title=package summary"`
397400
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"`
@@ -407,6 +410,11 @@ type RPMScripts struct {
407410
Verify string `yaml:"verify,omitempty" json:"verify,omitempty" jsonschema:"title=verify script"`
408411
}
409412

413+
// RPMRequires represents qualified RPM Requires dependencies.
414+
type RPMRequires struct {
415+
Post []string `yaml:"post,omitempty" json:"post,omitempty" jsonschema:"title=post requires directive,example=nfpm"`
416+
}
417+
410418
type PackageSignature struct {
411419
// PGP secret key, can be ASCII-armored
412420
KeyFile string `yaml:"key_file,omitempty" json:"key_file,omitempty" jsonschema:"title=key file,example=key.gpg"`

rpm/rpm.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ const (
3030
tagChangelogText = 1082
3131
// https://github.com/rpm-software-management/rpm/blob/master/include/rpm/rpmtag.h#L183
3232
tagSourcePackage = 1106
33+
// RPMSENSE_SCRIPT_POST marks a dependency as Requires(post).
34+
// https://github.com/rpm-software-management/rpm/blob/master/include/rpm/rpmds.h
35+
rpmSenseScriptPost = 1 << 10
3336

3437
// Symbolic link
3538
tagLink = 0o120000
@@ -248,6 +251,9 @@ func buildRPMMeta(info *nfpm.Info) (*rpmpack.RPMMetaData, error) {
248251
if depends, err = toRelation(info.Depends); err != nil {
249252
return nil, err
250253
}
254+
if err = addPostRequires(&depends, info.RPM.Requires.Post); err != nil {
255+
return nil, err
256+
}
251257
if recommends, err = toRelation(info.Recommends); err != nil {
252258
return nil, err
253259
}
@@ -328,6 +334,19 @@ func toRelation(items []string) (rpmpack.Relations, error) {
328334
return relations, nil
329335
}
330336

337+
func addPostRequires(relations *rpmpack.Relations, items []string) error {
338+
for idx := range items {
339+
relation, err := rpmpack.NewRelation(items[idx])
340+
if err != nil {
341+
return err
342+
}
343+
relation.Sense |= rpmSenseScriptPost
344+
*relations = append(*relations, relation)
345+
}
346+
347+
return nil
348+
}
349+
331350
func addScriptFiles(info *nfpm.Info, rpm *rpmpack.RPM) error {
332351
if info.RPM.Scripts.PreTrans != "" {
333352
data, err := os.ReadFile(info.RPM.Scripts.PreTrans)

rpm/rpm_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ import (
2222
"github.com/stretchr/testify/require"
2323
)
2424

25+
const (
26+
tagRequireFlags = 1048
27+
tagRequireName = 1049
28+
tagRequireVersion = 1050
29+
)
30+
2531
func exampleInfo() *nfpm.Info {
2632
return setDefaults(nfpm.WithDefaults(&nfpm.Info{
2733
Name: "foo",
@@ -154,6 +160,50 @@ func TestRPM(t *testing.T) {
154160
require.Equal(t, "Foo does things", description)
155161
}
156162

163+
func TestRPMPostRequires(t *testing.T) {
164+
info := exampleInfo()
165+
info.RPM.Requires.Post = []string{"systemd", "coreutils >= 9.0"}
166+
167+
var buf bytes.Buffer
168+
err := DefaultRPM.Package(info, &buf)
169+
require.NoError(t, err)
170+
171+
rpm, err := rpmutils.ReadRpm(&buf)
172+
require.NoError(t, err)
173+
174+
namesRaw, err := rpm.Header.Get(tagRequireName)
175+
require.NoError(t, err)
176+
names, ok := namesRaw.([]string)
177+
require.True(t, ok)
178+
versionsRaw, err := rpm.Header.Get(tagRequireVersion)
179+
require.NoError(t, err)
180+
versions, ok := versionsRaw.([]string)
181+
require.True(t, ok)
182+
flagsRaw, err := rpm.Header.Get(tagRequireFlags)
183+
require.NoError(t, err)
184+
flags, ok := flagsRaw.([]uint32)
185+
require.True(t, ok)
186+
187+
requireRPMRequire(t, names, versions, flags, "systemd", "", rpmSenseScriptPost)
188+
requireRPMRequire(t, names, versions, flags, "coreutils", "9.0", rpmSenseScriptPost|4|8)
189+
}
190+
191+
func requireRPMRequire(
192+
t *testing.T,
193+
names, versions []string,
194+
flags []uint32,
195+
name, version string,
196+
flag uint32,
197+
) {
198+
t.Helper()
199+
for idx := range names {
200+
if names[idx] == name && versions[idx] == version && flags[idx] == flag {
201+
return
202+
}
203+
}
204+
require.Failf(t, "RPM require not found", "name=%s version=%s flag=%d", name, version, flag)
205+
}
206+
157207
func TestRPMRiscv64(t *testing.T) {
158208
f, err := os.CreateTemp(t.TempDir(), "test-riscv.rpm")
159209
require.NoError(t, err)

testdata/acceptance/rpm.dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,9 @@ FROM min AS verify
226226
RUN rpm -V foo
227227
RUN rm /tmp/postinstall-proof
228228
RUN ! rpm -V foo
229+
230+
# ---- postrequires test ----
231+
FROM min AS postrequires
232+
RUN rpm -qp --qf '[%{REQUIRENAME} %{REQUIREFLAGS} %{REQUIREVERSION}\n]' /tmp/foo.rpm
233+
RUN rpm -qp --qf '[%{REQUIRENAME} %{REQUIREFLAGS} %{REQUIREVERSION}\n]' /tmp/foo.rpm | grep -E '^bash 1024 ?$'
234+
RUN rpm -qp --qf '[%{REQUIRENAME} %{REQUIREFLAGS} %{REQUIREVERSION}\n]' /tmp/foo.rpm | grep -E '^coreutils 1036 9\.0$'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: "foo"
2+
arch: "${BUILD_ARCH}"
3+
platform: "linux"
4+
version: "v1.2.3"
5+
maintainer: "Foo Bar"
6+
release: "4"
7+
description: |
8+
Foo bar
9+
Multiple lines
10+
vendor: "foobar"
11+
homepage: "https://foobar.org"
12+
license: "MIT"
13+
contents:
14+
- src: ./testdata/fake
15+
dst: /usr/bin/fake
16+
rpm:
17+
requires:
18+
post:
19+
- bash
20+
- coreutils >= 9.0

www/content/docs/configuration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,12 @@ rpm:
340340
# The verify script runs when verifying packages using `rpm -V`.
341341
verify: ./scripts/verify.sh
342342

343+
# RPM specific qualified Requires dependencies.
344+
requires:
345+
# Adds `Requires(post): systemd`.
346+
post:
347+
- systemd
348+
343349
# The package group. This option is deprecated by most distros
344350
# but required by old distros like CentOS 5 / EL 5 and earlier.
345351
group: Unspecified

www/static/schema.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,10 @@
974974
"$ref": "#/$defs/RPMScripts",
975975
"title": "rpm-specific scripts"
976976
},
977+
"requires": {
978+
"$ref": "#/$defs/RPMRequires",
979+
"title": "rpm-specific requires"
980+
},
977981
"group": {
978982
"type": "string",
979983
"title": "package group",
@@ -1015,6 +1019,22 @@
10151019
"additionalProperties": false,
10161020
"type": "object"
10171021
},
1022+
"RPMRequires": {
1023+
"properties": {
1024+
"post": {
1025+
"items": {
1026+
"type": "string",
1027+
"examples": [
1028+
"nfpm"
1029+
]
1030+
},
1031+
"type": "array",
1032+
"title": "post requires directive"
1033+
}
1034+
},
1035+
"additionalProperties": false,
1036+
"type": "object"
1037+
},
10181038
"RPMScripts": {
10191039
"properties": {
10201040
"pretrans": {

0 commit comments

Comments
 (0)