aboutsummaryrefslogtreecommitdiff
path: root/src/update
diff options
context:
space:
mode:
authorMax Audron <audron@cocaine.farm>2022-06-07 12:28:18 +0200
committerMaximilian Manz <maximilian.manz@de.clara.net>2022-06-20 11:33:04 +0200
commite9dc01ffb547d0fa605bfe38b34672ddd5161be4 (patch)
tree5ca50547512b7cc2256ef457d468c4252ae23a0b /src/update
parentimplement cloning of new repos (diff)
reorganize file structure and cleanup lints
Diffstat (limited to 'src/update')
-rw-r--r--src/update/mod.rs114
1 files changed, 112 insertions, 2 deletions
diff --git a/src/update/mod.rs b/src/update/mod.rs
index 0991b1a..dfc800c 100644
--- a/src/update/mod.rs
+++ b/src/update/mod.rs
@@ -1,9 +1,14 @@
-use gtree::local::Repos;
+use std::fmt::{Debug, Display};
+
+use git2::BranchType;
+use tracing::debug;
+
+use crate::repo::{Repo, RepoError, Repos};
impl crate::GTree {
pub async fn update(&self, repos: Repos) {
for mut repo in repos {
- if let Some(_) = repo.repo {
+ if repo.repo.is_some() {
match repo.update() {
Ok(u) => println!("{}", u),
Err(u) => println!("{}", u),
@@ -12,3 +17,108 @@ impl crate::GTree {
}
}
}
+
+impl Repo {
+ /// Fetch any new state from the remote and fast forward merge changes into local branches
+ #[tracing::instrument(level = "trace")]
+ pub fn update(&mut self) -> Result<UpdateResult, UpdateResult> {
+ let repo_name = self.name.clone();
+ if self.repo.is_some() {
+ self.update_inner()
+ .map_err(|e| UpdateResult::err(repo_name, e))
+ } else {
+ Ok(UpdateResult::err(repo_name, RepoError::NoLocalRepo))
+ }
+ }
+
+ fn update_inner(&mut self) -> Result<UpdateResult, RepoError> {
+ let repo = self.repo.as_ref().unwrap();
+ let mut remote = self.main_remote(repo)?;
+
+ self.fetch(&mut remote)?;
+
+ self.default_branch = remote.default_branch()?.as_str().unwrap().to_string();
+
+ debug!("default branch: {}", self.default_branch);
+
+ if self.is_clean()? {
+ debug!("repo is clean");
+
+ let merged = repo.branches(Some(BranchType::Local))?
+ .filter_map(|x| x.ok())
+ .try_fold(false, |mut merged, (mut branch, _)| {
+ let name = format!("refs/heads/{}", Repo::branch_name(&branch));
+
+ if branch.upstream().is_ok() {
+ let upstream = branch.upstream().unwrap();
+
+ debug!("branch: {}", name);
+
+ merged |= self.merge(repo, &mut branch, &upstream)?;
+ Ok::<bool, RepoError>(merged)
+ } else {
+ debug!("not updating branch: {}: branch does not have upstream tracking branch set", name);
+ Ok(merged)
+ }
+ })?;
+
+ if merged {
+ Ok(UpdateResult::merged(self.name.clone()))
+ } else {
+ Ok(UpdateResult::no_changes(self.name.clone()))
+ }
+ } else {
+ Ok(UpdateResult::dirty(self.name.clone()))
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum UpdateResult {
+ NoChanges { name: String },
+ Dirty { name: String },
+ Merged { name: String },
+ Error { name: String, error: RepoError },
+}
+
+impl UpdateResult {
+ pub fn err(name: String, error: RepoError) -> UpdateResult {
+ UpdateResult::Error { name, error }
+ }
+
+ pub fn merged(name: String) -> UpdateResult {
+ UpdateResult::Merged { name }
+ }
+
+ pub fn dirty(name: String) -> UpdateResult {
+ UpdateResult::Dirty { name }
+ }
+
+ pub fn no_changes(name: String) -> UpdateResult {
+ UpdateResult::NoChanges { name }
+ }
+}
+
+impl Display for UpdateResult {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use ansi_term::Colour::{Blue, Green, Red, Yellow};
+
+ match self {
+ UpdateResult::NoChanges { name } => {
+ f.write_fmt(format_args!("{} {}", Blue.paint("FETCHED"), name))
+ }
+ UpdateResult::Dirty { name } => {
+ f.write_fmt(format_args!("{} {}", Yellow.paint("DIRTY "), name))
+ }
+ UpdateResult::Merged { name } => {
+ f.write_fmt(format_args!("{} {}", Green.paint("PULLED "), name))
+ }
+ UpdateResult::Error { name, error } => f.write_fmt(format_args!(
+ "{} {} [{}]",
+ Red.paint("ERROR "),
+ name,
+ error
+ )),
+ }
+ }
+}