summaryrefslogtreecommitdiffstats
path: root/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java')
-rw-r--r--gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java185
1 files changed, 185 insertions, 0 deletions
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java
new file mode 100644
index 0000000000..a368706d6e
--- /dev/null
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java
@@ -0,0 +1,185 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.httpd.rpc.project;
+
+import com.google.gerrit.common.errors.InvalidNameException;
+import com.google.gerrit.common.errors.InvalidRevisionException;
+import com.google.gerrit.httpd.rpc.Handler;
+import com.google.gerrit.reviewdb.Branch;
+import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.ReplicationQueue;
+import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.ObjectWalk;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.List;
+
+class AddBranch extends Handler<List<Branch>> {
+ private static final Logger log = LoggerFactory.getLogger(AddBranch.class);
+
+ interface Factory {
+ AddBranch create(@Assisted Project.NameKey projectName,
+ @Assisted("branchName") String branchName,
+ @Assisted("startingRevision") String startingRevision);
+ }
+
+ private final ProjectControl.Factory projectControlFactory;
+ private final ListBranches.Factory listBranchesFactory;
+ private final IdentifiedUser identifiedUser;
+ private final GitRepositoryManager repoManager;
+ private final ReplicationQueue replication;
+
+ private final Project.NameKey projectName;
+ private final String branchName;
+ private final String startingRevision;
+
+ @Inject
+ AddBranch(final ProjectControl.Factory projectControlFactory,
+ final ListBranches.Factory listBranchesFactory,
+ final IdentifiedUser identifiedUser, final GitRepositoryManager repoManager,
+ final ReplicationQueue replication,
+
+ @Assisted Project.NameKey projectName,
+ @Assisted("branchName") String branchName,
+ @Assisted("startingRevision") String startingRevision) {
+ this.projectControlFactory = projectControlFactory;
+ this.listBranchesFactory = listBranchesFactory;
+ this.identifiedUser = identifiedUser;
+ this.repoManager = repoManager;
+ this.replication = replication;
+
+ this.projectName = projectName;
+ this.branchName = branchName;
+ this.startingRevision = startingRevision;
+ }
+
+ @Override
+ public List<Branch> call() throws NoSuchProjectException,
+ InvalidNameException, InvalidRevisionException, IOException {
+ final ProjectControl projectControl =
+ projectControlFactory.validateFor(projectName, ProjectControl.OWNER
+ | ProjectControl.VISIBLE);
+
+ String refname = branchName;
+ while (refname.startsWith("/")) {
+ refname = refname.substring(1);
+ }
+ if (!refname.startsWith(Constants.R_REFS)) {
+ refname = Constants.R_HEADS + refname;
+ }
+ if (!Repository.isValidRefName(refname)) {
+ throw new InvalidNameException();
+ }
+ if (!projectControl.canCreateRef(refname)) {
+ throw new IllegalStateException("Cannot create " + refname);
+ }
+
+ final Branch.NameKey name = new Branch.NameKey(projectName, refname);
+ final Repository repo = repoManager.openRepository(projectName.get());
+ try {
+ final ObjectId revid = parseStartingRevision(repo);
+ final RevWalk rw = verifyConnected(repo, revid);
+
+ try {
+ final RefUpdate u = repo.updateRef(refname);
+ u.setExpectedOldObjectId(ObjectId.zeroId());
+ u.setNewObjectId(revid);
+ u.setRefLogIdent(identifiedUser.newPersonIdent());
+ u.setRefLogMessage("created via web from " + startingRevision, false);
+ final RefUpdate.Result result = u.update(rw);
+ switch (result) {
+ case FAST_FORWARD:
+ case NEW:
+ case NO_CHANGE:
+ replication.scheduleUpdate(name.getParentKey(), refname);
+ break;
+ default: {
+ final String msg =
+ "Cannot create branch " + name + ": " + result.name();
+ log.error(msg);
+ throw new IOException(result.name());
+ }
+ }
+ } catch (IOException err) {
+ log.error("Cannot create branch " + name, err);
+ throw err;
+ }
+ } finally {
+ repo.close();
+ }
+
+ return listBranchesFactory.create(projectName).call();
+ }
+
+ private ObjectId parseStartingRevision(final Repository repo)
+ throws InvalidRevisionException {
+ try {
+ final ObjectId revid = repo.resolve(startingRevision);
+ if (revid == null) {
+ throw new InvalidRevisionException();
+ }
+ return revid;
+ } catch (IOException err) {
+ log.error("Cannot resolve \"" + startingRevision + "\" in project \""
+ + projectName + "\"", err);
+ throw new InvalidRevisionException();
+ }
+ }
+
+ private RevWalk verifyConnected(final Repository repo, final ObjectId revid)
+ throws InvalidRevisionException {
+ try {
+ final ObjectWalk rw = new ObjectWalk(repo);
+ try {
+ rw.markStart(rw.parseCommit(revid));
+ } catch (IncorrectObjectTypeException err) {
+ throw new InvalidRevisionException();
+ }
+ for (final Ref r : repo.getAllRefs().values()) {
+ try {
+ rw.markUninteresting(rw.parseAny(r.getObjectId()));
+ } catch (MissingObjectException err) {
+ continue;
+ }
+ }
+ rw.checkConnectivity();
+ return rw;
+ } catch (IncorrectObjectTypeException err) {
+ throw new InvalidRevisionException();
+ } catch (MissingObjectException err) {
+ throw new InvalidRevisionException();
+ } catch (IOException err) {
+ log.error("Repository \"" + repo.getDirectory()
+ + "\" may be corrupt; suggest running git fsck", err);
+ throw new InvalidRevisionException();
+ }
+ }
+}