mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 21:20:17 +00:00
improve documentation of some functions and more readme work
This commit is contained in:
52
src/main.rs
52
src/main.rs
@@ -1,3 +1,4 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![feature(uefi_std)]
|
||||
|
||||
use crate::context::{RootContext, SproutContext};
|
||||
@@ -20,15 +21,20 @@ pub mod phases;
|
||||
pub mod setup;
|
||||
pub mod utils;
|
||||
|
||||
/// The main entrypoint of sprout.
|
||||
/// It is possible this function will not return if actions that are executed
|
||||
/// exit boot services or do not return control to sprout.
|
||||
fn main() -> Result<()> {
|
||||
// Initialize the basic UEFI environment.
|
||||
setup::init()?;
|
||||
|
||||
let config = config::load()?;
|
||||
|
||||
if config.version != config::latest_version() {
|
||||
bail!("unsupported configuration version: {}", config.version);
|
||||
}
|
||||
// Load the configuration of sprout.
|
||||
// At this point, the configuration has been validated and the specified
|
||||
// version is checked to ensure compatibility.
|
||||
let config = config::loader::load()?;
|
||||
|
||||
// Load the root context.
|
||||
// This is done in a block to ensure the release of the LoadedImageDevicePath protocol.
|
||||
let mut root = {
|
||||
let current_image_device_path_protocol = uefi::boot::open_protocol_exclusive::<
|
||||
LoadedImageDevicePath,
|
||||
@@ -42,16 +48,25 @@ fn main() -> Result<()> {
|
||||
RootContext::new(loaded_image_path)
|
||||
};
|
||||
|
||||
// Insert the configuration actions into the root context.
|
||||
root.actions_mut().extend(config.actions.clone());
|
||||
|
||||
// Create a new sprout context with the root context.
|
||||
let mut context = SproutContext::new(root);
|
||||
|
||||
// Insert the configuration values into the sprout context.
|
||||
context.insert(&config.values);
|
||||
|
||||
// Freeze the sprout context so it can be shared and cheaply cloned.
|
||||
let context = context.freeze();
|
||||
|
||||
// Execute the early phase.
|
||||
phase(context.clone(), &config.phases.early).context("unable to execute early phase")?;
|
||||
|
||||
// Load all configured drivers.
|
||||
drivers::load(context.clone(), &config.drivers).context("unable to load drivers")?;
|
||||
|
||||
// Run all the extractors declared in the configuration.
|
||||
let mut extracted = BTreeMap::new();
|
||||
for (name, extractor) in &config.extractors {
|
||||
let value = extractors::extract(context.clone(), extractor)
|
||||
@@ -60,50 +75,69 @@ fn main() -> Result<()> {
|
||||
extracted.insert(name.clone(), value);
|
||||
}
|
||||
let mut context = context.fork();
|
||||
// Insert the extracted values into the sprout context.
|
||||
context.insert(&extracted);
|
||||
let context = context.freeze();
|
||||
|
||||
// Execute the late phase.
|
||||
phase(context.clone(), &config.phases.startup).context("unable to execute startup phase")?;
|
||||
|
||||
let mut all_entries = Vec::new();
|
||||
let mut staged_entries = Vec::new();
|
||||
|
||||
// Insert all the static entries from the configuration into the entry list.
|
||||
for (_name, entry) in config.entries {
|
||||
all_entries.push((context.clone(), entry));
|
||||
// Associate the main context with the static entry.
|
||||
staged_entries.push((context.clone(), entry));
|
||||
}
|
||||
|
||||
// Run all the generators declared in the configuration.
|
||||
for (_name, generator) in config.generators {
|
||||
let context = context.fork().freeze();
|
||||
|
||||
// Add all the entries generated by the generator to the entry list.
|
||||
// The generator specifies the context associated with the entry.
|
||||
for entry in generators::generate(context.clone(), &generator)? {
|
||||
all_entries.push(entry);
|
||||
staged_entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a list of all the final boot entries.
|
||||
let mut final_entries = Vec::new();
|
||||
for (context, entry) in all_entries {
|
||||
for (context, entry) in staged_entries {
|
||||
let mut context = context.fork();
|
||||
// Insert the values from the entry configuration into the
|
||||
// sprout context to use with the entry itself.
|
||||
context.insert(&entry.values);
|
||||
let context = context.finalize().freeze();
|
||||
|
||||
// Insert the entry configuration into final boot entries with the extended context.
|
||||
final_entries.push((context, entry));
|
||||
}
|
||||
|
||||
// TODO(azenla): Implement boot menu here.
|
||||
// For now, we just print all of the entries.
|
||||
info!("entries:");
|
||||
for (index, (context, entry)) in final_entries.iter().enumerate() {
|
||||
let title = context.stamp(&entry.title);
|
||||
info!(" entry {}: {}", index + 1, title);
|
||||
}
|
||||
|
||||
// Execute the late phase.
|
||||
phase(context.clone(), &config.phases.late).context("unable to execute late phase")?;
|
||||
|
||||
// Pick the first entry from the list of final entries until a boot menu is implemented.
|
||||
let Some((context, entry)) = final_entries.first() else {
|
||||
bail!("no entries found");
|
||||
};
|
||||
|
||||
// Execute all the actions for the selected entry.
|
||||
for action in &entry.actions {
|
||||
let action = context.stamp(action);
|
||||
actions::execute(context.clone(), &action)
|
||||
.context(format!("unable to execute action '{}'", action))?;
|
||||
}
|
||||
|
||||
// Sprout doesn't necessarily guarantee anything was booted.
|
||||
// If we reach here, we will exit back to whoever called us.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user