mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 15:40:16 +00:00
feat(bls): initial support for sorting of entries, not using version comparison
This commit is contained in:
@@ -4,6 +4,7 @@ use crate::generators::bls::entry::BlsEntry;
|
|||||||
use crate::utils;
|
use crate::utils;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use uefi::cstr16;
|
use uefi::cstr16;
|
||||||
@@ -40,6 +41,55 @@ fn quirk_initrd_remove_tuned(input: String) -> String {
|
|||||||
input.replace("$tuned_initrd", "").trim().to_string()
|
input.replace("$tuned_initrd", "").trim().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sorts two entries according to the BLS sort system.
|
||||||
|
/// Reference: https://uapi-group.org/specifications/specs/boot_loader_specification/#sorting
|
||||||
|
fn sort_entries(a: &(BlsEntry, BootableEntry), b: &(BlsEntry, BootableEntry)) -> Ordering {
|
||||||
|
// Grab the components of both entries.
|
||||||
|
let (a_bls, a_boot) = a;
|
||||||
|
let (b_bls, b_boot) = b;
|
||||||
|
|
||||||
|
// Grab the sort keys from both entries.
|
||||||
|
let a_sort_key = a_bls.sort_key();
|
||||||
|
let b_sort_key = b_bls.sort_key();
|
||||||
|
|
||||||
|
// Compare the sort keys of both entries.
|
||||||
|
match a_sort_key.cmp(&b_sort_key) {
|
||||||
|
// If A and B sort keys are equal, sort by machine-id.
|
||||||
|
Ordering::Equal => {
|
||||||
|
// Grab the machine-id from both entries.
|
||||||
|
let a_machine_id = a_bls.machine_id();
|
||||||
|
let b_machine_id = b_bls.machine_id();
|
||||||
|
|
||||||
|
// Compare the machine-id of both entries.
|
||||||
|
match a_machine_id.cmp(&b_machine_id) {
|
||||||
|
// If both machine-id values are equal, sort by version.
|
||||||
|
Ordering::Equal => {
|
||||||
|
// Grab the version from both entries.
|
||||||
|
let a_version = a_bls.version();
|
||||||
|
let b_version = b_bls.version();
|
||||||
|
|
||||||
|
// Compare the version of both entries, sorting newer versions first.
|
||||||
|
match b_version.cmp(&a_version) {
|
||||||
|
// If both versions are equal, sort by file name in reverse order.
|
||||||
|
Ordering::Equal => {
|
||||||
|
// Grab the file name from both entries.
|
||||||
|
let a_name = a_boot.name();
|
||||||
|
let b_name = b_boot.name();
|
||||||
|
|
||||||
|
// Compare the file names of both entries, sorting newer entries first.
|
||||||
|
b_name.cmp(a_name)
|
||||||
|
}
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates entries from the BLS entries directory using the specified `bls` configuration and
|
/// Generates entries from the BLS entries directory using the specified `bls` configuration and
|
||||||
/// `context`. The BLS conversion is best-effort and will ignore any unsupported entries.
|
/// `context`. The BLS conversion is best-effort and will ignore any unsupported entries.
|
||||||
pub fn generate(context: Rc<SproutContext>, bls: &BlsConfiguration) -> Result<Vec<BootableEntry>> {
|
pub fn generate(context: Rc<SproutContext>, bls: &BlsConfiguration) -> Result<Vec<BootableEntry>> {
|
||||||
@@ -132,9 +182,11 @@ pub fn generate(context: Rc<SproutContext>, bls: &BlsConfiguration) -> Result<Ve
|
|||||||
context.set("chainload", chainload);
|
context.set("chainload", chainload);
|
||||||
context.set("options", options);
|
context.set("options", options);
|
||||||
context.set("initrd", initrd);
|
context.set("initrd", initrd);
|
||||||
|
context.set("version", entry.version().unwrap_or_default());
|
||||||
|
context.set("machine-id", entry.machine_id().unwrap_or_default());
|
||||||
|
|
||||||
// Produce a new bootable entry.
|
// Produce a new bootable entry.
|
||||||
let mut entry = BootableEntry::new(
|
let mut boot = BootableEntry::new(
|
||||||
name,
|
name,
|
||||||
bls.entry.title.clone(),
|
bls.entry.title.clone(),
|
||||||
context.freeze(),
|
context.freeze(),
|
||||||
@@ -144,11 +196,15 @@ pub fn generate(context: Rc<SproutContext>, bls: &BlsConfiguration) -> Result<Ve
|
|||||||
// Pin the entry name to prevent prefixing.
|
// Pin the entry name to prevent prefixing.
|
||||||
// This is needed as the bootloader interface requires the name to be
|
// This is needed as the bootloader interface requires the name to be
|
||||||
// the same as the entry file name, minus the .conf extension.
|
// the same as the entry file name, minus the .conf extension.
|
||||||
entry.mark_pin_name();
|
boot.mark_pin_name();
|
||||||
|
|
||||||
// Add the entry to the list with a frozen context.
|
// Add the BLS entry to the list, along with the bootable entry.
|
||||||
entries.push(entry);
|
entries.push((entry, boot));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(entries)
|
// Sort all the entries according to the BLS sort system.
|
||||||
|
entries.sort_by(sort_entries);
|
||||||
|
|
||||||
|
// Collect all the bootable entries and return them.
|
||||||
|
Ok(entries.into_iter().map(|(_, boot)| boot).collect())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ pub struct BlsEntry {
|
|||||||
pub initrd: Option<String>,
|
pub initrd: Option<String>,
|
||||||
/// The path to an EFI image.
|
/// The path to an EFI image.
|
||||||
pub efi: Option<String>,
|
pub efi: Option<String>,
|
||||||
|
/// The sort key for the entry.
|
||||||
|
pub sort_key: Option<String>,
|
||||||
|
/// The version of the entry.
|
||||||
|
pub version: Option<String>,
|
||||||
|
/// The machine id of the entry.
|
||||||
|
pub machine_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a BLS entry.
|
/// Parser for a BLS entry.
|
||||||
@@ -30,6 +36,9 @@ impl FromStr for BlsEntry {
|
|||||||
let mut linux: Option<String> = None;
|
let mut linux: Option<String> = None;
|
||||||
let mut initrd: Option<String> = None;
|
let mut initrd: Option<String> = None;
|
||||||
let mut efi: Option<String> = None;
|
let mut efi: Option<String> = None;
|
||||||
|
let mut sort_key: Option<String> = None;
|
||||||
|
let mut version: Option<String> = None;
|
||||||
|
let mut machine_id: Option<String> = None;
|
||||||
|
|
||||||
// Iterate over each line in the input and parse it.
|
// Iterate over each line in the input and parse it.
|
||||||
for line in input.lines() {
|
for line in input.lines() {
|
||||||
@@ -74,6 +83,18 @@ impl FromStr for BlsEntry {
|
|||||||
efi = Some(value.trim().to_string());
|
efi = Some(value.trim().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"sort-key" => {
|
||||||
|
sort_key = Some(value.trim().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
"version" => {
|
||||||
|
version = Some(value.trim().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
"machine-id" => {
|
||||||
|
machine_id = Some(value.trim().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore any other key.
|
// Ignore any other key.
|
||||||
_ => {
|
_ => {
|
||||||
continue;
|
continue;
|
||||||
@@ -88,6 +109,9 @@ impl FromStr for BlsEntry {
|
|||||||
linux,
|
linux,
|
||||||
initrd,
|
initrd,
|
||||||
efi,
|
efi,
|
||||||
|
sort_key,
|
||||||
|
version,
|
||||||
|
machine_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,4 +149,19 @@ impl BlsEntry {
|
|||||||
pub fn title(&self) -> Option<String> {
|
pub fn title(&self) -> Option<String> {
|
||||||
self.title.clone()
|
self.title.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetches the sort key of the entry, if any.
|
||||||
|
pub fn sort_key(&self) -> Option<String> {
|
||||||
|
self.sort_key.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetches the version of the entry, if any.
|
||||||
|
pub fn version(&self) -> Option<String> {
|
||||||
|
self.version.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetches the machine id of the entry, if any.
|
||||||
|
pub fn machine_id(&self) -> Option<String> {
|
||||||
|
self.machine_id.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user