use crate::command_runner::CommandRunner; use crate::symbols::Symbol; use std::borrow::Borrow; use std::error::Error; use std::ffi::OsStr; use std::marker::PhantomData; use std::path::Path; #[derive(Debug)] pub struct Checkout<_C, C, P, S, B> { target: P, source: S, branch: B, command_runner: C, phantom: PhantomData<_C>, } impl Checkout<_C, C, P, S, B> { pub fn new(target: P, source: S, branch: B, command_runner: C) -> Self { Self { target, source, branch, command_runner, phantom: PhantomData::default(), } } } impl, P: AsRef, S, B> Checkout { fn _run_in_target_repo(&self, args: &[impl AsRef]) -> Result, Box> { let mut new_args = vec![OsStr::new("-C"), self.target.as_ref().as_ref()]; new_args.extend(args.iter().map(AsRef::as_ref)); self.command_runner.borrow().get_output("git", &new_args) } } impl, P: AsRef, S: AsRef, B: AsRef> Symbol for Checkout { fn target_reached(&self) -> Result> { if !self.target.as_ref().exists() { return Ok(false); } self._run_in_target_repo(&["fetch", self.source.as_ref(), self.branch.as_ref()])?; // git rev-list resolves tag objects let fetch_head = self._run_in_target_repo(&["rev-list", "-1", "FETCH_HEAD"])?; let head = self._run_in_target_repo(&["rev-list", "-1", "HEAD"])?; Ok(fetch_head == head) } fn execute(&self) -> Result<(), Box> { if !self.target.as_ref().exists() { return self.command_runner.borrow().run_successfully( "git", args![ "clone", "--depth", "1", "-b", self.branch.as_ref(), self.source.as_ref(), self.target.as_ref(), ], ); } self._run_in_target_repo(&["fetch", self.source.as_ref(), self.branch.as_ref()])?; self._run_in_target_repo(&["merge", "FETCH_HEAD"])?; Ok(()) } } #[cfg(test)] mod test {}