From a88763958c5228e68540405431ce853c69746b55 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Thu, 31 May 2018 20:45:49 +0100 Subject: [PATCH] Start redefining GitDB interface with a new test plan --- src/main/java/net/kemitix/gitdb/GitDB.java | 67 ++++-- .../java/net/kemitix/gitdb/GitDBLocal.java | 221 ++++++++++++------ .../java/net/kemitix/gitdb/GitDBTest.java | 119 ++++++++-- 3 files changed, 294 insertions(+), 113 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/GitDB.java b/src/main/java/net/kemitix/gitdb/GitDB.java index 810038e..03137b6 100644 --- a/src/main/java/net/kemitix/gitdb/GitDB.java +++ b/src/main/java/net/kemitix/gitdb/GitDB.java @@ -1,33 +1,64 @@ package net.kemitix.gitdb; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; + +import java.io.Closeable; +import java.io.IOException; import java.nio.file.Path; import java.util.stream.Stream; -public interface GitDB { +public interface GitDB extends Closeable { - static GitDB local(Path dbDir) { - return new GitDBLocal(dbDir); + /** + * Open an existing local gitdb. + * + * @param dbDir the path to the local repo + * @return a GitDB instance for the local gitdb + */ + static GitDB local(final Path dbDir) throws IOException { + return new GitDBLocal(Git.open(dbDir.toFile())); } - void close(); + /** + * Initialise a new local gitdb. + * + * @param dbDir the path to initialise the local repo in + * @return a GitDB instance for the created local gitdb + */ + static GitDB initLocal(final Path dbDir) throws GitAPIException { + return new GitDBLocal(Git.init() + .setGitDir(dbDir.toFile()) + .setBare(true) + .call()); + } - String get(Branch branch, Key key); + /** + * Select a branch. + * + * @param branch the branch to select + * @return a branch within the gitdb + */ + GitDbBranch branch(Branch branch); - T get(Branch branch, Key key, Class type); + interface GitDbBranch { - Stream getFiles(Branch branch, Key key); +// String get(Key key); +// +// T get(Key key, Class type); +// +// Key put(Message message, Document document, Author author); +// +// GitDbBranch delete(Branch branch, Key key, Message message, Author author); +// +// GitDbBranch tag(Reference reference); +// +// Transaction startTransaction(Branch branch); +// +// GitDbBranch fork(Branch branch); - Stream getFiles(Branch branch, Key key, Class type); + } - String save(Branch branch, Message message, Document document, Author author); + Stream allBranches(); - String delete(Branch branch, Key key, Message message, Author author); - - void tag(Reference reference); - - void createBranch(Reference reference); - - Stream getAllBranches(); - - Transaction createTransaction(Branch branch); } diff --git a/src/main/java/net/kemitix/gitdb/GitDBLocal.java b/src/main/java/net/kemitix/gitdb/GitDBLocal.java index f66f290..9a71689 100644 --- a/src/main/java/net/kemitix/gitdb/GitDBLocal.java +++ b/src/main/java/net/kemitix/gitdb/GitDBLocal.java @@ -1,101 +1,182 @@ package net.kemitix.gitdb; +import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.*; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; -import java.io.IOException; +import java.io.*; import java.nio.file.Path; import java.util.Optional; import java.util.stream.Stream; +@RequiredArgsConstructor class GitDBLocal implements GitDB { - private final Repository repository; - - @SneakyThrows - GitDBLocal(final Path gitDir) { - this.repository = openRepo(gitDir) - .orElseGet(() -> initRepo(gitDir)); - } - - @SneakyThrows - private Repository initRepo(Path gitDir) { - return Git.init() - .setGitDir(gitDir.toFile()) - .setBare(true) - .call() - .getRepository(); - } - - private Optional openRepo(final Path gitDir) throws IOException { - final Repository build = new FileRepositoryBuilder() - .setBare() - .setMustExist(false) - .setGitDir(gitDir.toFile()) - .setup() - .build(); - if (build.getObjectDatabase().exists()) { - return Optional.of(build); - } else { - return Optional.empty(); - } - } + private final Git git; @Override public void close() { - repository.close(); + git.close(); } @Override - public String get(Branch branch, Key key) { - return get(branch, key, String.class); - } - - @Override - public T get(Branch branch, Key key, Class type) { + public GitDbBranch branch(Branch branch) { return null; } @Override - public Stream getFiles(Branch branch, Key key) { - return getFiles(branch, key, String.class); - } - - @Override - public Stream getFiles(Branch branch, Key key, Class type) { + public Stream allBranches() { return null; } - @Override - public String save(Branch branch, Message message, Document document, Author author) { - return document.getValue(); - } +// @Override +// public String get(Branch branch, Key key) { +// return get(branch, key, String.class); +// } +// +// @Override +// @SneakyThrows +// public T get(Branch branch, Key key, Class type) { + //branch +// final RefDatabase refDatabase = repository.getRefDatabase(); +// final String branchValue = branch.getValue(); +// final Ref refDatabaseRef = refDatabase.getRef(branchValue); +// final ObjectId commitId = refDatabaseRef.getObjectId(); +// +// final RevCommit revCommit = repository.parseCommit(commitId); +// final RevTree tree = revCommit.getTree(); +// tree.copyTo(System.out); +// +// final ObjectLoader open = repository.getObjectDatabase().open(objectId, Constants.OBJ_TREE); +// final byte[] bytes = open.getBytes(); +// final String s = new String(bytes); +// System.out.println("s = " + s); +// //key +// return null; +// } - @Override - public String delete(Branch branch, Key key, Message message, Author author) { - return null; - } +// @Override +// @SneakyThrows +// public String put(Branch branch, Message message, Document document, Author author) { +//// return document.getValue(); +// +// final ObjectInserter objectInserter = repository.newObjectInserter(); +// final ObjectReader objectReader = repository.newObjectReader(); +// final RevWalk revWalk = new RevWalk(repository); +// +// //blob +// System.out.println("document = " + document.getKey()); +// final ObjectId blobId = objectInserter.insert(Constants.OBJ_BLOB, document.getValue().getBytes(UTF_8)); +// //tree +// final TreeFormatter treeFormatter = new TreeFormatter(); +// treeFormatter.append(document.getKey().getValue(), FileMode.REGULAR_FILE, blobId); +// final ObjectId treeId = objectInserter.insert(treeFormatter); +// //commit +// final CommitBuilder commitBuilder = new CommitBuilder(); +// final PersonIdent ident = new PersonIdent(author.getName(), author.getEmail()); +// commitBuilder.setCommitter(ident); +// commitBuilder.setAuthor(ident); +// commitBuilder.setTreeId(treeId); +// commitBuilder.setMessage(message.getValue()); +// //TODO: setParentId() +// final ObjectId commitId = objectInserter.insert(commitBuilder); +// //branch +// final RevCommit revCommit = revWalk.parseCommit(commitId); +// revCommit.getShortMessage(); +// git.branchCreate() +// .setStartPoint(revCommit) +// .setName(branch.getValue()) +// .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.NOTRACK) +// .call(); +// +// //READ +// +// //block +// final String readBlob = new String(objectReader.open(blobId).getBytes()); +// System.out.println("readBlob = " + readBlob); +// final RevBlob revBlob = revWalk.lookupBlob(blobId); +// System.out.println("revBlob = " + revBlob); +// final String blobName = revBlob.name(); +// System.out.println("blobName = " + blobName); +// //tree +// final RevTree revTree = revWalk.lookupTree(treeId); +// System.out.println("revTree = " + revTree); +// final String treeName = revTree.name(); +// System.out.println("treeName = " + treeName); +// //commit +// System.out.println("revCommit= " + revCommit); +// final String commitName = revCommit.getName(); +// System.out.println("commitName= " + commitName); +// //branch +// final Ref branchRef = repository.getRefDatabase().getRef(branch.getValue()); +// System.out.println("branchRef = " + branchRef.getName()); +// +//// final TreeWalk treeWalk = new TreeWalk(repository); +//// treeWalk.addTree(treeId); +//// treeWalk.next(); +//// final String nameString = treeWalk.getNameString(); +//// System.out.println("name = " + nameString); +//// final ObjectId objectId = treeWalk.getObjectId(0); +//// System.out.println("objectId = " + objectId); +// +//// final ObjectLoader openTree = repository.newObjectReader().open(treeId); +//// final int type = openTree.openStream().getType(); +//// final long size = openTree.openStream().getSize(); +//// final String readTree = new String(openTree.getBytes()); +// +//// +//// //commit +//// final CommitBuilder commitBuilder = new CommitBuilder(); +//// commitBuilder.setAuthor(new PersonIdent(author.getName(), author.getEmail())); +//// commitBuilder.setCommitter(new PersonIdent(author.getName(), author.getEmail())); +//// commitBuilder.setMessage(message.getValue()); +//// findParentCommit(branch) +//// .ifPresent(commitBuilder::setParentId); +//// commitBuilder.setTreeId(treeId); +//// final ObjectId commitId = repository.newObjectInserter().insert(commitBuilder); +//// +//// //branch +//// repository.updateRef(branch.getValue()).setNewObjectId(commitId); +//// +//// //get +//// return get(branch, document.getKey()); +// return document.getValue(); +// } - @Override - public void tag(Reference reference) { +// @SneakyThrows +// private Optional findParentCommit(final Branch branch) { +// return Optional.ofNullable( +// repository.getRefDatabase() +// .getRef(branch.getValue())) +// .map(Ref::getObjectId); +// } - } - - @Override - public void createBranch(Reference reference) { - - } - - @Override - public Stream getAllBranches() { - return null; - } - - @Override - public Transaction createTransaction(Branch branch) { - return null; - } +// @Override +// public String delete(Branch branch, Key key, Message message, Author author) { +// return null; +// } +// +// @Override +// public void tag(Reference reference) { +// +// } +// +// @Override +// public void createBranch(Reference reference) { +// +// } +// +// @Override +// public Stream getAllBranches() { +// return null; +// } +// +// @Override +// public Transaction createTransaction(Branch branch) { +// return null; +// } } diff --git a/src/test/java/net/kemitix/gitdb/GitDBTest.java b/src/test/java/net/kemitix/gitdb/GitDBTest.java index c82c7d6..2cb0848 100644 --- a/src/test/java/net/kemitix/gitdb/GitDBTest.java +++ b/src/test/java/net/kemitix/gitdb/GitDBTest.java @@ -1,33 +1,39 @@ package net.kemitix.gitdb; -import org.junit.jupiter.api.AfterEach; +import org.eclipse.jgit.api.errors.GitAPIException; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; class GitDBTest { - private final Path dbDir = Files.createTempDirectory("gitdb"); - private final GitDB gitDB = GitDB.local(dbDir); private final Branch master = Branch.name("master"); private final Message message = Message.message(UUID.randomUUID().toString()); private final Key key = Key.name(UUID.randomUUID().toString()); private final Author author = Author.name("junit", "gitdb@kemitix.net"); - GitDBTest() throws IOException { + // When initialising a repo in a dir that doesn't exist then a bare repo is created + @Test + void initRepo_whenDirNotExist_thenCreateBareRepo() throws IOException, GitAPIException { + //given + final Path dir = dirDoesNotExist(); + //when + final GitDB gitdb = GitDB.initLocal(dir); + //then + assertThat(gitdb).isNotNull(); + assertThatIsBareRepo(dir); } - @Test - void shouldInitialiseGitDB() throws IOException { - //then - assertThat(gitDB).isNotNull(); - assertThat(Files.isDirectory(dbDir)).isTrue(); - assertThat(Files.newDirectoryStream(dbDir).iterator()) + private void assertThatIsBareRepo(final Path dbDir) throws IOException { + final DirectoryStream paths = Files.newDirectoryStream(dbDir); + assertThat(paths.iterator()) .contains( dbDir.resolve("branches"), dbDir.resolve("HEAD"), @@ -37,25 +43,88 @@ class GitDBTest { dbDir.resolve("hooks"), dbDir.resolve("objects") ); + final List config = Files.readAllLines(dbDir.resolve("config")); + assertThat(config).contains("\tbare = true"); } + private Path dirDoesNotExist() throws IOException { + return Files.createTempDirectory("gitdb"); + } + + // When initialising a repo in a dir that is a file then an exception is thrown @Test - void saveDocumentGivesSavedValue() { - //given - final String value = UUID.randomUUID().toString(); - final Document document = Document.create(key, value); - //when - final String result = gitDB.save(master, message, document, author); - //then - assertThat(result).isEqualTo(value); + void initRepo_whenDirIsFile_thenThrowException() { } - @AfterEach - void tearDown() throws IOException { - gitDB.close(); - Files.walk(dbDir) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); + // When initialising a repo in a dir is exists then an exception is thrown + @Test + void initRepo_whenDirExists_thenThrowException() { } + + // When opening a repo in a dir that doesn't exist then an exception is thrown + // When opening a repo in a dir that is a file then an exception is thrown + // When opening a repo in a dir that is not a bare repo then an exception is thrown + // When opening a repo in a dir that is a bare repo then GitDb is returned + + // Given a valid GitDb handle + // When select a branch that doesn't exist then an exception is thrown + // When select a valid branch then a GitDbBranch is returned + + // Given a valid GitDbBranch handle + // When getting a key that does not exist then return an empty Optional + // When putting a key/value pair then a GitDbBranch is returned + // When getting a key that does exist then the value is returned inside an Optional + // When removing a key that does not exist then the GitDbBranch is returned + // When removing a key that does exist then a GitDbBranch is returned + // When starting a named transaction then GitDbTransaction is returned + // When starting an anonymous transaction then a GitDbTransaction is returned + + // Given a GitDbTransaction handle + // When putting a new key/value pair then the GitDbBranch can't find it + // When putting an existing key/value pair then the GitDbBranch finds the original value + // When removing a key from then the GitDbBRanch still finds it + + // Given a GitDbTransaction handle with a added, updated and removed keys + // When closing the transaction an GitDbBranch is returned + // When closing the transaction the added key/value is found + // When closing the transaction the updated value is found + // When closing the transaction the removed key is not found + + +// @Test +// void saveFirstDocumentCreatesNewMasterBranch() { +// //given +// final String value = "{\"key\":\"value\"}"; +// final Document document = Document.create(key, value); +// final JsonObject expected = Json.createObjectBuilder() +// .add("key", "value") +// .build(); +// //when +// final Key savedKey = gitDB.branch(master) +// .put(message, document, author); +// //then +// final String retrievedObject = gitDB.branch(master).get(savedKey); +// +// } + +// @Test +// void getGivesSavedValue() { +// //given +// final String value = UUID.randomUUID().toString(); +// final Document document = Document.create(key, value); +// gitDB.save(master, message, document, author); +// //when +// final String result = gitDB.get(master, key); +// //then +// assertThat(result).isEqualTo(value); +// } + +// @AfterEach +// void tearDown() throws IOException { +// gitDB.close(); +// //Files.walk(dbDir) +// // .sorted(Comparator.reverseOrder()) +// // .map(Path::toFile) +// // .forEach(File::delete); +// } }