aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/rosa/all.go
blob: 41aacddbf4999884280d01c0fe9ac9aaa73e63c8 (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
package rosa

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"strconv"
	"sync"

	"hakurei.app/internal/pkg"
)

// PArtifact is a lazily-initialised [pkg.Artifact] preset.
type PArtifact int

const (
	LLVMCompilerRT PArtifact = iota
	LLVMRuntimes
	LLVMClang

	// ImageInitramfs is the Rosa OS initramfs archive.
	ImageInitramfs

	// Kernel is the generic Rosa OS Linux kernel.
	Kernel
	// KernelHeaders is an installation of kernel headers for [Kernel].
	KernelHeaders
	// KernelSource is a writable kernel source tree installed to [AbsUsrSrc].
	KernelSource

	ACL
	ArgpStandalone
	Attr
	Autoconf
	Automake
	BC
	Bash
	Binutils
	Bison
	Bzip2
	CMake
	Coreutils
	Curl
	DTC
	Diffutils
	Elfutils
	Fakeroot
	Findutils
	Flex
	Fuse
	GMP
	GLib
	Gawk
	GenInitCPIO
	Gettext
	Git
	Go
	Gperf
	Grep
	Gzip
	Hakurei
	HakureiDist
	Kmod
	LibXau
	Libcap
	Libexpat
	Libiconv
	Libpsl
	Libffi
	Libgd
	Libtool
	Libseccomp
	Libucontext
	Libxml2
	Libxslt
	M4
	MPC
	MPFR
	Make
	Meson
	Mksh
	MuslFts
	MuslObstack
	NSS
	NSSCACert
	Ncurses
	Ninja
	OpenSSL
	PCRE2
	Patch
	Perl
	PerlLocaleGettext
	PerlMIMECharset
	PerlModuleBuild
	PerlPodParser
	PerlSGMLS
	PerlTermReadKey
	PerlTextCharWidth
	PerlTextWrapI18N
	PerlUnicodeGCString
	PerlYAMLTiny
	PkgConfig
	Procps
	Python
	PythonIniConfig
	PythonPackaging
	PythonPluggy
	PythonPyTest
	PythonPygments
	QEMU
	Rsync
	Sed
	Setuptools
	SquashfsTools
	TamaGo
	Tar
	Texinfo
	Toybox
	toyboxEarly
	Unzip
	UtilLinux
	Wayland
	WaylandProtocols
	XCB
	XCBProto
	Xproto
	XZ
	Zlib
	Zstd

	// PresetUnexportedStart is the first unexported preset.
	PresetUnexportedStart

	buildcatrust = iota - 1
	utilMacros

	// Musl is a standalone libc that does not depend on the toolchain.
	Musl

	// gcc is a hacked-to-pieces GCC toolchain meant for use in intermediate
	// stages only. This preset and its direct output must never be exposed.
	gcc

	// Stage0 is a tarball containing all compile-time dependencies of artifacts
	// part of the [Std] toolchain.
	Stage0

	// PresetEnd is the total number of presets and does not denote a preset.
	PresetEnd
)

// Metadata is stage-agnostic information of a [PArtifact] not directly
// representable in the resulting [pkg.Artifact].
type Metadata struct {
	f func(t Toolchain) (a pkg.Artifact, version string)

	// Unique package name.
	Name string `json:"name"`
	// Short user-facing description.
	Description string `json:"description"`
	// Project home page.
	Website string `json:"website,omitempty"`

	// Project identifier on [Anitya].
	//
	// [Anitya]: https://release-monitoring.org/
	ID int `json:"-"`

	// Optional custom version checking behaviour.
	latest func(v *Versions) string
}

// GetLatest returns the latest version described by v.
func (meta *Metadata) GetLatest(v *Versions) string {
	if meta.latest != nil {
		return meta.latest(v)
	}
	return v.Latest
}

// Unversioned denotes an unversioned [PArtifact].
const Unversioned = "\x00"

// UnpopulatedIDError is returned by [Metadata.GetLatest] for an instance of
// [Metadata] where ID is not populated.
type UnpopulatedIDError struct{}

func (UnpopulatedIDError) Unwrap() error { return errors.ErrUnsupported }
func (UnpopulatedIDError) Error() string { return "Anitya ID is not populated" }

// Versions are package versions returned by Anitya.
type Versions struct {
	// The latest version for the project, as determined by the version sorting algorithm.
	Latest string `json:"latest_version"`
	// List of all versions that aren’t flagged as pre-release.
	Stable []string `json:"stable_versions"`
	// List of all versions stored, sorted from newest to oldest.
	All []string `json:"versions"`
}

// getStable returns the first Stable version, or Latest if that is unavailable.
func (v *Versions) getStable() string {
	if len(v.Stable) == 0 {
		return v.Latest
	}
	return v.Stable[0]
}

// GetVersions returns versions fetched from Anitya.
func (meta *Metadata) GetVersions(ctx context.Context) (*Versions, error) {
	if meta.ID == 0 {
		return nil, UnpopulatedIDError{}
	}

	var resp *http.Response
	if req, err := http.NewRequestWithContext(
		ctx,
		http.MethodGet,
		"https://release-monitoring.org/api/v2/versions/?project_id="+
			strconv.Itoa(meta.ID),
		nil,
	); err != nil {
		return nil, err
	} else {
		req.Header.Set("User-Agent", "Rosa/1.1")
		if resp, err = http.DefaultClient.Do(req); err != nil {
			return nil, err
		}
	}

	var v Versions
	err := json.NewDecoder(resp.Body).Decode(&v)
	return &v, errors.Join(err, resp.Body.Close())
}

var (
	// artifactsM is an array of [PArtifact] metadata.
	artifactsM [PresetEnd]Metadata

	// artifacts stores the result of Metadata.f.
	artifacts [_toolchainEnd][len(artifactsM)]pkg.Artifact
	// versions stores the version of [PArtifact].
	versions [_toolchainEnd][len(artifactsM)]string
	// artifactsOnce is for lazy initialisation of artifacts.
	artifactsOnce [_toolchainEnd][len(artifactsM)]sync.Once
)

// GetMetadata returns [Metadata] of a [PArtifact].
func GetMetadata(p PArtifact) *Metadata { return &artifactsM[p] }

// Load returns the resulting [pkg.Artifact] of [PArtifact].
func (t Toolchain) Load(p PArtifact) pkg.Artifact {
	artifactsOnce[t][p].Do(func() {
		artifacts[t][p], versions[t][p] = artifactsM[p].f(t)
	})
	return artifacts[t][p]
}

// Version returns the version string of [PArtifact].
func (t Toolchain) Version(p PArtifact) string {
	artifactsOnce[t][p].Do(func() {
		artifacts[t][p], versions[t][p] = artifactsM[p].f(t)
	})
	return versions[t][p]
}

// ResolveName returns a [PArtifact] by name.
func ResolveName(name string) (p PArtifact, ok bool) {
	for i := range PresetUnexportedStart {
		if name == artifactsM[i].Name {
			return i, true
		}
	}
	return 0, false
}