diff --git a/src/de/uni_passau/fim/seibt/gitwrapper/repo/Status.java b/src/de/uni_passau/fim/seibt/gitwrapper/repo/Status.java index 7ff96537728f710bc5f84fc5aa8f475ece5c2a1a..a3809129882b16d63195d9a0411c25de4c164239 100644 --- a/src/de/uni_passau/fim/seibt/gitwrapper/repo/Status.java +++ b/src/de/uni_passau/fim/seibt/gitwrapper/repo/Status.java @@ -2,10 +2,13 @@ package de.uni_passau.fim.seibt.gitwrapper.repo; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -22,7 +25,17 @@ import static de.uni_passau.fim.seibt.gitwrapper.repo.Status.StatusCode.UNTRACKE */ public class Status { - private static final Pattern STATUS_ENTRY = Pattern.compile("(..) ([^\0]*)\0(?:([^\0 ]*)\0)?"); + private static final Logger LOG = Logger.getLogger(Status.class.getCanonicalName()); + + private static final String G_RCODE = "rcode"; + private static final String G_TO = "to"; + private static final String G_FROM = "from"; + private static final String G_CODE = "code"; + private static final String G_PATH = "path"; + + private static final String regex = String.format("(?:(?<%s>R[ MD]) (?<%s>[^\0]*)\0(?<%s>[^\0]*)\0|(?<%s>[ MADRCU]{2}|\\?\\?|!!) (?<%s>[^\0]*)\0)", + G_RCODE, G_TO, G_FROM, G_CODE, G_PATH); + private static final Pattern STATUS_ENTRY = Pattern.compile(regex); /** * Two {@link StatusCode StatusCodes} are used to represent the status of a file in a git {@link Repository}. @@ -137,20 +150,36 @@ public class Status { */ public final Map<Path, FileStatus> unmerged; + /** + * The list of untracked files. + */ + public final List<Path> untracked; + + /** + * The list of ignored files. + */ + public final List<Path> ignored; + /** * Constructs a new {@link Status}. * * @param commit * the current HEAD {@link Commit} at the time this {@link Status} is constructed * @param changed - * a map of changed files and heir status codes + * the map of changed files and heir status codes * @param unmerged - * a map of unmerged files an their status code. + * the map of unmerged files an their status code + * @param untracked + * the list of untracked files + * @param ignored + * the list of ignored files */ - private Status(Commit commit, Map<Path, FileStatus> changed, Map<Path, FileStatus> unmerged) { + private Status(Commit commit, Map<Path, FileStatus> changed, Map<Path, FileStatus> unmerged, List<Path> untracked, List<Path> ignored) { this.commit = commit; - this.changed = Collections.unmodifiableMap(changed); - this.unmerged = Collections.unmodifiableMap(unmerged); + this.changed = changed.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(changed); + this.unmerged = unmerged.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(unmerged); + this.untracked = untracked.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(untracked); + this.ignored = ignored.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(ignored); } /** @@ -204,26 +233,49 @@ public class Status { static Optional<Status> parseStatus(Repository repo, String gitOutput) { Map<Path, FileStatus> changed = new HashMap<>(); Map<Path, FileStatus> unmerged = new HashMap<>(); + List<Path> untracked = new ArrayList<>(); + List<Path> ignored = new ArrayList<>(); Matcher matcher = STATUS_ENTRY.matcher(gitOutput); while (matcher.find()) { - String code = matcher.group(1).toUpperCase(); - StatusCode x = StatusCode.forChar(code.charAt(0)); - StatusCode y = StatusCode.forChar(code.charAt(1)); + String code; + StatusCode x; + StatusCode y; - Path file = Paths.get(matcher.group(2)); - Optional<Path> oldFile = Optional.ofNullable(matcher.group(3)).map(Paths::get); + Path file; + Optional<Path> oldFile; - FileStatus status = new FileStatus(x, y, oldFile, file); + if ((code = matcher.group(G_CODE)) != null) { + file = Paths.get(matcher.group(G_PATH)); + oldFile = Optional.empty(); + } else if ((code = matcher.group(G_RCODE)) != null) { + file = Paths.get(matcher.group(G_TO)); + oldFile = Optional.of(matcher.group(G_FROM)).map(Paths::get); + } else { + // This 'should' not be possible... + LOG.warning(() -> "Could not find the status codes for the status entry '" + matcher.group() + "'."); + continue; + } - if (x == UNMERGED || y == UNMERGED || (x == ADDED && y == ADDED) || (x == DELETED && y == DELETED)) { - unmerged.put(file, status); + x = StatusCode.forChar(code.charAt(0)); + y = StatusCode.forChar(code.charAt(1)); + + if (x == UNTRACKED && y == UNTRACKED) { + untracked.add(file); + } else if (x == IGNORED && y == IGNORED) { + ignored.add(file); } else { - changed.put(file, status); + FileStatus status = new FileStatus(x, y, oldFile, file); + + if (x == UNMERGED || y == UNMERGED || (x == ADDED && y == ADDED) || (x == DELETED && y == DELETED)) { + unmerged.put(file, status); + } else { + changed.put(file, status); + } } } - return repo.getCurrentHEAD().map(head -> new Status(head, changed, unmerged)); + return repo.getCurrentHEAD().map(head -> new Status(head, changed, unmerged, untracked, ignored)); } }