Files
hakurei/internal/rosa/all.go
Ophestra a36b3ece16
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m44s
Test / Hakurei (push) Successful in 3m35s
Test / ShareFS (push) Successful in 3m48s
Test / Sandbox (race detector) (push) Successful in 4m56s
Test / Hakurei (race detector) (push) Successful in 5m53s
Test / Flake checks (push) Successful in 1m30s
internal/rosa: release monitoring via Anitya
This is much more sustainable than manual package flagging.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-05 20:57:05 +09:00

251 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 (
// ImageInitramfs is the Rosa OS initramfs archive.
ImageInitramfs PArtifact = iota
// 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
IniConfig
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
Packaging
Patch
Perl
PerlLocaleGettext
PerlMIMECharset
PerlModuleBuild
PerlPodParser
PerlSGMLS
PerlTermReadKey
PerlTextCharWidth
PerlTextWrapI18N
PerlUnicodeGCString
PerlYAMLTiny
PkgConfig
Pluggy
Procps
PyTest
Pygments
Python
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:"-"`
}
// 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 arent flagged as pre-release.
Stable []string `json:"stable_versions"`
// List of all versions stored, sorted from newest to oldest.
All []string `json:"versions"`
}
// 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 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
}