mirror of
https://github.com/peridotbuild/peridot.git
synced 2024-10-13 11:15:08 +00:00
refactor kernel_repack with new features to ease usage and maintenance
fairly large change, but has been tested and in use for a while. * new command: getchangelog - * new command: updatekernel - run an update
This commit is contained in:
parent
850969184d
commit
f3f72c3af0
75
tools/kernelmanager/cmd/getchangelog/main.go
Normal file
75
tools/kernelmanager/cmd/getchangelog/main.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
repack_v1 "go.resf.org/peridot/tools/kernelmanager/packager/v1"
|
||||
)
|
||||
|
||||
func readChangelogFromSpec(specBytes []byte) []*repack_v1.ChangelogEntry {
|
||||
// Parse spec down to %changelog
|
||||
var changelogLines []string
|
||||
|
||||
lines := strings.Split(string(specBytes), "\n")
|
||||
for i, line := range lines {
|
||||
if strings.Contains(line, "%changelog") {
|
||||
changelogLines = lines[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Parse changelog
|
||||
var entries []*repack_v1.ChangelogEntry
|
||||
currentEntry := &repack_v1.ChangelogEntry{}
|
||||
for _, line := range changelogLines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
if currentEntry.Subject != "" {
|
||||
entries = append(entries, currentEntry)
|
||||
currentEntry = &repack_v1.ChangelogEntry{}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "* ") {
|
||||
currentEntry.Subject = strings.TrimPrefix(line, "* ")
|
||||
} else if strings.HasPrefix(line, "- ") {
|
||||
currentEntry.Messages = append(currentEntry.Messages, strings.TrimPrefix(line, "- "))
|
||||
}
|
||||
}
|
||||
|
||||
if currentEntry.Subject != "" {
|
||||
entries = append(entries, currentEntry)
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := os.Args[1:]
|
||||
if len(args) == 0 {
|
||||
panic("usage: getchangelog <path to spec>")
|
||||
}
|
||||
|
||||
specPath := args[0]
|
||||
specBytes, err := os.ReadFile(specPath)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "failed to read spec file"))
|
||||
}
|
||||
|
||||
entries := readChangelogFromSpec(specBytes)
|
||||
|
||||
jsonBytes, err := json.Marshal(entries)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "failed to marshal entries"))
|
||||
}
|
||||
|
||||
_, err = fmt.Println(string(jsonBytes))
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "failed to write entries"))
|
||||
}
|
||||
}
|
42
tools/kernelmanager/cmd/getchangelog/main_test.go
Normal file
42
tools/kernelmanager/cmd/getchangelog/main_test.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func readSpec(t *testing.T, name string) []byte {
|
||||
specBytes, err := os.ReadFile(fmt.Sprintf("testdata/%s.spec", name))
|
||||
require.Nil(t, err)
|
||||
|
||||
return specBytes
|
||||
}
|
||||
|
||||
func TestReadChangelogFromSpec_1(t *testing.T) {
|
||||
specBytes := readSpec(t, "1")
|
||||
entries := readChangelogFromSpec(specBytes)
|
||||
|
||||
require.Len(t, entries, 1)
|
||||
require.Equal(t, "Tue Feb 22 2024 Mustafa Gezen - 1.0-123", entries[0].Subject)
|
||||
require.Len(t, entries[0].Messages, 1)
|
||||
require.Equal(t, "Test changelog", entries[0].Messages[0])
|
||||
}
|
||||
|
||||
func TestReadChangelogFromSpec_2(t *testing.T) {
|
||||
specBytes := readSpec(t, "2")
|
||||
entries := readChangelogFromSpec(specBytes)
|
||||
|
||||
require.Len(t, entries, 2)
|
||||
|
||||
require.Equal(t, "Tue Feb 22 2024 Mustafa Gezen - 1.0-123", entries[0].Subject)
|
||||
require.Len(t, entries[0].Messages, 1)
|
||||
require.Equal(t, "Test changelog", entries[0].Messages[0])
|
||||
|
||||
require.Equal(t, "Tue Feb 22 2024 Mustafa Gezen - 1.0-123", entries[1].Subject)
|
||||
require.Len(t, entries[1].Messages, 2)
|
||||
require.Equal(t, "msg1 2", entries[1].Messages[0])
|
||||
require.Equal(t, "msg2", entries[1].Messages[1])
|
||||
}
|
172
tools/kernelmanager/cmd/getchangelog/testdata/1.spec
vendored
Normal file
172
tools/kernelmanager/cmd/getchangelog/testdata/1.spec
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
# All global changes to build and install should follow this line.
|
||||
|
||||
# Disable LTO in userspace packages.
|
||||
%global _lto_cflags %{nil}
|
||||
|
||||
# The libexec directory is not used by the linker, so the shared object there
|
||||
# should not be exported to RPM provides.
|
||||
%global __provides_exclude_from ^%{_libexecdir}/kselftests
|
||||
|
||||
# Disable the find-provides.ksyms script.
|
||||
%global __provided_ksyms_provides %{nil}
|
||||
|
||||
# All global wide changes should be above this line otherwise
|
||||
# the %%install section will not see them.
|
||||
%global __spec_install_pre %{___build_pre}
|
||||
|
||||
# Kernel has several large (hundreds of mbytes) rpms, they take ~5 mins
|
||||
# to compress by single-threaded xz. Switch to threaded compression,
|
||||
# and from level 2 to 3 to keep compressed sizes close to "w2" results.
|
||||
#
|
||||
# NB: if default compression in /usr/lib/rpm/redhat/macros ever changes,
|
||||
# this one might need tweaking (e.g. if default changes to w3.xzdio,
|
||||
# change below to w4T.xzdio):
|
||||
%global _binary_payload w3T.xzdio
|
||||
|
||||
# Define the version of the Linux Kernel Archive tarball.
|
||||
%global LKAver 1.0
|
||||
|
||||
# Define the buildid, if required.
|
||||
%global buildid 123
|
||||
|
||||
# Determine the sublevel number and set pkg_version.
|
||||
%define sublevel %(echo %{LKAver} | %{__awk} -F\. '{ print $3 }')
|
||||
%if "%{sublevel}" == ""
|
||||
%global pkg_version %{LKAver}.0
|
||||
%else
|
||||
%global pkg_version %{LKAver}
|
||||
%endif
|
||||
|
||||
# Set pkg_release.
|
||||
%global pkg_release 1%{?buildid}%{?dist}
|
||||
|
||||
# Architectures upon which we can sign the kernel
|
||||
# for secure boot authentication.
|
||||
%ifarch x86_64 || aarch64
|
||||
%global signkernel 1
|
||||
%else
|
||||
%global signkernel 0
|
||||
%endif
|
||||
|
||||
# Sign modules on all architectures that build modules.
|
||||
%ifarch x86_64 || aarch64
|
||||
%global signmodules 1
|
||||
%else
|
||||
%global signmodules 0
|
||||
%endif
|
||||
|
||||
# Compress modules on all architectures that build modules.
|
||||
%ifarch x86_64 || aarch64
|
||||
%global zipmodules 1
|
||||
%else
|
||||
%global zipmodules 0
|
||||
%endif
|
||||
|
||||
%if %{zipmodules}
|
||||
%global zipsed -e 's/\.ko$/\.ko.xz/'
|
||||
# For parallel xz processes. Replace with 1 to go back to single process.
|
||||
%global zcpu `nproc --all`
|
||||
%endif
|
||||
|
||||
# The following build options are enabled by default, but may become disabled
|
||||
# by later architecture-specific checks. These can also be disabled by using
|
||||
# --without <opt> in the rpmbuild command, or by forcing these values to 0.
|
||||
#
|
||||
# {{.KernelPackage}}
|
||||
%define with_std %{?_without_std: 0} %{?!_without_std: 1}
|
||||
#
|
||||
# {{.KernelPackage}}-headers
|
||||
%define with_headers %{?_without_headers: 0} %{?!_without_headers: 1}
|
||||
#
|
||||
# {{.KernelPackage}}-doc
|
||||
%define with_doc %{?_without_doc: 0} %{?!_without_doc: 1}
|
||||
#
|
||||
# perf
|
||||
%define with_perf %{?_without_perf: 0} %{?!_without_perf: 1}
|
||||
#
|
||||
# tools
|
||||
%define with_tools %{?_without_tools: 0} %{?!_without_tools: 1}
|
||||
#
|
||||
# bpf tool
|
||||
%define with_bpftool %{?_without_bpftool: 0} %{?!_without_bpftool: 1}
|
||||
#
|
||||
# control whether to install the vdso directories
|
||||
%define with_vdso_install %{?_without_vdso_install: 0} %{?!_without_vdso_install: 1}
|
||||
#
|
||||
# Additional option for toracat-friendly, one-off, {{.KernelPackage}} building.
|
||||
# Only build the base {{.KernelPackage}} (--with baseonly):
|
||||
%define with_baseonly %{?_with_baseonly: 1} %{?!_with_baseonly: 0}
|
||||
|
||||
%global KVERREL %{pkg_version}-%{pkg_release}.%{_target_cpu}
|
||||
|
||||
# If requested, only build base {{.KernelPackage}} package.
|
||||
%if %{with_baseonly}
|
||||
%define with_doc 0
|
||||
%define with_perf 0
|
||||
%define with_tools 0
|
||||
%define with_bpftool 0
|
||||
%define with_vdso_install 0
|
||||
%endif
|
||||
|
||||
%ifarch noarch
|
||||
%define with_std 0
|
||||
%define with_headers 0
|
||||
%define with_perf 0
|
||||
%define with_tools 0
|
||||
%define with_bpftool 0
|
||||
%define with_vdso_install 0
|
||||
%endif
|
||||
|
||||
%ifarch x86_64 || aarch64
|
||||
%define with_doc 0
|
||||
### as of {{.KernelPackage}}-6.5.4, no more perf and bpftool -ay
|
||||
%define with_perf 0
|
||||
%define with_bpftool 0
|
||||
%endif
|
||||
|
||||
%ifarch x86_64
|
||||
%define asmarch x86
|
||||
%define bldarch x86_64
|
||||
%define hdrarch x86_64
|
||||
%define make_target bzImage
|
||||
%define kernel_image arch/x86/boot/bzImage
|
||||
%endif
|
||||
|
||||
%ifarch aarch64
|
||||
%define asmarch arm64
|
||||
%define bldarch arm64
|
||||
%define hdrarch arm64
|
||||
%define make_target Image.gz
|
||||
%define kernel_image arch/arm64/boot/Image.gz
|
||||
%endif
|
||||
|
||||
%if %{with_vdso_install}
|
||||
%define use_vdso 1
|
||||
%define _use_vdso 1
|
||||
%else
|
||||
%define _use_vdso 0
|
||||
%endif
|
||||
|
||||
#
|
||||
# Packages that need to be installed before the kernel is installed,
|
||||
# as they will be used by the %%post scripts.
|
||||
#
|
||||
%define kernel_ml_prereq coreutils, systemd >= 203-2, /usr/bin/kernel-install
|
||||
%define initrd_prereq dracut >= 027
|
||||
|
||||
Name: kernel
|
||||
Summary: The Linux kernel. (The core of any Linux kernel based operating system.)
|
||||
License: GPLv2 and Redistributable, no modification permitted.
|
||||
URL: https://www.kernel.org/
|
||||
Version: %{pkg_version}
|
||||
Release: %{pkg_release}
|
||||
ExclusiveArch: x86_64 aarch64 noarch
|
||||
ExclusiveOS: Linux
|
||||
Provides: kernel = %{version}-%{release}
|
||||
Provides: installonlypkg(kernel)
|
||||
Requires: %{name}-core-uname-r = %{KVERREL}
|
||||
Requires: %{name}-modules-uname-r = %{KVERREL}
|
||||
|
||||
%changelog
|
||||
* Tue Feb 22 2024 Mustafa Gezen - 1.0-123
|
||||
- Test changelog
|
10
tools/kernelmanager/cmd/getchangelog/testdata/2.spec
vendored
Normal file
10
tools/kernelmanager/cmd/getchangelog/testdata/2.spec
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
%changelog
|
||||
* Tue Feb 22 2024 Mustafa Gezen - 1.0-123
|
||||
- Test changelog
|
||||
|
||||
|
||||
* Tue Feb 22 2024 Mustafa Gezen - 1.0-123
|
||||
- msg1 2
|
||||
- msg2
|
||||
|
||||
|
261
tools/kernelmanager/cmd/updatekernel/main.go
Normal file
261
tools/kernelmanager/cmd/updatekernel/main.go
Normal file
@ -0,0 +1,261 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.resf.org/peridot/tools/kernelmanager/packager/kernelorg"
|
||||
"go.resf.org/peridot/tools/kernelmanager/packager"
|
||||
repack_v1 "go.resf.org/peridot/tools/kernelmanager/packager/v1"
|
||||
|
||||
"github.com/go-git/go-billy/v5/osfs"
|
||||
)
|
||||
|
||||
// readCustomConfigs reads custom kernel configs from a directory
|
||||
// There are two options for declaring configs
|
||||
// - A file with the name "variant-X.Y.config" where X.Y is the version. This is common arch-independent config
|
||||
// - A file with the name "variant-X.Y-ARCH.config" where X.Y is the version and arch is the architecture. This is arch-specific config
|
||||
// - Stable does not have a version, so the file name will be "stable.config" or "stable-ARCH.config"
|
||||
//
|
||||
// Both approaches can be used for the same variant and version. Both can be present at the same time and merges into the slice
|
||||
func readCustomConfigs(directory string, variant string, version string) ([]*repack_v1.KernelConfig, error) {
|
||||
version = strings.TrimSuffix(version, ".")
|
||||
var configs []*repack_v1.KernelConfig
|
||||
|
||||
files, err := os.ReadDir(directory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(file.Name(), ".config") {
|
||||
continue
|
||||
}
|
||||
|
||||
filePath := filepath.Join(directory, file.Name())
|
||||
|
||||
// Stable variant
|
||||
if strings.HasPrefix(file.Name(), "stable") && variant == "stable" {
|
||||
|
||||
configBytes, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configMap, _, err := repack_v1.ParseConfigFile(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if arch-specific
|
||||
if strings.Contains(file.Name(), "-") {
|
||||
arch := strings.TrimSuffix(strings.Split(file.Name(), "-")[1], ".config")
|
||||
log.Printf("applying arch-specific config: %s", arch)
|
||||
|
||||
configs = append(configs, &repack_v1.KernelConfig{
|
||||
Arch: arch,
|
||||
Map: configMap,
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
log.Println("applying arch-independent config")
|
||||
}
|
||||
|
||||
configs = append(configs, &repack_v1.KernelConfig{
|
||||
Arch: "all",
|
||||
Map: configMap,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Other variants
|
||||
if strings.HasPrefix(file.Name(), variant+"-"+version) {
|
||||
log.Printf("reading config: %s", file.Name())
|
||||
|
||||
configBytes, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configMap, _, err := repack_v1.ParseConfigFile(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if arch-specific
|
||||
newName := strings.TrimPrefix(file.Name(), variant+"-"+version+"-")
|
||||
if newName != ".config" {
|
||||
arch := strings.TrimSuffix(newName, ".config")
|
||||
log.Printf("applying arch-specific config: %s", arch)
|
||||
|
||||
configs = append(configs, &repack_v1.KernelConfig{
|
||||
Arch: arch,
|
||||
Map: configMap,
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
log.Println("applying arch-independent config")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// variant can only be one of the following: "stable", "longterm"
|
||||
allowedVariants := []string{"stable", "longterm"}
|
||||
variant := flag.String("variant", "", "variant to use")
|
||||
version := flag.String("version", "", "version to use")
|
||||
changelogFile := flag.String("changelog", "/tmp/changelog.json", "changelog file to use")
|
||||
kernelDirectory := flag.String("kernel-directory", "", "directory to store kernel")
|
||||
configDirectory := flag.String("config-directory", "configs", "directory to store configs")
|
||||
sourceOutputDirectory := flag.String("source-output-directory", "/tmp/sources", "directory to store source output")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
// Validation
|
||||
isAllowedVariant := false
|
||||
for _, v := range allowedVariants {
|
||||
if *variant == v {
|
||||
isAllowedVariant = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAllowedVariant {
|
||||
log.Fatalf("variant %s is not allowed", *variant)
|
||||
}
|
||||
if *variant != "stable" && len(*version) == 0 {
|
||||
log.Fatalf("version is required")
|
||||
}
|
||||
if *variant == "stable" && len(*version) > 0 {
|
||||
log.Fatalf("version is not allowed for stable variant")
|
||||
}
|
||||
if len(*version) > 0 && !strings.HasSuffix(*version, ".") {
|
||||
*version = *version + "."
|
||||
}
|
||||
if len(*kernelDirectory) == 0 {
|
||||
log.Fatalf("kernel directory is required")
|
||||
}
|
||||
|
||||
// Read changelog file
|
||||
changelog, err := os.ReadFile(*changelogFile)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
log.Fatalf("failed to read changelog file: %v", err)
|
||||
}
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
log.Printf("changelog file %s does not exist, continuing without previous changelog", *changelogFile)
|
||||
}
|
||||
|
||||
var changelogEntries []*repack_v1.ChangelogEntry
|
||||
if changelog != nil && len(changelog) > 0 {
|
||||
err = json.Unmarshal(changelog, &changelogEntries)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to unmarshal changelog: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get kernel tarball and version
|
||||
var tarball []byte
|
||||
var output *packager.Output
|
||||
var kVersion string
|
||||
|
||||
// BuildID should be YYYYMMDDHHMM
|
||||
buildID := time.Now().Format("200601021504")
|
||||
|
||||
// Check if there are any custom config files
|
||||
customConfigs, err := readCustomConfigs(*configDirectory, *variant, *version)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read custom configs: %v", err)
|
||||
}
|
||||
|
||||
switch *variant {
|
||||
case "stable":
|
||||
kVersion, tarball, _, err = kernelorg.GetLatestStable()
|
||||
case "longterm":
|
||||
kVersion, tarball, _, err = kernelorg.GetLatestLT(*version)
|
||||
}
|
||||
|
||||
changelogEntry := &repack_v1.ChangelogEntry{
|
||||
Date: time.Now().Format("Mon Jan 02 2006"),
|
||||
Name: "RESF AutoPackager",
|
||||
Version: kVersion,
|
||||
BuildID: buildID,
|
||||
Messages: []string{
|
||||
fmt.Sprintf("Rebase to %s", kVersion),
|
||||
},
|
||||
}
|
||||
|
||||
// Prepend the new changelog entry
|
||||
changelogEntries = append([]*repack_v1.ChangelogEntry{changelogEntry}, changelogEntries...)
|
||||
|
||||
input := &repack_v1.Input{
|
||||
Version: kVersion,
|
||||
BuildID: buildID,
|
||||
KernelPackage: "kernel",
|
||||
Changelog: changelogEntries,
|
||||
AdditionalKernelConfig: customConfigs,
|
||||
Tarball: tarball,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get kernel: %v", err)
|
||||
}
|
||||
|
||||
output, err = repack_v1.ML(input)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to repack: %v", err)
|
||||
}
|
||||
|
||||
// Write files
|
||||
_ = os.MkdirAll(*kernelDirectory, 0755)
|
||||
fs := osfs.New(*kernelDirectory)
|
||||
err = output.ToFS(fs)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write files: %v", err)
|
||||
}
|
||||
|
||||
_ = os.MkdirAll(*sourceOutputDirectory, 0755)
|
||||
f, err := os.Create(filepath.Join(*sourceOutputDirectory, output.TarballName))
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create tarball: %v", err)
|
||||
}
|
||||
|
||||
_, err = f.Write(output.Tarball)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write tarball: %v", err)
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to close tarball: %v", err)
|
||||
}
|
||||
|
||||
for _, otherFile := range output.OtherFiles {
|
||||
f, err := os.OpenFile(filepath.Join(*sourceOutputDirectory, otherFile.Name), os.O_CREATE|os.O_RDWR|os.O_TRUNC, otherFile.Permissions)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create file: %v", err)
|
||||
}
|
||||
|
||||
_, err = f.Write(otherFile.Data)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write file: %v", err)
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to close file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("repack successful :)")
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
package repack_v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"embed"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"go.resf.org/peridot/tools/kernelmanager/kernel_repack"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//go:embed data/*
|
||||
var Data embed.FS
|
||||
|
||||
type ChangelogEntry struct {
|
||||
Date string
|
||||
Name string
|
||||
Version string
|
||||
BuildID string
|
||||
Text string
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
Version string
|
||||
BuildID string
|
||||
KernelPackage string
|
||||
Changelog []*ChangelogEntry
|
||||
AdditionalKernelConfig []string
|
||||
Tarball []byte
|
||||
}
|
||||
|
||||
func kernel(kernelType string, in *Input) (*kernel_repack.Output, error) {
|
||||
var spec *kernel_repack.File
|
||||
var files []*kernel_repack.File
|
||||
|
||||
dir, err := Data.ReadDir("data")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, file := range dir {
|
||||
if strings.HasSuffix(file.Name(), ".spec") {
|
||||
if file.Name() != kernelType+".spec" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Read spec file
|
||||
f, err := Data.Open("data/" + file.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
specBytes, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
specName := fmt.Sprintf("%s.spec", in.KernelPackage)
|
||||
spec = &kernel_repack.File{
|
||||
Name: specName,
|
||||
Data: specBytes,
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Read other files
|
||||
f, err := Data.Open("data/" + file.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the file starts with "config-", then it's a kernel config file.
|
||||
// Append additional kernel config to the end of the file.
|
||||
if strings.HasPrefix(file.Name(), "config-") {
|
||||
data = append(data, []byte("\n")...)
|
||||
for _, config := range in.AdditionalKernelConfig {
|
||||
data = append(data, []byte(config)...)
|
||||
data = append(data, []byte("\n")...)
|
||||
}
|
||||
}
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := stat.Mode()
|
||||
|
||||
// If file name ends with ".sh", set executable bit
|
||||
if strings.HasSuffix(file.Name(), ".sh") {
|
||||
mode |= 0111
|
||||
}
|
||||
|
||||
files = append(files, &kernel_repack.File{
|
||||
Name: file.Name(),
|
||||
Data: data,
|
||||
Permissions: mode,
|
||||
})
|
||||
}
|
||||
|
||||
// Get sha256sum of tarball
|
||||
hash := sha256.New()
|
||||
_, err = hash.Write(in.Tarball)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sum := hex.EncodeToString(hash.Sum(nil))
|
||||
|
||||
// Create .metadata file
|
||||
suffix := "xz"
|
||||
if in.Tarball[0] == 0x1f && in.Tarball[1] == 0x8b {
|
||||
suffix = "gz"
|
||||
}
|
||||
metadata := fmt.Sprintf("%s SOURCES/linux-%s.tar.%s", sum, in.Version, suffix)
|
||||
|
||||
// Create .[kernelpackage].metadata
|
||||
metadataName := fmt.Sprintf(".%s.metadata", in.KernelPackage)
|
||||
|
||||
// Replace placeholders in spec file
|
||||
var buf bytes.Buffer
|
||||
txtTemplate, err := template.New("spec").Parse(string(spec.Data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = txtTemplate.Execute(&buf, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spec.Data = buf.Bytes()
|
||||
|
||||
output := &kernel_repack.Output{
|
||||
Spec: spec,
|
||||
Tarball: in.Tarball,
|
||||
TarballSha256: sum,
|
||||
Metadata: &kernel_repack.File{
|
||||
Name: metadataName,
|
||||
Data: []byte(metadata),
|
||||
},
|
||||
OtherFiles: files,
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// LT creates a new kernel package for the LT kernel
|
||||
// Returns spec and SOURCE files
|
||||
func LT(in *Input) (*kernel_repack.Output, error) {
|
||||
return kernel("lt", in)
|
||||
}
|
||||
|
||||
// ML creates a new kernel package for the ML kernel
|
||||
// Returns spec and SOURCE files
|
||||
func ML(in *Input) (*kernel_repack.Output, error) {
|
||||
return kernel("ml", in)
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "kernel_repack",
|
||||
name = "packager",
|
||||
srcs = ["repack.go"],
|
||||
importpath = "go.resf.org/peridot/tools/kernelmanager/kernel_repack",
|
||||
importpath = "go.resf.org/peridot/tools/kernelmanager/packager",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/go-git/go-billy/v5:go-billy"],
|
||||
)
|
@ -10,7 +10,7 @@ go_library(
|
||||
"gregkh.asc",
|
||||
"torvalds.asc",
|
||||
],
|
||||
importpath = "go.resf.org/peridot/tools/kernelmanager/kernel_repack/kernelorg",
|
||||
importpath = "go.resf.org/peridot/tools/kernelmanager/packager/kernelorg",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/xi2/xz",
|
@ -1,8 +1,18 @@
|
||||
package kernel_repack
|
||||
package packager
|
||||
|
||||
import (
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTarballEmpty = errors.New("tarball is empty")
|
||||
ErrTarballHashMismatch = errors.New("tarball hash mismatch")
|
||||
)
|
||||
|
||||
type File struct {
|
||||
@ -14,12 +24,39 @@ type File struct {
|
||||
type Output struct {
|
||||
Spec *File
|
||||
Tarball []byte
|
||||
TarballName string
|
||||
TarballSha256 string
|
||||
Metadata *File
|
||||
OtherFiles []*File
|
||||
}
|
||||
|
||||
func (o *Output) ToFS(fs billy.Filesystem) error {
|
||||
// Verify that tarball is not empty
|
||||
if len(o.Tarball) == 0 {
|
||||
return ErrTarballEmpty
|
||||
}
|
||||
|
||||
// Verify that tarball hash matches
|
||||
hash := sha256.New()
|
||||
_, err := hash.Write(o.Tarball)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sum := hash.Sum(nil)
|
||||
if o.TarballSha256 != hex.EncodeToString(sum) {
|
||||
return errors.Wrap(ErrTarballHashMismatch, fmt.Sprintf("expected %s, got %s", o.TarballSha256, hex.EncodeToString(sum)))
|
||||
}
|
||||
|
||||
// Verify that spec file is not empty
|
||||
if o.Spec == nil || len(o.Spec.Data) == 0 {
|
||||
return errors.New("spec file is empty")
|
||||
}
|
||||
|
||||
// Verify that the metadata file has a name
|
||||
if o.Metadata == nil || len(o.Metadata.Name) == 0 {
|
||||
return errors.New("metadata file has no name")
|
||||
}
|
||||
|
||||
// Create directories first
|
||||
dirs := []string{"SPECS", "SOURCES"}
|
||||
for _, dir := range dirs {
|
@ -1,7 +1,7 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "kernel_repack",
|
||||
name = "packager",
|
||||
srcs = ["v1.go"],
|
||||
embedsrcs = [
|
||||
"data/config-x86_64",
|
||||
@ -23,7 +23,7 @@ go_library(
|
||||
"data/x509.genkey",
|
||||
"data/rockydup1.x509",
|
||||
],
|
||||
importpath = "go.resf.org/peridot/tools/kernelmanager/kernel_repack/v1",
|
||||
importpath = "go.resf.org/peridot/tools/kernelmanager/packager/v1",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//tools/kernelmanager/kernel_repack"],
|
||||
deps = ["//tools/kernelmanager/packager"],
|
||||
)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1407,7 +1407,11 @@ fi
|
||||
### BCAT
|
||||
|
||||
%files -n %{name}-tools-libs
|
||||
{{if (eq (compareVersion .Version "6.2") 1)}}
|
||||
%{_libdir}/libcpupower.so.1
|
||||
{{else}}
|
||||
%{_libdir}/libcpupower.so.0
|
||||
{{end}}
|
||||
%{_libdir}/libcpupower.so.0.0.1
|
||||
|
||||
%files -n %{name}-tools-libs-devel
|
||||
@ -1491,7 +1495,7 @@ fi
|
||||
%kernel_ml_variant_files %{_use_vdso} %{with_std}
|
||||
|
||||
%changelog
|
||||
{{range $val := .Changelog}}
|
||||
* {{$val.Date}} {{$val.Name}} - {{$val.Version}}-{{$val.BuildID}}
|
||||
- {{$val.Text}}
|
||||
{{range $val := .Changelog}}* {{if $val.Subject}}{{$val.Subject}}{{else}}{{$val.Date}} {{$val.Name}} - {{$val.Version}}-{{$val.BuildID}}{{end}}
|
||||
{{range $text := $val.Messages}}- {{$text}}
|
||||
{{end}}
|
||||
{{end}}
|
274
tools/kernelmanager/packager/v1/v1.go
Normal file
274
tools/kernelmanager/packager/v1/v1.go
Normal file
@ -0,0 +1,274 @@
|
||||
package repack_v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"embed"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
packager "go.resf.org/peridot/tools/kernelmanager/kernel_repack"
|
||||
)
|
||||
|
||||
//go:embed data/*
|
||||
var Data embed.FS
|
||||
|
||||
type ChangelogEntry struct {
|
||||
Date string `json:"-"`
|
||||
Name string `json:"-"`
|
||||
Version string `json:"-"`
|
||||
BuildID string `json:"-"`
|
||||
Messages []string `json:"messages"`
|
||||
|
||||
// Subject covers the first line of the changelog entry
|
||||
Subject string `json:"subject"`
|
||||
}
|
||||
|
||||
type KernelConfig struct {
|
||||
Arch string
|
||||
Map map[string]string
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
Version string
|
||||
BuildID string
|
||||
KernelPackage string
|
||||
Changelog []*ChangelogEntry
|
||||
AdditionalKernelConfig []*KernelConfig
|
||||
Tarball []byte
|
||||
}
|
||||
|
||||
// compareVersion takes in two kernel version strings either in the form of "X.Y" or "X.Y.Z" and returns:
|
||||
// 1 if a > b
|
||||
// 0 if a == b
|
||||
// -1 if a < b
|
||||
func compareVersion(a, b string) int {
|
||||
// Split version strings into parts
|
||||
aParts := strings.Split(a, ".")
|
||||
bParts := strings.Split(b, ".")
|
||||
|
||||
// Compare major version
|
||||
if aParts[0] != bParts[0] {
|
||||
if aParts[0] > bParts[0] {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Compare minor version
|
||||
if aParts[1] != bParts[1] {
|
||||
if aParts[1] > bParts[1] {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// If there's a third part, compare it
|
||||
if len(aParts) == 3 && len(bParts) == 3 {
|
||||
if aParts[2] != bParts[2] {
|
||||
if aParts[2] > bParts[2] {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func kernel(kernelType string, in *Input) (*packager.Output, error) {
|
||||
var spec *packager.File
|
||||
var files []*packager.File
|
||||
|
||||
dir, err := Data.ReadDir("data")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, file := range dir {
|
||||
if strings.HasSuffix(file.Name(), ".spec") {
|
||||
if file.Name() != kernelType+".spec" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Read spec file
|
||||
f, err := Data.Open("data/" + file.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
specBytes, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
specName := fmt.Sprintf("%s.spec", in.KernelPackage)
|
||||
spec = &packager.File{
|
||||
Name: specName,
|
||||
Data: specBytes,
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Read other files
|
||||
f, err := Data.Open("data/" + file.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the file starts with "config-", then it's a kernel config file.
|
||||
// Merge additional kernel config
|
||||
if strings.HasPrefix(file.Name(), "config-") {
|
||||
parsedConfig, comments, err := ParseConfigFile(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, conf := range in.AdditionalKernelConfig {
|
||||
if conf.Arch == strings.TrimPrefix(file.Name(), "config-") || conf.Arch == "all" {
|
||||
for k, v := range conf.Map {
|
||||
parsedConfig[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the config back to the data slice
|
||||
data = WriteConfigFile(parsedConfig, comments)
|
||||
}
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := stat.Mode()
|
||||
|
||||
// If file name ends with ".sh", set executable bit
|
||||
if strings.HasSuffix(file.Name(), ".sh") {
|
||||
mode |= 0111
|
||||
}
|
||||
|
||||
// Read first line of file. If it starts with "#!", set executable bit
|
||||
if len(data) > 2 && data[0] == 0x23 && data[1] == 0x21 {
|
||||
mode |= 0111
|
||||
}
|
||||
|
||||
files = append(files, &packager.File{
|
||||
Name: file.Name(),
|
||||
Data: data,
|
||||
Permissions: mode,
|
||||
})
|
||||
}
|
||||
|
||||
// Get sha256sum of tarball
|
||||
hash := sha256.New()
|
||||
_, err = hash.Write(in.Tarball)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sum := hex.EncodeToString(hash.Sum(nil))
|
||||
|
||||
// Create .metadata file
|
||||
suffix := "xz"
|
||||
if in.Tarball[0] == 0x1f && in.Tarball[1] == 0x8b {
|
||||
suffix = "gz"
|
||||
}
|
||||
tarballName := fmt.Sprintf("linux-%s.tar.%s", in.Version, suffix)
|
||||
metadata := fmt.Sprintf("%s SOURCES/%s", tarballName)
|
||||
|
||||
// Create .[kernelpackage].metadata
|
||||
metadataName := fmt.Sprintf(".%s.metadata", in.KernelPackage)
|
||||
|
||||
// Replace placeholders in spec file
|
||||
var buf bytes.Buffer
|
||||
txtTemplate, err := template.
|
||||
New("spec").
|
||||
Funcs(template.FuncMap{
|
||||
"compareVersion": compareVersion,
|
||||
}).
|
||||
Parse(string(spec.Data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = txtTemplate.Execute(&buf, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spec.Data = buf.Bytes()
|
||||
|
||||
output := &packager.Output{
|
||||
Spec: spec,
|
||||
Tarball: in.Tarball,
|
||||
TarballName: tarballName,
|
||||
TarballSha256: sum,
|
||||
Metadata: &packager.File{
|
||||
Name: metadataName,
|
||||
Data: []byte(metadata),
|
||||
},
|
||||
OtherFiles: files,
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func ParseConfigFile(data []byte) (map[string]string, []string, error) {
|
||||
// Split into lines so we can parse it
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
var comments []string
|
||||
var config []string
|
||||
// Loop, and add all lines that start with "#" to the comment slice
|
||||
// and all other lines to the config slice
|
||||
for _, line := range lines {
|
||||
// Ignore empty lines
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "#") {
|
||||
comments = append(comments, line)
|
||||
} else {
|
||||
config = append(config, line)
|
||||
}
|
||||
}
|
||||
|
||||
parsedConfig := make(map[string]string)
|
||||
for _, line := range config {
|
||||
// Split the line into key and value
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return nil, nil, fmt.Errorf("invalid kernel config line: %s", line)
|
||||
}
|
||||
parsedConfig[parts[0]] = parts[1]
|
||||
}
|
||||
|
||||
return parsedConfig, comments, nil
|
||||
}
|
||||
|
||||
func WriteConfigFile(config map[string]string, comments []string) []byte {
|
||||
var newConfig []string
|
||||
for _, comment := range comments {
|
||||
newConfig = append(newConfig, comment)
|
||||
}
|
||||
for k, v := range config {
|
||||
newConfig = append(newConfig, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
data := []byte(strings.Join(newConfig, "\n"))
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// ML creates a new kernel package for the ML kernel
|
||||
// Returns spec and SOURCE files
|
||||
func ML(in *Input) (*packager.Output, error) {
|
||||
return kernel("ml", in)
|
||||
}
|
Loading…
Reference in New Issue
Block a user