pkg/archive/rpm.go (161 lines of code) (raw):
package archive
import (
"bytes"
"fmt"
"path/filepath"
"strings"
"text/template"
"dagger.io/dagger"
)
var (
nothing empty
rpmDistroMap = map[string]string{
"rhel8": "el8",
"rhel9": "el9",
"mariner2": "cm2",
}
rpmArchMap = map[string]string{
"amd64": "x86_64",
"arm64": "aarch64",
}
rpmPkgBlacklist = mapSet{
"rhel9": {
"libcgroup": nothing,
},
}
)
type (
empty struct{}
mapSet map[string]map[string]empty
RpmPackager struct {
a Archive
mirrorPrefix string
}
)
func (m mapSet) contains(distro, pkg string) bool {
if mm, ok := m[distro]; ok {
if _, ok := mm[pkg]; ok {
return true
}
}
return false
}
func NewRPMPackager(a *Archive, mp string) *RpmPackager {
if a == nil {
panic("nil archive supplied")
}
return &RpmPackager{
a: *a,
mirrorPrefix: mp,
}
}
func (r *RpmPackager) Package(client *dagger.Client, c *dagger.Container, project *Spec) *dagger.Directory {
dir := client.Directory()
rootDir := "/package"
c = c.WithDirectory(rootDir, dir)
c = r.moveStaticFiles(c, rootDir)
pkgDir := c.Directory(rootDir)
fpm := fpmContainer(client, r.mirrorPrefix)
filename := fmt.Sprintf("%s-%s-%s.%s.%s.rpm", project.Pkg, project.Tag, project.Revision, rpmDistroMap[project.Distro], rpmArchMap[project.Arch])
fpmArgs := []string{"fpm",
"-s", "dir",
"-t", "rpm",
"-n", project.Pkg,
"--version", project.Tag,
"--iteration", project.Revision,
"--rpm-dist", rpmDistroMap[project.Distro],
"--architecture", strings.Replace(project.Arch, "/", "", -1),
"--description", r.a.Description,
"--url", r.a.Webpage,
}
for i := range r.a.RuntimeDeps {
dep := r.a.RuntimeDeps[i]
if rpmPkgBlacklist.contains(project.Distro, dep) {
continue
}
fpmArgs = append(fpmArgs, "-d", dep)
}
for i := range r.a.Conflicts {
conf := r.a.Conflicts[i]
fpmArgs = append(fpmArgs, "--conflicts", conf)
}
var args []string
c, args = r.withInstallScripts(c)
fpmArgs = append(fpmArgs, args...)
fpmArgs = append(fpmArgs, ".")
return fpm.WithDirectory("/package", pkgDir).
WithDirectory("/build", c.Directory("/build")).
WithWorkdir("/package").
WithEnvVariable("OUTPUT_FILENAME", filename).
WithExec(fpmArgs).
WithExec([]string{"bash", "-c", `mkdir -vp /out; mv *.rpm "/out/${OUTPUT_FILENAME}"`}).
Directory("/out")
}
func (r *RpmPackager) withInstallScripts(c *dagger.Container) (*dagger.Container, []string) {
newArgs := []string{}
for i := range r.a.InstallScripts {
script := r.a.InstallScripts[i]
var a []string
c, a = r.installScript(&script, c)
newArgs = append(newArgs, a...)
}
return c, newArgs
}
func (r *RpmPackager) installScript(script *InstallScript, c *dagger.Container) (*dagger.Container, []string) {
newArgs := []string{}
var templateStr, filename, flag string
switch script.When {
case PkgActionPostInstall:
filename = filenamePostInstall
flag = flagPostInstall
templateStr = `
{{ replace .Script "\n" "\n " }}
`
case PkgActionUpgrade:
filename = filenamePostUpgrade
flag = flagUpgrade
templateStr = `
if [ $1 -ge 1 ]; then
{{ replace .Script "\n" "\n " }}
fi
`
case PkgActionPreRemoval, PkgActionPostRemoval:
filename = filenamePreRm
flag = flagPreRm
templateStr = `
if [ $1 -eq 0 ]; then
{{ replace .Script "\n" "\n " }}
fi
`
default:
panic("unrecognized package action: " + fmt.Sprintf("%d", script.When))
}
filename = filepath.Join("/build", filename)
tpl, err := template.New("installScript").Funcs(template.FuncMap{"replace": strings.ReplaceAll}).Parse(templateStr)
if err != nil {
panic(err)
}
buf := new(bytes.Buffer)
err = tpl.Execute(buf, script)
if err != nil {
panic(err)
}
c = c.WithNewFile(filename, buf.String())
newArgs = append(newArgs, flag, filename)
return c, newArgs
}
func (r *RpmPackager) moveStaticFiles(c *dagger.Container, rootdir string) *dagger.Container {
files := r.a.Files
for i := range r.a.Systemd {
sd := r.a.Systemd[i]
files = append(files, File{
Source: sd.Source,
Dest: sd.Dest,
})
}
for i := range files {
f := files[i]
c = f.MoveStaticFile(c, rootdir)
}
return c
}