initramfs_builder/image/
rootfs.rs1use anyhow::Result;
2use std::path::{Path, PathBuf};
3use tempfile::TempDir;
4use tracing::info;
5
6use super::LayerExtractor;
7use crate::registry::{PullOptions, RegistryClient};
8
9pub struct RootfsBuilder {
10 client: RegistryClient,
11 options: PullOptions,
12 exclude_patterns: Vec<String>,
13 temp_dir: Option<TempDir>,
14}
15
16impl RootfsBuilder {
17 pub fn new(client: RegistryClient) -> Self {
18 Self {
19 client,
20 options: PullOptions::default(),
21 exclude_patterns: Vec::new(),
22 temp_dir: None,
23 }
24 }
25
26 pub fn platform(mut self, os: &str, arch: &str) -> Self {
27 self.options.platform_os = os.to_string();
28 self.options.platform_arch = arch.to_string();
29 self
30 }
31
32 pub fn exclude(mut self, patterns: &[&str]) -> Self {
33 self.exclude_patterns
34 .extend(patterns.iter().map(|s| s.to_string()));
35 self
36 }
37
38 pub async fn build(&mut self, image: &str) -> Result<PathBuf> {
39 let reference = RegistryClient::parse_reference(image)?;
40
41 info!("Fetching manifest for {}", image);
42 let manifest = self
43 .client
44 .fetch_manifest(&reference, &self.options)
45 .await?;
46
47 info!(
48 "Image has {} layers, total size: {} bytes",
49 manifest.layers.len(),
50 manifest.total_size
51 );
52
53 info!("Pulling layers...");
54 let layers = self
55 .client
56 .pull_all_layers(&reference, &manifest, None)
57 .await?;
58
59 let temp_dir = TempDir::new()?;
60 let rootfs_path = temp_dir.path().to_path_buf();
61
62 info!("Extracting layers to {:?}", rootfs_path);
63 let exclude_refs: Vec<&str> = self.exclude_patterns.iter().map(|s| s.as_str()).collect();
64 let mut extractor = LayerExtractor::new().with_excludes(&exclude_refs)?;
65 extractor.extract_all_layers(&layers, &rootfs_path)?;
66
67 self.temp_dir = Some(temp_dir);
68
69 Ok(rootfs_path)
70 }
71
72 pub fn rootfs_path(&self) -> Option<&Path> {
73 self.temp_dir.as_ref().map(|t| t.path())
74 }
75}