build.rs/src/backend/mod.rs

106 lines
3.2 KiB
Rust

use std::boxed::Box;
use std::path::{Path, PathBuf};
mod git;
mod mercurial;
pub use git::Git;
pub use mercurial::Mercurial;
/// Generates Some(Backend) from an optional String, or defaults to Git,
/// or None when the backend is not recognized. If you want to implement your own
/// backend outside of this crate, you should override this method.
/// TODO: fallback backend should be customizable
pub fn backend(setting: Option<String>) -> Option<Box<dyn Backend>> {
// Git is the default setting until further notice
setting.map_or(Some(Box::new(Git)), |name| match name.as_ref() {
"git" => Some(Box::new(Git)),
"mercurial" => Some(Box::new(Mercurial)),
_ => None,
})
}
/// The trait implemented by DVCS backends (git, mercurial).
/// NOTE: This interface may evolve quickly. Currently no state is stored inside
/// the backend and it's assumed the current working dir is the repository we're operating on
pub trait Backend: std::fmt::Debug {
/// Clone a src repository and all related submodules to dest
fn download(&self, src: &str, dest: &Path) -> bool;
/// List all submodules in repo, as a list of PathBuf's
/// Returns an empty vector when no submodules are declared
fn submodules(&self) -> Vec<PathBuf>;
/// Returns the current branch/commit/tag tracked by the repo
fn branch(&self) -> String;
/// Checkouts out a specific branch/commit/tag to track on the repo
fn checkout(&self, branch: &str) -> bool;
/// Checks for updates in repo. Does not account for submodules
fn has_updates(&self) -> bool;
/// Applies updates on the main repo, and on submodules if subupdates is enabled. Returns true
/// if some updates were applied, false otherwise.
fn update(&self) -> bool;
/// Applies submodule updates. Returns true if some updates were applied, false otherwise.
fn subupdate(&self) -> bool;
}
#[derive(Debug)]
pub struct Repo {
pub backend: Box<dyn Backend>,
pub source: String,
pub dest: PathBuf,
pub subupdates: bool,
}
impl Repo {
pub fn new(backend: Box<dyn Backend>, source: &str, dest: &Path, subupdates: bool) -> Repo {
Repo {
backend,
source: source.to_string(),
dest: dest.to_path_buf(),
subupdates,
}
}
pub fn download(&self) -> bool {
let success = self.backend.download(&self.source, &self.dest);
// If the clone was successful and subupdates is enabled,
// List submodules and check them for updates
if success && self.subupdates {
self.subupdate();
}
return success;
}
pub fn checkout(&self, target: &str) -> bool {
self.backend.checkout(target)
}
pub fn has_updates(&self) -> bool {
self.backend.has_updates()
}
pub fn update(&self) -> bool {
// First try to run submodules updates
let had_subupdates = if self.subupdates { self.subupdate() } else { false };
// Now run main repo updates
if self.has_updates() {
self.backend.update() || had_subupdates
} else {
had_subupdates
}
}
pub fn subupdate(&self) -> bool {
self.backend.subupdate()
}
}