summaryrefslogtreecommitdiff
path: root/stdlib/os/debian/apt.go
blob: aad8b65e2e1843cbd33ea7f825054c2e1d824050 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package debian

import (
	"bufio"
	"bytes"
	_ "embed"
	"log/slog"
	"os"
	"os/exec"
	"strings"

	gonf "git.adyxax.org/adyxax/gonf/v2/pkg"
	"git.adyxax.org/adyxax/gonf/v2/stdlib/os/systemd"
)

var packages map[string]string

func init() {
	packages_list()
}

//go:embed apt-norecommends
var apt_norecommends []byte

//go:embed sources.list
var sources_list []byte

func Promise() {
	rootDir := gonf.ModeUserGroup(0755, "root", "root")
	rootRO := gonf.ModeUserGroup(0444, "root", "root")
	gonf.Default("debian-release", "stable")
	gonf.AppendVariable("debian-extra-sources", "# Extra sources")
	apt_update := gonf.Command("apt-get", "update", "-qq")
	gonf.File("/etc/apt/sources.list").
		Permissions(rootRO).
		Template(sources_list).
		Promise().
		IfRepaired(apt_update)
	gonf.File("/etc/apt/apt.conf.d/99_norecommends").
		DirectoriesPermissions(rootDir).
		Permissions(rootRO).
		Template(apt_norecommends).
		Promise()
	gonf.SetPackagesConfiguration(packages_install, packages_list, apt_update)
	gonf.Service("opensmtpd").State("enabled", "started").Promise()
	systemd.Promise()
}

func packages_install(names []string) (gonf.Status, []string) {
	gonf.FilterSlice(&names, func(n string) bool {
		_, ok := packages[n]
		return !ok
	})
	if len(names) == 0 {
		return gonf.KEPT, nil
	}
	args := append([]string{"install", "-y", "--no-install-recommends"}, names...)
	cmd := gonf.CommandWithEnv([]string{"DEBIAN_FRONTEND=noninteractive", "LC_ALL=C"}, "apt-get", args...)
	cmd.Resolve()
	packages_list()
	return cmd.Status, names
}

func packages_list() {
	packages = make(map[string]string)
	ecmd := exec.Command("dpkg-query", "-W")
	out, err := ecmd.CombinedOutput()
	if err != nil {
		slog.Error("dpkg-query", "error", err)
		os.Exit(1)
	}
	s := bufio.NewScanner(bytes.NewReader(out))
	s.Split(bufio.ScanWords)
	for s.Scan() {
		name := s.Text()
		if !s.Scan() {
			slog.Error("dpkg-query", "error", "parsing error: no version after name")
			os.Exit(1)
		}
		if strings.Contains(name, ":") { // some packages are named with the arch like something:amd64
			name = strings.Split(name, ":")[0] // in this case we want only the name
		}
		packages[name] = s.Text()
	}
}