From d65f712ea3d8941f4b9145c0630c30c20af80d13 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Fri, 11 Nov 2011 17:22:21 -0500
Subject: [PATCH] Documentation. Add javadoc and source jars to the gbapi download.

---
 src/com/gitblit/FederationPullExecutor.java |  128 ++++++++++++++++++++++++++++++++++--------
 1 files changed, 103 insertions(+), 25 deletions(-)

diff --git a/src/com/gitblit/FederationPullExecutor.java b/src/com/gitblit/FederationPullExecutor.java
index 127e1fc..b190e7b 100644
--- a/src/com/gitblit/FederationPullExecutor.java
+++ b/src/com/gitblit/FederationPullExecutor.java
@@ -15,21 +15,28 @@
  */
 package com.gitblit;
 
+import static org.eclipse.jgit.lib.Constants.DOT_GIT_EXT;
+
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.net.InetAddress;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
 import org.slf4j.Logger;
@@ -37,14 +44,15 @@
 
 import com.gitblit.Constants.FederationPullStatus;
 import com.gitblit.Constants.FederationStrategy;
+import com.gitblit.GitBlitException.ForbiddenException;
 import com.gitblit.models.FederationModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.FederationUtils;
 import com.gitblit.utils.JGitUtils;
-import com.gitblit.utils.TimeUtils;
 import com.gitblit.utils.JGitUtils.CloneResult;
 import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TimeUtils;
 
 /**
  * FederationPullExecutor pulls repository updates and, optionally, user
@@ -56,6 +64,8 @@
 
 	private final List<FederationModel> registrations;
 
+	private final boolean isDaemon;
+
 	/**
 	 * Constructor for specifying a single federation registration. This
 	 * constructor is used to schedule the next pull execution.
@@ -63,7 +73,7 @@
 	 * @param registration
 	 */
 	private FederationPullExecutor(FederationModel registration) {
-		this(Arrays.asList(registration));
+		this(Arrays.asList(registration), true);
 	}
 
 	/**
@@ -72,9 +82,13 @@
 	 * on each registrations frequency setting.
 	 * 
 	 * @param registrations
+	 * @param isDaemon
+	 *            if true, registrations are rescheduled in perpetuity. if
+	 *            false, the federation pull operation is executed once.
 	 */
-	public FederationPullExecutor(List<FederationModel> registrations) {
+	public FederationPullExecutor(List<FederationModel> registrations, boolean isDaemon) {
 		this.registrations = registrations;
+		this.isDaemon = isDaemon;
 	}
 
 	/**
@@ -108,14 +122,16 @@
 						"Failed to pull from federated gitblit ({0} @ {1})", registration.name,
 						registration.url), t);
 			} finally {
-				schedule(registration);
+				if (isDaemon) {
+					schedule(registration);
+				}
 			}
 		}
 	}
 
 	/**
 	 * Mirrors a repository and, optionally, the server's users, and/or
-	 * configuration settings from a remote Gitblit instance.
+	 * configuration settings from a origin Gitblit instance.
 	 * 
 	 * @param registration
 	 * @throws Exception
@@ -148,6 +164,7 @@
 				continue;
 			}
 
+			// Determine local repository name
 			String repositoryName;
 			if (StringUtils.isEmpty(registrationFolder)) {
 				repositoryName = repository.name;
@@ -155,13 +172,32 @@
 				repositoryName = registrationFolder + "/" + repository.name;
 			}
 
+			if (registration.bare) {
+				// bare repository, ensure .git suffix
+				if (!repositoryName.toLowerCase().endsWith(DOT_GIT_EXT)) {
+					repositoryName += DOT_GIT_EXT;
+				}
+			} else {
+				// normal repository, strip .git suffix
+				if (repositoryName.toLowerCase().endsWith(DOT_GIT_EXT)) {
+					repositoryName = repositoryName.substring(0,
+							repositoryName.indexOf(DOT_GIT_EXT));
+				}
+			}
+
 			// confirm that the origin of any pre-existing repository matches
 			// the clone url
+			String fetchHead = null;
 			Repository existingRepository = GitBlit.self().getRepository(repositoryName);
 			if (existingRepository != null) {
 				StoredConfig config = existingRepository.getConfig();
 				config.load();
 				String origin = config.getString("remote", "origin", "url");
+				RevCommit commit = JGitUtils.getCommit(existingRepository,
+						"refs/remotes/origin/master");
+				if (commit != null) {
+					fetchHead = commit.getName();
+				}
 				existingRepository.close();
 				if (!origin.startsWith(registration.url)) {
 					logger.warn(MessageFormat
@@ -177,20 +213,64 @@
 					Constants.FEDERATION_USER, registration.token);
 			logger.info(MessageFormat.format("Pulling federated repository {0} from {1} @ {2}",
 					repository.name, registration.name, registration.url));
+
 			CloneResult result = JGitUtils.cloneRepository(registrationFolderFile, repository.name,
-					cloneUrl, credentials);
+					cloneUrl, registration.bare, credentials);
 			Repository r = GitBlit.self().getRepository(repositoryName);
 			RepositoryModel rm = GitBlit.self().getRepositoryModel(repositoryName);
+			repository.isFrozen = registration.mirror;
 			if (result.createdRepository) {
 				// default local settings
 				repository.federationStrategy = FederationStrategy.EXCLUDE;
-				repository.isFrozen = true;
+				repository.isFrozen = registration.mirror;
+				repository.showRemoteBranches = !registration.mirror;
+				logger.info(MessageFormat.format("     cloning {0}", repository.name));
+				registration.updateStatus(repository, FederationPullStatus.MIRRORED);
 			} else {
+				// fetch and update
+				boolean fetched = false;
+				RevCommit commit = JGitUtils.getCommit(r, "refs/remotes/origin/master");
+				String origin = commit.getName();
+				fetched = fetchHead == null || !fetchHead.equals(origin);
+
+				if (registration.mirror) {
+					// mirror
+					if (fetched) {
+						// reset the local HEAD to origin/master
+						Ref ref = JGitUtils.resetHEAD(r, "origin/master");
+						logger.info(MessageFormat.format("     resetting HEAD of {0} to {1}",
+								repository.name, ref.getObjectId().getName()));
+						registration.updateStatus(repository, FederationPullStatus.MIRRORED);
+					} else {
+						// indicate no commits pulled
+						registration.updateStatus(repository, FederationPullStatus.NOCHANGE);
+					}
+				} else {
+					// non-mirror
+					if (fetched) {
+						// indicate commits pulled to origin/master
+						registration.updateStatus(repository, FederationPullStatus.PULLED);
+					} else {
+						// indicate no commits pulled
+						registration.updateStatus(repository, FederationPullStatus.NOCHANGE);
+					}
+				}
+
 				// preserve local settings
 				repository.isFrozen = rm.isFrozen;
 				repository.federationStrategy = rm.federationStrategy;
+
+				// merge federation sets
+				Set<String> federationSets = new HashSet<String>();
+				if (rm.federationSets != null) {
+					federationSets.addAll(rm.federationSets);
+				}
+				if (repository.federationSets != null) {
+					federationSets.addAll(repository.federationSets);
+				}
+				repository.federationSets = new ArrayList<String>(federationSets);
 			}
-			// only repositories that are actually _cloned_ from the source
+			// only repositories that are actually _cloned_ from the origin
 			// Gitblit repository are marked as federated. If the origin
 			// is from somewhere else, these repositories are not considered
 			// "federated" repositories.
@@ -198,7 +278,6 @@
 
 			GitBlit.self().updateConfiguration(r, repository);
 			r.close();
-			registration.updateStatus(repository, FederationPullStatus.PULLED);
 		}
 
 		try {
@@ -212,7 +291,7 @@
 				for (UserModel user : users) {
 					userService.updateUserModel(user.username, user);
 
-					// merge the remote permissions and remote accounts into
+					// merge the origin permissions and origin accounts into
 					// the user accounts of this Gitblit instance
 					if (registration.mergeAccounts) {
 						// reparent all repository permissions if the local
@@ -242,13 +321,12 @@
 					}
 				}
 			}
-		} catch (Exception e) {
-			// a 403 error code is normal for a PULL_REPOSITORIES token
-			if (!e.getMessage().contains("403")) {
-				logger.warn(MessageFormat.format(
-						"Failed to retrieve USERS from federated gitblit ({0} @ {1})",
-						registration.name, registration.url), e);
-			}
+		} catch (ForbiddenException e) {
+			// ignore forbidden exceptions
+		} catch (IOException e) {
+			logger.warn(MessageFormat.format(
+					"Failed to retrieve USERS from federated gitblit ({0} @ {1})",
+					registration.name, registration.url), e);
 		}
 
 		try {
@@ -262,18 +340,17 @@
 				properties.store(os, null);
 				os.close();
 			}
-		} catch (Exception e) {
-			// a 403 error code is normal for a PULL_REPOSITORIES token
-			if (!e.getMessage().contains("403")) {
-				logger.warn(MessageFormat.format(
-						"Failed to retrieve SETTINGS from federated gitblit ({0} @ {1})",
-						registration.name, registration.url), e);
-			}
+		} catch (ForbiddenException e) {
+			// ignore forbidden exceptions
+		} catch (IOException e) {
+			logger.warn(MessageFormat.format(
+					"Failed to retrieve SETTINGS from federated gitblit ({0} @ {1})",
+					registration.name, registration.url), e);
 		}
 	}
 
 	/**
-	 * Sends a status acknowledgment to the source Gitblit instance. This
+	 * Sends a status acknowledgment to the origin Gitblit instance. This
 	 * includes the results of the federated pull.
 	 * 
 	 * @param registration
@@ -290,6 +367,7 @@
 			federationName = addr.getHostName();
 		}
 		FederationUtils.acknowledgeStatus(addr.getHostAddress(), registration);
+		logger.info(MessageFormat.format("Pull status sent to {0}", registration.url));
 	}
 
 	/**

--
Gitblit v1.9.1