Refactoring: extract GitTreeReader
This commit is contained in:
parent
ffc2b56b05
commit
c57a17b937
4 changed files with 174 additions and 78 deletions
|
@ -28,7 +28,6 @@ import org.eclipse.jgit.lib.Ref;
|
|||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
@ -58,8 +57,8 @@ public class GitDBBranch {
|
|||
/**
|
||||
* Initialise the creation of new GitDBBranch instances.
|
||||
*
|
||||
* @param repository the Git Repository
|
||||
* @param userName the user name to record against changes
|
||||
* @param repository the Git Repository
|
||||
* @param userName the user name to record against changes
|
||||
* @param userEmailAddress the user's email address to record against changes
|
||||
* @return a Function for creating a GitDBBranch when supplied with a Ref for a branch
|
||||
*/
|
||||
|
@ -68,7 +67,7 @@ public class GitDBBranch {
|
|||
final String userName,
|
||||
final String userEmailAddress
|
||||
) {
|
||||
return ref -> select(ref, GitDBRepo.in(repository), userName, userEmailAddress);
|
||||
return ref -> select(ref, new GitDBRepo(repository), userName, userEmailAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,11 +90,14 @@ public class GitDBBranch {
|
|||
* @throws IOException if there was an error writing the value
|
||||
*/
|
||||
public GitDBBranch put(final String key, final String value) throws IOException {
|
||||
final ObjectId objectId = insertBlob(value.getBytes(StandardCharsets.UTF_8));
|
||||
final ObjectId treeId = insertTree(KEY_PREFIX + key, objectId);
|
||||
final String commitMessage = String.format("Add key [%s] = [%s]", key, value);
|
||||
final ObjectId commitId = insertCommit(treeId, commitMessage);
|
||||
return updateBranch(commitId);
|
||||
final ObjectId newTree = gitDBRepo.writeValue(branchRef, KEY_PREFIX + key, value);
|
||||
final Ref newBranch =
|
||||
gitDBRepo.writeCommit(branchRef, newTree, commitMessageForAdd(key, value), userName, userEmailAddress);
|
||||
return select(newBranch, gitDBRepo, userName, userEmailAddress);
|
||||
}
|
||||
|
||||
private String commitMessageForAdd(final String key, final String value) {
|
||||
return String.format("Add key [%s] = [%s]", key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,21 +110,4 @@ public class GitDBBranch {
|
|||
return this;
|
||||
}
|
||||
|
||||
private ObjectId insertBlob(final byte[] blob) throws IOException {
|
||||
return gitDBRepo.insertBlob(blob);
|
||||
}
|
||||
|
||||
private ObjectId insertTree(final String key, final ObjectId valueId) throws IOException {
|
||||
return gitDBRepo.insertTree(branchRef, key, valueId);
|
||||
}
|
||||
|
||||
private ObjectId insertCommit(final ObjectId treeId, final String message) throws IOException {
|
||||
final ObjectId headCommitId = branchRef.getObjectId();
|
||||
return gitDBRepo.insertCommit(treeId, message, userName, userEmailAddress, headCommitId);
|
||||
}
|
||||
|
||||
private GitDBBranch updateBranch(final ObjectId commitId) throws IOException {
|
||||
final Ref updatedRef = gitDBRepo.writeHead(branchRef.getName(), commitId);
|
||||
return select(updatedRef, gitDBRepo, userName, userEmailAddress);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,9 @@
|
|||
|
||||
package net.kemitix.gitdb;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import org.eclipse.jgit.lib.*;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -39,21 +36,11 @@ import java.util.*;
|
|||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@RequiredArgsConstructor
|
||||
class GitDBRepo {
|
||||
|
||||
private final Repository repository;
|
||||
|
||||
/**
|
||||
* Create a GitDBRepo wrapper for the Repository.
|
||||
*
|
||||
* @param repository the repository to wrap
|
||||
* @return the GitDBRepo wrapper
|
||||
*/
|
||||
public static GitDBRepo in(final Repository repository) {
|
||||
return new GitDBRepo(repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a blob into the store, returning its unique id.
|
||||
*
|
||||
|
@ -98,15 +85,6 @@ class GitDBRepo {
|
|||
return writeTree(key, valueId, treeFormatterForBranch(branchRef));
|
||||
}
|
||||
|
||||
private ObjectId writeTree(
|
||||
final String key,
|
||||
final ObjectId valueId,
|
||||
final TreeFormatter treeFormatter
|
||||
) throws IOException {
|
||||
treeFormatter.append(key, FileMode.REGULAR_FILE, valueId);
|
||||
return repository.getObjectDatabase().newInserter().insert(treeFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a commit into the store, returning its unique id.
|
||||
*
|
||||
|
@ -135,15 +113,7 @@ class GitDBRepo {
|
|||
return repository.getObjectDatabase().newInserter().insert(commitBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the branch to point to the new commit.
|
||||
*
|
||||
* @param branchName the branch to update
|
||||
* @param commitId the commit to point the branch at
|
||||
* @return the Ref of the updated branch
|
||||
* @throws IOException if there was an error writing the branch
|
||||
*/
|
||||
Ref writeHead(
|
||||
private Ref writeHead(
|
||||
final String branchName,
|
||||
final ObjectId commitId
|
||||
) throws IOException {
|
||||
|
@ -169,33 +139,68 @@ class GitDBRepo {
|
|||
final Ref branchRef,
|
||||
final String key
|
||||
) throws IOException {
|
||||
try (TreeWalk treeWalk = getTreeWalk(branchRef)) {
|
||||
treeWalk.setFilter(PathFilter.create(key));
|
||||
if (treeWalk.next()) {
|
||||
return Optional.of(new String(
|
||||
repository.open(treeWalk.getObjectId(0), Constants.OBJ_BLOB).getBytes()));
|
||||
}
|
||||
val blob = new GitTreeReader(repository)
|
||||
.treeFilter(key)
|
||||
.stream(branchRef)
|
||||
.findFirst();
|
||||
if (blob.isPresent()) {
|
||||
return Optional.of(blob.get().blobAsString());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private ObjectId writeTree(
|
||||
final String key,
|
||||
final ObjectId valueId,
|
||||
final TreeFormatter treeFormatter
|
||||
) throws IOException {
|
||||
treeFormatter.append(key, FileMode.REGULAR_FILE, valueId);
|
||||
return repository.getObjectDatabase().newInserter().insert(treeFormatter);
|
||||
}
|
||||
|
||||
private TreeFormatter treeFormatterForBranch(final Ref branchRef) throws IOException {
|
||||
final TreeFormatter treeFormatter = new TreeFormatter();
|
||||
try (TreeWalk treeWalk = getTreeWalk(branchRef)) {
|
||||
while (treeWalk.next()) {
|
||||
treeFormatter.append(
|
||||
treeWalk.getNameString(),
|
||||
new RevWalk(repository).lookupBlob(treeWalk.getObjectId(0)));
|
||||
}
|
||||
}
|
||||
final GitTreeReader gitTreeReader = new GitTreeReader(repository);
|
||||
gitTreeReader.stream(branchRef)
|
||||
.forEach(item -> treeFormatter.append(item.getName(), item.getRevBlob()));
|
||||
return treeFormatter;
|
||||
}
|
||||
|
||||
private TreeWalk getTreeWalk(final Ref branchRef) throws IOException {
|
||||
final TreeWalk treeWalk = new TreeWalk(repository);
|
||||
treeWalk.addTree(new RevWalk(repository).parseCommit(branchRef.getObjectId()).getTree());
|
||||
treeWalk.setRecursive(false);
|
||||
return treeWalk;
|
||||
/**
|
||||
* Add the key/value to the repo, returning the tree containing the update.
|
||||
*
|
||||
* <p>N.B. this creates a tree that has not been committed remains unaware of the update.</p>
|
||||
*
|
||||
* @param branchRef the branch to start from
|
||||
* @param key the key to place the value under
|
||||
* @param value the value (must be Serializable)
|
||||
* @return the id of the updated tree containing the update
|
||||
* @throws IOException if there was an error writing the value
|
||||
*/
|
||||
ObjectId writeValue(final Ref branchRef, final String key, final String value) throws IOException {
|
||||
final ObjectId blob = insertBlob(value.getBytes(StandardCharsets.UTF_8));
|
||||
return insertTree(branchRef, key, blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the branch to point to the new commit.
|
||||
*
|
||||
* @param branchRef the branch to update
|
||||
* @param tree the tree to commit onto the branch
|
||||
* @param message the commit message
|
||||
* @param userName the user name
|
||||
* @param userEmailAddress the use email address
|
||||
* @return the Ref of the updated branch
|
||||
* @throws IOException if there was an error writing the branch
|
||||
*/
|
||||
Ref writeCommit(
|
||||
final Ref branchRef,
|
||||
final ObjectId tree,
|
||||
final String message,
|
||||
final String userName,
|
||||
final String userEmailAddress
|
||||
) throws IOException {
|
||||
final ObjectId commitId = insertCommit(tree, message, userName, userEmailAddress, branchRef.getObjectId());
|
||||
return writeHead(branchRef.getName(), commitId);
|
||||
}
|
||||
}
|
||||
|
|
106
src/main/java/net/kemitix/gitdb/GitTreeReader.java
Normal file
106
src/main/java/net/kemitix/gitdb/GitTreeReader.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Paul Campbell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies
|
||||
or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
|
||||
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.kemitix.gitdb;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevBlob;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
||||
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Reads the entries in a Git Tree object.
|
||||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
class GitTreeReader {
|
||||
|
||||
private final Repository repository;
|
||||
|
||||
private TreeFilter treeFilter;
|
||||
|
||||
/**
|
||||
* Opens a stream of entries found on the branch.
|
||||
*
|
||||
* @param branchRef the branch to read
|
||||
* @return a stream of key/value pairs as NamedRevBlobs
|
||||
* @throws IOException if there is an error reading the commit or walking the tree
|
||||
*/
|
||||
Stream<NamedRevBlob> stream(final Ref branchRef) throws IOException {
|
||||
final TreeWalk treeWalk = new TreeWalk(repository);
|
||||
treeWalk.addTree(new RevWalk(repository).parseCommit(branchRef.getObjectId()).getTree());
|
||||
treeWalk.setRecursive(false);
|
||||
Optional.ofNullable(treeFilter)
|
||||
.ifPresent(treeWalk::setFilter);
|
||||
final Stream.Builder<NamedRevBlob> builder = Stream.builder();
|
||||
while (treeWalk.next()) {
|
||||
builder.add(new NamedRevBlob(
|
||||
treeWalk.getNameString(),
|
||||
new RevWalk(repository).lookupBlob(treeWalk.getObjectId(0))));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a path filter to limit the stream by.
|
||||
*
|
||||
* @param path the path to filter by
|
||||
* @return the GitTreeReader
|
||||
*/
|
||||
GitTreeReader treeFilter(final String path) {
|
||||
this.treeFilter = PathFilter.create(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the key/value pairs read from the tree.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
class NamedRevBlob {
|
||||
|
||||
private final String name;
|
||||
private final RevBlob revBlob;
|
||||
|
||||
/**
|
||||
* Converts the blob to a String.
|
||||
*
|
||||
* @return a string
|
||||
* @throws IOException of there was an error reading the blob
|
||||
*/
|
||||
String blobAsString() throws IOException {
|
||||
return new String(repository.open(revBlob.getId(), Constants.OBJ_BLOB).getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -64,7 +64,7 @@ class InitGitDBRepo {
|
|||
}
|
||||
|
||||
private void createInitialBranchOnMaster(final Repository repository) throws IOException {
|
||||
final GitDBRepo repo = GitDBRepo.in(repository);
|
||||
final GitDBRepo repo = new GitDBRepo(repository);
|
||||
final ObjectId objectId = repo.insertBlob(new byte[0]);
|
||||
final ObjectId treeId = repo.insertNewTree(IS_GIT_DB, objectId);
|
||||
final ObjectId commitId = repo.insertCommit(treeId, INIT_MESSAGE, INIT_USER, INIT_EMAIL, ObjectId.zeroId());
|
||||
|
|
Loading…
Reference in a new issue