pkg/archive/deb.go (213 lines of code) (raw):

package archive import ( "bytes" "fmt" "path/filepath" "strings" "text/template" "dagger.io/dagger" ) func join(a []string) string { return strings.Join(a, ", ") } const ControlTemplate = ` Source: {{ .Name }} Section: admin Priority: optional Maintainer: Microsoft <support@microsoft.com> Build-Depends: bash-completion, go-md2man <!cross>, go-md2man:amd64 <cross>, pkg-config, {{ join .BuildDeps }} Rules-Requires-Root: no Homepage: {{ .Webpage }} Package: {{ .Name }} Architecture: linux-any Depends: ${misc:Depends}, ${shlibs:Depends}, {{ join .RuntimeDeps }} Recommends: {{ join .Recommends }} Conflicts: {{ join .Conflicts }} Replaces: {{ join .Replaces }} Provides: {{ join .Provides }} Description: {{ .Description }} ` var ( DebDistroMap = map[string]string{ "xenial": "ubuntu16.04", "yakkety": "ubuntu16.10", "zesty": "ubuntu17.04", "artful": "ubuntu17.10", "bionic": "ubuntu18.04", "cosmic": "ubuntu18.10", "disco": "ubuntu19.04", "eoan": "ubuntu19.10", "focal": "ubuntu20.04", "groovy": "ubuntu20.10", "hirsute": "ubuntu21.04", "impish": "ubuntu21.10", "jammy": "ubuntu22.04", "kinetic": "ubuntu22.10", "noble": "ubuntu24.04", "lunar": "ubuntu23.04", "buster": "debian10", "bullseye": "debian11", "bookworm": "debian12", "trixie": "debian13", "forky": "debian14", } ) type DebPackager struct { a Archive mirrorPrefix string } func NewDebPackager(a *Archive, mp string) *DebPackager { if a == nil { panic("nil archive supplied") } return &DebPackager{ a: *a, mirrorPrefix: mp, } } func (d *DebPackager) Package(client *dagger.Client, c *dagger.Container, project *Spec) *dagger.Directory { dir := client.Directory() rootDir := "/package" version := fmt.Sprintf("%s-%su%s", project.Tag, DebDistroMap[project.Distro], project.Revision) c = c.WithDirectory(rootDir, dir) c = d.moveStaticFiles(c, rootDir) c = d.withControlFile(c, version, project) pkgDir := c.Directory(rootDir) fpmArgs := []string{"fpm", "-s", "dir", "-t", "deb", "-n", project.Pkg, "--version", version, "--architecture", strings.Replace(project.Arch, "/", "", -1), "--deb-custom-control", "/build/control", } var newArgs []string c, newArgs = d.withInstallScripts(c) fpmArgs = append(fpmArgs, d.systemdArgs()...) fpmArgs = append(fpmArgs, newArgs...) fpmArgs = append(fpmArgs, ".") fpm := fpmContainer(client, d.mirrorPrefix) return fpm.WithDirectory("/package", pkgDir). WithDirectory("/build", c.Directory("/build")). WithWorkdir("/package"). WithExec(fpmArgs). WithExec([]string{"bash", "-ec", `mkdir -vp /out; mv *.deb /out`}). Directory("/out") } func (d *DebPackager) moveStaticFiles(c *dagger.Container, rootdir string) *dagger.Container { for i := range d.a.Files { f := d.a.Files[i] c = f.MoveStaticFile(c, rootdir) } return c } func (d *DebPackager) withInstallScripts(c *dagger.Container) (*dagger.Container, []string) { newArgs := []string{} for i := range d.a.InstallScripts { script := d.a.InstallScripts[i] var a []string c, a = d.installScript(&script, c) newArgs = append(newArgs, a...) } return c, newArgs } func (d *DebPackager) 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 = ` {{ replace .Script "\n" "\n " }} ` case PkgActionPreRemoval: filename = filenamePreRm flag = flagPreRm templateStr = ` {{ replace .Script "\n" "\n " }} ` case PkgActionPostRemoval: filename = filenamePostRm flag = flagPostRm templateStr = ` {{ replace .Script "\n" "\n " }} ` 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 (d *DebPackager) withControlFile(c *dagger.Container, version string, project *Spec) *dagger.Container { t := ControlTemplate tpl, err := template.New("control").Funcs(template.FuncMap{"join": join}).Parse(t) if err != nil { panic(err) } buf := new(bytes.Buffer) err = tpl.Execute(buf, d.a) if err != nil { panic(err) } return c. WithNewFile("/build/debian/control", buf.String()). WithEnvVariable("PROJECT_NAME", project.Pkg). WithEnvVariable("VERSION", version). WithEnvVariable("DISTRO", project.Distro). WithEnvVariable("_BINARIES", strings.Join(d.a.Binaries, " ")). WithExec([]string{ "bash", "-exuc", ` : ${PROJECT_NAME} : ${VERSION} : ${DISTRO} : ${_BINARIES} cat /build/debian/control BINARIES=($_BINARIES) cat <<EOF > debian/changelog $PROJECT_NAME ($VERSION) $DISTRO; urgency=low * Version: 1.0 -- Microsoft <support@microsoft.com> Mon, 12 Mar 2018 00:00:00 +0000 EOF args=() for b in "${BINARIES[@]}"; do args+=(-e "$b") done dpkg-shlibdeps "${args[@]}" dpkg-gencontrol -P/package -Ocontrol `, }) } func (d *DebPackager) systemdArgs() []string { args := []string{} for i := range d.a.Systemd { sd := d.a.Systemd[i] args = append(args, "--deb-systemd", sd.Source) } // this could change args = append(args, "--deb-systemd-enable", "--deb-systemd-auto-start", "--deb-systemd-restart-after-upgrade", ) return args }