packaging/linux/deb/template_rules.go (139 lines of code) (raw):
package deb
import (
"bytes"
_ "embed"
"fmt"
"io"
"path/filepath"
"strings"
"text/template"
"github.com/Azure/dalec"
"github.com/moby/buildkit/client/llb"
"golang.org/x/exp/maps"
)
var (
//go:embed templates/debian_rules.tmpl
rulesTmplContent []byte
rulesTmpl = template.Must(template.New("rules").Parse(string(rulesTmplContent)))
)
func Rules(spec *dalec.Spec, in llb.State, dir, target string) (llb.State, error) {
buf := bytes.NewBuffer(nil)
if dir == "" {
dir = "debian"
}
if err := WriteRules(spec, buf, target); err != nil {
return llb.Scratch(), err
}
return in.
File(llb.Mkdir(dir, 0o755, llb.WithParents(true))).
File(llb.Mkfile(filepath.Join(dir, "rules"), 0o700, buf.Bytes())),
nil
}
func WriteRules(spec *dalec.Spec, w io.Writer, target string) error {
return rulesTmpl.Execute(w, &rulesWrapper{spec, target})
}
type rulesWrapper struct {
*dalec.Spec
target string
}
func (w *rulesWrapper) Envs() fmt.Stringer {
b := &strings.Builder{}
for k, v := range w.Spec.Build.Env {
fmt.Fprintf(b, "export %s := %s\n", k, v)
}
if w.Spec.HasGomods() {
fmt.Fprintf(b, "export %s := $(PWD)/%s\n", "GOMODCACHE", gomodsName)
}
if w.Spec.HasCargohomes() {
fmt.Fprintf(b, "export %s := $(PWD)/%s\n", "CARGO_HOME", cargohomeName)
}
return b
}
func (w *rulesWrapper) OverridePerms() fmt.Stringer {
b := &strings.Builder{}
artifacts := w.GetArtifacts(w.target)
var fixPerms bool
checkPerms := func(cfgs map[string]dalec.ArtifactConfig) bool {
for _, cfg := range cfgs {
if cfg.Permissions.Perm() != 0 {
return true
}
}
return false
}
checkDirPerms := func(dirConfigs map[string]dalec.ArtifactDirConfig) bool {
for _, cfg := range dirConfigs {
if cfg.Mode.Perm() != 0 {
return true
}
}
return false
}
fixPerms = checkPerms(artifacts.Binaries) ||
checkPerms(artifacts.ConfigFiles) ||
checkPerms(artifacts.Manpages) ||
checkPerms(artifacts.Headers) ||
checkPerms(artifacts.Licenses) ||
checkPerms(artifacts.Docs) ||
checkPerms(artifacts.Libs) ||
checkPerms(artifacts.Libexec) ||
checkPerms(artifacts.DataDirs) ||
checkDirPerms(artifacts.Directories.GetConfig()) ||
checkDirPerms(artifacts.Directories.GetState())
if fixPerms {
// Normally this should be `execute_after_dh_fixperms`, however this doesn't
// work on Ubuntu 18.04.
// Instead we need to override dh_fixperms and run it ourselves and then
// our extra script.
b.WriteString("override_dh_fixperms:\n")
b.WriteString("\tdh_fixperms\n")
b.WriteString("\tdebian/dalec/fix_perms.sh\n\n")
}
return b
}
// groupUnitsByBaseName indexes the provided list by the unit basename.
// A unit basename is the name of the unit without the suffix (e.g. ".service", ".socket", etc).
// The nested map is key'd on the fully resolved unit name.
func groupUnitsByBaseName(ls map[string]dalec.SystemdUnitConfig) map[string]map[string]dalec.SystemdUnitConfig {
idx := make(map[string]map[string]dalec.SystemdUnitConfig)
for k, v := range ls {
base, suffix := v.SplitName(k)
if idx[base] == nil {
idx[base] = make(map[string]dalec.SystemdUnitConfig)
}
idx[base][base+"."+suffix] = v
}
return idx
}
func (w *rulesWrapper) OverrideSystemd() (fmt.Stringer, error) {
b := &strings.Builder{}
artifacts := w.GetArtifacts(w.target)
units := artifacts.Systemd.GetUnits()
if len(units) == 0 {
return b, nil
}
b.WriteString("override_dh_installsystemd:\n")
grouped := groupUnitsByBaseName(units)
sorted := dalec.SortMapKeys(grouped)
var includeCustomEnable bool
for _, basename := range sorted {
grouping := grouped[basename]
needsCustomEnable := requiresCustomEnable(grouping)
if needsCustomEnable {
includeCustomEnable = true
}
// dh_installsystemd does not want the suffix of the file, so trim it off
// here.
// Otherwise it will _silently_ fail, *yay*.
// We also need to check if there are multiple units with the same base name
// with different `Enable` options set.
// `dh_installsystemd` cannot deal with this, in those cases we'll write a
// custom postinst/postrm script.
//
// We also only need to do this once per basename, so we don't need to
// iterate over every unit.
// Get the first key which we'll use to check if the unit is enabled.
// Either all units are enabled or not enabled OR we need to do custom enable
firstKey := maps.Keys(grouping)[0]
enable := grouping[firstKey].Enable
b.WriteString("\tdh_installsystemd --name=" + basename)
if !enable || needsCustomEnable {
b.WriteString(" --no-enable")
}
b.WriteString("\n")
}
if includeCustomEnable {
b.WriteString("\t[ -f debian/postinst ] || (echo '#!/bin/sh' > debian/postinst; echo 'set -e' >> debian/postinst)\n")
b.WriteString("\t[ -x debian/postinst ] || chmod +x debian/postinst\n")
b.WriteString("\tcat debian/dalec/" + customSystemdPostinstFile + " >> debian/postinst\n")
}
return b, nil
}
func (w *rulesWrapper) OverrideStrip() fmt.Stringer {
artifacts := w.Spec.GetArtifacts(w.target)
buf := &strings.Builder{}
if artifacts.DisableStrip {
buf.WriteString("override_dh_strip:\n")
}
return buf
}