cargo_image_runner/bootloader/
fetcher.rs1use crate::core::error::{Error, Result};
2use std::path::{Path, PathBuf};
3
4#[cfg(feature = "limine")]
6pub struct GitFetcher {
7 cache_dir: PathBuf,
8}
9
10#[cfg(feature = "limine")]
11impl GitFetcher {
12 pub fn new(cache_dir: PathBuf) -> Self {
14 Self { cache_dir }
15 }
16
17 pub fn fetch(&self, url: &str, name: &str, branch: &str) -> Result<PathBuf> {
22 let repo_path = self.cache_dir.join(name);
23
24 if repo_path.exists() {
26 println!("Using cached {} from {}", name, repo_path.display());
27 return Ok(repo_path);
28 }
29
30 println!("Fetching {} from {}...", name, url);
31 std::fs::create_dir_all(&self.cache_dir)?;
32
33 let mut builder = git2::build::RepoBuilder::new();
35 builder.branch(branch);
36
37 builder
38 .clone(url, &repo_path)
39 .map_err(|e| Error::bootloader(format!("failed to clone {}: {}", url, e)))?;
40
41 println!("Fetched {} successfully", name);
42 Ok(repo_path)
43 }
44
45 pub fn fetch_ref(&self, url: &str, name: &str, git_ref: &str) -> Result<PathBuf> {
47 let repo_path = self.cache_dir.join(format!("{}-{}", name, git_ref));
48
49 if repo_path.exists() {
51 println!("Using cached {} ({}) from {}", name, git_ref, repo_path.display());
52 return Ok(repo_path);
53 }
54
55 println!("Fetching {} ({}) from {}...", name, git_ref, url);
56 std::fs::create_dir_all(&self.cache_dir)?;
57
58 let repo = git2::Repository::clone(url, &repo_path)
60 .map_err(|e| Error::bootloader(format!("failed to clone {}: {}", url, e)))?;
61
62 let (object, reference) = repo.revparse_ext(git_ref)
64 .map_err(|e| Error::bootloader(format!("failed to find ref {}: {}", git_ref, e)))?;
65
66 repo.checkout_tree(&object, None)
67 .map_err(|e| Error::bootloader(format!("failed to checkout {}: {}", git_ref, e)))?;
68
69 match reference {
70 Some(gref) => repo.set_head(gref.name().unwrap()),
71 None => repo.set_head_detached(object.id()),
72 }
73 .map_err(|e| Error::bootloader(format!("failed to set HEAD: {}", e)))?;
74
75 println!("Fetched {} ({}) successfully", name, git_ref);
76 Ok(repo_path)
77 }
78
79 pub fn copy_files(&self, repo_path: &Path, files: &[&str], dest_dir: &Path) -> Result<Vec<PathBuf>> {
81 let mut copied = Vec::new();
82
83 for file in files {
84 let src = repo_path.join(file);
85 if !src.exists() {
86 return Err(Error::bootloader(format!(
87 "required file not found in repository: {}",
88 file
89 )));
90 }
91
92 let dest = dest_dir.join(
93 Path::new(file)
94 .file_name()
95 .ok_or_else(|| Error::bootloader("invalid file path"))?,
96 );
97
98 std::fs::create_dir_all(dest_dir)?;
99 std::fs::copy(&src, &dest)?;
100 copied.push(dest);
101 }
102
103 Ok(copied)
104 }
105}
106
107#[cfg(not(feature = "limine"))]
109pub struct GitFetcher;
110
111#[cfg(not(feature = "limine"))]
112impl GitFetcher {
113 pub fn new(_cache_dir: PathBuf) -> Self {
114 Self
115 }
116
117 pub fn fetch(&self, _url: &str, _name: &str, _branch: &str) -> Result<PathBuf> {
118 Err(Error::feature_not_enabled("limine"))
119 }
120
121 pub fn fetch_ref(&self, _url: &str, _name: &str, _git_ref: &str) -> Result<PathBuf> {
122 Err(Error::feature_not_enabled("limine"))
123 }
124
125 pub fn copy_files(&self, _repo_path: &Path, _files: &[&str], _dest_dir: &Path) -> Result<Vec<PathBuf>> {
126 Err(Error::feature_not_enabled("limine"))
127 }
128}