Implement system state management with TOML serialization

- Introduced `SystemState` struct to manage system state, including stage, target, architecture, and layers.
- Added functions to load and save system state from/to a TOML file.
- Implemented layer management functions: add, set, and remove packages from layers.
- Created initialization function for LBI layout, including directory and symlink creation.
- Added tests for layer management and LBI layout initialization.
This commit is contained in:
2026-05-20 19:54:00 -05:00
parent d61d59f4f5
commit 1833a2c42d
18 changed files with 8820 additions and 354 deletions
+111
View File
@@ -112,6 +112,117 @@ pub(super) fn run_config(args: ConfigArgs) -> Result<()> {
Ok(())
}
pub(super) fn run_system(args: SystemArgs) -> Result<()> {
let SystemArgs {
rootfs_args,
command,
} = args;
let rootfs = rootfs_args.rootfs;
let config = config::Config::for_rootfs(&rootfs);
let mut system_lock = locking::open_lock(&config)?;
let system_lock_path = locking::lock_path(&config);
match command {
crate::cli::SystemCommands::Status => {
let _guard = locking::try_read(&system_lock, &system_lock_path, "system status")?;
let state = crate::system_state::load(&config)?;
print_system_state(&state);
}
crate::cli::SystemCommands::Stage { stage } => {
let _guard = locking::try_write(&mut system_lock, &system_lock_path, "system stage")?;
let state = crate::system_state::set_stage(&config, stage)?;
ui::success(format!(
"Moved system status to stage {}",
state.stage.as_deref().unwrap_or("unknown")
));
}
crate::cli::SystemCommands::Layer { command } => {
let _guard = locking::try_write(&mut system_lock, &system_lock_path, "system layer")?;
match command {
crate::cli::SystemLayerCommands::Add { layer, packages } => {
let package_count = packages.len();
crate::system_state::add_packages_to_layer(&config, layer.clone(), &packages)?;
ui::success(format!(
"Added {} package(s) to layer {}",
package_count, layer
));
}
crate::cli::SystemLayerCommands::Remove { layer, packages } => {
let package_count = packages.len();
crate::system_state::remove_packages_from_layer(
&config,
layer.clone(),
&packages,
)?;
ui::success(format!(
"Removed {} package(s) from layer {}",
package_count, layer
));
}
crate::cli::SystemLayerCommands::List => {
drop(_guard);
let _guard =
locking::try_read(&system_lock, &system_lock_path, "system layer list")?;
let state = crate::system_state::load(&config)?;
print_system_layers(&state);
}
}
}
crate::cli::SystemCommands::InitLbi {
target,
arch,
force,
} => {
let _guard =
locking::try_write(&mut system_lock, &system_lock_path, "system init-lbi")?;
let state = crate::system_state::init_lbi_layout(
&rootfs,
&config,
&target,
arch.as_deref(),
force,
)?;
ui::success(format!(
"Initialized Linux by Intent layout for {} ({})",
state.target.as_deref().unwrap_or("unknown"),
state.arch.as_deref().unwrap_or("unknown")
));
}
}
Ok(())
}
fn print_system_state(state: &crate::system_state::SystemState) {
println!(
"Stage: {}",
state.stage.as_deref().unwrap_or("uninitialized")
);
if let Some(target) = &state.target {
println!("Target: {target}");
}
if let Some(arch) = &state.arch {
println!("Arch: {arch}");
}
print_system_layers(state);
}
fn print_system_layers(state: &crate::system_state::SystemState) {
if state.layers.is_empty() {
println!("Layers: none");
return;
}
println!("Layers:");
for (layer, packages) in &state.layers {
if packages.is_empty() {
println!(" {layer}:");
} else {
println!(" {}: {}", layer, packages.join(", "));
}
}
}
pub(super) fn run_make_spec(args: crate::cli::MakeSpecArgs) -> Result<()> {
let output = args.output;
let spec = package::create_interactive()?;