diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java index fad294eba59f..49dbe64997fe 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryReader.java @@ -19,8 +19,10 @@ import com.intellij.dvcs.repo.RepoStateException; import com.intellij.dvcs.repo.Repository; import com.intellij.dvcs.repo.RepositoryUtil; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.impl.HashImpl; import git4idea.GitBranch; @@ -37,7 +39,6 @@ import java.io.File; import java.io.FileReader; import java.util.*; import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -214,38 +215,40 @@ class GitRepositoryReader { return null; } - final AtomicReference hashRef = new AtomicReference(); - readPackedRefsFile(new PackedRefsLineResultHandler() { + List hashAndNames = readPackedRefsFile(new Condition() { @Override - public void handleResult(String hash, String branchName) { - if (hash == null || branchName == null) { - return; - } - if (branchName.endsWith(ref)) { - hashRef.set(shortBuffer(hash)); - stop(); - } + public boolean value(HashAndName hashAndName) { + return hashAndName.name.endsWith(ref); } }); - if (hashRef.get() != null) { - return hashRef.get(); - } - - return null; + return hashAndNames.get(0).hash; } - private void readPackedRefsFile(@NotNull final PackedRefsLineResultHandler handler) { - RepositoryUtil.tryOrThrow(new Callable() { + /** + * @param firstMatchCondition If specified, we read the packed-refs file until the first entry which matches the given condition, + * and return a singleton list of this entry. + * If null, the whole file is read, and all valid entries are returned. + */ + private List readPackedRefsFile(@Nullable final Condition firstMatchCondition) { + return RepositoryUtil.tryOrThrow(new Callable>() { @Override - public String call() throws Exception { + public List call() throws Exception { + List hashAndNames = ContainerUtil.newArrayList(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(myPackedRefsFile)); - String line; - while ((line = reader.readLine()) != null) { - parsePackedRefsLine(line, handler); - if (handler.stopped()) { - return null; + for (String line = reader.readLine(); line != null ; line = reader.readLine()) { + HashAndName hashAndName = parsePackedRefsLine(line); + if (hashAndName == null) { + continue; + } + if (firstMatchCondition != null) { + if (firstMatchCondition.value(hashAndName)) { + return Collections.singletonList(hashAndName); + } + } + else { + hashAndNames.add(hashAndName); } } } @@ -254,7 +257,7 @@ class GitRepositoryReader { reader.close(); } } - return null; + return hashAndNames; } }, myPackedRefsFile); } @@ -370,27 +373,24 @@ class GitRepositoryReader { return GitBranchesCollection.EMPTY; } - readPackedRefsFile(new PackedRefsLineResultHandler() { - @Override public void handleResult(@Nullable String hashString, @Nullable String branchName) { - if (hashString == null || branchName == null) { - return; - } - hashString = shortBuffer(hashString); - Hash hash = createHash(hashString); - if (hash == null) { - return; - } - if (branchName.startsWith(REFS_HEADS_PREFIX)) { - localBranches.add(new GitLocalBranch(branchName, hash)); - } - else if (branchName.startsWith(REFS_REMOTES_PREFIX)) { - GitRemoteBranch remoteBranch = GitBranchUtil.parseRemoteBranch(branchName, hash, remotes); - if (remoteBranch != null) { - remoteBranches.add(remoteBranch); - } + List hashAndNames = readPackedRefsFile(null); + for (HashAndName hashAndName : hashAndNames) { + Hash hash = createHash(hashAndName.hash); + if (hash == null) { + continue; + } + String branchName = hashAndName.name; + + if (branchName.startsWith(REFS_HEADS_PREFIX)) { + localBranches.add(new GitLocalBranch(branchName, hash)); + } + else if (branchName.startsWith(REFS_REMOTES_PREFIX)) { + GitRemoteBranch remoteBranch = GitBranchUtil.parseRemoteBranch(branchName, hash, remotes); + if (remoteBranch != null) { + remoteBranches.add(remoteBranch); } } - }); + } return new GitBranchesCollection(localBranches, remoteBranches); } @@ -419,53 +419,49 @@ class GitRepositoryReader { } /** - * Parses a line from the .git/packed-refs file. - * Passes the parsed hash-branch pair to the resultHandler. - * Comments, tags and incorrectly formatted lines are ignored, and (null, null) is passed to the handler then. - * Using a special handler may seem to be an overhead, but it is to avoid code duplication in two methods that parse packed-refs. + * Parses a line from the .git/packed-refs file returning a pair of hash and ref name. + * Comments and tags are ignored, and null is returned. + * Incorrectly formatted lines are ignored, a warning is printed to the log, null is returned. + * A line indicating a hash which an annotated tag (specified in the previous line) points to, is ignored: null is returned. */ - private static void parsePackedRefsLine(@NotNull String line, @NotNull PackedRefsLineResultHandler resultHandler) { - try { - line = line.trim(); - char firstChar = line.isEmpty() ? 0 : line.charAt(0); - if (firstChar == '#') { // ignoring comments - return; + @Nullable + private static HashAndName parsePackedRefsLine(@NotNull String line) { + line = line.trim(); + char firstChar = line.isEmpty() ? 0 : line.charAt(0); + if (firstChar == '#') { // ignoring comments + return null; + } + if (firstChar == '^') { + // ignoring the hash which an annotated tag above points to + return null; + } + String hash = null; + int i; + for (i = 0; i < line.length(); i++) { + char c = line.charAt(i); + if (!Character.isLetterOrDigit(c)) { + hash = line.substring(0, i); + break; } - if (firstChar == '^') { - // ignoring the hash which an annotated tag above points to - return; - } - String hash = null; - int i; - for (i = 0; i < line.length(); i++) { + } + String branch = null; + int start = i; + if (hash != null && start < line.length() && line.charAt(start++) == ' ') { + for (i = start; i < line.length(); i++) { char c = line.charAt(i); - if (!Character.isLetterOrDigit(c)) { - hash = line.substring(0, i); + if (Character.isWhitespace(c)) { break; } } - String branch = null; - int start = i; - if (hash != null && start < line.length() && line.charAt(start++) == ' ') { - for (i = start; i < line.length(); i++) { - char c = line.charAt(i); - if (Character.isWhitespace(c)) { - break; - } - } - branch = line.substring(start, i); - } + branch = line.substring(start, i); + } - if (hash != null && branch != null) { - resultHandler.handleResult(hash.trim(), branch); - } - else { - LOG.info("Ignoring invalid packed-refs line: [" + line + "]"); - } - } - finally { - resultHandler.handleResult(null, null); + if (hash != null && branch != null) { + return new HashAndName(shortBuffer(hash.trim()), shortBuffer(branch)); } + + LOG.info("Ignoring invalid packed-refs line: [" + line + "]"); + return null; } @NotNull @@ -473,20 +469,13 @@ class GitRepositoryReader { return new String(raw); } - private abstract static class PackedRefsLineResultHandler { - private boolean myStopped; + private static class HashAndName { + private final String hash; + private final String name; - abstract void handleResult(@Nullable String hash, @Nullable String branchName); - - /** - * Call this to stop further lines reading. - */ - final void stop() { - myStopped = true; - } - - final boolean stopped() { - return myStopped; + public HashAndName(String hash, String name) { + this.hash = hash; + this.name = name; } }