When putting a key/value pair then a GitDbBranch is returned
This commit is contained in:
parent
265bd61a11
commit
02b5ba34bc
5 changed files with 357 additions and 90 deletions
|
@ -39,12 +39,14 @@ public interface GitDB {
|
||||||
* Initialise a new local gitdb.
|
* Initialise a new local gitdb.
|
||||||
*
|
*
|
||||||
* @param dbDir the path to initialise the local repo in
|
* @param dbDir the path to initialise the local repo in
|
||||||
|
* @param userName the user name
|
||||||
|
* @param userEmailAddress the user email address
|
||||||
* @return a GitDB instance for the created local gitdb
|
* @return a GitDB instance for the created local gitdb
|
||||||
* @throws IOException if there {@code dbDir} is a file or a non-empty directory
|
* @throws IOException if there {@code dbDir} is a file or a non-empty directory
|
||||||
*/
|
*/
|
||||||
static GitDB initLocal(final Path dbDir) throws IOException {
|
static GitDB initLocal(final Path dbDir, final String userName, final String userEmailAddress) throws IOException {
|
||||||
return new GitDBLocal(
|
return new GitDBLocal(
|
||||||
dbDir.toFile()
|
dbDir.toFile(), userName, userEmailAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,14 +54,16 @@ public interface GitDB {
|
||||||
* Open an existing local gitdb.
|
* Open an existing local gitdb.
|
||||||
*
|
*
|
||||||
* @param dbDir the path to open as a local repo
|
* @param dbDir the path to open as a local repo
|
||||||
|
* @param userName the user name
|
||||||
|
* @param userEmailAddress the user email address
|
||||||
* @return a GitDB instance for the local gitdb
|
* @return a GitDB instance for the local gitdb
|
||||||
*/
|
*/
|
||||||
static GitDBLocal openLocal(final Path dbDir) {
|
static GitDBLocal openLocal(final Path dbDir, final String userName, final String userEmailAddress) {
|
||||||
try {
|
try {
|
||||||
return Optional.of(Git.open(dbDir.toFile()))
|
return Optional.of(Git.open(dbDir.toFile()))
|
||||||
.map(Git::getRepository)
|
.map(Git::getRepository)
|
||||||
.filter(Repository::isBare)
|
.filter(Repository::isBare)
|
||||||
.map(GitDBLocal::new)
|
.map(repository -> new GitDBLocal(repository, userName, userEmailAddress))
|
||||||
.orElseThrow(() -> new InvalidRepositoryException("Not a bare repo", dbDir));
|
.orElseThrow(() -> new InvalidRepositoryException("Not a bare repo", dbDir));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidRepositoryException("Error opening repository", dbDir, e);
|
throw new InvalidRepositoryException("Error opening repository", dbDir, e);
|
||||||
|
|
|
@ -23,8 +23,12 @@ package net.kemitix.gitdb;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.eclipse.jgit.lib.AnyObjectId;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,27 +39,80 @@ import java.util.Optional;
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class GitDBBranch {
|
public class GitDBBranch {
|
||||||
|
|
||||||
private final Ref ref;
|
private static final String KEY_PREFIX = "key:";
|
||||||
|
private final Ref branchRef;
|
||||||
|
private final GitDBRepo gitDBRepo;
|
||||||
|
private final String userName;
|
||||||
|
private final String userEmailAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of GitDBBranch for the Ref.
|
* Create a new instance of GitDBBranch for the Ref.
|
||||||
*
|
*
|
||||||
* @param ref the Ref
|
* @param ref the Ref
|
||||||
|
* @param gitDBRepo the GitDBRepo
|
||||||
|
* @param userName the user name
|
||||||
|
* @param userEmailAddress the user email address
|
||||||
* @return a GitDBBranch
|
* @return a GitDBBranch
|
||||||
*/
|
*/
|
||||||
public static GitDBBranch withRef(final Ref ref) {
|
public static GitDBBranch withRef(
|
||||||
return new GitDBBranch(ref);
|
final Ref ref,
|
||||||
|
final GitDBRepo gitDBRepo,
|
||||||
|
final String userName,
|
||||||
|
final String userEmailAddress
|
||||||
|
) {
|
||||||
|
return new GitDBBranch(ref, gitDBRepo, userName, userEmailAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup a value for the key.
|
* Lookup a value for the key.
|
||||||
*
|
*
|
||||||
* @param key the key to lookup
|
* @param key the key to lookup
|
||||||
* @param valueClass the expected class of the value
|
|
||||||
* @param <T> the Class of the value
|
|
||||||
* @return an Optional containing the value, if it exists, or empty if not
|
* @return an Optional containing the value, if it exists, or empty if not
|
||||||
|
* @throws IOException if there was an error reading the value
|
||||||
*/
|
*/
|
||||||
public <T> Optional<T> get(final String key, final Class<T> valueClass) {
|
public Optional<String> get(final String key) throws IOException {
|
||||||
return Optional.empty();
|
return gitDBRepo.readValue(branchRef, KEY_PREFIX + key)
|
||||||
|
.map(String::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put a value into the store for the key.
|
||||||
|
*
|
||||||
|
* @param key the key to place the value under
|
||||||
|
* @param value the value (must be Serializable)
|
||||||
|
* @return an updated branch containing the new key/value
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return gitDBRepo.insertCommit(treeId, message, userName, userEmailAddress, head());
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnyObjectId head() {
|
||||||
|
return branchRef.getObjectId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GitDBBranch updateBranch(final ObjectId commitId) throws IOException {
|
||||||
|
final Ref updatedRef = gitDBRepo.writeHead(branchRef.getName(), commitId);
|
||||||
|
return GitDBBranch.withRef(updatedRef, gitDBRepo, userName, userEmailAddress);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,32 +42,44 @@ import java.util.Optional;
|
||||||
class GitDBLocal implements GitDB {
|
class GitDBLocal implements GitDB {
|
||||||
|
|
||||||
private final Repository repository;
|
private final Repository repository;
|
||||||
|
private final String userName;
|
||||||
|
private final String userEmailAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new GitDB instance, while initialising a new git repo.
|
* Create a new GitDB instance, while initialising a new git repo.
|
||||||
*
|
*
|
||||||
* @param dbDir the path to instantiate the git repo in
|
* @param dbDir the path to instantiate the git repo in
|
||||||
|
* @param userName the user name
|
||||||
|
* @param userEmailAddress the user email address
|
||||||
* @throws IOException if there {@code dbDir} is a file or a non-empty directory
|
* @throws IOException if there {@code dbDir} is a file or a non-empty directory
|
||||||
*/
|
*/
|
||||||
GitDBLocal(final File dbDir) throws IOException {
|
GitDBLocal(
|
||||||
validateDbDir(dbDir);
|
final File dbDir,
|
||||||
this.repository = initRepo(dbDir);
|
final String userName,
|
||||||
|
final String userEmailAddress
|
||||||
|
) throws IOException {
|
||||||
|
this(GitDBLocal.initRepo(validDbDir(dbDir)), userName, userEmailAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new GitDB instance using the Git repo.
|
* Create a new GitDB instance using the Git repo.
|
||||||
*
|
*
|
||||||
* @param repository the Git repository
|
* @param repository the Git repository
|
||||||
|
* @param userName the user name
|
||||||
|
* @param userEmailAddress the user email address
|
||||||
*/
|
*/
|
||||||
GitDBLocal(final Repository repository) {
|
GitDBLocal(final Repository repository, final String userName, final String userEmailAddress) {
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
|
this.userName = userName;
|
||||||
|
this.userEmailAddress = userEmailAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateDbDir(final File dbDir) throws IOException {
|
private static File validDbDir(final File dbDir) throws IOException {
|
||||||
verifyIsNotAFile(dbDir);
|
verifyIsNotAFile(dbDir);
|
||||||
if (dbDir.exists()) {
|
if (dbDir.exists()) {
|
||||||
verifyIsEmpty(dbDir);
|
verifyIsEmpty(dbDir);
|
||||||
}
|
}
|
||||||
|
return dbDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyIsEmpty(final File dbDir) throws IOException {
|
private static void verifyIsEmpty(final File dbDir) throws IOException {
|
||||||
|
@ -82,6 +94,12 @@ class GitDBLocal implements GitDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<GitDBBranch> branch(final String name) throws IOException {
|
||||||
|
return Optional.ofNullable(repository.findRef(name))
|
||||||
|
.map(ref -> GitDBBranch.withRef(ref, GitDBRepo.in(repository), userName, userEmailAddress));
|
||||||
|
}
|
||||||
|
|
||||||
private static Repository initRepo(final File dbDir) throws IOException {
|
private static Repository initRepo(final File dbDir) throws IOException {
|
||||||
dbDir.mkdirs();
|
dbDir.mkdirs();
|
||||||
final Repository repository = RepositoryCache.FileKey.exact(dbDir, FS.DETECTED).open(false);
|
final Repository repository = RepositoryCache.FileKey.exact(dbDir, FS.DETECTED).open(false);
|
||||||
|
@ -91,58 +109,30 @@ class GitDBLocal implements GitDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void createInitialBranchOnMaster(final Repository repository) throws IOException {
|
private static void createInitialBranchOnMaster(final Repository repository) throws IOException {
|
||||||
// create empty file
|
final GitDBRepo repo = GitDBRepo.in(repository);
|
||||||
final ObjectId objectId = insertAnEmptyBlob(repository);
|
final ObjectId objectId = repo.insertBlob(new byte[0]);
|
||||||
// create tree
|
final ObjectId treeId = repo.insertNewTree("isGitDB", objectId);
|
||||||
final ObjectId treeId = insertTree(repository, objectId);
|
final ObjectId commitId = repo.insertCommit(
|
||||||
// create commit
|
treeId,
|
||||||
final ObjectId commitId = insertCommit(repository, treeId);
|
"Initialise GitDB v1",
|
||||||
// create branch
|
"GitDB",
|
||||||
writeBranch(repository, commitId, "master");
|
"pcampbell@kemitix.net",
|
||||||
|
ObjectId.zeroId());
|
||||||
|
createBranch(repository, commitId, "master");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeBranch(
|
private static void createBranch(
|
||||||
final Repository repository,
|
final Repository repository,
|
||||||
final ObjectId commitId,
|
final ObjectId commitId,
|
||||||
final String branchName
|
final String branchName
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
final Path branchRefPath =
|
final Path branchRefPath = repository
|
||||||
repository.getDirectory().toPath().resolve("refs/heads/" + branchName).toAbsolutePath();
|
.getDirectory()
|
||||||
|
.toPath()
|
||||||
|
.resolve("refs/heads/" + branchName)
|
||||||
|
.toAbsolutePath();
|
||||||
final byte[] commitIdBytes = commitId.name().getBytes(StandardCharsets.UTF_8);
|
final byte[] commitIdBytes = commitId.name().getBytes(StandardCharsets.UTF_8);
|
||||||
Files.write(branchRefPath, commitIdBytes);
|
Files.write(branchRefPath, commitIdBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectId insertCommit(
|
|
||||||
final Repository repository,
|
|
||||||
final ObjectId treeId
|
|
||||||
) throws IOException {
|
|
||||||
final CommitBuilder commitBuilder = new CommitBuilder();
|
|
||||||
commitBuilder.setTreeId(treeId);
|
|
||||||
commitBuilder.setMessage("Initialise GitDB v1");
|
|
||||||
final PersonIdent ident = new PersonIdent("GitDB", "pcampbell@kemitix.net");
|
|
||||||
commitBuilder.setAuthor(ident);
|
|
||||||
commitBuilder.setCommitter(ident);
|
|
||||||
commitBuilder.setParentId(ObjectId.zeroId());
|
|
||||||
return repository.getObjectDatabase().newInserter().insert(commitBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectId insertTree(
|
|
||||||
final Repository repository,
|
|
||||||
final ObjectId objectId
|
|
||||||
) throws IOException {
|
|
||||||
final TreeFormatter treeFormatter = new TreeFormatter();
|
|
||||||
treeFormatter.append("isGitDB", FileMode.REGULAR_FILE, objectId);
|
|
||||||
return repository.getObjectDatabase().newInserter().insert(treeFormatter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectId insertAnEmptyBlob(final Repository repository) throws IOException {
|
|
||||||
return repository.getObjectDatabase().newInserter().insert(Constants.OBJ_BLOB, new byte[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<GitDBBranch> branch(final String name) throws IOException {
|
|
||||||
return Optional.ofNullable(repository.findRef(name))
|
|
||||||
.map(GitDBBranch::withRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
200
src/main/java/net/kemitix/gitdb/GitDBRepo.java
Normal file
200
src/main/java/net/kemitix/gitdb/GitDBRepo.java
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
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.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
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;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for interacting with the GitDB Repository.
|
||||||
|
*
|
||||||
|
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param blob content of the blob
|
||||||
|
* @return the id of the blob
|
||||||
|
* @throws IOException the blob could not be stored
|
||||||
|
*/
|
||||||
|
ObjectId insertBlob(final byte[] blob) throws IOException {
|
||||||
|
return repository.getObjectDatabase().newInserter().insert(Constants.OBJ_BLOB, blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new, empty tree into the store, returning its unique id.
|
||||||
|
*
|
||||||
|
* @param key the key to insert
|
||||||
|
* @param valueId id of the value
|
||||||
|
* @return the id of the inserted tree
|
||||||
|
* @throws IOException the tree could not be stored
|
||||||
|
*/
|
||||||
|
ObjectId insertNewTree(
|
||||||
|
final String key,
|
||||||
|
final ObjectId valueId
|
||||||
|
) throws IOException {
|
||||||
|
final TreeFormatter treeFormatter = new TreeFormatter();
|
||||||
|
return writeTree(key, valueId, treeFormatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a tree into the store, copying the exiting tree from the branch, returning its new unique id.
|
||||||
|
*
|
||||||
|
* @param branchRef the branch to copy the tree from
|
||||||
|
* @param key the key to insert
|
||||||
|
* @param valueId id of the value
|
||||||
|
* @return the id of the inserted tree
|
||||||
|
* @throws IOException the tree could not be stored
|
||||||
|
*/
|
||||||
|
ObjectId insertTree(
|
||||||
|
final Ref branchRef,
|
||||||
|
final String key,
|
||||||
|
final ObjectId valueId
|
||||||
|
) throws IOException {
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param treeId id of the tree
|
||||||
|
* @param message the message
|
||||||
|
* @param userName the user name
|
||||||
|
* @param userEmailAddress the user email address
|
||||||
|
* @param parent the commit to link to as parent
|
||||||
|
* @return the id of the commit
|
||||||
|
* @throws IOException the commit could not be stored
|
||||||
|
*/
|
||||||
|
ObjectId insertCommit(
|
||||||
|
final ObjectId treeId,
|
||||||
|
final String message,
|
||||||
|
final String userName,
|
||||||
|
final String userEmailAddress,
|
||||||
|
final AnyObjectId parent
|
||||||
|
) throws IOException {
|
||||||
|
final CommitBuilder commitBuilder = new CommitBuilder();
|
||||||
|
commitBuilder.setTreeId(treeId);
|
||||||
|
commitBuilder.setMessage(message);
|
||||||
|
final PersonIdent ident = new PersonIdent(userName, userEmailAddress);
|
||||||
|
commitBuilder.setAuthor(ident);
|
||||||
|
commitBuilder.setCommitter(ident);
|
||||||
|
commitBuilder.setParentId(parent);
|
||||||
|
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(
|
||||||
|
final String branchName,
|
||||||
|
final ObjectId commitId
|
||||||
|
) throws IOException {
|
||||||
|
final Path branchRefPath = repository
|
||||||
|
.getDirectory()
|
||||||
|
.toPath()
|
||||||
|
.resolve(branchName)
|
||||||
|
.toAbsolutePath();
|
||||||
|
final byte[] commitIdBytes = commitId.name().getBytes(StandardCharsets.UTF_8);
|
||||||
|
Files.write(branchRefPath, commitIdBytes);
|
||||||
|
return repository.findRef(branchName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a value from the branch with the given key.
|
||||||
|
*
|
||||||
|
* @param branchRef the branch to select from
|
||||||
|
* @param key the key to get the value for
|
||||||
|
* @return an Optional containing the value if found, or empty
|
||||||
|
* @throws IOException if there was an error reading the value
|
||||||
|
*/
|
||||||
|
Optional<byte[]> readValue(
|
||||||
|
final Ref branchRef,
|
||||||
|
final String key
|
||||||
|
) throws IOException {
|
||||||
|
try (TreeWalk treeWalk = getTreeWalk(branchRef)) {
|
||||||
|
treeWalk.setFilter(PathFilter.create(key));
|
||||||
|
if (treeWalk.next()) {
|
||||||
|
return Optional.of(repository.open(treeWalk.getObjectId(0), Constants.OBJ_BLOB).getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
package net.kemitix.gitdb;
|
package net.kemitix.gitdb;
|
||||||
|
|
||||||
import org.assertj.core.api.Assumptions;
|
|
||||||
import org.assertj.core.api.WithAssertions;
|
import org.assertj.core.api.WithAssertions;
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
@ -19,10 +19,8 @@ import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class GitDBTest implements WithAssertions {
|
class GitDBTest implements WithAssertions {
|
||||||
|
|
||||||
// private final Branch master = Branch.name("master");
|
private String userName = "user name";
|
||||||
// private final Message message = Message.message(UUID.randomUUID().toString());
|
private String userEmailAddress = "user@email.com";
|
||||||
// private final Key key = Key.name(UUID.randomUUID().toString());
|
|
||||||
// private final Author author = Author.name("junit", "gitdb@kemitix.net");
|
|
||||||
|
|
||||||
// When initialising a repo in a dir that doesn't exist then a bare repo is created
|
// When initialising a repo in a dir that doesn't exist then a bare repo is created
|
||||||
@Test
|
@Test
|
||||||
|
@ -30,7 +28,7 @@ class GitDBTest implements WithAssertions {
|
||||||
//given
|
//given
|
||||||
final Path dir = dirDoesNotExist();
|
final Path dir = dirDoesNotExist();
|
||||||
//when
|
//when
|
||||||
final GitDB gitDB = GitDB.initLocal(dir);
|
final GitDB gitDB = GitDB.initLocal(dir, userName, userEmailAddress);
|
||||||
//then
|
//then
|
||||||
assertThat(gitDB).isNotNull();
|
assertThat(gitDB).isNotNull();
|
||||||
assertThatIsBareRepo(dir);
|
assertThatIsBareRepo(dir);
|
||||||
|
@ -57,7 +55,7 @@ class GitDBTest implements WithAssertions {
|
||||||
final Path dir = fileExists();
|
final Path dir = fileExists();
|
||||||
//then
|
//then
|
||||||
assertThatExceptionOfType(NotDirectoryException.class)
|
assertThatExceptionOfType(NotDirectoryException.class)
|
||||||
.isThrownBy(() -> GitDB.initLocal(dir))
|
.isThrownBy(() -> GitDB.initLocal(dir, userName, userEmailAddress))
|
||||||
.withMessageContaining(dir.toString());
|
.withMessageContaining(dir.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +71,7 @@ class GitDBTest implements WithAssertions {
|
||||||
filesExistIn(dir);
|
filesExistIn(dir);
|
||||||
//then
|
//then
|
||||||
assertThatExceptionOfType(DirectoryNotEmptyException.class)
|
assertThatExceptionOfType(DirectoryNotEmptyException.class)
|
||||||
.isThrownBy(() -> GitDB.initLocal(dir))
|
.isThrownBy(() -> GitDB.initLocal(dir, userName, userEmailAddress))
|
||||||
.withMessageContaining(dir.toString());
|
.withMessageContaining(dir.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +89,7 @@ class GitDBTest implements WithAssertions {
|
||||||
//given
|
//given
|
||||||
final Path dir = dirExists();
|
final Path dir = dirExists();
|
||||||
//when
|
//when
|
||||||
final GitDB gitDB = GitDB.initLocal(dir);
|
final GitDB gitDB = GitDB.initLocal(dir, userName, userEmailAddress);
|
||||||
//then
|
//then
|
||||||
assertThat(gitDB).isNotNull();
|
assertThat(gitDB).isNotNull();
|
||||||
assertThatIsBareRepo(dir);
|
assertThatIsBareRepo(dir);
|
||||||
|
@ -104,7 +102,7 @@ class GitDBTest implements WithAssertions {
|
||||||
final Path dir = dirExists();
|
final Path dir = dirExists();
|
||||||
//then
|
//then
|
||||||
assertThatExceptionOfType(InvalidRepositoryException.class)
|
assertThatExceptionOfType(InvalidRepositoryException.class)
|
||||||
.isThrownBy(() -> GitDB.openLocal(dir))
|
.isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress))
|
||||||
.withMessageContaining(dir.toString());
|
.withMessageContaining(dir.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +113,7 @@ class GitDBTest implements WithAssertions {
|
||||||
final Path dir = fileExists();
|
final Path dir = fileExists();
|
||||||
//then
|
//then
|
||||||
assertThatExceptionOfType(InvalidRepositoryException.class)
|
assertThatExceptionOfType(InvalidRepositoryException.class)
|
||||||
.isThrownBy(() -> GitDB.openLocal(dir))
|
.isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress))
|
||||||
.withMessageContaining(dir.toString());
|
.withMessageContaining(dir.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +124,7 @@ class GitDBTest implements WithAssertions {
|
||||||
final Path dir = dirDoesNotExist();
|
final Path dir = dirDoesNotExist();
|
||||||
//then
|
//then
|
||||||
assertThatExceptionOfType(InvalidRepositoryException.class)
|
assertThatExceptionOfType(InvalidRepositoryException.class)
|
||||||
.isThrownBy(() -> GitDB.openLocal(dir))
|
.isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress))
|
||||||
.withMessageContaining(dir.toString());
|
.withMessageContaining(dir.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +135,7 @@ class GitDBTest implements WithAssertions {
|
||||||
final Path dir = nonBareRepo();
|
final Path dir = nonBareRepo();
|
||||||
//then
|
//then
|
||||||
assertThatExceptionOfType(InvalidRepositoryException.class)
|
assertThatExceptionOfType(InvalidRepositoryException.class)
|
||||||
.isThrownBy(() -> GitDB.openLocal(dir))
|
.isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress))
|
||||||
.withMessageContaining("Invalid GitDB repo")
|
.withMessageContaining("Invalid GitDB repo")
|
||||||
.withMessageContaining("Not a bare repo")
|
.withMessageContaining("Not a bare repo")
|
||||||
.withMessageContaining(dir.toString());
|
.withMessageContaining(dir.toString());
|
||||||
|
@ -155,14 +153,14 @@ class GitDBTest implements WithAssertions {
|
||||||
//given
|
//given
|
||||||
final Path dir = gitDBRepoPath();
|
final Path dir = gitDBRepoPath();
|
||||||
//when
|
//when
|
||||||
final GitDBLocal gitDB = GitDB.openLocal(dir);
|
final GitDBLocal gitDB = GitDB.openLocal(dir, userName, userEmailAddress);
|
||||||
//then
|
//then
|
||||||
assertThat(gitDB).isNotNull();
|
assertThat(gitDB).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path gitDBRepoPath() throws IOException {
|
private Path gitDBRepoPath() throws IOException {
|
||||||
final Path dbDir = dirDoesNotExist();
|
final Path dbDir = dirDoesNotExist();
|
||||||
GitDB.initLocal(dbDir);
|
GitDB.initLocal(dbDir, userName, userEmailAddress);
|
||||||
return dbDir;
|
return dbDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,15 +169,15 @@ class GitDBTest implements WithAssertions {
|
||||||
@Test
|
@Test
|
||||||
void selectBranch_whenBranchNotExist_thenEmptyOptional() throws IOException {
|
void selectBranch_whenBranchNotExist_thenEmptyOptional() throws IOException {
|
||||||
//given
|
//given
|
||||||
final GitDB gitDb = newGitDBRepo(dirDoesNotExist());
|
final GitDB gitDb = gitDB(dirDoesNotExist());
|
||||||
//when
|
//when
|
||||||
final Optional<GitDBBranch> branch = gitDb.branch("unknown");
|
final Optional<GitDBBranch> branch = gitDb.branch("unknown");
|
||||||
//then
|
//then
|
||||||
assertThat(branch).isEmpty();
|
assertThat(branch).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private GitDB newGitDBRepo(final Path dbDir) throws IOException {
|
private GitDB gitDB(final Path dbDir) throws IOException {
|
||||||
return GitDB.initLocal(dbDir);
|
return GitDB.initLocal(dbDir, userName, userEmailAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When select a valid branch then a GitDbBranch is returned
|
// When select a valid branch then a GitDbBranch is returned
|
||||||
|
@ -187,7 +185,7 @@ class GitDBTest implements WithAssertions {
|
||||||
void selectBranch_branchExists_thenReturnBranch() throws IOException {
|
void selectBranch_branchExists_thenReturnBranch() throws IOException {
|
||||||
//given
|
//given
|
||||||
final Path dbDir = dirDoesNotExist();
|
final Path dbDir = dirDoesNotExist();
|
||||||
final GitDB gitDb = newGitDBRepo(dbDir);
|
final GitDB gitDb = gitDB(dbDir);
|
||||||
//when
|
//when
|
||||||
final Optional<GitDBBranch> branch = gitDb.branch("master");
|
final Optional<GitDBBranch> branch = gitDb.branch("master");
|
||||||
//then
|
//then
|
||||||
|
@ -197,19 +195,37 @@ class GitDBTest implements WithAssertions {
|
||||||
// Given a valid GitDbBranch handle
|
// Given a valid GitDbBranch handle
|
||||||
// When getting a key that does not exist then return an empty Optional
|
// When getting a key that does not exist then return an empty Optional
|
||||||
@Test
|
@Test
|
||||||
void getKey_whenKeyNotExist_thenReturnEmptyOptional() throws IOException {
|
void getKey_whenKeyNotExist_thenReturnEmptyOptional() throws IOException, ClassNotFoundException {
|
||||||
//given
|
//given
|
||||||
final GitDB gitDB = newGitDBRepo(dirDoesNotExist());
|
final GitDBBranch branch = gitDBBranch();
|
||||||
final Optional<GitDBBranch> branchOptional = gitDB.branch("master");
|
|
||||||
assumeThat(branchOptional).isNotEmpty();
|
|
||||||
final GitDBBranch master = branchOptional.get();
|
|
||||||
//when
|
//when
|
||||||
final Optional<String> value = master.get("unknown", String.class);
|
final Optional<String> value = branch.get("unknown");
|
||||||
//then
|
//then
|
||||||
assertThat(value).isEmpty();
|
assertThat(value).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GitDBBranch gitDBBranch() throws IOException {
|
||||||
|
final GitDB gitDB = gitDB(dirDoesNotExist());
|
||||||
|
final Optional<GitDBBranch> branchOptional = gitDB.branch("master");
|
||||||
|
assumeThat(branchOptional).isNotEmpty();
|
||||||
|
return branchOptional.get();
|
||||||
|
}
|
||||||
|
|
||||||
// When putting a key/value pair then a GitDbBranch is returned
|
// When putting a key/value pair then a GitDbBranch is returned
|
||||||
|
@Test
|
||||||
|
void putValue_thenReturnUpdatedGitDBBranch() throws IOException, ClassNotFoundException {
|
||||||
|
//given
|
||||||
|
final GitDBBranch originalBranch = gitDBBranch();
|
||||||
|
//when
|
||||||
|
final GitDBBranch updatedBranch = originalBranch.put("key-name", "value");
|
||||||
|
//then
|
||||||
|
assertThat(updatedBranch).isNotNull();
|
||||||
|
assertThat(updatedBranch).isNotSameAs(originalBranch);
|
||||||
|
final Optional<String> optional = updatedBranch.get("key-name");
|
||||||
|
assertThat(optional).contains("value");
|
||||||
|
//assertThat(originalBranch.get("key", String.class)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
// When getting a key that does exist then the value is returned inside an Optional
|
// 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 not exist then the GitDbBranch is returned
|
||||||
// When removing a key that does exist then a GitDbBranch is returned
|
// When removing a key that does exist then a GitDbBranch is returned
|
||||||
|
|
Loading…
Reference in a new issue