From 193a0f380b879574a97d6cafa181e8b197eb96af Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 24 Jun 2018 09:16:05 +0100 Subject: [PATCH] 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();