2013-03-22 48 views
1

我正在使用“git grep -e”来查找与内容中的模式相匹配的文件。 我查看了jgit的索引,找不到“grep”,但最接近的是PatternMatchRevFilter。这与“git grep”在做什么相似吗?如何用jgit做“git grep -e <pattern>”?

在官方JGit用户指南中,它说“TODO谈论过滤器”。 :)有人有一个如何使用这个过滤器的例子吗?

谢谢!

Jason

ps。这可能是一个单独的问题 - 我怎样才能为搜索指定一个分支?

回答

4

首先,PatternMatchRevFilter不是你想要的。 RevFilter用于在步行中选择某些修订(提交)。所以它相当于git log --grep=pattern

你想要的是走一个修订版本的树并读取blob内容。

相当于git grep还没有简单易用的API。你必须结合低级别的API:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

import org.eclipse.jgit.diff.RawText; 
import org.eclipse.jgit.lib.ObjectId; 
import org.eclipse.jgit.lib.ObjectLoader; 
import org.eclipse.jgit.lib.ObjectReader; 
import org.eclipse.jgit.lib.Repository; 
import org.eclipse.jgit.revwalk.RevCommit; 
import org.eclipse.jgit.revwalk.RevWalk; 
import org.eclipse.jgit.treewalk.AbstractTreeIterator; 
import org.eclipse.jgit.treewalk.CanonicalTreeParser; 
import org.eclipse.jgit.treewalk.TreeWalk; 

public class Grep { 

    private final Repository repository; 
    private final Pattern pattern; 

    private final String revName; 

    public Grep(Repository repository, Pattern pattern, String revName) { 
     this.repository = repository; 
     this.pattern = pattern; 
     this.revName = revName; 
    } 

    public void grepPrintingResults() throws IOException { 
     ObjectReader objectReader = repository.newObjectReader(); 
     try { 
      ObjectId commitId = repository.resolve(revName); 
      impl(objectReader, commitId); 
     } finally { 
      objectReader.release(); 
     } 
    } 

    private void impl(ObjectReader objectReader, ObjectId commitId) 
      throws IOException { 

     TreeWalk treeWalk = new TreeWalk(objectReader); 
     RevWalk revWalk = new RevWalk(objectReader); 
     RevCommit commit = revWalk.parseCommit(commitId); 

     CanonicalTreeParser treeParser = new CanonicalTreeParser(); 
     treeParser.reset(objectReader, commit.getTree()); 

     int treeIndex = treeWalk.addTree(treeParser); 
     treeWalk.setRecursive(true); 

     while (treeWalk.next()) { 
      AbstractTreeIterator it = treeWalk.getTree(treeIndex, 
        AbstractTreeIterator.class); 
      ObjectId objectId = it.getEntryObjectId(); 
      ObjectLoader objectLoader = objectReader.open(objectId); 

      if (!isBinary(objectLoader.openStream())) { 
       List<String> matchedLines = getMatchedLines(objectLoader 
         .openStream()); 
       if (!matchedLines.isEmpty()) { 
        String path = it.getEntryPathString(); 
        for (String matchedLine : matchedLines) { 
         System.out.println(path + ":" + matchedLine); 
        } 
       } 
      } 
     } 
    } 

    private List<String> getMatchedLines(InputStream stream) throws IOException { 
     BufferedReader buf = null; 
     try { 
      List<String> matchedLines = new ArrayList<String>(); 
      InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); 
      buf = new BufferedReader(reader); 
      String line; 
      while ((line = buf.readLine()) != null) { 
       Matcher m = pattern.matcher(line); 
       if (m.find()) { 
        matchedLines.add(line); 
       } 
      } 
      return matchedLines; 
     } finally { 
      if (buf != null) { 
       buf.close(); 
      } 
     } 
    } 

    private static boolean isBinary(InputStream stream) throws IOException { 
     try { 
      return RawText.isBinary(stream); 
     } finally { 
      try { 
       stream.close(); 
      } catch (IOException e) { 
       // Ignore, we were just reading 
      } 
     } 
    } 
} 

使用方法如下:

Grep grep = new Grep(repository, Pattern.compile("test"), "HEAD"); 
grep.grepPrintingResults(); 
+0

谢谢@robinst,我给一个试试吧! – Jason 2013-05-03 17:58:48

+0

以上可以做成jgit的GrepCommand,我只是不确定它是否也应该提供并行grepping,例如,通过一个ExecutorService。 – robinst 2013-05-04 12:30:10