Skip to content
Snippets Groups Projects
Commit 8d93dd5a authored by Florian Heck's avatar Florian Heck
Browse files

Changed package structure and eliminated obsolete abstract repository class

parent 54a020f2
No related branches found
No related tags found
1 merge request!2Change package structure
Showing
with 227 additions and 320 deletions
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.nio.file.Path;
import java.util.Collections;
......@@ -68,7 +68,7 @@ public class BlameLine {
/**
* Constructs a new {@link BlameLine}. This method is to be used when the 'git blame' parser in
* {@link LocalRepository#parseBlameLines(String)} first reads the commit header for a commit.
* {@link Repository#parseBlameLines(String)} first reads the commit header for a commit.
*
* @param commit
* the last commit to change the line
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.util.Optional;
import java.util.function.Function;
import java.util.logging.Logger;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor;
import de.uni_passau.fim.processexecutor.ProcessExecutor;
/**
* A {@link Branch} is a named {@link Reference} to a git branch pointing to a {@link Commit}.
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.nio.file.Path;
import java.time.Instant;
......@@ -13,7 +13,7 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import de.uni_passau.fim.processexecutor.ProcessExecutor;
/**
* A {@link Commit} made in a {@link Repository}.
......@@ -59,8 +59,8 @@ public class Commit extends Reference {
* <code>false</code>, if not and an {@link Optional#EMPTY empty optional}, if an error occurred.
*/
public Optional<Boolean> checkAncestry(Commit ancestor) {
Optional<ExecRes> res = git.exec(repo.getDir(), "merge-base", "--is-ancestor", ancestor.getId(), id);
Function<ExecRes, Boolean> toBoolean = execRes -> {
Optional<ProcessExecutor.ExecRes> res = git.exec(repo.getDir(), "merge-base", "--is-ancestor", ancestor.getId(), id);
Function<ProcessExecutor.ExecRes, Boolean> toBoolean = execRes -> {
if (execRes.exitCode == 0) {
return Boolean.TRUE;
......@@ -83,8 +83,8 @@ public class Commit extends Reference {
* @return optionally the {@link List} of {@link Path Paths}
*/
public Optional<List<Path>> getAffectedPaths() {
Optional<ExecRes> res = git.exec(repo.getDir(), "log", "-m", "-1", "--name-only", "--pretty=format:", id);
Function<ExecRes, List<Path>> toPaths = execRes -> {
Optional<ProcessExecutor.ExecRes> res = git.exec(repo.getDir(), "log", "-m", "-1", "--name-only", "--pretty=format:", id);
Function<ProcessExecutor.ExecRes, List<Path>> toPaths = execRes -> {
Supplier<String> errorMsg = () -> "Failed to determine the paths affected by '" + this + "'.";
if (git.failed(execRes)) {
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.util.Optional;
import static de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import de.uni_passau.fim.processexecutor.ProcessExecutor;
/**
* A {@link MergeStrategy} representing the default 'git merge' merge implementation.
......@@ -24,7 +24,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
@Override
public Optional<Status> merge(Reference left, Reference right) {
Optional<ExecRes> mergeBase = repo.getGit().exec(repo.getDir(), "merge", "-n", "-q", right.getId());
Optional<ProcessExecutor.ExecRes> mergeBase = repo.getGit().exec(repo.getDir(), "merge", "-n", "-q", right.getId());
return mergeBase.flatMap(res -> repo.getStatus());
}
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.time.OffsetDateTime;
import java.util.logging.Logger;
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.io.File;
import java.io.IOException;
......@@ -21,9 +21,9 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import de.uni_passau.fim.seibt.gitwrapper.process.ToolNotWorkingException;
import de.uni_passau.fim.seibt.gitwrapper.process.ToolWrapper;
import de.uni_passau.fim.processexecutor.ProcessExecutor;
import de.uni_passau.fim.processexecutor.ToolNotWorkingException;
import de.uni_passau.fim.processexecutor.ToolWrapper;
import static java.util.Collections.singletonList;
......@@ -84,7 +84,7 @@ public class GitWrapper extends ToolWrapper {
@Override
protected boolean isWorking() {
Function<ExecRes, Boolean> checkPrefix = execRes -> execRes.getStdOutTrimmed().startsWith(GIT_VERSION_PREFIX);
Function<ProcessExecutor.ExecRes, Boolean> checkPrefix = execRes -> execRes.getStdOutTrimmed().startsWith(GIT_VERSION_PREFIX);
return exec(new File("."), true, singletonList(GIT_VERSION_C)).map(checkPrefix).orElse(false);
}
......@@ -104,8 +104,8 @@ public class GitWrapper extends ToolWrapper {
public Optional<Repository> clone(File parentDir, String url, boolean fetch) {
LOG.fine(() -> String.format("Cloning '%s'.", url));
Optional<ExecRes> res = exec(parentDir, "clone", url);
Function<ExecRes, Repository> toRepo = execRes -> {
Optional<ProcessExecutor.ExecRes> res = exec(parentDir, "clone", url);
Function<ProcessExecutor.ExecRes, Repository> toRepo = execRes -> {
Scanner sc = new Scanner(execRes.getStdOutTrimmed());
if (!sc.hasNextLine()) {
......@@ -133,7 +133,7 @@ public class GitWrapper extends ToolWrapper {
if (execRes.succeeded()) {
LOG.fine(() -> String.format("Cloned '%s' into '%s'.", url, repoPath));
return new LocalRepository(this, url, repoDir);
return new Repository(this, url, repoDir);
} else {
LOG.fine(() -> String.format("Found '%s' which would be produced for '%s'", repoPath, url));
......@@ -143,7 +143,7 @@ public class GitWrapper extends ToolWrapper {
}
LOG.fine(() -> String.format("'%s' is a git repository. Assuming it is a clone of '%s'.", repoPath, url));
Repository repo = new LocalRepository(this, url, repoDir);
Repository repo = new Repository(this, url, repoDir);
if (fetch && !repo.fetch()) {
LOG.warning("Could not fetch " + repo + ". It may be out of date.");
......@@ -169,8 +169,8 @@ public class GitWrapper extends ToolWrapper {
return Optional.empty();
}
Optional<ExecRes> originURL = exec(directory, "config", "--get", "remote.origin.url");
Function<ExecRes, Repository> toRepository = res -> {
Optional<ProcessExecutor.ExecRes> originURL = exec(directory, "config", "--get", "remote.origin.url");
Function<ProcessExecutor.ExecRes, Repository> toRepository = res -> {
String repoUrl = null;
if (failed(res)) {
......@@ -194,7 +194,7 @@ public class GitWrapper extends ToolWrapper {
}
}
return new LocalRepository(this, repoUrl, directory);
return new Repository(this, repoUrl, directory);
};
return originURL.map(toRepository);
......@@ -215,7 +215,7 @@ public class GitWrapper extends ToolWrapper {
return false;
}
Optional<ExecRes> status = exec(directory, "rev-parse", "--is-inside-git-dir");
Optional<ProcessExecutor.ExecRes> status = exec(directory, "rev-parse", "--is-inside-git-dir");
return status.map(res -> !failed(res)).orElse(false);
}
......@@ -224,10 +224,10 @@ public class GitWrapper extends ToolWrapper {
* the output (in case of failure) starts with either "{@value FATAL_PREFIX}" or "{@value ERROR_PREFIX}".
*
* @param res
* the {@link ExecRes} to check
* the {@link ProcessExecutor.ExecRes} to check
* @return whether the git command failed
*/
public boolean failed(ExecRes res) {
public boolean failed(ProcessExecutor.ExecRes res) {
return res.failed() || failedPrefix(res);
}
......@@ -236,10 +236,10 @@ public class GitWrapper extends ToolWrapper {
* "{@value FATAL_PREFIX}" or "{@value ERROR_PREFIX}". This method ignores the exit code.
*
* @param res
* the {@link ExecRes} to check
* the {@link ProcessExecutor.ExecRes} to check
* @return whether the git command failed
*/
public boolean failedPrefix(ExecRes res) {
public boolean failedPrefix(ProcessExecutor.ExecRes res) {
return res.getStdOutTrimmed().startsWith(FATAL_PREFIX) || res.getStdOutTrimmed().startsWith(ERROR_PREFIX);
}
......@@ -352,7 +352,7 @@ public class GitWrapper extends ToolWrapper {
* the git parameters
* @return the result of the execution
*/
public Optional<ExecRes> exec(File workingDirectory, String firstParameter, String... parameters) {
public Optional<ProcessExecutor.ExecRes> exec(File workingDirectory, String firstParameter, String... parameters) {
return exec(workingDirectory, null, firstParameter, parameters);
}
......@@ -370,7 +370,7 @@ public class GitWrapper extends ToolWrapper {
* the git parameters
* @return the result of the execution
*/
public Optional<ExecRes> exec(File workingDirectory, Map<String, String> environment, String firstParameter, String... parameters) {
public Optional<ProcessExecutor.ExecRes> exec(File workingDirectory, Map<String, String> environment, String firstParameter, String... parameters) {
List<String> pars = new ArrayList<>(defaultOptions.size() + ((parameters != null) ? parameters.length + 1 : 1));
pars.addAll(defaultOptions);
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.nio.file.Path;
import java.util.Collections;
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.util.Optional;
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.util.Arrays;
import java.util.List;
......@@ -8,7 +8,7 @@ import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import de.uni_passau.fim.processexecutor.ProcessExecutor;
/**
* A git object referencing a tree-ish object.
......@@ -66,8 +66,8 @@ public abstract class Reference {
return Optional.empty();
}
Optional<ExecRes> mergeBase = git.exec(repo.getDir(), "merge-base", getId(), other.getId());
Function<ExecRes, Commit> toCommit = res -> {
Optional<ProcessExecutor.ExecRes> mergeBase = git.exec(repo.getDir(), "merge-base", getId(), other.getId());
Function<ProcessExecutor.ExecRes, Commit> toCommit = res -> {
if (git.failed(res)) {
LOG.warning(() -> String.format("Failed to obtain a merge base for %s and %s.", this, other));
......@@ -108,8 +108,8 @@ public abstract class Reference {
* @return the parent {@link Commit} objects
*/
public Optional<List<Commit>> getParents() {
Optional<ExecRes> revList = git.exec(repo.getDir(), "rev-list", "--parents", "-n", "1", id);
Function<ExecRes, List<Commit>> toParentsList = res -> {
Optional<ProcessExecutor.ExecRes> revList = git.exec(repo.getDir(), "rev-list", "--parents", "-n", "1", id);
Function<ProcessExecutor.ExecRes, List<Commit>> toParentsList = res -> {
if (git.failed(res)) {
LOG.warning(() -> String.format("Could not find the parents of %s.", this));
return null;
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
......@@ -6,33 +8,23 @@ import java.nio.file.Path;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Scanner;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import org.apache.commons.io.FileUtils;
import static de.uni_passau.fim.seibt.gitwrapper.repo.LocalRepository.ConflictMarker.CONFLICT_END;
import static de.uni_passau.fim.seibt.gitwrapper.repo.LocalRepository.ConflictMarker.CONFLICT_MIDDLE;
import static de.uni_passau.fim.seibt.gitwrapper.repo.LocalRepository.ConflictMarker.CONFLICT_START;
import static de.uni_passau.fim.gitwrapper.Repository.ConflictMarker.CONFLICT_END;
import static de.uni_passau.fim.gitwrapper.Repository.ConflictMarker.CONFLICT_MIDDLE;
import static de.uni_passau.fim.gitwrapper.Repository.ConflictMarker.CONFLICT_START;
import static de.uni_passau.fim.processexecutor.ProcessExecutor.ExecRes;
/**
* A git {@link Repository}.
*/
public class LocalRepository extends Repository {
public class Repository {
private static final Logger LOG = Logger.getLogger(LocalRepository.class.getCanonicalName());
private static final Logger LOG = Logger.getLogger(Repository.class.getCanonicalName());
// Constants defining expected commit header fields when parsing the output of 'git blame --porcelain'.
private static final String AUTHOR = "author";
......@@ -82,16 +74,16 @@ public class LocalRepository extends Repository {
private Map<String, Branch> branches;
/**
* Constructs a new {@link LocalRepository}.
* Constructs a new {@link Repository}.
*
* @param git
* the {@link GitWrapper} to use
* @param url
* the url the {@link LocalRepository} was cloned from
* the url the {@link Repository} was cloned from
* @param dir
* the directory containing the {@link LocalRepository}
* the directory containing the {@link Repository}
*/
LocalRepository(GitWrapper git, String url, File dir) {
Repository(GitWrapper git, String url, File dir) {
this.git = git;
this.url = url;
......@@ -107,7 +99,14 @@ public class LocalRepository extends Repository {
this.branches = new HashMap<>();
}
@Override
/**
* Performs a checkout of the given {@link Reference}.
*
* @param ref
* the {@link Reference} to checkout
* @return whether the checkout was successful
* @see <a href=https://git-scm.com/docs/git-checkout>git checkout</a>
*/
public boolean checkout(Reference ref) {
Optional<ExecRes> checkout = git.exec(dir, "checkout", ref.getId());
Function<ExecRes, Boolean> toBoolean = res -> {
......@@ -123,7 +122,14 @@ public class LocalRepository extends Repository {
return checkout.map(toBoolean).orElse(false);
}
@Override
/**
* Performs a checkout of the given {@link Reference}. All changes since last commit will be discarded.
*
* @param ref
* the {@link Reference} to checkout
* @return whether the checkout was successful
* @see <a href=https://git-scm.com/docs/git-checkout>git checkout</a>
*/
public boolean forceCheckout(Reference ref) {
Optional<ExecRes> checkout = git.exec(dir, "checkout", "-f", ref.getId());
Function<ExecRes, Boolean> toBoolean = res -> {
......@@ -140,7 +146,12 @@ public class LocalRepository extends Repository {
return checkout.map(toBoolean).orElse(false);
}
@Override
/**
* Performs a fetch in this {@link Repository}.
*
* @return whether the fetch was successful
* @see <a href=https://git-scm.com/docs/git-fetch>git fetch</a>
*/
public boolean fetch() {
Optional<ExecRes> fetch = git.exec(dir, "fetch", "--all", "--tags"); //TODO add "--prune"?
Function<ExecRes, Boolean> toBoolean = res -> {
......@@ -156,7 +167,12 @@ public class LocalRepository extends Repository {
return fetch.map(toBoolean).orElse(false);
}
@Override
/**
* Optionally returns a list of all merge commits in this repository. An empty {@link Optional} will be returned
* if there is an error retrieving the merge commits.
*
* @return the list of merge commits
*/
public Optional<List<Commit>> getMergeCommits() {
Optional<ExecRes> revList = git.exec(dir, "rev-list", "--all", "--merges");
Function<ExecRes, List<Commit>> toCommitList = res -> {
......@@ -186,7 +202,11 @@ public class LocalRepository extends Repository {
return revList.map(toCommitList);
}
@Override
/**
* Returns the {@link Commit} currently pointed at by <code>HEAD</code>.
*
* @return the <code>HEAD</code> commit or an empty {@link Optional} if there was an error
*/
public Optional<Commit> getCurrentHEAD() {
Optional<ExecRes> revParse = git.exec(dir, "rev-parse", "HEAD");
Function<ExecRes, Commit> toHEAD = res -> {
......@@ -202,12 +222,27 @@ public class LocalRepository extends Repository {
return revParse.map(toHEAD);
}
@Override
protected Commit getCommitUnchecked(String id) {
/**
* Returns a {@link Commit} for the given ID. The caller must ensure that the ID is a full SHA1 hash of a
* commit that exists in this repository.
*
* @param id
* the ID for the {@link Commit}
* @return the {@link Commit}
* @see #getCommit(String)
*/
Commit getCommitUnchecked(String id) {
return commits.computeIfAbsent(id, theID -> new Commit(this, theID));
}
@Override
/**
* Optionally returns a {@link Commit} for the given ID. If the given ID does not designate a commit that exists in
* this {@link Repository}, an empty {@link Optional} will be returned. The ID will be resolved to a full SHA1 hash.
*
* @param id
* the ID of the commit
* @return the {@link Commit} or an empty {@link Optional} if the ID is invalid or an exception occurs
*/
public Optional<Commit> getCommit(String id) {
if (commits.containsKey(id)) {
return Optional.of(commits.get(id));
......@@ -216,7 +251,14 @@ public class LocalRepository extends Repository {
return verify(false, id, TYPE_COMMIT).map(sha1 -> commits.computeIfAbsent(sha1, fullID -> new Commit(this, fullID)));
}
@Override
/**
* Optionally returns a {@link Branch} for the given name. If the given name does not designate a branch that
* exists in this {@link Repository}, an empty {@link Optional} will be returned.
*
* @param name
* the name of the branch
* @return the {@link Branch} or an empty {@link Optional} if the name is invalid or an exception occurs
*/
public Optional<Branch> getBranch(String name) {
if (branches.containsKey(name)) {
return Optional.of(branches.get(name));
......@@ -253,7 +295,6 @@ public class LocalRepository extends Repository {
* @return the full SHA1 hash or an empty {@link Optional} if an exception occurs or {@code id} can not be converted
* to its associated git hash
*/
@Override
protected Optional<String> toHash(String id) {
return verify(false, id, null);
}
......@@ -300,7 +341,14 @@ public class LocalRepository extends Repository {
return revParse.map(toHash);
}
@Override
/**
* Copies this {@link Repository} to the given <code>destination</code> directory.
*
* @param destination
* the destination directory
* @return a copy of this {@link Repository} at the new location
* @see FileUtils#copyDirectory(File, File)
*/
public Optional<Repository> copy(File destination) {
try {
if (destination.exists() && destination.isDirectory()) {
......@@ -315,7 +363,7 @@ public class LocalRepository extends Repository {
return Optional.empty();
}
LocalRepository repo = new LocalRepository(git, url, destination);
Repository repo = new Repository(git, url, destination);
for (Map.Entry<String, Commit> entry : commits.entrySet()) {
repo.getCommitUnchecked(entry.getValue().getId());
......@@ -324,7 +372,15 @@ public class LocalRepository extends Repository {
return Optional.of(repo);
}
@Override
/**
* Parses the output of 'git blame' for the given {@code file} and returns a list of {@link BlameLine BlameLines}
* containing the resulting information about every line of the file. If there is an exception parsing or obtaining
* the 'git blame' output, an empty {@link Optional} will be returned.
*
* @param file
* the path to the file to analyze (relative to the git root or absolute)
* @return optionally the list of {@link BlameLine BlameLines}
*/
public Optional<List<BlameLine>> blameFile(Path file) {
Path path = dir.toPath().relativize(dir.toPath().resolve(file));
Optional<ExecRes> output = git.exec(dir, "blame", "-p", path.toString());
......@@ -479,7 +535,18 @@ public class LocalRepository extends Repository {
while (lines.hasNextLine() && !lines.nextLine().startsWith("\t"));
}
@Override
/**
* Parses the output of 'git blame' for an unmerged file and extracts the merge conflicts that occurred in the file.
* Every merge conflict is represented by a {@link MergeConflict} instance containing the {@link BlameLine BlameLines}
* that represent the lines involved in the conflict. If there are no conflicts in the given file, an empty list
* will be returned. If there is an exception parsing or obtaining the 'git blame' output, an empty {@link Optional}
* will be returned.
*
* @param file
* the path to the unmerged file to analyze (relative to the git root or absolute)
* @return optionally the list of {@link MergeConflict MergeConflicts}
* @see #blameFile(Path)
*/
public Optional<List<MergeConflict>> blameUnmergedFile(Path file) {
Optional<List<BlameLine>> blame = blameFile(file);
......@@ -513,12 +580,27 @@ public class LocalRepository extends Repository {
return Optional.of(conflicts);
}
@Override
/**
* Parses and returns the current output of 'git status' for this {@link Repository}. This includes untracked files
* but excludes ignored files. If there is an exception parsing or obtaining the status output, an empty
* {@link Optional} will be returned.
*
* @return optionally the {@link Status} of this {@link Repository}
*/
public Optional<Status> getStatus() {
return getStatus(false, true);
}
@Override
/**
* Parses and returns the current output of 'git status' for this {@link Repository}.
* If there is an exception parsing or obtaining the status output, an empty {@link Optional} will be returned.
*
* @param ignored
* whether to include ignored files in the {@link Status}
* @param untracked
* whether to include untracked files in the {@link Status}
* @return optionally the {@link Status} of this {@link Repository}
*/
public Optional<Status> getStatus(boolean ignored, boolean untracked) {
Optional<ExecRes> output;
String untrackedPar = "--untracked=" + (untracked ? "all" : "no");
......@@ -542,7 +624,15 @@ public class LocalRepository extends Repository {
return output.flatMap(toStatus);
}
@Override
/**
* Adds a remote to the this repository if it does not yet exist.
*
* @param name
* the name of the remote
* @param forkURL
* the url of the remote
* @return <code>true</code>, if adding was successful or the remote already exists, <code>false</code> otherwise
*/
public boolean addRemote(String name, String forkURL) {
Optional<ExecRes> checkRes = git.exec(dir, "remote");
Optional<Boolean> check = checkRes.map(res -> {
......@@ -567,7 +657,13 @@ public class LocalRepository extends Repository {
return check.map(addRemote).orElse(false);
}
@Override
/**
* Creates a clean working directory at the currently checked out Reference
*
* @param retain
* patterns to be used as <a href=https://git-scm.com/docs/git-clean#git-clean--eltpatterngt>ignore rules</a>
* @return {@code true} if the cleanup was successful
*/
public boolean cleanup(String... retain) {
List<String> pars = new ArrayList<>(3 + retain.length * 2);
......@@ -592,22 +688,38 @@ public class LocalRepository extends Repository {
return true;
}
@Override
/**
* Returns the {@link GitWrapper} used by this {@link Repository}.
*
* @return the {@link GitWrapper}
*/
public GitWrapper getGit() {
return git;
}
@Override
/**
* Returns the URL this {@link Repository} was cloned from.
*
* @return the URL
*/
public String getUrl() {
return url;
}
@Override
/**
* Returns the directory containing this {@link Repository}.
*
* @return the repository directory
*/
public File getDir() {
return dir;
}
@Override
/**
* Returns the name of the directory this {@link Repository} is based in.
*
* @return the name of the {@link Repository}
*/
public String getName() {
return getDir().getName();
}
......@@ -616,4 +728,24 @@ public class LocalRepository extends Repository {
public String toString() {
return String.format("LocalRepository{url=%s, dir=%s}", url, dir);
}
@Override
public final boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Repository)) {
return false;
}
Repository that = (Repository) o;
return Objects.equals(getUrl(), that.getUrl())
&& Objects.equals(getDir().getAbsoluteFile(), that.getDir().getAbsoluteFile());
}
@Override
public final int hashCode() {
return Objects.hash(getUrl(), getDir().getAbsoluteFile());
}
}
package de.uni_passau.fim.seibt.gitwrapper.repo;
package de.uni_passau.fim.gitwrapper;
import java.nio.file.Path;
import java.util.ArrayList;
......@@ -11,11 +11,11 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static de.uni_passau.fim.seibt.gitwrapper.repo.Status.StatusCode.ADDED;
import static de.uni_passau.fim.seibt.gitwrapper.repo.Status.StatusCode.DELETED;
import static de.uni_passau.fim.seibt.gitwrapper.repo.Status.StatusCode.IGNORED;
import static de.uni_passau.fim.seibt.gitwrapper.repo.Status.StatusCode.UNMERGED;
import static de.uni_passau.fim.seibt.gitwrapper.repo.Status.StatusCode.UNTRACKED;
import static de.uni_passau.fim.gitwrapper.Status.StatusCode.ADDED;
import static de.uni_passau.fim.gitwrapper.Status.StatusCode.DELETED;
import static de.uni_passau.fim.gitwrapper.Status.StatusCode.IGNORED;
import static de.uni_passau.fim.gitwrapper.Status.StatusCode.UNMERGED;
import static de.uni_passau.fim.gitwrapper.Status.StatusCode.UNTRACKED;
/**
* The status of a {@link Repository}.
......
package de.uni_passau.fim.seibt.gitwrapper.process;
package de.uni_passau.fim.processexecutor;
import java.io.File;
import java.io.IOException;
......
package de.uni_passau.fim.seibt.gitwrapper.process;
package de.uni_passau.fim.processexecutor;
/**
* An {@link Exception} indicating that a wrapped tool is not working.
......
package de.uni_passau.fim.seibt.gitwrapper.process;
package de.uni_passau.fim.processexecutor;
import java.io.File;
import java.util.ArrayList;
......@@ -6,7 +6,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import de.uni_passau.fim.processexecutor.ProcessExecutor.ExecRes;
/**
* Abstract superclass of all wrappers for external tools.
......
package de.uni_passau.fim.seibt.gitwrapper.repo;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.apache.commons.io.FileUtils;
/**
* A git repository providing methods for accessing its state.
*/
public abstract class Repository {
/**
* Performs a checkout of the given {@link Reference}.
*
* @param ref
* the {@link Reference} to checkout
* @return whether the checkout was successful
* @see <a href=https://git-scm.com/docs/git-checkout>git checkout</a>
*/
public abstract boolean checkout(Reference ref);
/**
* Performs a checkout of the given {@link Reference}. All changes since last commit will be discarded.
*
* @param ref
* the {@link Reference} to checkout
* @return whether the checkout was successful
* @see <a href=https://git-scm.com/docs/git-checkout>git checkout</a>
*/
public abstract boolean forceCheckout(Reference ref);
/**
* Performs a fetch in this {@link Repository}.
*
* @return whether the fetch was successful
* @see <a href=https://git-scm.com/docs/git-fetch>git fetch</a>
*/
public abstract boolean fetch();
/**
* Optionally returns a list of all merge commits in this repository. An empty {@link Optional} will be returned
* if there is an error retrieving the merge commits.
*
* @return the list of merge commits
*/
public abstract Optional<List<Commit>> getMergeCommits();
/**
* Returns the {@link Commit} currently pointed at by <code>HEAD</code>.
*
* @return the <code>HEAD</code> commit or an empty {@link Optional} if there was an error
*/
public abstract Optional<Commit> getCurrentHEAD();
/**
* Returns a {@link Commit} for the given ID. The caller must ensure that the ID is a full SHA1 hash of a
* commit that exists in this repository.
*
* @param id
* the ID for the {@link Commit}
* @return the {@link Commit}
*
* @see #getCommit(String)
*/
protected abstract Commit getCommitUnchecked(String id);
/**
* Optionally returns a {@link Commit} for the given ID. If the given ID does not designate a commit that exists in
* this {@link Repository}, an empty {@link Optional} will be returned. The ID will be resolved to a full SHA1 hash.
*
* @param id
* the ID of the commit
* @return the {@link Commit} or an empty {@link Optional} if the ID is invalid or an exception occurs
*/
public abstract Optional<Commit> getCommit(String id);
/**
* Optionally returns a {@link Branch} for the given name. If the given name does not designate a branch that
* exists in this {@link Repository}, an empty {@link Optional} will be returned.
*
* @param name
* the name of the branch
* @return the {@link Branch} or an empty {@link Optional} if the name is invalid or an exception occurs
*/
public abstract Optional<Branch> getBranch(String name);
/**
* Resolves the given <code>id</code> to the full SHA1 hash.
*
* @param id
* the <code>id</code> to transform
* @return the full SHA1 hash or an empty {@link Optional} if an exception occurs or {@code id} can not be converted
* to its associated git hash
*/
protected abstract Optional<String> toHash(String id);
/**
* Copies this {@link Repository} to the given <code>destination</code> directory.
*
* @param destination
* the destination directory
* @return a copy of this {@link Repository} at the new location
* @see FileUtils#copyDirectory(File, File)
*/
public abstract Optional<Repository> copy(File destination);
/**
* Parses the output of 'git blame' for the given {@code file} and returns a list of {@link BlameLine BlameLines}
* containing the resulting information about every line of the file. If there is an exception parsing or obtaining
* the 'git blame' output, an empty {@link Optional} will be returned.
*
* @param file
* the path to the file to analyze (relative to the git root or absolute)
* @return optionally the list of {@link BlameLine BlameLines}
*/
public abstract Optional<List<BlameLine>> blameFile(Path file);
/**
* Parses the output of 'git blame' for an unmerged file and extracts the merge conflicts that occurred in the file.
* Every merge conflict is represented by a {@link MergeConflict} instance containing the {@link BlameLine BlameLines}
* that represent the lines involved in the conflict. If there are no conflicts in the given file, an empty list
* will be returned. If there is an exception parsing or obtaining the 'git blame' output, an empty {@link Optional}
* will be returned.
*
* @param file
* the path to the unmerged file to analyze (relative to the git root or absolute)
* @return optionally the list of {@link MergeConflict MergeConflicts}
* @see #blameFile(Path)
*/
public abstract Optional<List<MergeConflict>> blameUnmergedFile(Path file);
/**
* Parses and returns the current output of 'git status' for this {@link Repository}. This includes untracked files
* but excludes ignored files. If there is an exception parsing or obtaining the status output, an empty
* {@link Optional} will be returned.
*
* @return optionally the {@link Status} of this {@link Repository}
*/
public abstract Optional<Status> getStatus();
/**
* Parses and returns the current output of 'git status' for this {@link Repository}.
* If there is an exception parsing or obtaining the status output, an empty {@link Optional} will be returned.
*
* @param ignored
* whether to include ignored files in the {@link Status}
* @param untracked
* whether to include untracked files in the {@link Status}
* @return optionally the {@link Status} of this {@link Repository}
*/
public abstract Optional<Status> getStatus(boolean ignored, boolean untracked);
/**
* Adds a remote to the this repository if it does not yet exist.
*
* @param name
* the name of the remote
* @param forkURL
* the url of the remote
* @return <code>true</code>, if adding was successful or the remote already exists, <code>false</code> otherwise
*/
public abstract boolean addRemote(String name, String forkURL);
/**
* Creates a clean working directory at the currently checked out Reference
*
* @param retain
* patterns to be used as <a href=https://git-scm.com/docs/git-clean#git-clean--eltpatterngt>ignore rules</a>
*
* @return {@code true} if the cleanup was successful
*/
public abstract boolean cleanup(String... retain);
/**
* Returns the {@link GitWrapper} used by this {@link Repository}.
*
* @return the {@link GitWrapper}
*/
protected abstract GitWrapper getGit();
/**
* Returns the URL this {@link Repository} was cloned from.
*
* @return the URL
*/
public abstract String getUrl();
/**
* Returns the directory containing this {@link Repository}.
*
* @return the repository directory
*/
public abstract File getDir();
/**
* Returns the name of the directory this {@link Repository} is based in.
*
* @return the name of the {@link Repository}
*/
public abstract String getName();
@Override
public final boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Repository)) {
return false;
}
Repository that = (Repository) o;
return Objects.equals(getUrl(), that.getUrl())
&& Objects.equals(getDir().getAbsoluteFile(), that.getDir().getAbsoluteFile());
}
@Override
public final int hashCode() {
return Objects.hash(getUrl(), getDir().getAbsoluteFile());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment