diff options
author | Grzegorz Kossakowski <grek@google.com> | 2009-09-10 12:54:44 -0700 |
---|---|---|
committer | Grzegorz Kossakowski <grek@google.com> | 2009-09-10 14:32:09 -0700 |
commit | 8c9bfc4a89bdf71280d5f18926996c361e44071a (patch) | |
tree | 9cf0d24db8b9ce16139d07c0fd889e5082e523e8 | |
parent | a6992c36fc0d23bba01e6f07e2eb2f998b535079 (diff) | |
download | gimd-8c9bfc4a89bdf71280d5f18926996c361e44071a.tar.gz |
Added branch support for JGit-based implementation of Database trait.
Introduced JGitBranch class which holds complete information about branch:
its name and repository where it's defined.
Since now JGitDatabase can be constructed out of JGitBranch only.
Also adapted all JGit-related test-cases to operate on specific branch
instead of repository instance alone.
Change-Id: I35a89c7d9dc12d2cb0d9efad98cfa9dde0f54d38
Signed-off-by: Grzegorz Kossakowski <grek@google.com>
10 files changed, 107 insertions, 53 deletions
diff --git a/src/main/scala/com/google/gimd/jgit/InvalidJGitBranchNameException.scala b/src/main/scala/com/google/gimd/jgit/InvalidJGitBranchNameException.scala new file mode 100644 index 0000000..e3c65f7 --- /dev/null +++ b/src/main/scala/com/google/gimd/jgit/InvalidJGitBranchNameException.scala @@ -0,0 +1,22 @@ +// 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.gimd.jgit + +import org.spearce.jgit.lib.Repository + +final class InvalidJGitBranchNameException(val repository: Repository, name: String) + extends JGitDatabaseException(JGitBranch(repository, ""), //not sure if creating artificial + //branch istance is a good idea + "'%1s' is invalid branch name".format(name)) diff --git a/src/main/scala/com/google/gimd/jgit/JGitBranch.scala b/src/main/scala/com/google/gimd/jgit/JGitBranch.scala new file mode 100644 index 0000000..081463d --- /dev/null +++ b/src/main/scala/com/google/gimd/jgit/JGitBranch.scala @@ -0,0 +1,30 @@ +// 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.gimd.jgit + +import org.spearce.jgit.lib.Repository + +/** + * <p>Class that stores information about branch which consists of name of branch and repository + * where that branch is stored.</p> + * + * @throws InvalidJGitBranchNameException if supplied <code>name</code> does not pass + * <code>Repository.isValidRefName</code> test. + */ +@throws(classOf[InvalidJGitBranchNameException]) +final case class JGitBranch(repository: Repository, name: String) { + if (!Repository.isValidRefName(name)) + throw new InvalidJGitBranchNameException(repository, name) +} diff --git a/src/main/scala/com/google/gimd/jgit/JGitDatabase.scala b/src/main/scala/com/google/gimd/jgit/JGitDatabase.scala index 0b02a6f..760ccb8 100644 --- a/src/main/scala/com/google/gimd/jgit/JGitDatabase.scala +++ b/src/main/scala/com/google/gimd/jgit/JGitDatabase.scala @@ -24,7 +24,7 @@ import org.spearce.jgit.lib.RefUpdate.Result import org.spearce.jgit.dircache.{DirCache, DirCacheEditor, DirCacheEntry} import org.spearce.jgit.revwalk.{RevCommit, RevTree, RevWalk} -final class JGitDatabase(repository: Repository) extends Database { +final class JGitDatabase(branch: JGitBranch) extends Database { /** * The maximal number of merge/transaction rebase retries. @@ -42,12 +42,14 @@ final class JGitDatabase(repository: Repository) extends Database { */ private val MERGE_RETRIES = 10 + private val repository = branch.repository + def latestSnapshot: JGitSnapshot = { try { - val id = repository.resolve(Constants.HEAD) - new JGitSnapshot(repository, new RevWalk(repository).parseCommit(id)) + val id = repository.resolve(branch.name) + new JGitSnapshot(branch, new RevWalk(repository).parseCommit(id)) } catch { - case e: IOException => throw new JGitDatabaseException(repository, e) + case e: IOException => throw new JGitDatabaseException(branch, e) } } @@ -56,37 +58,37 @@ final class JGitDatabase(repository: Repository) extends Database { retry(MERGE_RETRIES) { val snapshot = latestSnapshot val dbModification = modification(snapshot) - applyModification(dbModification, Constants.HEAD, snapshot.commit) + applyModification(dbModification, snapshot.commit) } } catch { - case e: IOException => throw new JGitDatabaseException(repository, e) + case e: IOException => throw new JGitDatabaseException(branch, e) } if (!successful) - throw new JGitMergeRetriesExceededException(repository, MERGE_RETRIES) + throw new JGitMergeRetriesExceededException(branch, MERGE_RETRIES) } - def applyModification(modification: DatabaseModification, branch: String, onto: RevCommit): + def applyModification(modification: DatabaseModification, onto: RevCommit): Boolean = { val treeId = writeMessages(modification, onto.getTree) val commitId = createCommit(treeId, onto) - val result = updateRef(branch, onto, commitId) + val result = updateRef(onto, commitId) result match { //there was no change to database since onto commit so changes were applied cleanly case Result.FAST_FORWARD => true //if there was a change since onto commit update gets rejected. Still it might be that change //did not affected files we are trying to modify. Thus we are trying merging both changes. - case Result.REJECTED => tryMerging(branch, commitId) + case Result.REJECTED => tryMerging(commitId) //TODO: There should be a special treatment of LOCK_FAILURE case but it's low-priority task //the idea is to not try merging if just JGit fails to obtain lock for given reference case _ => - throw new JGitDatabaseException(repository, + throw new JGitDatabaseException(branch, "RefUpdate returned unexpected result: %1s.".format(result)) } } - private def updateRef(name: String, oldCommit: ObjectId, newCommit: ObjectId): Result = { - val refUpdate = repository.updateRef(name) + private def updateRef(oldCommit: ObjectId, newCommit: ObjectId): Result = { + val refUpdate = repository.updateRef(branch.name) refUpdate.setExpectedOldObjectId(oldCommit) refUpdate.setNewObjectId(newCommit) refUpdate.update() @@ -130,20 +132,20 @@ final class JGitDatabase(repository: Repository) extends Database { dirCache.writeTree(objectWriter) } - private def merge(branch: String, commitToBeMerged: ObjectId): Boolean = { - val baseCommit = repository.resolve(branch) + private def merge(commitToBeMerged: ObjectId): Boolean = { + val baseCommit = repository.resolve(branch.name) val merger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(repository) if (merger.merge(baseCommit, commitToBeMerged)) { val treeId = merger.getResultTreeId val mergeCommit = createCommit(treeId, baseCommit, commitToBeMerged) - val result = updateRef(branch, baseCommit, mergeCommit) + val result = updateRef(baseCommit, mergeCommit) Result.FAST_FORWARD == result } else false } - private def tryMerging(branch: String, commitToBeMerged: ObjectId) = - retry(MERGE_RETRIES)(merge(branch, commitToBeMerged)) + private def tryMerging(commitToBeMerged: ObjectId) = + retry(MERGE_RETRIES)(merge(commitToBeMerged)) private def retry(howManyTimes: Int)(what: => Boolean): Boolean = if (howManyTimes > 0) diff --git a/src/main/scala/com/google/gimd/jgit/JGitDatabaseException.scala b/src/main/scala/com/google/gimd/jgit/JGitDatabaseException.scala index 1245df9..16429a3 100644 --- a/src/main/scala/com/google/gimd/jgit/JGitDatabaseException.scala +++ b/src/main/scala/com/google/gimd/jgit/JGitDatabaseException.scala @@ -14,14 +14,11 @@ package com.google.gimd.jgit +case class JGitDatabaseException(val branch: JGitBranch, + val msg: String, + val cause: Throwable) extends GimdException(msg, cause) { -import org.spearce.jgit.lib.Repository + def this(branch: JGitBranch, msg: String) = this(branch, msg, null) -class JGitDatabaseException(val repository: Repository, - val msg: String, - val cause: Throwable) extends GimdException(msg, cause) { - - def this(repository: Repository, msg: String) = this(repository, msg, null) - - def this(repository: Repository, cause: Throwable) = this(repository, null, cause) + def this(branch: JGitBranch, cause: Throwable) = this(branch, null, cause) } diff --git a/src/main/scala/com/google/gimd/jgit/JGitFile.scala b/src/main/scala/com/google/gimd/jgit/JGitFile.scala index dd110d5..4cdf3ca 100644 --- a/src/main/scala/com/google/gimd/jgit/JGitFile.scala +++ b/src/main/scala/com/google/gimd/jgit/JGitFile.scala @@ -20,15 +20,15 @@ import org.spearce.jgit.lib.{ObjectId, Repository} import text.Parser final class JGitFile[T](val path: String, val blobId: ObjectId, val fileType: FileType[T], - val repository: Repository) extends File[T] { + val branch: JGitBranch) extends File[T] { lazy val message = Parser.parse(new InputStreamReader(blobInputStream, "UTF-8")) lazy val userObject = fileType.userType.toUserObject(message) private lazy val blobInputStream = { - val objectLoader = repository.openBlob(blobId) + val objectLoader = branch.repository.openBlob(blobId) if (objectLoader == null) - throw new JGitDatabaseException(repository, "Blob '" + blobId.name + "' does not exist.") + throw new JGitDatabaseException(branch, "Blob '" + blobId.name + "' does not exist.") new ByteArrayInputStream(objectLoader.getCachedBytes) } diff --git a/src/main/scala/com/google/gimd/jgit/JGitMergeRetriesExceededException.scala b/src/main/scala/com/google/gimd/jgit/JGitMergeRetriesExceededException.scala index b982850..ca2bb2a 100644 --- a/src/main/scala/com/google/gimd/jgit/JGitMergeRetriesExceededException.scala +++ b/src/main/scala/com/google/gimd/jgit/JGitMergeRetriesExceededException.scala @@ -21,6 +21,6 @@ import org.spearce.jgit.lib.Repository * * @see JGitDatabase */ -class JGitMergeRetriesExceededException(override val repository: Repository, val retries: Int) - extends JGitDatabaseException(repository, ("Tried to rebase transaction %1s times and " + +class JGitMergeRetriesExceededException(override val branch: JGitBranch, val retries: Int) + extends JGitDatabaseException(branch, ("Tried to rebase transaction %1s times and " + "failed to merge changes successfuly. Aborting.").format(retries)) diff --git a/src/main/scala/com/google/gimd/jgit/JGitSnapshot.scala b/src/main/scala/com/google/gimd/jgit/JGitSnapshot.scala index 2fd01ef..1f8f553 100644 --- a/src/main/scala/com/google/gimd/jgit/JGitSnapshot.scala +++ b/src/main/scala/com/google/gimd/jgit/JGitSnapshot.scala @@ -20,10 +20,10 @@ import org.spearce.jgit.revwalk.RevCommit import org.spearce.jgit.treewalk.filter.{PathFilter, PathSuffixFilter, AndTreeFilter, TreeFilter} import org.spearce.jgit.treewalk.TreeWalk -final class JGitSnapshot(val repository: Repository, val commit: RevCommit) extends Snapshot { +final class JGitSnapshot(val branch: JGitBranch, val commit: RevCommit) extends Snapshot { def all[T](fileType: FileType[T]): Iterator[File[T]] = { - val treeWalk = new TreeWalk(repository) + val treeWalk = new TreeWalk(branch.repository) treeWalk.reset(commit.getTree) treeWalk.setRecursive(true) treeWalk.setFilter(treeFilter(fileType)) @@ -35,7 +35,7 @@ final class JGitSnapshot(val repository: Repository, val commit: RevCommit) exte if (!hasNext) throw new NoSuchElementException val result = - new JGitFile(treeWalk.getPathString, treeWalk.getObjectId(0), fileType, repository) + new JGitFile(treeWalk.getPathString, treeWalk.getObjectId(0), fileType, branch) doesHasNext = treeWalk.next result } diff --git a/src/test/scala/com/google/gimd/jgit/AbstractJGitTestCase.scala b/src/test/scala/com/google/gimd/jgit/AbstractJGitTestCase.scala index ad8f110..33de36f 100644 --- a/src/test/scala/com/google/gimd/jgit/AbstractJGitTestCase.scala +++ b/src/test/scala/com/google/gimd/jgit/AbstractJGitTestCase.scala @@ -14,23 +14,26 @@ package com.google.gimd.jgit - import java.io.{ByteArrayInputStream, IOException, File} import org.junit.{After, Before} import org.spearce.jgit.lib._ + abstract class AbstractJGitTestCase { private val repositoryPath = "test-repository/.git" - var repository: Repository = null + protected val masterRef = Constants.R_HEADS + Constants.MASTER + + protected var masterBranch: JGitBranch = null @Before protected def createRepository { val file = new File(repositoryPath) - repository = new Repository(file) + val repository = new Repository(file) if (file.exists) throw new IOException("Repository already exists: " + file) file.mkdirs() repository.create() + masterBranch = JGitBranch(repository, masterRef) } @After protected def removeRepository { @@ -38,7 +41,7 @@ abstract class AbstractJGitTestCase { } protected def writeTextContent(text: String): ObjectId = { - val ow = new ObjectWriter(repository) + val ow = new ObjectWriter(masterBranch.repository) ow.writeBlob(text.getBytes("UTF-8")) } @@ -55,11 +58,11 @@ abstract class AbstractJGitTestCase { builder.add(entry) } builder.finish() - dc.writeTree(new ObjectWriter(repository)) + dc.writeTree(new ObjectWriter(masterBranch.repository)) } protected def createCommit(message: String, treeId: ObjectId): ObjectId = { - val commit = new Commit(repository, Array()) + val commit = new Commit(masterBranch.repository, Array()) val person = new PersonIdent("A U Thor", "author@example.com") commit.setAuthor(person) commit.setCommitter(person) @@ -69,8 +72,8 @@ abstract class AbstractJGitTestCase { commit.getCommitId } - protected def moveHEAD(commitId: ObjectId) { - val refUpdate = repository.updateRef(Constants.HEAD) + protected def moveMaster(commitId: ObjectId) { + val refUpdate = masterBranch.repository.updateRef(masterRef) refUpdate.setNewObjectId(commitId) refUpdate.forceUpdate() } diff --git a/src/test/scala/com/google/gimd/jgit/JGitDatabaseTestCase.scala b/src/test/scala/com/google/gimd/jgit/JGitDatabaseTestCase.scala index 14ad484..7fdfaf7 100644 --- a/src/test/scala/com/google/gimd/jgit/JGitDatabaseTestCase.scala +++ b/src/test/scala/com/google/gimd/jgit/JGitDatabaseTestCase.scala @@ -52,7 +52,7 @@ final class JGitDatabaseTestCase extends AbstractJGitTestCase { ) commit(files) - val db = new JGitDatabase(repository) + val db = new JGitDatabase(masterBranch) val foundFiles = db.latestSnapshot.all(SimpleMessageFileType).toList @@ -72,7 +72,7 @@ final class JGitDatabaseTestCase extends AbstractJGitTestCase { ) commit(files) - val db = new JGitDatabase(repository) + val db = new JGitDatabase(masterBranch) val foundFiles = db.latestSnapshot.all(SimpleMessageFileType).toList @@ -89,11 +89,11 @@ final class JGitDatabaseTestCase extends AbstractJGitTestCase { entry.setObjectId(writeTextContent("text content")) builder.add(entry) builder.finish() - val treeId = dc.writeTree(new org.spearce.jgit.lib.ObjectWriter(repository)) + val treeId = dc.writeTree(new org.spearce.jgit.lib.ObjectWriter(masterBranch.repository)) val commitId = createCommit("Test commit", treeId) - moveHEAD(commitId) + moveMaster(commitId) - val db = new JGitDatabase(repository) + val db = new JGitDatabase(masterBranch) val foundFiles = db.latestSnapshot.all(SimpleMessageFileType).toList assertEquals(Nil, foundFiles) @@ -112,7 +112,7 @@ final class JGitDatabaseTestCase extends AbstractJGitTestCase { ) commit(files) - val db = new JGitDatabase(repository) + val db = new JGitDatabase(masterBranch) db.modify { snapshot => val sms = snapshot.query(SimpleMessageFileType, (sm: SimpleMessage) => sm.name == "second") @@ -140,7 +140,7 @@ final class JGitDatabaseTestCase extends AbstractJGitTestCase { ) commit(files) - val db = new JGitDatabase(repository) + val db = new JGitDatabase(masterBranch) db.modify { snapshot => val sms = snapshot.query(SimpleMessageFileType, (sm: SimpleMessage) => sm.name == "second") @@ -158,7 +158,7 @@ final class JGitDatabaseTestCase extends AbstractJGitTestCase { private def commit(files: List[(String, ObjectId)]) { val treeId = addFiles(files) val commitId = createCommit("Test", treeId) - moveHEAD(commitId) + moveMaster(commitId) } } diff --git a/src/test/scala/com/google/gimd/jgit/JGitFileTestCase.scala b/src/test/scala/com/google/gimd/jgit/JGitFileTestCase.scala index ec1a7ee..2c1ca42 100644 --- a/src/test/scala/com/google/gimd/jgit/JGitFileTestCase.scala +++ b/src/test/scala/com/google/gimd/jgit/JGitFileTestCase.scala @@ -45,7 +45,7 @@ class JGitFileTestCase extends AbstractJGitTestCase { val blobId = writeTextContent(expected.toString) - val jGitFile = new JGitFile("test", blobId, SimpleMessageFileType, repository) + val jGitFile = new JGitFile("test", blobId, SimpleMessageFileType, masterBranch) assertEquals(expected, jGitFile.message) } @@ -56,13 +56,13 @@ class JGitFileTestCase extends AbstractJGitTestCase { val blobId = writeTextContent(message.toString) - val jGitFile = new JGitFile("test", blobId, SimpleMessageFileType, repository) + val jGitFile = new JGitFile("test", blobId, SimpleMessageFileType, masterBranch) assertEquals(expected, jGitFile.userObject) } @Test{val expected = classOf[JGitDatabaseException]} def testMessageOfNonExistingObject { - val jGitFile = new JGitFile("test", ObjectId.zeroId, SimpleMessageFileType, repository) + val jGitFile = new JGitFile("test", ObjectId.zeroId, SimpleMessageFileType, masterBranch) jGitFile.message } } |