use crate::core::error::{Error, Result};
use std::path::{Path, PathBuf};
#[cfg(feature = "limine")]
pub struct GitFetcher {
cache_dir: PathBuf,
verbose: bool,
}
#[cfg(feature = "limine")]
impl GitFetcher {
pub fn new(cache_dir: PathBuf, verbose: bool) -> Self {
Self { cache_dir, verbose }
}
pub fn fetch(&self, url: &str, name: &str, branch: &str) -> Result<PathBuf> {
let repo_path = self.cache_dir.join(name);
if repo_path.exists() {
if self.verbose {
println!("Using cached {} from {}", name, repo_path.display());
}
return Ok(repo_path);
}
if self.verbose {
println!("Fetching {} from {}...", name, url);
}
std::fs::create_dir_all(&self.cache_dir)?;
let mut builder = git2::build::RepoBuilder::new();
builder.branch(branch);
builder
.clone(url, &repo_path)
.map_err(|e| Error::bootloader(format!("failed to clone {}: {}", url, e)))?;
if self.verbose {
println!("Fetched {} successfully", name);
}
Ok(repo_path)
}
pub fn fetch_ref(&self, url: &str, name: &str, git_ref: &str) -> Result<PathBuf> {
let repo_path = self.cache_dir.join(format!("{}-{}", name, git_ref));
if repo_path.exists() {
if self.verbose {
println!("Using cached {} ({}) from {}", name, git_ref, repo_path.display());
}
return Ok(repo_path);
}
if self.verbose {
println!("Fetching {} ({}) from {}...", name, git_ref, url);
}
std::fs::create_dir_all(&self.cache_dir)?;
let repo = git2::Repository::clone(url, &repo_path)
.map_err(|e| Error::bootloader(format!("failed to clone {}: {}", url, e)))?;
let (object, reference) = repo.revparse_ext(git_ref)
.map_err(|e| Error::bootloader(format!("failed to find ref {}: {}", git_ref, e)))?;
repo.checkout_tree(&object, None)
.map_err(|e| Error::bootloader(format!("failed to checkout {}: {}", git_ref, e)))?;
match reference {
Some(gref) => repo.set_head(gref.name().unwrap()),
None => repo.set_head_detached(object.id()),
}
.map_err(|e| Error::bootloader(format!("failed to set HEAD: {}", e)))?;
if self.verbose {
println!("Fetched {} ({}) successfully", name, git_ref);
}
Ok(repo_path)
}
pub fn copy_files(&self, repo_path: &Path, files: &[&str], dest_dir: &Path) -> Result<Vec<PathBuf>> {
let mut copied = Vec::new();
for file in files {
let src = repo_path.join(file);
if !src.exists() {
return Err(Error::bootloader(format!(
"required file not found in repository: {}",
file
)));
}
let dest = dest_dir.join(
Path::new(file)
.file_name()
.ok_or_else(|| Error::bootloader("invalid file path"))?,
);
std::fs::create_dir_all(dest_dir)?;
std::fs::copy(&src, &dest)?;
copied.push(dest);
}
Ok(copied)
}
}
#[cfg(not(feature = "limine"))]
pub struct GitFetcher;
#[cfg(not(feature = "limine"))]
impl GitFetcher {
pub fn new(_cache_dir: PathBuf, _verbose: bool) -> Self {
Self
}
pub fn fetch(&self, _url: &str, _name: &str, _branch: &str) -> Result<PathBuf> {
Err(Error::feature_not_enabled("limine"))
}
pub fn fetch_ref(&self, _url: &str, _name: &str, _git_ref: &str) -> Result<PathBuf> {
Err(Error::feature_not_enabled("limine"))
}
pub fn copy_files(&self, _repo_path: &Path, _files: &[&str], _dest_dir: &Path) -> Result<Vec<PathBuf>> {
Err(Error::feature_not_enabled("limine"))
}
}