From 6a3687466fd0702238bebb34aca0bc67c9ef3a0f Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 23 Jun 2018 17:34:54 +0100 Subject: [PATCH 01/10] Upgrade mon to 0.7.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cd99ab0..c40c88c 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.11.0.201803080745-r 5.2.0 3.10.0 - 0.4.0 + 0.7.0 2.18.3 0.9.0 From 193a0f380b879574a97d6cafa181e8b197eb96af Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 24 Jun 2018 09:16:05 +0100 Subject: [PATCH 02/10] GitDB returns Result values --- src/main/java/net/kemitix/gitdb/GitDB.java | 16 +- .../net/kemitix/gitdb/impl/InitGitDBRepo.java | 57 ++++--- .../net/kemitix/gitdb/impl/LocalGitDB.java | 7 +- .../kemitix/gitdb/impl/LocalGitDBImpl.java | 55 +++--- .../net/kemitix/gitdb/test/GitDBTest.java | 157 +++++++++++------- 5 files changed, 175 insertions(+), 117 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/GitDB.java b/src/main/java/net/kemitix/gitdb/GitDB.java index c458467..7a0fd4a 100644 --- a/src/main/java/net/kemitix/gitdb/GitDB.java +++ b/src/main/java/net/kemitix/gitdb/GitDB.java @@ -22,10 +22,10 @@ package net.kemitix.gitdb; import net.kemitix.gitdb.impl.LocalGitDB; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; -import java.io.IOException; import java.nio.file.Path; -import java.util.Optional; /** * Main API for connecting to a Git repo as a database. @@ -41,13 +41,12 @@ public interface GitDB { * @param userName the user name * @param userEmailAddress the user email address * @return a GitDB instance for the created local gitdb - * @throws IOException if there {@code dbDir} is a file or a non-empty directory */ - static GitDB initLocal( + static Result initLocal( final Path dbDir, final String userName, final String userEmailAddress - ) throws IOException { + ) { return LocalGitDB.init(dbDir, userName, userEmailAddress); } @@ -59,7 +58,7 @@ public interface GitDB { * @param userEmailAddress the user email address * @return a GitDB instance for the local gitdb */ - static GitDB openLocal(final Path dbDir, final String userName, final String userEmailAddress) { + static Result openLocal(final Path dbDir, final String userName, final String userEmailAddress) { return LocalGitDB.open(dbDir, userName, userEmailAddress); } @@ -67,9 +66,8 @@ public interface GitDB { * Select the named branch. * * @param name the branch to select - * @return an Optional containing the branch if it exists - * @throws IOException if there is an error accessing the branch name + * @return an Result Maybe containing the branch if it exists */ - Optional branch(String name) throws IOException; + Result> branch(String name); } diff --git a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java index a2bd757..25b4fb4 100644 --- a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java @@ -22,6 +22,7 @@ package net.kemitix.gitdb.impl; import net.kemitix.gitdb.FormatVersion; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; @@ -52,14 +53,30 @@ class InitGitDBRepo { * @param dbDir the directory to initialise the repo in * @throws IOException if there is an error in creating the repo files */ - static void create(final Path dbDir) throws IOException { + static Result create(final Path dbDir) { final InitGitDBRepo initRepo = new InitGitDBRepo(); - final File validDbDir = initRepo.validDbDir(dbDir.toFile()); + final File validDbDir; + try { + validDbDir = initRepo.validDbDir(dbDir.toFile()); + } catch (IOException e) { + return Result.error(e); + } validDbDir.mkdirs(); try (Repository repository = RepositoryCache.FileKey.exact(validDbDir, FS.DETECTED).open(false)) { repository.create(true); initRepo.createInitialBranchOnMaster(repository); + } catch (IOException e) { + return Result.error(e); } + return Result.ok(null); + } + + private File validDbDir(final File dbDir) throws IOException { + verifyIsNotAFile(dbDir); + if (dbDir.exists()) { + verifyIsEmpty(dbDir); + } + return dbDir; } private void createInitialBranchOnMaster(final Repository repository) throws IOException { @@ -71,6 +88,20 @@ class InitGitDBRepo { createBranch(repository, commitId, MASTER); } + private void verifyIsNotAFile(final File dbDir) throws NotDirectoryException { + if (dbDir.isFile()) { + throw new NotDirectoryException(dbDir.toString()); + } + } + + private void verifyIsEmpty(final File dbDir) throws IOException { + try (DirectoryStream directoryStream = Files.newDirectoryStream(dbDir.toPath())) { + if (directoryStream.iterator().hasNext()) { + throw new DirectoryNotEmptyException(dbDir.toString()); + } + } + } + private void createBranch( final Repository repository, final ObjectId commitId, @@ -90,26 +121,4 @@ class InitGitDBRepo { .resolve(String.format(REFS_HEADS_FORMAT, branchName)) .toAbsolutePath(); } - - private File validDbDir(final File dbDir) throws IOException { - verifyIsNotAFile(dbDir); - if (dbDir.exists()) { - verifyIsEmpty(dbDir); - } - return dbDir; - } - - private void verifyIsEmpty(final File dbDir) throws IOException { - try (DirectoryStream directoryStream = Files.newDirectoryStream(dbDir.toPath())) { - if (directoryStream.iterator().hasNext()) { - throw new DirectoryNotEmptyException(dbDir.toString()); - } - } - } - - private void verifyIsNotAFile(final File dbDir) throws NotDirectoryException { - if (dbDir.isFile()) { - throw new NotDirectoryException(dbDir.toString()); - } - } } diff --git a/src/main/java/net/kemitix/gitdb/impl/LocalGitDB.java b/src/main/java/net/kemitix/gitdb/impl/LocalGitDB.java index b6bbb09..0965c62 100644 --- a/src/main/java/net/kemitix/gitdb/impl/LocalGitDB.java +++ b/src/main/java/net/kemitix/gitdb/impl/LocalGitDB.java @@ -22,8 +22,8 @@ package net.kemitix.gitdb.impl; import net.kemitix.gitdb.GitDB; +import net.kemitix.mon.result.Result; -import java.io.IOException; import java.nio.file.Path; /** @@ -40,9 +40,8 @@ public interface LocalGitDB extends GitDB { * @param userName the user name * @param userEmailAddress the user email address * @return a GitDB instance for the created local gitdb - * @throws IOException if there {@code dbDir} is a file or a non-empty directory */ - static GitDB init(final Path dbDir, final String userName, final String userEmailAddress) throws IOException { + static Result init(final Path dbDir, final String userName, final String userEmailAddress) { return LocalGitDBImpl.init(dbDir, userName, userEmailAddress); } @@ -54,7 +53,7 @@ public interface LocalGitDB extends GitDB { * @param userEmailAddress the user email address * @return a GitDB instance for the created local gitdb */ - static GitDB open(final Path dbDir, final String userName, final String userEmailAddress) { + static Result open(final Path dbDir, final String userName, final String userEmailAddress) { return LocalGitDBImpl.open(dbDir, userName, userEmailAddress); } diff --git a/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java b/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java index 7d9f4d7..549e0d6 100644 --- a/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java +++ b/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java @@ -24,12 +24,14 @@ package net.kemitix.gitdb.impl; import net.kemitix.gitdb.GitDB; import net.kemitix.gitdb.GitDBBranch; import net.kemitix.gitdb.InvalidRepositoryException; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.lib.*; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; import java.io.IOException; import java.nio.file.Path; -import java.util.Optional; import java.util.function.Function; /** @@ -43,8 +45,6 @@ final class LocalGitDBImpl implements GitDB, LocalGitDB { private static final String ERROR_OPENING_REPOSITORY = "Error opening repository"; private final Repository repository; - private final String userName; - private final String userEmailAddress; private final Function branchInit; @@ -54,9 +54,7 @@ final class LocalGitDBImpl implements GitDB, LocalGitDB { final String userEmailAddress ) { this.repository = repository; - this.userName = userName; - this.userEmailAddress = userEmailAddress; - branchInit = GitDBBranchImpl.init(this.repository, this.userName, this.userEmailAddress); + branchInit = GitDBBranchImpl.init(this.repository, userName, userEmailAddress); } /** @@ -66,15 +64,14 @@ final class LocalGitDBImpl implements GitDB, LocalGitDB { * @param userName the user name * @param userEmailAddress the user email address * @return a GitDB instance for the created local gitdb - * @throws IOException if there {@code dbDir} is a file or a non-empty directory */ - static GitDB init( + static Result init( final Path dbDir, final String userName, final String userEmailAddress - ) throws IOException { - InitGitDBRepo.create(dbDir); - return open(dbDir, userName, userEmailAddress); + ) { + return InitGitDBRepo.create(dbDir) + .flatMap(c -> open(dbDir, userName, userEmailAddress)); } /** @@ -85,25 +82,41 @@ final class LocalGitDBImpl implements GitDB, LocalGitDB { * @param userEmailAddress the user email address * @return a GitDB instance for the created local gitdb */ - static GitDB open( + static Result open( final Path dbDir, final String userName, final String userEmailAddress ) { + return gitOpen(dbDir) + .map(Git::getRepository) + .maybe(Repository::isBare) + .flatMap(asErrorIfNotBare(dbDir)) + .map(toLocalGitDB(userName, userEmailAddress)); + } + + private static Result gitOpen(Path dbDir) { try { - return Optional.of(Git.open(dbDir.toFile())) - .map(Git::getRepository) - .filter(Repository::isBare) - .map(repository -> new LocalGitDBImpl(repository, userName, userEmailAddress)) - .orElseThrow(() -> new InvalidRepositoryException(NOT_A_BARE_REPO, dbDir)); + return Result.ok(Git.open(dbDir.toFile())); } catch (IOException e) { - throw new InvalidRepositoryException(ERROR_OPENING_REPOSITORY, dbDir, e); + return Result.error(new InvalidRepositoryException(ERROR_OPENING_REPOSITORY, dbDir, e)); } } + private static Function, Result> asErrorIfNotBare(final Path dbDir) { + return maybe -> Result.fromMaybe(maybe, () -> new InvalidRepositoryException(NOT_A_BARE_REPO, dbDir)); + } + + private static Function toLocalGitDB(final String userName, final String userEmailAddress) { + return repository -> new LocalGitDBImpl(repository, userName, userEmailAddress); + } + @Override - public Optional branch(final String name) throws IOException { - return Optional.ofNullable(repository.findRef(name)).map(branchInit); + public Result> branch(final String name) { + try { + return Result.ok(Maybe.maybe(repository.findRef(name)).map(branchInit)); + } catch (IOException e) { + return Result.error(e); + } } } diff --git a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java index c2736b7..8a703da 100644 --- a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java +++ b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java @@ -5,6 +5,8 @@ import net.kemitix.gitdb.FormatVersion; import net.kemitix.gitdb.GitDB; import net.kemitix.gitdb.GitDBBranch; import net.kemitix.gitdb.InvalidRepositoryException; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; import org.assertj.core.api.WithAssertions; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; @@ -26,8 +28,6 @@ import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; -import static org.assertj.core.api.Assumptions.assumeThat; - @ExtendWith(MockitoExtension.class) class GitDBTest implements WithAssertions { @@ -51,12 +51,18 @@ class GitDBTest implements WithAssertions { //given final Path dir = dirDoesNotExist(); //when - final GitDB gitDB = GitDB.initLocal(dir, userName, userEmailAddress); + final Result gitDB = GitDB.initLocal(dir, userName, userEmailAddress); //then - assertThat(gitDB).isNotNull(); + assertThat(gitDB.isOkay()).isTrue(); assertThatIsBareRepo(dir); } + private Path dirDoesNotExist() throws IOException { + final Path directory = Files.createTempDirectory("gitdb"); + Files.delete(directory); + return directory; + } + private void assertThatIsBareRepo(final Path dbDir) throws IOException { final Git git = Git.open(dbDir.toFile()); final Repository repository = git.getRepository(); @@ -65,21 +71,20 @@ class GitDBTest implements WithAssertions { assertThat(repository.getDirectory()).isEqualTo(dbDir.toFile()); } - private Path dirDoesNotExist() throws IOException { - final Path directory = Files.createTempDirectory("gitdb"); - Files.delete(directory); - return directory; - } - // When initialising a repo in a dir that is a file then an exception is thrown @Test void initRepo_whenDirIsFile_thenThrowException() throws IOException { //given final Path dir = fileExists(); + //when + final Result gitDBResult = GitDB.initLocal(dir, userName, userEmailAddress); //then - assertThatExceptionOfType(NotDirectoryException.class) - .isThrownBy(() -> GitDB.initLocal(dir, userName, userEmailAddress)) - .withMessageContaining(dir.toString()); + gitDBResult.match( + success -> fail("Is a file not a directory"), + error -> assertThat(error) + .isInstanceOf(NotDirectoryException.class) + .hasMessageContaining(dir.toString()) + ); } private Path fileExists() throws IOException { @@ -92,29 +97,34 @@ class GitDBTest implements WithAssertions { //given final Path dir = dirExists(); filesExistIn(dir); + //when + final Result gitDBResult = GitDB.initLocal(dir, userName, userEmailAddress); //then - assertThatExceptionOfType(DirectoryNotEmptyException.class) - .isThrownBy(() -> GitDB.initLocal(dir, userName, userEmailAddress)) - .withMessageContaining(dir.toString()); - } - - private void filesExistIn(final Path dir) throws IOException { - Files.createTempFile(dir, "gitdb", "file"); + gitDBResult.match( + success -> fail("Directory is not empty"), + error -> assertThat(error) + .isInstanceOf(DirectoryNotEmptyException.class) + .hasMessageContaining(dir.toString()) + ); } private Path dirExists() throws IOException { return Files.createTempDirectory("gitdb"); } + private void filesExistIn(final Path dir) throws IOException { + Files.createTempFile(dir, "gitdb", "file"); + } + // When initialising a repo in a empty dir then a bare repo is created @Test void initRepo_whenEmptyDir_thenCreateBareRepo() throws IOException { //given final Path dir = dirExists(); //when - final GitDB gitDB = GitDB.initLocal(dir, userName, userEmailAddress); + final Result gitDB = GitDB.initLocal(dir, userName, userEmailAddress); //then - assertThat(gitDB).isNotNull(); + assertThat(gitDB.isOkay()).isTrue(); assertThatIsBareRepo(dir); } @@ -123,10 +133,16 @@ class GitDBTest implements WithAssertions { void openRepo_NotBareRepo_thenThrowException() throws IOException { //given final Path dir = dirExists(); + //when + final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then - assertThatExceptionOfType(InvalidRepositoryException.class) - .isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress)) - .withMessageContaining(dir.toString()); + gitDBResult.match( + success -> fail("Not a bare repo"), + error -> assertThat(error) + .isInstanceOf(InvalidRepositoryException.class) + .hasMessageContaining(dir.toString()) + ); + } // When opening a repo in a dir that is a file then an exception is thrown @@ -134,10 +150,15 @@ class GitDBTest implements WithAssertions { void openRepo_whenDirIsFile_thenThrowException() throws IOException { //given final Path dir = fileExists(); + //when + final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then - assertThatExceptionOfType(InvalidRepositoryException.class) - .isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress)) - .withMessageContaining(dir.toString()); + gitDBResult.match( + success -> fail("Directory is a file"), + error -> assertThat(error) + .isInstanceOf(InvalidRepositoryException.class) + .hasMessageContaining(dir.toString()) + ); } // When opening a repo in a dir that doesn't exist then an exception is thrown @@ -145,10 +166,15 @@ class GitDBTest implements WithAssertions { void openRepo_whenDirNotExist_thenThrowException() throws IOException { //given final Path dir = dirDoesNotExist(); + //when + final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then - assertThatExceptionOfType(InvalidRepositoryException.class) - .isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress)) - .withMessageContaining(dir.toString()); + gitDBResult.match( + success -> fail("Directory does not exist"), + error -> assertThat(error) + .isInstanceOf(InvalidRepositoryException.class) + .hasMessageContaining(dir.toString()) + ); } // When opening a repo in a dir that is not a bare repo then an exception is thrown @@ -156,12 +182,17 @@ class GitDBTest implements WithAssertions { void openRepo_whenRepoNotBare_thenThrowException() throws IOException, GitAPIException { //given final Path dir = nonBareRepo(); + //when + final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then - assertThatExceptionOfType(InvalidRepositoryException.class) - .isThrownBy(() -> GitDB.openLocal(dir, userName, userEmailAddress)) - .withMessageContaining("Invalid GitDB repo") - .withMessageContaining("Not a bare repo") - .withMessageContaining(dir.toString()); + gitDBResult.match( + success -> fail("Not a bare repo"), + error -> assertThat(error) + .isInstanceOf(InvalidRepositoryException.class) + .hasMessageContaining("Invalid GitDB repo") + .hasMessageContaining("Not a bare repo") + .hasMessageContaining(dir.toString()) + ); } private Path nonBareRepo() throws IOException, GitAPIException { @@ -176,9 +207,13 @@ class GitDBTest implements WithAssertions { //given final Path dir = gitDBRepoPath(); //when - final GitDB gitDB = GitDB.openLocal(dir, userName, userEmailAddress); + final Result gitDB = GitDB.openLocal(dir, userName, userEmailAddress); //then - assertThat(gitDB).isNotNull(); + assertThat(gitDB.isOkay()).isTrue(); + gitDB.match( + success -> assertThat(success).isNotNull(), + error -> fail("did not open local repo") + ); } private Path gitDBRepoPath() throws IOException { @@ -189,45 +224,38 @@ class GitDBTest implements WithAssertions { // Given a valid GitDb handle - private GitDB gitDB(final Path dbDir) throws IOException { - return GitDB.initLocal(dbDir, userName, userEmailAddress); - } - // When select a branch that doesn't exist then an empty Optional is returned @Test - void selectBranch_whenBranchNotExist_thenEmptyOptional() throws IOException { + void selectBranch_whenBranchNotExist_thenEmptyOptional() throws Throwable { //given - final GitDB gitDb = gitDB(dirDoesNotExist()); + final Result gitDb = gitDB(dirDoesNotExist()); //when - final Optional branch = gitDb.branch("unknown"); + final Result> branch = gitDb.flatMap(db -> db.branch("unknown")); //then - assertThat(branch).isEmpty(); + assertThat(branch.orElseThrow().toOptional()).isEmpty(); + } + + private Result gitDB(final Path dbDir) { + return GitDB.initLocal(dbDir, userName, userEmailAddress); } // When select a valid branch then a GitDbBranch is returned @Test - void selectBranch_branchExists_thenReturnBranch() throws IOException { + void selectBranch_branchExists_thenReturnBranch() throws Throwable { //given final Path dbDir = dirDoesNotExist(); - final GitDB gitDb = gitDB(dbDir); + final Result gitDb = gitDB(dbDir); //when - final Optional branch = gitDb.branch("master"); + final Result> branch = gitDb.flatMap(db -> db.branch("master")); //then - assertThat(branch).as("Branch master exists").isNotEmpty(); + assertThat(branch.orElseThrow().toOptional()).as("Branch master exists").isNotEmpty(); } // Given a valid GitDbBranch handle - private GitDBBranch gitDBBranch() throws IOException { - final GitDB gitDB = gitDB(dirDoesNotExist()); - final Optional branchOptional = gitDB.branch("master"); - assumeThat(branchOptional).isNotEmpty(); - return branchOptional.get(); - } - // When getting a key that does not exist then return an empty Optional @Test - void getKey_whenKeyNotExist_thenReturnEmptyOptional() throws IOException, ClassNotFoundException { + void getKey_whenKeyNotExist_thenReturnEmptyOptional() throws IOException { //given final GitDBBranch branch = gitDBBranch(); //when @@ -236,6 +264,17 @@ class GitDBTest implements WithAssertions { assertThat(value).isEmpty(); } + private GitDBBranch gitDBBranch() { + try { + return gitDB(dirDoesNotExist()) + .flatMap(db -> db.branch("master")) + .orElseThrow() + .orElse(null); + } catch (Throwable throwable) { + throw new RuntimeException("Couldn't create master branch"); + } + } + // When getting the format version it matches expected @Test void getVersionFormat_thenFormatIsSet() throws IOException { @@ -263,7 +302,7 @@ class GitDBTest implements WithAssertions { // When getting a key that does exist then the value is returned inside an Optional @Test - void getKey_whenExists_thenReturnValueInOptional() throws IOException, ClassNotFoundException { + void getKey_whenExists_thenReturnValueInOptional() throws IOException { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); From f5483f419bfc214f93f9d49895afef25df36500f Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Mon, 25 Jun 2018 20:03:29 +0100 Subject: [PATCH 03/10] GitDBBranch returns Result values --- .../java/net/kemitix/gitdb/GitDBBranch.java | 17 +-- .../kemitix/gitdb/impl/GitDBBranchImpl.java | 76 +++++++----- .../net/kemitix/gitdb/impl/GitDBRepo.java | 82 +++++++------ .../net/kemitix/gitdb/impl/KeyRemover.java | 54 ++++---- .../kemitix/gitdb/impl/LocalGitDBImpl.java | 6 +- .../net/kemitix/gitdb/test/GitDBTest.java | 116 ++++++++++++------ 6 files changed, 205 insertions(+), 146 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/GitDBBranch.java b/src/main/java/net/kemitix/gitdb/GitDBBranch.java index e1fa7cf..fe08fb9 100644 --- a/src/main/java/net/kemitix/gitdb/GitDBBranch.java +++ b/src/main/java/net/kemitix/gitdb/GitDBBranch.java @@ -22,9 +22,8 @@ package net.kemitix.gitdb; import com.github.zafarkhaja.semver.Version; - -import java.io.IOException; -import java.util.Optional; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; /** * API for interacting with a branch in a GirDB. @@ -38,9 +37,8 @@ public interface GitDBBranch { * * @param key the key to lookup * @return an Optional containing the value, if it exists, or empty if not - * @throws IOException if there was an error reading the value */ - Optional get(String key) throws IOException; + Result> get(String key); /** * Put a value into the store for the key. @@ -48,18 +46,16 @@ public interface GitDBBranch { * @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 key/value */ - GitDBBranch put(String key, String value) throws IOException; + Result put(String key, String value); /** * Removes a key and its value from the store. * * @param key the key to remove * @return an updated branch without the key, or the original if the key was not found - * @throws IOException if there was an error removing the key/value */ - GitDBBranch remove(String key) throws IOException; + Result remove(String key); /** * Returns the GitDB format for the current branch. @@ -67,8 +63,7 @@ public interface GitDBBranch { *

Different branches can have different versions.

* * @return the format as per semantic versioning, i.e. "x.y.z" within an Optional - * @throws IOException error reading version */ - Optional getFormatVersion() throws IOException; + Result> getFormatVersion(); } diff --git a/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java b/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java index 097c646..9b90a36 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java @@ -25,12 +25,13 @@ import com.github.zafarkhaja.semver.Version; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import net.kemitix.gitdb.GitDBBranch; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import java.io.IOException; -import java.util.Optional; import java.util.function.Function; /** @@ -48,15 +49,6 @@ class GitDBBranchImpl implements GitDBBranch { private final String userEmailAddress; private final String name; - private static GitDBBranch select( - final Ref branchRef, - final GitDBRepo gitDBRepo, - final String userName, - final String userEmailAddress - ) { - return new GitDBBranchImpl(branchRef, gitDBRepo, userName, userEmailAddress, branchRef.getName()); - } - /** * Initialise the creation of new GitDBBranch instances. * @@ -65,7 +57,7 @@ class GitDBBranchImpl implements GitDBBranch { * @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 */ - static Function init( + static Function> init( final Repository repository, final String userName, final String userEmailAddress @@ -73,38 +65,56 @@ class GitDBBranchImpl implements GitDBBranch { return ref -> select(ref, new GitDBRepo(repository), userName, userEmailAddress); } + private static Result select( + final Ref branchRef, + final GitDBRepo gitDBRepo, + final String userName, + final String userEmailAddress + ) { + return Result.ok(new GitDBBranchImpl(branchRef, gitDBRepo, userName, userEmailAddress, branchRef.getName())); + } + @Override - public Optional get(final String key) throws IOException { + public Result> get(final String key) { return gitDBRepo.readValue(branchRef, KEY_PREFIX + key); } @Override - public GitDBBranch put(final String key, final String value) throws IOException { - final ObjectId newTree = gitDBRepo.writeValue(branchRef, KEY_PREFIX + key, value); - final String message = String.format("Add key [%s] = [%s]", key, value); - final Ref newBranch = gitDBRepo.writeCommit(branchRef, newTree, message, userName, userEmailAddress); - return select(newBranch, gitDBRepo, userName, userEmailAddress); - } - - @Override - public GitDBBranch remove(final String key) throws IOException { - final Optional newTree = gitDBRepo.removeKey(branchRef, KEY_PREFIX + key); - if (newTree.isPresent()) { - final Ref newBranch = - gitDBRepo.writeCommit( - branchRef, newTree.get(), - String.format("Remove Key [%s]", key), - userName, - userEmailAddress); - return select(newBranch, gitDBRepo, userName, userEmailAddress); + public Result put(final String key, final String value) { + try { + final ObjectId newTree = gitDBRepo.writeValue(branchRef, KEY_PREFIX + key, value); + final String message = String.format("Add key [%s] = [%s]", key, value); + final Result newBranch = gitDBRepo.writeCommit(branchRef, newTree, message, userName, userEmailAddress); + return newBranch.flatMap(b -> select(b, gitDBRepo, userName, userEmailAddress)); + } catch (IOException e) { + return Result.error(e); } - return this; } @Override - public Optional getFormatVersion() throws IOException { + public Result remove(final String key) { + return gitDBRepo.removeKey(branchRef, KEY_PREFIX + key).flatMap(treeId -> + writeRemoveKeyCommit(key, treeId) + .map(selectUpdatedBranch()) + .orElse(Result.ok(this))); + } + + private Maybe> writeRemoveKeyCommit(final String key, final Maybe idMaybe) { + return idMaybe.map(objectId -> { + final String message = String.format("Remove Key [%s]", key); + return gitDBRepo.writeCommit(branchRef, objectId, message, userName, userEmailAddress); + }); + } + + private Function, Result> selectUpdatedBranch() { + return refResult -> refResult.flatMap(ref -> + select(ref, gitDBRepo, userName, userEmailAddress)); + } + + @Override + public Result> getFormatVersion() { return gitDBRepo.readValue(branchRef, "GitDB.Version") - .map(Version::valueOf); + .map(version -> version.map(Version::valueOf)); } } diff --git a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java index 1efbe7c..7af698b 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java @@ -22,13 +22,14 @@ package net.kemitix.gitdb.impl; import lombok.val; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Optional; /** * Wrapper for interacting with the GitDB Repository. @@ -47,7 +48,7 @@ class GitDBRepo { /** * Creates a new instance of this class. * - * @param repository the Git Repository + * @param repository the Git Repository */ GitDBRepo(final Repository repository) { this.repository = repository; @@ -73,47 +74,29 @@ class GitDBRepo { return keyWriter.writeFirst(key, valueId); } - /** - * Insert a commit into the store, returning its unique id. - * - * @param treeId id of the tree - * @param branchRef the branch to commit to - * @param message the message - * @param userName the user name - * @param userEmailAddress the user email address - * @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 Ref branchRef - ) throws IOException { - return commitWriter.write(treeId, branchRef, message, userName, userEmailAddress); - } - /** * 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 readValue( + Result> readValue( final Ref branchRef, final String key - ) throws IOException { - val blob = new GitTreeReader(repository) - .treeFilter(key) - .stream(branchRef) - .findFirst(); - if (blob.isPresent()) { - return Optional.of(blob.get().blobAsString()); + ) { + try { + val blob = new GitTreeReader(repository) + .treeFilter(key) + .stream(branchRef) + .findFirst(); + if (blob.isPresent()) { + return Result.ok(Maybe.just(blob.get().blobAsString())); + } + return Result.ok(Maybe.nothing()); + } catch (IOException e) { + return Result.error(e); } - return Optional.empty(); } /** @@ -143,15 +126,40 @@ class GitDBRepo { * @return the Ref of the updated branch * @throws IOException if there was an error writing the branch */ - Ref writeCommit( + Result writeCommit( final Ref branchRef, final ObjectId tree, final String message, final String userName, final String userEmailAddress + ) { + try { + final ObjectId commitId = insertCommit(tree, message, userName, userEmailAddress, branchRef); + return Result.ok(headWriter.write(branchRef.getName(), commitId)); + } catch (IOException e) { + return Result.error(e); + } + } + + /** + * Insert a commit into the store, returning its unique id. + * + * @param treeId id of the tree + * @param branchRef the branch to commit to + * @param message the message + * @param userName the user name + * @param userEmailAddress the user email address + * @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 Ref branchRef ) throws IOException { - final ObjectId commitId = insertCommit(tree, message, userName, userEmailAddress, branchRef); - return headWriter.write(branchRef.getName(), commitId); + return commitWriter.write(treeId, branchRef, message, userName, userEmailAddress); } /** @@ -184,7 +192,7 @@ class GitDBRepo { * empty Optional if there key was not found, the there was no changes made * @throws IOException if there was an error writing the value */ - Optional removeKey(final Ref branchRef, final String key) throws IOException { + Result> removeKey(final Ref branchRef, final String key) { return keyRemover.remove(branchRef, key); } diff --git a/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java b/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java index f8cd7d0..6146f0c 100644 --- a/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java +++ b/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java @@ -22,10 +22,11 @@ package net.kemitix.gitdb.impl; import lombok.RequiredArgsConstructor; +import net.kemitix.mon.maybe.Maybe; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.*; import java.io.IOException; -import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Predicate; @@ -40,6 +41,28 @@ class KeyRemover { private final Repository repository; + /** + * Remove a key from the repository. + * + * @param branchRef the branch to update + * @param key the key to remove + * @return the id of the updated tree + */ + Result> remove(final Ref branchRef, final String key) { + final TreeFormatter treeFormatter = new TreeFormatter(); + final AtomicBoolean removed = new AtomicBoolean(false); + try { + new GitTreeReader(repository) + .stream(branchRef) + .peek(flagIfFound(key, removed)) + .filter(isNotKey(key)) + .forEach(addToTree(treeFormatter)); + return insertTree(treeFormatter).maybe(oi -> removed.get()); + } catch (IOException e) { + return Result.error(e); + } + } + /** * Sets the boolean to true if the key matches a NamedRevBlob's name. * @@ -75,38 +98,17 @@ class KeyRemover { return item -> treeFormatter.append(item.getName(), item.getRevBlob()); } - /** - * Remove a key from the repository. - * - * @param branchRef the branch to update - * @param key the key to remove - * @return the id of the updated tree - * @throws IOException if there is an error writing the value - */ - Optional remove(final Ref branchRef, final String key) throws IOException { - final TreeFormatter treeFormatter = new TreeFormatter(); - final AtomicBoolean removed = new AtomicBoolean(false); - new GitTreeReader(repository) - .stream(branchRef) - .peek(flagIfFound(key, removed)) - .filter(isNotKey(key)) - .forEach(addToTree(treeFormatter)); - if (removed.get()) { - return Optional.of(insertTree(treeFormatter)); - } - return Optional.empty(); - } - /** * Insert a tree into the repo, returning its id. * * @param treeFormatter the formatter containing the proposed tree's data. * @return the name of the tree object. - * @throws IOException the object could not be stored. */ - private ObjectId insertTree(final TreeFormatter treeFormatter) throws IOException { + private Result insertTree(final TreeFormatter treeFormatter) { try (ObjectInserter inserter = repository.getObjectDatabase().newInserter()) { - return inserter.insert(treeFormatter); + return Result.ok(inserter.insert(treeFormatter)); + } catch (IOException e) { + return Result.error(e); } } } diff --git a/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java b/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java index 549e0d6..9164a96 100644 --- a/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java +++ b/src/main/java/net/kemitix/gitdb/impl/LocalGitDBImpl.java @@ -46,7 +46,7 @@ final class LocalGitDBImpl implements GitDB, LocalGitDB { private final Repository repository; - private final Function branchInit; + private final Function> branchInit; private LocalGitDBImpl( final Repository repository, @@ -113,7 +113,9 @@ final class LocalGitDBImpl implements GitDB, LocalGitDB { @Override public Result> branch(final String name) { try { - return Result.ok(Maybe.maybe(repository.findRef(name)).map(branchInit)); + return Result.invert(Maybe.maybe( + repository.findRef(name)) + .map(branchInit::apply)); } catch (IOException e) { return Result.error(e); } diff --git a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java index 8a703da..23428e8 100644 --- a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java +++ b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java @@ -24,8 +24,8 @@ import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.NotDirectoryException; import java.nio.file.Path; -import java.util.Optional; import java.util.UUID; +import java.util.function.Consumer; import java.util.function.Supplier; @ExtendWith(MockitoExtension.class) @@ -80,7 +80,7 @@ class GitDBTest implements WithAssertions { final Result gitDBResult = GitDB.initLocal(dir, userName, userEmailAddress); //then gitDBResult.match( - success -> fail("Is a file not a directory"), + failOnSuccess("Is a file not a directory"), error -> assertThat(error) .isInstanceOf(NotDirectoryException.class) .hasMessageContaining(dir.toString()) @@ -91,6 +91,10 @@ class GitDBTest implements WithAssertions { return Files.createTempFile("gitdb", "file"); } + private Consumer failOnSuccess(String message) { + return success -> fail(message); + } + // When initialising a repo in a non-empty dir then an exception is thrown @Test void initRepo_whenNotEmptyDir_thenThrowException() throws IOException { @@ -101,7 +105,7 @@ class GitDBTest implements WithAssertions { final Result gitDBResult = GitDB.initLocal(dir, userName, userEmailAddress); //then gitDBResult.match( - success -> fail("Directory is not empty"), + failOnSuccess("Directory is not empty"), error -> assertThat(error) .isInstanceOf(DirectoryNotEmptyException.class) .hasMessageContaining(dir.toString()) @@ -137,7 +141,7 @@ class GitDBTest implements WithAssertions { final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then gitDBResult.match( - success -> fail("Not a bare repo"), + failOnSuccess("Not a bare repo"), error -> assertThat(error) .isInstanceOf(InvalidRepositoryException.class) .hasMessageContaining(dir.toString()) @@ -154,7 +158,7 @@ class GitDBTest implements WithAssertions { final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then gitDBResult.match( - success -> fail("Directory is a file"), + failOnSuccess("Directory is a file"), error -> assertThat(error) .isInstanceOf(InvalidRepositoryException.class) .hasMessageContaining(dir.toString()) @@ -170,7 +174,7 @@ class GitDBTest implements WithAssertions { final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then gitDBResult.match( - success -> fail("Directory does not exist"), + failOnSuccess("Directory does not exist"), error -> assertThat(error) .isInstanceOf(InvalidRepositoryException.class) .hasMessageContaining(dir.toString()) @@ -186,7 +190,7 @@ class GitDBTest implements WithAssertions { final Result gitDBResult = GitDB.openLocal(dir, userName, userEmailAddress); //then gitDBResult.match( - success -> fail("Not a bare repo"), + failOnSuccess("Not a bare repo"), error -> assertThat(error) .isInstanceOf(InvalidRepositoryException.class) .hasMessageContaining("Invalid GitDB repo") @@ -259,33 +263,50 @@ class GitDBTest implements WithAssertions { //given final GitDBBranch branch = gitDBBranch(); //when - final Optional value = branch.get("unknown"); + final Result> value = branch.get("unknown"); //then - assertThat(value).isEmpty(); + value.match( + success -> assertThat(success.toOptional()).isEmpty(), + failOnError() + ); } private GitDBBranch gitDBBranch() { try { - return gitDB(dirDoesNotExist()) - .flatMap(db -> db.branch("master")) - .orElseThrow() - .orElse(null); + final Result gitDBResult = gitDB(dirDoesNotExist()); + System.out.println("gitDBResult = " + gitDBResult); + final Result> master = gitDBResult.flatMap(db -> { + final Result> maybeResult = db.branch("master"); + System.out.println("maybeResult = " + maybeResult); + return maybeResult; + }); + assert master != null; + System.out.println("master = " + master); + final Maybe gitDBBranchMaybe = master.orElseThrow(); + final GitDBBranch gitDBBranch = gitDBBranchMaybe.orElse(null); + return gitDBBranch; } catch (Throwable throwable) { - throw new RuntimeException("Couldn't create master branch"); + throw new RuntimeException("Couldn't create master branch", throwable); } } + private Consumer failOnError() { + return error -> fail("Not an error"); + } + // When getting the format version it matches expected @Test void getVersionFormat_thenFormatIsSet() throws IOException { //given final GitDBBranch gitDBBranch = gitDBBranch(); - //when - final Optional formatVersion = gitDBBranch.getFormatVersion(); - //then final Version version = new FormatVersion().getVersion(); - assertThat(formatVersion).contains(version); - assertThat(formatVersion.get()).isNotSameAs(version); + //when + final Result> formatVersion = gitDBBranch.getFormatVersion(); + //then + formatVersion.match( + success -> success.peek(v -> assertThat(v).isEqualTo(version).isNotSameAs(version)), + failOnError() + ); } // When putting a key/value pair then a GitDbBranch is returned @@ -294,10 +315,14 @@ class GitDBTest implements WithAssertions { //given final GitDBBranch originalBranch = gitDBBranch(); //when - final GitDBBranch updatedBranch = originalBranch.put("key-name", "value"); + final Result updatedBranch = originalBranch.put("key-name", "value"); //then - assertThat(updatedBranch).isNotNull(); - assertThat(updatedBranch).isNotSameAs(originalBranch); + updatedBranch.match( + success -> assertThat(success).isNotNull().isNotSameAs(originalBranch), + failOnError() + ); + assertThat(updatedBranch).isNotNull() + .isNotSameAs(originalBranch); } // When getting a key that does exist then the value is returned inside an Optional @@ -307,11 +332,14 @@ class GitDBTest implements WithAssertions { final String key = stringSupplier.get(); final String value = stringSupplier.get(); final GitDBBranch originalBranch = gitDBBranch(); - final GitDBBranch updatedBranch = originalBranch.put(key, value); + final Result updatedBranch = originalBranch.put(key, value); //when - final Optional result = updatedBranch.get(key); + final Result> result = updatedBranch.flatMap(b -> b.get(key)); //then - assertThat(result).contains(value); + result.match( + success -> success.map(v -> assertThat(v).contains(value)), + failOnError() + ); } // When removing a key that does not exist then the GitDbBranch is returned @@ -320,9 +348,12 @@ class GitDBTest implements WithAssertions { //given final GitDBBranch gitDBBranch = gitDBBranch(); //when - final GitDBBranch result = gitDBBranch.remove("unknown"); + final Result result = gitDBBranch.remove("unknown"); //then - assertThat(result).isSameAs(gitDBBranch); + result.match( + success -> assertThat(success).isSameAs(gitDBBranch), + failOnError() + ); } // When removing a key that does exist then a GitDbBranch is returned @@ -331,14 +362,17 @@ class GitDBTest implements WithAssertions { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); - final GitDBBranch originalBranch = gitDBBranchWithKeyValue(key, value); + final Result originalBranch = gitDBBranchWithKeyValue(key, value); //when - final GitDBBranch updatedBranch = originalBranch.remove(key); + final Result updatedBranch = originalBranch.flatMap(b -> b.remove(key)); //then - assertThat(updatedBranch).isNotSameAs(originalBranch); + updatedBranch.match( + success -> assertThat(success).isNotSameAs(originalBranch), + failOnError() + ); } - private GitDBBranch gitDBBranchWithKeyValue(final String key, final String value) throws IOException { + private Result gitDBBranchWithKeyValue(final String key, final String value) throws IOException { return gitDBBranch().put(key, value); } @@ -348,11 +382,15 @@ class GitDBTest implements WithAssertions { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); - final GitDBBranch originalBranch = gitDBBranchWithKeyValue(key, value); + final Result originalBranch = gitDBBranchWithKeyValue(key, value); //when - final GitDBBranch updatedBranch = originalBranch.remove(key); + final Result updatedBranch = originalBranch.flatMap(b -> b.remove(key)); //then - assertThat(originalBranch.get(key)).contains(value); + originalBranch.flatMap(b -> b.get(key)) + .match( + success -> assertThat(success.toOptional()).contains(value), + failOnError() + ); } // When removing a key that does exist then the updated GitDbBranch can't find it @@ -361,11 +399,15 @@ class GitDBTest implements WithAssertions { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); - final GitDBBranch originalBranch = gitDBBranchWithKeyValue(key, value); + final Result originalBranch = gitDBBranchWithKeyValue(key, value); //when - final GitDBBranch updatedBranch = originalBranch.remove(key); + final Result updatedBranch = originalBranch.flatMap(b -> b.remove(key)); //then - assertThat(updatedBranch.get(key)).isEmpty(); + updatedBranch.flatMap(b -> b.get(key)) + .match( + success -> assertThat(success.toOptional()).isEmpty(), + failOnError() + ); } } From 2de83ba3bcfdb5d35c1e3a39bf8863777cc07408 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Mon, 25 Jun 2018 21:51:08 +0100 Subject: [PATCH 04/10] Refactoring GitDBTest --- .../net/kemitix/gitdb/test/GitDBTest.java | 54 +++++++------------ 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java index 23428e8..7302324 100644 --- a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java +++ b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java @@ -13,38 +13,23 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.NotDirectoryException; import java.nio.file.Path; import java.util.UUID; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; -@ExtendWith(MockitoExtension.class) class GitDBTest implements WithAssertions { private final Supplier stringSupplier = UUID.randomUUID()::toString; private final String userName = stringSupplier.get(); private final String userEmailAddress = stringSupplier.get(); - private static void tree(final Path dbDir, final PrintStream out) throws IOException { - final Process treeProcess = new ProcessBuilder("tree", dbDir.toString()).start(); - try (final BufferedReader reader = new BufferedReader(new InputStreamReader(treeProcess.getInputStream()))) { - String line; - while (null != (line = reader.readLine())) { - out.println("line = " + line); - } - } - } - // When initialising a repo in a dir that doesn't exist then a bare repo is created @Test void initRepo_whenDirNotExist_thenCreateBareRepo() throws IOException { @@ -53,7 +38,7 @@ class GitDBTest implements WithAssertions { //when final Result gitDB = GitDB.initLocal(dir, userName, userEmailAddress); //then - assertThat(gitDB.isOkay()).isTrue(); + assertThatResultIsOkay(gitDB); assertThatIsBareRepo(dir); } @@ -63,6 +48,10 @@ class GitDBTest implements WithAssertions { return directory; } + private void assertThatResultIsOkay(final Result result) { + assertThat(result.isOkay()).isTrue(); + } + private void assertThatIsBareRepo(final Path dbDir) throws IOException { final Git git = Git.open(dbDir.toFile()); final Repository repository = git.getRepository(); @@ -128,7 +117,7 @@ class GitDBTest implements WithAssertions { //when final Result gitDB = GitDB.initLocal(dir, userName, userEmailAddress); //then - assertThat(gitDB.isOkay()).isTrue(); + assertThatResultIsOkay(gitDB); assertThatIsBareRepo(dir); } @@ -234,7 +223,7 @@ class GitDBTest implements WithAssertions { //given final Result gitDb = gitDB(dirDoesNotExist()); //when - final Result> branch = gitDb.flatMap(db -> db.branch("unknown")); + final Result> branch = gitDb.flatMap(selectBranch("unknown")); //then assertThat(branch.orElseThrow().toOptional()).isEmpty(); } @@ -243,6 +232,12 @@ class GitDBTest implements WithAssertions { return GitDB.initLocal(dbDir, userName, userEmailAddress); } + private Function>> selectBranch(final String branchName) { + return db -> db.branch(branchName); + } + + // Given a valid GitDbBranch handle + // When select a valid branch then a GitDbBranch is returned @Test void selectBranch_branchExists_thenReturnBranch() throws Throwable { @@ -250,13 +245,11 @@ class GitDBTest implements WithAssertions { final Path dbDir = dirDoesNotExist(); final Result gitDb = gitDB(dbDir); //when - final Result> branch = gitDb.flatMap(db -> db.branch("master")); + final Result> branch = gitDb.flatMap(selectBranch("master")); //then assertThat(branch.orElseThrow().toOptional()).as("Branch master exists").isNotEmpty(); } - // Given a valid GitDbBranch handle - // When getting a key that does not exist then return an empty Optional @Test void getKey_whenKeyNotExist_thenReturnEmptyOptional() throws IOException { @@ -273,18 +266,9 @@ class GitDBTest implements WithAssertions { private GitDBBranch gitDBBranch() { try { - final Result gitDBResult = gitDB(dirDoesNotExist()); - System.out.println("gitDBResult = " + gitDBResult); - final Result> master = gitDBResult.flatMap(db -> { - final Result> maybeResult = db.branch("master"); - System.out.println("maybeResult = " + maybeResult); - return maybeResult; - }); - assert master != null; - System.out.println("master = " + master); - final Maybe gitDBBranchMaybe = master.orElseThrow(); - final GitDBBranch gitDBBranch = gitDBBranchMaybe.orElse(null); - return gitDBBranch; + return gitDB(dirDoesNotExist()) + .flatMap(selectBranch("master")) + .orElseThrow().orElse(null); } catch (Throwable throwable) { throw new RuntimeException("Couldn't create master branch", throwable); } @@ -321,8 +305,6 @@ class GitDBTest implements WithAssertions { success -> assertThat(success).isNotNull().isNotSameAs(originalBranch), failOnError() ); - assertThat(updatedBranch).isNotNull() - .isNotSameAs(originalBranch); } // When getting a key that does exist then the value is returned inside an Optional From 98b81a44dcd02349db150c1f9952047a0a95c98e Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Tue, 26 Jun 2018 23:06:03 +0100 Subject: [PATCH 05/10] NamedRevBlob returns Result values --- .../net/kemitix/gitdb/impl/GitDBRepo.java | 20 ++++++++++--------- .../net/kemitix/gitdb/impl/NamedRevBlob.java | 13 +++++++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java index 7af698b..ffc12c3 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java @@ -21,7 +21,6 @@ package net.kemitix.gitdb.impl; -import lombok.val; import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.ObjectId; @@ -30,6 +29,7 @@ import org.eclipse.jgit.lib.Repository; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; /** * Wrapper for interacting with the GitDB Repository. @@ -85,15 +85,17 @@ class GitDBRepo { final Ref branchRef, final String key ) { + final GitTreeReader treeFilter = new GitTreeReader(repository).treeFilter(key); + return streamTree(branchRef, treeFilter).flatMap(s -> + Result.invert(s.findFirst() + .map(NamedRevBlob::blobAsString) + .map(Maybe::just) + .orElseGet(Maybe::nothing))); + } + + private Result> streamTree(final Ref branchRef, final GitTreeReader treeFilter) { try { - val blob = new GitTreeReader(repository) - .treeFilter(key) - .stream(branchRef) - .findFirst(); - if (blob.isPresent()) { - return Result.ok(Maybe.just(blob.get().blobAsString())); - } - return Result.ok(Maybe.nothing()); + return Result.ok(treeFilter.stream(branchRef)); } catch (IOException e) { return Result.error(e); } diff --git a/src/main/java/net/kemitix/gitdb/impl/NamedRevBlob.java b/src/main/java/net/kemitix/gitdb/impl/NamedRevBlob.java index 09a39ec..d8376b6 100644 --- a/src/main/java/net/kemitix/gitdb/impl/NamedRevBlob.java +++ b/src/main/java/net/kemitix/gitdb/impl/NamedRevBlob.java @@ -24,7 +24,9 @@ package net.kemitix.gitdb.impl; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevBlob; @@ -48,10 +50,15 @@ class NamedRevBlob { * 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()); + Result blobAsString() { + try { + return Result.ok(repository.open(revBlob.getId(), Constants.OBJ_BLOB)) + .map(ObjectLoader::getBytes) + .map(String::new); + } catch (IOException e) { + return Result.error(e); + } } } From 9eff624a054de72d7b1c8a4f17c608b84864e110 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 30 Jun 2018 20:37:32 +0100 Subject: [PATCH 06/10] More classes return Result values --- pom.xml | 2 +- .../kemitix/gitdb/impl/GitDBBranchImpl.java | 13 ++-- .../net/kemitix/gitdb/impl/GitDBRepo.java | 18 ++--- .../net/kemitix/gitdb/impl/GitTreeReader.java | 69 ++++++++++++++----- .../net/kemitix/gitdb/impl/InitGitDBRepo.java | 24 ++++--- .../net/kemitix/gitdb/impl/KeyRemover.java | 16 ++--- .../net/kemitix/gitdb/impl/KeyWriter.java | 32 ++++----- .../net/kemitix/gitdb/impl/ValueWriter.java | 8 +-- 8 files changed, 103 insertions(+), 79 deletions(-) diff --git a/pom.xml b/pom.xml index c40c88c..aaa405f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.11.0.201803080745-r 5.2.0 3.10.0 - 0.7.0 + 0.8.0 2.18.3 0.9.0 diff --git a/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java b/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java index 9b90a36..92b495b 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitDBBranchImpl.java @@ -31,7 +31,6 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; -import java.io.IOException; import java.util.function.Function; /** @@ -81,14 +80,10 @@ class GitDBBranchImpl implements GitDBBranch { @Override public Result put(final String key, final String value) { - try { - final ObjectId newTree = gitDBRepo.writeValue(branchRef, KEY_PREFIX + key, value); - final String message = String.format("Add key [%s] = [%s]", key, value); - final Result newBranch = gitDBRepo.writeCommit(branchRef, newTree, message, userName, userEmailAddress); - return newBranch.flatMap(b -> select(b, gitDBRepo, userName, userEmailAddress)); - } catch (IOException e) { - return Result.error(e); - } + final String message = String.format("Add key [%s] = [%s]", key, value); + return gitDBRepo.writeValue(branchRef, KEY_PREFIX + key, value) + .flatMap(nt -> gitDBRepo.writeCommit(branchRef, nt, message, userName, userEmailAddress)) + .flatMap(nb -> select(nb, gitDBRepo, userName, userEmailAddress)); } @Override diff --git a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java index ffc12c3..3a9e1ab 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java @@ -65,12 +65,11 @@ class GitDBRepo { * @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( + Result insertNewTree( final String key, final ObjectId valueId - ) throws IOException { + ) { return keyWriter.writeFirst(key, valueId); } @@ -94,11 +93,7 @@ class GitDBRepo { } private Result> streamTree(final Ref branchRef, final GitTreeReader treeFilter) { - try { - return Result.ok(treeFilter.stream(branchRef)); - } catch (IOException e) { - return Result.error(e); - } + return treeFilter.stream(branchRef); } /** @@ -110,11 +105,10 @@ class GitDBRepo { * @param key the key to place the value under * @param value the value * @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 = valueWriter.write(value.getBytes(StandardCharsets.UTF_8)); - return keyWriter.write(key, blob, branchRef); + Result writeValue(final Ref branchRef, final String key, final String value) { + return valueWriter.write(value.getBytes(StandardCharsets.UTF_8)) + .flatMap(b -> keyWriter.write(key, b, branchRef)); } /** diff --git a/src/main/java/net/kemitix/gitdb/impl/GitTreeReader.java b/src/main/java/net/kemitix/gitdb/impl/GitTreeReader.java index 5abd235..76c82f7 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitTreeReader.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitTreeReader.java @@ -23,15 +23,20 @@ package net.kemitix.gitdb.impl; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; 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.concurrent.Callable; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Stream; /** @@ -51,23 +56,55 @@ class GitTreeReader { * * @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 stream(final Ref branchRef) throws IOException { + Result> stream(final Ref branchRef) { final TreeWalk treeWalk = new TreeWalk(repository); final RevWalk revWalk = new RevWalk(repository); - treeWalk.addTree(revWalk.parseCommit(branchRef.getObjectId()).getTree()); - treeWalk.setRecursive(false); - Optional.ofNullable(treeFilter) - .ifPresent(treeWalk::setFilter); - final Stream.Builder builder = Stream.builder(); - while (treeWalk.next()) { - builder.add(new NamedRevBlob( - treeWalk.getNameString(), - revWalk.lookupBlob(treeWalk.getObjectId(0)), - repository)); - } - return builder.build(); + return Result.of(parseBranchCommit(branchRef, revWalk)) + .map(RevCommit::getTree) + .flatMap(addTreeTo(treeWalk)) + .peek(disableRecursion(treeWalk)) + .peek(setTreeFilter(treeWalk)) + .flatMap(streamMatching(treeWalk, revWalk)); + } + + private Function>> streamMatching( + final TreeWalk treeWalk, + final RevWalk revWalk + ) { + return x -> Result.of(() -> { + final Stream.Builder builder = Stream.builder(); + while (treeWalk.next()) { + builder.add(namedRevBlob(treeWalk, revWalk)); + } + return builder.build(); + }); + } + + private NamedRevBlob namedRevBlob(TreeWalk treeWalk, RevWalk revWalk) { + return new NamedRevBlob( + treeWalk.getNameString(), + revWalk.lookupBlob(treeWalk.getObjectId(0)), + repository); + } + + private Consumer setTreeFilter(TreeWalk treeWalk) { + return x -> Optional.ofNullable(treeFilter).ifPresent(treeWalk::setFilter); + } + + private Consumer disableRecursion(TreeWalk treeWalk) { + return x -> treeWalk.setRecursive(false); + } + + private Function> addTreeTo(TreeWalk treeWalk) { + return tree -> Result.of(() -> { + treeWalk.addTree(tree); + return null; + }); + } + + private Callable parseBranchCommit(Ref branchRef, RevWalk revWalk) { + return () -> revWalk.parseCommit(branchRef.getObjectId()); } /** @@ -77,7 +114,7 @@ class GitTreeReader { * @return the GitTreeReader */ GitTreeReader treeFilter(final String path) { - this.treeFilter = PathFilter.create(path); + treeFilter = PathFilter.create(path); return this; } diff --git a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java index 25b4fb4..41004bd 100644 --- a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java @@ -79,13 +79,16 @@ class InitGitDBRepo { return dbDir; } - private void createInitialBranchOnMaster(final Repository repository) throws IOException { + private Result createInitialBranchOnMaster(final Repository repository) { final GitDBRepo repo = new GitDBRepo(repository); - final ValueWriter valueWriter = new ValueWriter(repository); - final ObjectId objectId = valueWriter.write(new FormatVersion().toBytes()); - final ObjectId treeId = repo.insertNewTree(GIT_DB_VERSION, objectId); - final ObjectId commitId = repo.initialCommit(treeId, INIT_MESSAGE, INIT_USER, INIT_EMAIL); - createBranch(repository, commitId, MASTER); + return new ValueWriter(repository) + .write(new FormatVersion().toBytes()) + .flatMap(oid -> repo.insertNewTree(GIT_DB_VERSION, oid)) + .flatMap(tid -> Result.of(() -> repo.initialCommit(tid, INIT_MESSAGE, INIT_USER, INIT_EMAIL))) + .flatMap(cid -> Result.of(() -> { + createBranch(repository, cid, MASTER); + return null; + })); } private void verifyIsNotAFile(final File dbDir) throws NotDirectoryException { @@ -102,14 +105,17 @@ class InitGitDBRepo { } } - private void createBranch( + private Result createBranch( final Repository repository, final ObjectId commitId, final String branchName - ) throws IOException { + ) { final Path branchRefPath = branchRefPath(repository, branchName); final byte[] commitIdBytes = commitId.name().getBytes(StandardCharsets.UTF_8); - Files.write(branchRefPath, commitIdBytes); + return Result.of(() -> { + Files.write(branchRefPath, commitIdBytes); + return null; + }); } private Path branchRefPath( diff --git a/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java b/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java index 6146f0c..392e540 100644 --- a/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java +++ b/src/main/java/net/kemitix/gitdb/impl/KeyRemover.java @@ -51,16 +51,12 @@ class KeyRemover { Result> remove(final Ref branchRef, final String key) { final TreeFormatter treeFormatter = new TreeFormatter(); final AtomicBoolean removed = new AtomicBoolean(false); - try { - new GitTreeReader(repository) - .stream(branchRef) - .peek(flagIfFound(key, removed)) - .filter(isNotKey(key)) - .forEach(addToTree(treeFormatter)); - return insertTree(treeFormatter).maybe(oi -> removed.get()); - } catch (IOException e) { - return Result.error(e); - } + new GitTreeReader(repository) + .stream(branchRef) + .peek(s -> s.peek(flagIfFound(key, removed)) + .filter(isNotKey(key)) + .forEach(addToTree(treeFormatter))); + return insertTree(treeFormatter).maybe(oi -> removed.get()); } /** diff --git a/src/main/java/net/kemitix/gitdb/impl/KeyWriter.java b/src/main/java/net/kemitix/gitdb/impl/KeyWriter.java index 1dc00c1..0c7364b 100644 --- a/src/main/java/net/kemitix/gitdb/impl/KeyWriter.java +++ b/src/main/java/net/kemitix/gitdb/impl/KeyWriter.java @@ -21,10 +21,9 @@ package net.kemitix.gitdb.impl; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.*; -import java.io.IOException; - /** * Writes Keys into the Git Repository. * @@ -48,42 +47,41 @@ class KeyWriter { /** * Write the first key into a new tree. * - * @param key the key + * @param key the key * @param valueId the id of the value * @return the id of the new tree - * @throws IOException if there is an error writing the key */ - ObjectId writeFirst(final String key, final ObjectId valueId) throws IOException { + Result writeFirst(final String key, final ObjectId valueId) { return writeTree(key, valueId, new TreeFormatter()); } /** * Write the key into a tree. * - * @param key the key - * @param valueId the id of the value + * @param key the key + * @param valueId the id of the value * @param branchRef the branch whose tree should be updated * @return the id of the updated tree - * @throws IOException if there is an error writing the key */ - ObjectId write(final String key, final ObjectId valueId, final Ref branchRef) throws IOException { - return writeTree(key, valueId, getTreeFormatter(branchRef)); + Result write(final String key, final ObjectId valueId, final Ref branchRef) { + return getTreeFormatter(branchRef) + .flatMap(f -> writeTree(key, valueId, f)); } - private TreeFormatter getTreeFormatter(final Ref branchRef) throws IOException { + private Result getTreeFormatter(final Ref branchRef) { final TreeFormatter treeFormatter = new TreeFormatter(); final GitTreeReader gitTreeReader = new GitTreeReader(repository); - gitTreeReader.stream(branchRef) - .forEach(item -> treeFormatter.append(item.getName(), item.getRevBlob())); - return treeFormatter; + return gitTreeReader.stream(branchRef) + .peek(s -> s.forEach(item -> treeFormatter.append(item.getName(), item.getRevBlob()))) + .map(x -> treeFormatter); } - private ObjectId writeTree( + private Result writeTree( final String key, final ObjectId valueId, final TreeFormatter treeFormatter - ) throws IOException { + ) { treeFormatter.append(key, FileMode.REGULAR_FILE, valueId); - return objectInserter.insert(treeFormatter); + return Result.of(() -> objectInserter.insert(treeFormatter)); } } diff --git a/src/main/java/net/kemitix/gitdb/impl/ValueWriter.java b/src/main/java/net/kemitix/gitdb/impl/ValueWriter.java index f066551..7fa9b37 100644 --- a/src/main/java/net/kemitix/gitdb/impl/ValueWriter.java +++ b/src/main/java/net/kemitix/gitdb/impl/ValueWriter.java @@ -21,13 +21,12 @@ package net.kemitix.gitdb.impl; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.Repository; -import java.io.IOException; - /** * Writes Values into the Git Repository. * @@ -51,9 +50,8 @@ class ValueWriter { * * @param blob the value blob * @return the id of the value object - * @throws IOException if there is an error writing the value */ - ObjectId write(final byte[] blob) throws IOException { - return objectInserter.insert(Constants.OBJ_BLOB, blob); + Result write(final byte[] blob) { + return Result.of(() -> objectInserter.insert(Constants.OBJ_BLOB, blob)); } } From ae852be86f86df982ea35c1655dbc4306d0e9466 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 30 Jun 2018 20:47:00 +0100 Subject: [PATCH 07/10] CommitWriter and GitDBRepo return Result values --- .../net/kemitix/gitdb/impl/CommitWriter.java | 15 +++++-------- .../net/kemitix/gitdb/impl/GitDBRepo.java | 22 ++++++------------- .../net/kemitix/gitdb/impl/InitGitDBRepo.java | 2 +- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/impl/CommitWriter.java b/src/main/java/net/kemitix/gitdb/impl/CommitWriter.java index 4f9cf11..9b2dd07 100644 --- a/src/main/java/net/kemitix/gitdb/impl/CommitWriter.java +++ b/src/main/java/net/kemitix/gitdb/impl/CommitWriter.java @@ -21,10 +21,9 @@ package net.kemitix.gitdb.impl; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.*; -import java.io.IOException; - /** * Commits Key/Value updates into the Git Repository. * @@ -52,15 +51,14 @@ class CommitWriter { * @param userName the user name * @param userEmailAddress the user email address * @return the id of the commit - * @throws IOException if there is an error writing the value */ - ObjectId write( + Result write( final ObjectId treeId, final ObjectId parentId, final String message, final String userName, final String userEmailAddress - ) throws IOException { + ) { final CommitBuilder commitBuilder = new CommitBuilder(); commitBuilder.setTreeId(treeId); commitBuilder.setMessage(message); @@ -68,7 +66,7 @@ class CommitWriter { commitBuilder.setAuthor(ident); commitBuilder.setCommitter(ident); commitBuilder.setParentId(parentId); - return objectInserter.insert(commitBuilder); + return Result.of(() -> objectInserter.insert(commitBuilder)); } /** @@ -82,15 +80,14 @@ class CommitWriter { * @param userName the user name * @param userEmailAddress the user email address * @return the id of the commit - * @throws IOException if there is an error writing the value */ - ObjectId write( + Result write( final ObjectId treeId, final Ref branchRef, final String message, final String userName, final String userEmailAddress - ) throws IOException { + ) { return write(treeId, branchRef.getObjectId(), message, userName, userEmailAddress); } } diff --git a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java index 3a9e1ab..8bdedce 100644 --- a/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/GitDBRepo.java @@ -27,7 +27,6 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.stream.Stream; @@ -120,7 +119,6 @@ class GitDBRepo { * @param userName the user name * @param userEmailAddress the user email address * @return the Ref of the updated branch - * @throws IOException if there was an error writing the branch */ Result writeCommit( final Ref branchRef, @@ -129,12 +127,9 @@ class GitDBRepo { final String userName, final String userEmailAddress ) { - try { - final ObjectId commitId = insertCommit(tree, message, userName, userEmailAddress, branchRef); - return Result.ok(headWriter.write(branchRef.getName(), commitId)); - } catch (IOException e) { - return Result.error(e); - } + return insertCommit(tree, message, userName, userEmailAddress, branchRef) + .flatMap(cid -> Result.of(() -> + headWriter.write(branchRef.getName(), cid))); } /** @@ -146,15 +141,14 @@ class GitDBRepo { * @param userName the user name * @param userEmailAddress the user email address * @return the id of the commit - * @throws IOException the commit could not be stored */ - ObjectId insertCommit( + Result insertCommit( final ObjectId treeId, final String message, final String userName, final String userEmailAddress, final Ref branchRef - ) throws IOException { + ) { return commitWriter.write(treeId, branchRef, message, userName, userEmailAddress); } @@ -166,14 +160,13 @@ class GitDBRepo { * @param initUser the user name * @param initEmail the user email address * @return the id of the commit - * @throws IOException if there was an error writing the commit */ - ObjectId initialCommit( + Result initialCommit( final ObjectId treeId, final String initMessage, final String initUser, final String initEmail - ) throws IOException { + ) { return commitWriter.write(treeId, ObjectId.zeroId(), initMessage, initUser, initEmail); } @@ -186,7 +179,6 @@ class GitDBRepo { * @param key the key to place the value under * @return an Optional containing the id of the updated tree containing the update, if the key was found, or an * empty Optional if there key was not found, the there was no changes made - * @throws IOException if there was an error writing the value */ Result> removeKey(final Ref branchRef, final String key) { return keyRemover.remove(branchRef, key); diff --git a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java index 41004bd..ae39f7b 100644 --- a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java @@ -84,7 +84,7 @@ class InitGitDBRepo { return new ValueWriter(repository) .write(new FormatVersion().toBytes()) .flatMap(oid -> repo.insertNewTree(GIT_DB_VERSION, oid)) - .flatMap(tid -> Result.of(() -> repo.initialCommit(tid, INIT_MESSAGE, INIT_USER, INIT_EMAIL))) + .flatMap(tid -> repo.initialCommit(tid, INIT_MESSAGE, INIT_USER, INIT_EMAIL)) .flatMap(cid -> Result.of(() -> { createBranch(repository, cid, MASTER); return null; From c4034a291fb67eb3613a1b84cf40f7af77cde78d Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 30 Jun 2018 21:02:09 +0100 Subject: [PATCH 08/10] InitGitDBRepo return Result values --- .../net/kemitix/gitdb/impl/InitGitDBRepo.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java index ae39f7b..b2cc831 100644 --- a/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java +++ b/src/main/java/net/kemitix/gitdb/impl/InitGitDBRepo.java @@ -51,32 +51,26 @@ class InitGitDBRepo { * Initialise a new GitDB repo. * * @param dbDir the directory to initialise the repo in - * @throws IOException if there is an error in creating the repo files */ static Result create(final Path dbDir) { final InitGitDBRepo initRepo = new InitGitDBRepo(); - final File validDbDir; - try { - validDbDir = initRepo.validDbDir(dbDir.toFile()); - } catch (IOException e) { - return Result.error(e); - } - validDbDir.mkdirs(); - try (Repository repository = RepositoryCache.FileKey.exact(validDbDir, FS.DETECTED).open(false)) { - repository.create(true); - initRepo.createInitialBranchOnMaster(repository); - } catch (IOException e) { - return Result.error(e); - } - return Result.ok(null); + return initRepo.validDbDir(dbDir.toFile()) + .peek(File::mkdirs) + .flatMap(dir -> { + try (Repository repository = RepositoryCache.FileKey.exact(dir, FS.DETECTED).open(false)) { + repository.create(true); + initRepo.createInitialBranchOnMaster(repository); + } catch (IOException e) { + return Result.error(e); + } + return Result.ok(null); + }); } - private File validDbDir(final File dbDir) throws IOException { - verifyIsNotAFile(dbDir); - if (dbDir.exists()) { - verifyIsEmpty(dbDir); - } - return dbDir; + private Result validDbDir(final File dbDir) { + return Result.ok(dbDir) + .flatMap(this::verifyIsNotAFile) + .flatMap(this::isEmptyIfExists); } private Result createInitialBranchOnMaster(final Repository repository) { @@ -91,18 +85,26 @@ class InitGitDBRepo { })); } - private void verifyIsNotAFile(final File dbDir) throws NotDirectoryException { + private Result verifyIsNotAFile(final File dbDir) { if (dbDir.isFile()) { - throw new NotDirectoryException(dbDir.toString()); + return Result.error(new NotDirectoryException(dbDir.toString())); } + return Result.ok(dbDir); } - private void verifyIsEmpty(final File dbDir) throws IOException { - try (DirectoryStream directoryStream = Files.newDirectoryStream(dbDir.toPath())) { - if (directoryStream.iterator().hasNext()) { - throw new DirectoryNotEmptyException(dbDir.toString()); - } + private Result isEmptyIfExists(final File dbDir) { + if (dbDir.exists()) { + return Result.of(() -> { + try (DirectoryStream directoryStream = Files.newDirectoryStream(dbDir.toPath())) { + if (directoryStream.iterator().hasNext()) { + throw new DirectoryNotEmptyException(dbDir.toString()); + } + } + return dbDir; + } + ); } + return Result.ok(dbDir); } private Result createBranch( From d1acd4a0dc3952f875d40c5ec374780d2c5f32ed Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 30 Jun 2018 21:05:38 +0100 Subject: [PATCH 09/10] HeadWriter returns Result values --- src/main/java/net/kemitix/gitdb/impl/HeadWriter.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/kemitix/gitdb/impl/HeadWriter.java b/src/main/java/net/kemitix/gitdb/impl/HeadWriter.java index 39f2107..c9d6351 100644 --- a/src/main/java/net/kemitix/gitdb/impl/HeadWriter.java +++ b/src/main/java/net/kemitix/gitdb/impl/HeadWriter.java @@ -22,11 +22,11 @@ package net.kemitix.gitdb.impl; import lombok.RequiredArgsConstructor; +import net.kemitix.mon.result.Result; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -47,16 +47,17 @@ class HeadWriter { * @param branchName the branch name * @param commitId the commit to point the branch at * @return the Ref of the new branch - * @throws IOException error writing branch head */ - Ref write(final String branchName, final ObjectId commitId) throws IOException { + Result write(final String branchName, final ObjectId commitId) { 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); + return Result.of(() -> { + Files.write(branchRefPath, commitIdBytes); + return repository.findRef(branchName); + }); } } From fd70dbacc393e2fa8638fb129b8f8c90fb5acd10 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 30 Jun 2018 21:08:12 +0100 Subject: [PATCH 10/10] GitDBTest clean up tests throwing exceptions --- .../java/net/kemitix/gitdb/test/GitDBTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java index 7302324..fdf15b8 100644 --- a/src/test/java/net/kemitix/gitdb/test/GitDBTest.java +++ b/src/test/java/net/kemitix/gitdb/test/GitDBTest.java @@ -252,7 +252,7 @@ class GitDBTest implements WithAssertions { // When getting a key that does not exist then return an empty Optional @Test - void getKey_whenKeyNotExist_thenReturnEmptyOptional() throws IOException { + void getKey_whenKeyNotExist_thenReturnEmptyOptional() { //given final GitDBBranch branch = gitDBBranch(); //when @@ -280,7 +280,7 @@ class GitDBTest implements WithAssertions { // When getting the format version it matches expected @Test - void getVersionFormat_thenFormatIsSet() throws IOException { + void getVersionFormat_thenFormatIsSet() { //given final GitDBBranch gitDBBranch = gitDBBranch(); final Version version = new FormatVersion().getVersion(); @@ -295,7 +295,7 @@ class GitDBTest implements WithAssertions { // When putting a key/value pair then a GitDbBranch is returned @Test - void putValue_thenReturnUpdatedGitDBBranch() throws IOException { + void putValue_thenReturnUpdatedGitDBBranch() { //given final GitDBBranch originalBranch = gitDBBranch(); //when @@ -309,7 +309,7 @@ class GitDBTest implements WithAssertions { // When getting a key that does exist then the value is returned inside an Optional @Test - void getKey_whenExists_thenReturnValueInOptional() throws IOException { + void getKey_whenExists_thenReturnValueInOptional() { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); @@ -326,7 +326,7 @@ class GitDBTest implements WithAssertions { // When removing a key that does not exist then the GitDbBranch is returned @Test - void removeKey_whenNotExist_thenReturnOriginal() throws IOException { + void removeKey_whenNotExist_thenReturnOriginal() { //given final GitDBBranch gitDBBranch = gitDBBranch(); //when @@ -340,7 +340,7 @@ class GitDBTest implements WithAssertions { // When removing a key that does exist then a GitDbBranch is returned @Test - void removeKey_whenExists_thenReturnUpdatedBranch() throws IOException { + void removeKey_whenExists_thenReturnUpdatedBranch() { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); @@ -354,13 +354,13 @@ class GitDBTest implements WithAssertions { ); } - private Result gitDBBranchWithKeyValue(final String key, final String value) throws IOException { + private Result gitDBBranchWithKeyValue(final String key, final String value) { return gitDBBranch().put(key, value); } // When removing a key that does exist then original GitDbBranch can still find it @Test - void removeKey_whenExists_thenOriginalCanStillFind() throws IOException { + void removeKey_whenExists_thenOriginalCanStillFind() { //given final String key = stringSupplier.get(); final String value = stringSupplier.get(); @@ -377,7 +377,7 @@ class GitDBTest implements WithAssertions { // When removing a key that does exist then the updated GitDbBranch can't find it @Test - void removeKey_whenExists_thenUpdatedCanNotFind() throws IOException { + void removeKey_whenExists_thenUpdatedCanNotFind() { //given final String key = stringSupplier.get(); final String value = stringSupplier.get();