diff options
author | Edwin Kempin <edwin.kempin@sap.com> | 2013-09-12 15:24:56 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-02-10 21:05:17 +0000 |
commit | 70371bc583fa0387e66ec42d6504641e2f5d7779 (patch) | |
tree | 5de8833789bc7d18057015eed1c3b8c6ec5b6c60 | |
parent | e5cb89869362bc0d75b786561c77952f3f5896d9 (diff) |
Create missing repositories on the remote site
If during the replication of a ref it is found that the repository is
missing on the remote site automatically create it on the remote
site.
E.g. a repository can be missing on the remote site if the remote
site was not available at the moment when a new project was created
and hence the repository for the new project could not be created on
the remote site.
This feature can also help to simplify the setup of a new remote site.
Whether missing repositories should be created or not can be
configured per destination. By default missing repositories are
created. This is a change of the current behaviour but for most
configurations it makes sense that the missing repositories are
created which is why this should be the default.
Change-Id: I4e587cdfca09445c9b1c528b2f1edae0944aec68
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
(cherry picked from commit a9fcff5c4d0d99d7bc209431377bdba01ee04c2c)
Reviewed-by: Ismo Haataja <ismo.haataja@digia.com>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
4 files changed, 61 insertions, 8 deletions
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java index 65e9631..1054aed 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java @@ -81,13 +81,14 @@ class Destination { private final PushOne.Factory opFactory; private final ProjectControl.Factory projectControlFactory; private final GitRepositoryManager gitManager; + private final boolean createMissingRepos; private final boolean replicatePermissions; private final String remoteNameStyle; private volatile WorkQueue.Executor pool; private final PerThreadRequestScope.Scoper threadScoper; protected static enum RetryReason { - TRANSPORT_ERROR, COLLISION; + TRANSPORT_ERROR, COLLISION, REPOSITORY_MISSING; } Destination(final Injector injector, @@ -106,6 +107,8 @@ class Destination { poolThreads = Math.max(0, getInt(rc, cfg, "threads", 1)); poolName = "ReplicateTo-" + rc.getName(); + createMissingRepos = + cfg.getBoolean("remote", rc.getName(), "createMissingRepositories", true); replicatePermissions = cfg.getBoolean("remote", rc.getName(), "replicatePermissions", true); remoteNameStyle = Objects.firstNonNull( @@ -438,6 +441,10 @@ class Destination { return false; } + boolean isCreateMissingRepos() { + return createMissingRepos; + } + boolean isReplicatePermissions() { return replicatePermissions; } diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java index 596d4ac..897d120 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java @@ -21,6 +21,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.git.ChangeCache; @@ -91,6 +92,7 @@ class PushOne implements ProjectRunnable { private final TagCache tagCache; private final PerThreadRequestScope.Scoper threadScoper; private final ChangeCache changeCache; + private final ReplicationQueue replicationQueue; private final Project.NameKey projectName; private final URIish uri; @@ -112,6 +114,7 @@ class PushOne implements ProjectRunnable { final TagCache tc, final PerThreadRequestScope.Scoper ts, final ChangeCache cc, + final ReplicationQueue rq, @Assisted final Project.NameKey d, @Assisted final URIish u) { gitManager = grm; @@ -122,6 +125,7 @@ class PushOne implements ProjectRunnable { tagCache = tc; threadScoper = ts; changeCache = cc; + replicationQueue = rq; projectName = d; uri = u; } @@ -268,7 +272,18 @@ class PushOne implements ProjectRunnable { log.error("Cannot replicate " + projectName + "; " + e.getMessage()); } catch (NoRemoteRepositoryException e) { - wrappedLog.error("Cannot replicate to " + uri + "; repository not found", getStatesAsArray()); + if (pool.isCreateMissingRepos()) { + try { + createRepository(); + log.warn("Missing repository created; retry replication to " + uri); + pool.reschedule(this, Destination.RetryReason.REPOSITORY_MISSING); + } catch (IOException ioe) { + wrappedLog.error("Cannot replicate to " + uri + "; failed to create missing repository", + ioe, getStatesAsArray()); + } + } else { + wrappedLog.error("Cannot replicate to " + uri + "; repository not found", getStatesAsArray()); + } } catch (NotSupportedException e) { wrappedLog.error("Cannot replicate to " + uri, e, getStatesAsArray()); @@ -301,6 +316,23 @@ class PushOne implements ProjectRunnable { } } + private void createRepository() throws IOException { + final Ref head = git.getRef(Constants.HEAD); + NewProjectCreatedListener.Event event = + new NewProjectCreatedListener.Event() { + @Override + public String getProjectName() { + return projectName.get(); + } + + @Override + public String getHeadName() { + return head != null ? head.getName() : null; + } + }; + replicationQueue.onNewProjectCreated(event); + } + private void runImpl() throws IOException { Transport tn = Transport.open(git, uri); PushResult res; diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java index a39d61c..502994a 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java @@ -319,9 +319,11 @@ class ReplicationQueue implements try { repo.create(true /* bare */); - RefUpdate u = repo.updateRef(Constants.HEAD); - u.disableRefLog(); - u.link(head); + if (head != null) { + RefUpdate u = repo.updateRef(Constants.HEAD); + u.disableRefLog(); + u.link(head); + } } finally { repo.close(); } @@ -333,9 +335,11 @@ class ReplicationQueue implements private static void createRemoteSsh(URIish uri, String head) { String quotedPath = QuotedString.BOURNE.quote(uri.getPath()); String cmd = "mkdir -p " + quotedPath - + "&& cd " + quotedPath - + "&& git init --bare" - + "&& git symbolic-ref HEAD " + QuotedString.BOURNE.quote(head); + + " && cd " + quotedPath + + " && git init --bare"; + if (head != null) { + cmd = cmd + " && git symbolic-ref HEAD " + QuotedString.BOURNE.quote(head); + } OutputStream errStream = newErrorBufferStream(); try { RemoteSession ssh = connect(uri); diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index 5205025..e22409a 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md @@ -205,6 +205,16 @@ remote.NAME.authGroup By default, replicates without group control, i.e. replicates everything to all remotes. +remote.NAME.createMissingRepositories +: If true, a repository is automatically created on the remote site + if during the replication of a ref it is found to be missing. + E.g. a repository can be missing on the remote site if the remote + site was not available at the moment when a new project was created + and hence the repository for the new project could not be created on + the remote site. + + By default, true, missing repositories are created. + remote.NAME.replicatePermissions : If true, permissions-only projects and the refs/meta/config branch will also be replicated to the remote site. These |