106 lines
3.2 KiB
Rust
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()
|
|
}
|
|
}
|