summaryrefslogtreecommitdiff
path: root/ofborg/tickborg/src/clone.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ofborg/tickborg/src/clone.rs')
-rw-r--r--ofborg/tickborg/src/clone.rs173
1 files changed, 173 insertions, 0 deletions
diff --git a/ofborg/tickborg/src/clone.rs b/ofborg/tickborg/src/clone.rs
new file mode 100644
index 0000000000..0dcb71c2c5
--- /dev/null
+++ b/ofborg/tickborg/src/clone.rs
@@ -0,0 +1,173 @@
+use fs2::FileExt;
+
+use std::ffi::OsStr;
+use std::fs;
+use std::io::Error;
+use std::path::PathBuf;
+use std::process::{Command, Stdio};
+
+use tracing::{debug, info, warn};
+
+pub struct Lock {
+ lock: Option<fs::File>,
+}
+
+impl Lock {
+ pub fn unlock(&mut self) {
+ self.lock = None
+ }
+}
+
+pub trait GitClonable {
+ fn clone_from(&self) -> String;
+ fn clone_to(&self) -> PathBuf;
+ fn extra_clone_args(&self) -> Vec<&OsStr>;
+
+ fn lock_path(&self) -> PathBuf;
+
+ fn lock(&self) -> Result<Lock, Error> {
+ debug!("Locking {:?}", self.lock_path());
+
+ match fs::File::create(self.lock_path()) {
+ Err(e) => {
+ warn!("Failed to create lock file {:?}: {}", self.lock_path(), e);
+ Err(e)
+ }
+ Ok(lock) => match lock.lock_exclusive() {
+ Err(e) => {
+ warn!(
+ "Failed to get exclusive lock on file {:?}: {}",
+ self.lock_path(),
+ e
+ );
+ Err(e)
+ }
+ Ok(_) => {
+ debug!("Got lock on {:?}", self.lock_path());
+ Ok(Lock { lock: Some(lock) })
+ }
+ },
+ }
+ }
+
+ fn clone_repo(&self) -> Result<(), Error> {
+ let mut lock = self.lock()?;
+
+ if self.clone_to().is_dir() {
+ debug!("Found dir at {:?}, initial clone is done", self.clone_to());
+ return Ok(());
+ }
+
+ info!(
+ "Initial cloning of {} to {:?}",
+ self.clone_from(),
+ self.clone_to()
+ );
+
+ let result = Command::new("git")
+ .arg("clone")
+ .args(self.extra_clone_args())
+ .arg(self.clone_from())
+ .arg(self.clone_to())
+ .stdout(Stdio::null())
+ .status()?;
+
+ lock.unlock();
+
+ if result.success() {
+ Ok(())
+ } else {
+ Err(Error::other(format!(
+ "Failed to clone from {:?} to {:?}",
+ self.clone_from(),
+ self.clone_to()
+ )))
+ }
+ }
+
+ fn fetch_repo(&self) -> Result<(), Error> {
+ let mut lock = self.lock()?;
+
+ info!("Fetching from origin in {:?}", self.clone_to());
+ let result = Command::new("git")
+ .arg("fetch")
+ .arg("origin")
+ .current_dir(self.clone_to())
+ .stdout(Stdio::null())
+ .status()?;
+
+ lock.unlock();
+
+ if result.success() {
+ Ok(())
+ } else {
+ Err(Error::other("Failed to fetch"))
+ }
+ }
+
+ fn clean(&self) -> Result<(), Error> {
+ let mut lock = self.lock()?;
+
+ debug!("git am --abort");
+ Command::new("git")
+ .arg("am")
+ .arg("--abort")
+ .current_dir(self.clone_to())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()?;
+
+ debug!("git merge --abort");
+ Command::new("git")
+ .arg("merge")
+ .arg("--abort")
+ .current_dir(self.clone_to())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()?;
+
+ debug!("git reset --hard");
+ Command::new("git")
+ .arg("reset")
+ .arg("--hard")
+ .current_dir(self.clone_to())
+ .stdout(Stdio::null())
+ .status()?;
+
+ debug!("git clean -x -d --force");
+ Command::new("git")
+ .arg("clean")
+ .arg("-x")
+ .arg("-d")
+ .arg("--force")
+ .current_dir(self.clone_to())
+ .stdout(Stdio::null())
+ .status()?;
+
+ lock.unlock();
+
+ Ok(())
+ }
+
+ fn checkout(&self, git_ref: &OsStr) -> Result<(), Error> {
+ let mut lock = self.lock()?;
+
+ debug!("git checkout {:?}", git_ref);
+ let result = Command::new("git")
+ .arg("checkout")
+ // we don't care if its dirty
+ .arg("--force")
+ .arg(git_ref)
+ .current_dir(self.clone_to())
+ .stdout(Stdio::null())
+ .status()?;
+
+ lock.unlock();
+
+ if result.success() {
+ Ok(())
+ } else {
+ Err(Error::other("Failed to checkout"))
+ }
+ }
+}