Skip to content
Snippets Groups Projects
Commit 862c4cac authored by Georg Seibt's avatar Georg Seibt :nerd:
Browse files

doc of Repository methods and small refactorings to blameMergeConflicts...

doc of Repository methods and small refactorings to blameMergeConflicts (including renaming if to blameUnmergedFile)
parent db6601f1
No related branches found
No related tags found
No related merge requests found
...@@ -36,7 +36,7 @@ public class BlameLine { ...@@ -36,7 +36,7 @@ public class BlameLine {
public final String line; public final String line;
/** /**
* Other (unrecognized) fields from the 'git blame' commit header. * Other (unrecognized) fields from the 'git blame' commit header. Unmodifiable.
*/ */
public final Map<String, String> otherHeaderFields; public final Map<String, String> otherHeaderFields;
......
package de.uni_passau.fim.seibt.gitwrapper.repo; package de.uni_passau.fim.seibt.gitwrapper.repo;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List; import java.util.List;
/**
* A merge conflict parsed from the output of 'git blame' by {@link Repository#blameUnmergedFile(Path)} (String)}.
*/
public class MergeConflict { public class MergeConflict {
private final List<BlameLine> left;
private final List<BlameLine> right;
public MergeConflict(List<BlameLine> left, List<BlameLine> right) { /**
this.left = left; * The lines making up the left side of the conflict. Unmodifiable.
this.right = right; */
} public final List<BlameLine> left;
public List<BlameLine> getLeft() { /**
return left; * The lines making up the right side of the conflict. Unmodifiable.
} */
public final List<BlameLine> right;
public List<BlameLine> getRight() { /**
return right; * Constructs a new {@link MergeConflict}. The given lists {@code left} and {@code right} will be stored
* unmodifiable.
*
* @param left
* the left lines of the conflict
* @param right
* the right lines of the conflict
*/
MergeConflict(List<BlameLine> left, List<BlameLine> right) {
this.left = Collections.unmodifiableList(left);
this.right = Collections.unmodifiableList(right);
} }
} }
...@@ -205,8 +205,8 @@ public class Repository { ...@@ -205,8 +205,8 @@ public class Repository {
} }
/** /**
* Returns a {@link Commit} for the given ID. If the given ID does not designate a commit that exists in this * Optionally returns a {@link Commit} for the given ID. If the given ID does not designate a commit that exists in
* {@link Repository} an empty {@link Optional} will be returned. The ID will be resolved to a full SHA1 hash. * this {@link Repository}, an empty {@link Optional} will be returned. The ID will be resolved to a full SHA1 hash.
* *
* @param id * @param id
* the ID of the commit * the ID of the commit
...@@ -252,6 +252,14 @@ public class Repository { ...@@ -252,6 +252,14 @@ public class Repository {
return catFile.map(toBoolean).orElse(false); return catFile.map(toBoolean).orElse(false);
} }
/**
* Optionally returns a {@link Branch} for the given name. If the given name does not designated 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) { public Optional<Branch> getBranch(String name) {
if (branches.containsKey(name)) { if (branches.containsKey(name)) {
return Optional.of(branches.get(name)); return Optional.of(branches.get(name));
...@@ -348,10 +356,13 @@ public class Repository { ...@@ -348,10 +356,13 @@ public class Repository {
} }
/** /**
* Creates a list of the lines of a file and their corresponding commit. * 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) * @param file
* @return the list of {@link BlameLine BlameLines} * 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) { public Optional<List<BlameLine>> blameFile(Path file) {
Path path = dir.toPath().relativize(dir.toPath().resolve(file)); Path path = dir.toPath().relativize(dir.toPath().resolve(file));
...@@ -377,6 +388,14 @@ public class Repository { ...@@ -377,6 +388,14 @@ public class Repository {
return output.map(toList); return output.map(toList);
} }
/**
* Parses the given 'git blame' output and returns a list of {@link BlameLine BlameLines} containing the resulting
* information about every line of the output.
*
* @param blameOutput
* the 'git blame' output to parse
* @return the list of {@link BlameLine BlameLines}
*/
private List<BlameLine> parseBlameLines(String blameOutput) { private List<BlameLine> parseBlameLines(String blameOutput) {
Scanner lines = new Scanner(blameOutput); Scanner lines = new Scanner(blameOutput);
...@@ -479,13 +498,18 @@ public class Repository { ...@@ -479,13 +498,18 @@ public class Repository {
} }
/** /**
* Gets a list of merge conflicts fo a file, as a pair of right side/left side of list of pairs of lines with their * Parses the output of 'git blame' for an unmerged file and extracts the merge conflicts that occurred in the file.
* commits. * 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 file to analyze * @param file
* @return list of failed chunks * 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>> blameMergeConflicts(Path file) { public Optional<List<MergeConflict>> blameUnmergedFile(Path file) {
Optional<List<BlameLine>> blame = blameFile(file); Optional<List<BlameLine>> blame = blameFile(file);
if (!blame.isPresent()) { if (!blame.isPresent()) {
...@@ -494,38 +518,46 @@ public class Repository { ...@@ -494,38 +518,46 @@ public class Repository {
List<MergeConflict> conflicts = new ArrayList<>(); List<MergeConflict> conflicts = new ArrayList<>();
MergeConflict currentConflict = null; List<BlameLine> left = null;
List<BlameLine> right = null;
String lastMarker = null; String lastMarker = null;
for (BlameLine line : blame.get()) { for (BlameLine line : blame.get()) {
if (line.line.startsWith(CONFLICT_START)) { if (line.line.startsWith(CONFLICT_START)) {
currentConflict = new MergeConflict(new ArrayList<>(), new ArrayList<>()); left = new ArrayList<>();
right = new ArrayList<>();
lastMarker = CONFLICT_START; lastMarker = CONFLICT_START;
} else if (line.line.startsWith(CONFLICT_MIDDLE)) { } else if (line.line.startsWith(CONFLICT_MIDDLE)) {
lastMarker = CONFLICT_MIDDLE; lastMarker = CONFLICT_MIDDLE;
} else if (line.line.startsWith(CONFLICT_END)) { } else if (line.line.startsWith(CONFLICT_END)) {
conflicts.add(currentConflict); conflicts.add(new MergeConflict(left, right));
lastMarker = CONFLICT_END; lastMarker = CONFLICT_END;
} else if (Objects.equals(lastMarker, CONFLICT_START)) { } else if (CONFLICT_START.equals(lastMarker)) {
//noinspection ConstantConditions: there is always a start marker before a relevant line. assert left != null; left.add(line);
currentConflict.getLeft().add(line); } else if (CONFLICT_MIDDLE.equals(lastMarker)) {
} else if (Objects.equals(lastMarker, CONFLICT_MIDDLE)) { assert right != null; right.add(line);
//noinspection ConstantConditions: there is always a start marker before a relevant line.
currentConflict.getRight().add(line);
} }
} }
return Optional.of(conflicts); return Optional.of(conflicts);
} }
/**
* 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.
*
* @return optionally the {@link Status} of this {@link Repository}
*/
public Optional<Status> getStatus() { public Optional<Status> getStatus() {
Optional<ExecRes> output = git.exec(dir, "status", "-z"); Optional<ExecRes> output = git.exec(dir, "status", "-z");
Function<ExecRes, Status> toStatus = execRes -> { Function<ExecRes, Status> toStatus = execRes -> {
if (git.failed(execRes)) { if (git.failed(execRes)) {
LOG.warning(() -> String.format("Failed to get status information for repo %s", this)); LOG.warning(() -> String.format("Failed to get status information for repo %s", this));
return null; return null;
} }
return Status.parseStatus(this, execRes.stdOut+"\0"); return Status.parseStatus(this, execRes.stdOut+"\0"); //TODO Parser so anpassen, dass kein \0 erforderlich ist.
}; };
return output.map(toStatus); return output.map(toStatus);
......
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