{"thread":{"id":"14094","subject":"[PATCH 1/2] Create a fnmatch-style pattern TreeFilter","startedAt":"2008-06-22T23:25:44Z","lastAt":"2008-06-23T17:43:34Z","messageCount":5,"participants":["Robin Rosenberg","Shawn O. Pearce","Florian Köberle"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"80655","messageId":"1214177145-18963-1-git-send-email-robin.rosenberg@dewire.com","threadId":"14094","inReplyTo":null,"subject":"[PATCH 1/2] Create a fnmatch-style pattern TreeFilter","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-06-22T23:25:44Z","receivedAt":"2008-06-22T23:25:44Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"This uses Florian's pattern matcher to perform the matching.\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../jgit/revwalk/filter/WildCardTreeFilter.java    |  101 ++++++++++++++++++++\n 1 files changed, 101 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/revwalk/filter/WildCardTreeFilter.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/filter/WildCardTreeFilter.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/filter/WildCardTreeFilter.java\nnew file mode 100644\nindex 0000000..fd75458\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/filter/WildCardTreeFilter.java\n@@ -0,0 +1,101 @@\n+/*\n+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.revwalk.filter;\n+\n+import java.io.IOException;\n+\n+import org.spearce.jgit.errors.IncorrectObjectTypeException;\n+import org.spearce.jgit.errors.InvalidPatternException;\n+import org.spearce.jgit.errors.MissingObjectException;\n+import org.spearce.jgit.fnmatch.FileNameMatcher;\n+import org.spearce.jgit.treewalk.TreeWalk;\n+import org.spearce.jgit.treewalk.filter.TreeFilter;\n+\n+/**\n+ * This class implements a TreeeFilter that uses the wildcard style pattern\n+ * matching like of Posix fnmatch function.\n+ */\n+public class WildCardTreeFilter extends TreeFilter {\n+\n+\tprivate final FileNameMatcher matcher;\n+\n+\tprivate final String pattern;\n+\n+\tprotected WildCardTreeFilter(final String pattern) {\n+\t\ttry {\n+\t\t\tthis.pattern = pattern;\n+\t\t\tmatcher = new FileNameMatcher(pattern, null);\n+\t\t} catch (InvalidPatternException e) {\n+\t\t\tthrow new IllegalArgumentException(e);\n+\t\t}\n+\t}\n+\n+\t@Override\n+\tpublic TreeFilter clone() {\n+\t\treturn new WildCardTreeFilter(pattern);\n+\t}\n+\n+\t@Override\n+\tpublic boolean include(TreeWalk walker) throws MissingObjectException,\n+\t\t\tIncorrectObjectTypeException, IOException {\n+\t\tmatcher.reset();\n+\t\tmatcher.append(walker.getPathString());\n+\t\tif (matcher.isMatch())\n+\t\t\treturn true;\n+\t\treturn false;\n+\t}\n+\n+\t@Override\n+\tpublic boolean shouldBeRecursive() {\n+\t\treturn true;\n+\t}\n+\n+\t/**\n+\t * Construct a WildCardmatcher like POSIX fnmatch.\n+\t * \n+\t * @param pattern\n+\t *            A POSIX wildcard pattern\n+\t * @return a {@link TreeFilter} that matches pattern\n+\t * @throws IllegalArgumentException\n+\t *             if the pattern is malformed\n+\t */\n+\tpublic static TreeFilter create(final String pattern) {\n+\t\treturn new WildCardTreeFilter(pattern);\n+\t}\n+\n+}\n-- \n1.5.5.1.178.g1f811\n"},{"id":"80656","messageId":"1214177145-18963-2-git-send-email-robin.rosenberg@dewire.com","threadId":"14094","inReplyTo":"1214177145-18963-1-git-send-email-robin.rosenberg@dewire.com","subject":"[PATCH 2/2] LsTree: Enable pattern matching in LsTree","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-06-22T23:25:45Z","receivedAt":"2008-06-22T23:25:45Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../src/org/spearce/jgit/pgm/LsTree.java           |   19 +++++++++++++------\n 1 files changed, 13 insertions(+), 6 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/LsTree.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/LsTree.java\nindex c242bd7..2cda485 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/LsTree.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/LsTree.java\n@@ -41,10 +41,13 @@ import java.io.File;\n \n import org.spearce.jgit.lib.Constants;\n import org.spearce.jgit.lib.FileMode;\n+import org.spearce.jgit.revwalk.filter.WildCardTreeFilter;\n import org.spearce.jgit.treewalk.FileTreeIterator;\n import org.spearce.jgit.treewalk.TreeWalk;\n+import org.spearce.jgit.treewalk.filter.TreeFilter;\n \n class LsTree extends TextBuiltin {\n+\n \t@Override\n \tvoid execute(final String[] args) throws Exception {\n \t\tfinal TreeWalk walk = new TreeWalk(db);\n@@ -60,17 +63,21 @@ class LsTree extends TextBuiltin {\n \t\t\t\tbreak;\n \t\t}\n \n-\t\tif (argi == args.length)\n-\t\t\tthrow die(\"usage: [-r] treename\");\n-\t\telse if (argi + 1 < args.length)\n-\t\t\tthrow die(\"too many arguments\");\n-\n-\t\tfinal String n = args[argi];\n+\t\tfinal String n = args[argi++];\n \t\tif (is_WorkDir(n))\n \t\t\twalk.addTree(new FileTreeIterator(new File(n)));\n \t\telse\n \t\t\twalk.addTree(resolve(n));\n \n+\t\tif (argi == args.length - 1) {\n+\t\t\tTreeFilter filter = WildCardTreeFilter.create(args[argi++]);\n+\t\t\twalk.setFilter(filter);\n+\t\t}\n+\t\tif (argi + 1 == args.length)\n+\t\t\tthrow die(\"usage: [-r] treename [pattern]\");\n+\t\telse if (argi + 1 < args.length)\n+\t\t\tthrow die(\"too many arguments\");\n+\n \t\twhile (walk.next()) {\n \t\t\tfinal FileMode mode = walk.getFileMode(1);\n \t\t\tif (mode == FileMode.TREE)\n-- \n1.5.5.1.178.g1f811\n"},{"id":"80658","messageId":"20080623002707.GK11793@spearce.org","threadId":"14094","inReplyTo":"1214177145-18963-1-git-send-email-robin.rosenberg@dewire.com","subject":"Re: [PATCH 1/2] Create a fnmatch-style pattern TreeFilter","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-06-23T00:27:07Z","receivedAt":"2008-06-23T00:27:07Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Robin Rosenberg <robin.rosenberg@dewire.com> wrote:\n> +\n> +package org.spearce.jgit.revwalk.filter;\n\nThis should be treewalk.filter, its a filter for tree entries.\n\n> + * This class implements a TreeeFilter that uses the wildcard style pattern\n\nfyi, minooooor typo on TreeFilter.\n\n> +public class WildCardTreeFilter extends TreeFilter {\n...\n> +\t@Override\n> +\tpublic boolean include(TreeWalk walker) throws MissingObjectException,\n> +\t\t\tIncorrectObjectTypeException, IOException {\n> +\t\tmatcher.reset();\n> +\t\tmatcher.append(walker.getPathString());\n> +\t\tif (matcher.isMatch())\n> +\t\t\treturn true;\n> +\t\treturn false;\n> +\t}\n\nHmm. \n\nIt isn't as efficient as it could be.  Obtaining the string of\nthe path is somewhat costly as we have to convert from the byte[]\nto a char[] and then wrap that into a String, just to check the\npattern again.  Its more accurate to convert to the string, but\nit is a lot slower.\n\nBut I'm wondering about what happens when the TreeWalk is considering\na subtree path name.  Does the matcher still match the pattern?  By\nthat I mean lets say the pattern was:\n\n\tsrc/xdiff/*.c\n\nIn this case the include method is first called with the path \"src\";\nif it returns false the TreeWalk won't recurse into the subtree and\nthus you'll never get to consider \"src/xdiff\" or \"src/xdiff/foo.c\".\n\n-- \nShawn.\n"},{"id":"80731","messageId":"485FDE42.1060106@web.de","threadId":"14094","inReplyTo":"1214177145-18963-1-git-send-email-robin.rosenberg@dewire.com","subject":"Re: [PATCH 1/2] Create a fnmatch-style pattern TreeFilter","fromName":"Florian Köberle","fromEmail":"florianskarten@web.de","sentAt":"2008-06-23T17:32:50Z","receivedAt":"2008-06-23T17:32:50Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n\nHi Robin,\n\nthank you for accepting my first patch :D.\n\n| +/**\n| + * This class implements a TreeeFilter that uses the wildcard style\npattern\n| + * matching like of Posix fnmatch function.\n| + */\nTypo: One 'e' to much in TreeeFilter.\n\nIt would be more efficient to\n| +\t@Override\n| +\tpublic TreeFilter clone() {\n| +\t\treturn new WildCardTreeFilter(pattern);\n| +\t}\n\nOne way to create a clone of the FileNameMatcher is to call:\noriginalMatcher.reset()\nFileNameMatcher clone = originalMatcher.createMatcherForSuffix()\n\nI will send a patch which implements a copy constructor for FileNameMatcher.\n\nFirst I wanted to implement a clone() method, but found this page and\ndecided then to implement a copy constructor:\nhttp://www.javapractices.com/topic/TopicAction.do?Id=71\n\nA Implementor of a super class could imply that clone() of object gets\ncalled, as stated in the javadoc of clone():\n\nquote (javadoc ob Object#clone()):\n- -----------\nBy convention, the returned object should be obtained by calling super.clone\n- -----------\n\nI think this is a bad convention, as one should not rely on\nObject#clone() to do the copy job for one. If you really need a clone\nmethod then I would do it the same way you did, by calling a constructor\nwhich does the job.\n\nBest regards,\nFlorian\n\n-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1.4.6 (GNU/Linux)\nComment: Using GnuPG with Mozilla - http://enigmail.mozdev.org\n\niD8DBQFIX94k59ca4mzhfxMRAgDjAJ9S76L8I5Lqed4lKfgTf+2cp2IQ9gCfQNVh\nz72+NGvmIy3H0gwveKRfn+w=\n=wnpy\n-----END PGP SIGNATURE-----\n"},{"id":"80733","messageId":"1214243014-8701-1-git-send-email-florianskarten@web.de","threadId":"14094","inReplyTo":"485FDE42.1060106@web.de","subject":"[[JGIT PATCH]] Implementation of a copy constructor for FileNameMatcher.","fromName":"Florian Köberle","fromEmail":"florianskarten@web.de","sentAt":"2008-06-23T17:43:34Z","receivedAt":"2008-06-23T17:43:34Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Köberle <florianskarten@web.de>\n---\n .../spearce/jgit/fnmatch/FileNameMatcherTest.java  |   31 ++++++++++++++++++++\n .../org/spearce/jgit/fnmatch/FileNameMatcher.java  |   30 +++++++++++++++++--\n 2 files changed, 58 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/fnmatch/FileNameMatcherTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/fnmatch/FileNameMatcherTest.java\nindex ad72ac8..0c9501b 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/fnmatch/FileNameMatcherTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/fnmatch/FileNameMatcherTest.java\n@@ -723,4 +723,35 @@ public class FileNameMatcherTest extends TestCase {\n \t\tassertEquals(true, childMatcher.isMatch());\n \t\tassertEquals(false, childMatcher.canAppendMatch());\n \t}\n+\n+\tpublic void testCopyConstructor() throws Exception {\n+\t\tfinal String pattern = \"helloworld\";\n+\t\tfinal FileNameMatcher matcher = new FileNameMatcher(pattern, null);\n+\t\tmatcher.append(\"hello\");\n+\t\tfinal FileNameMatcher copy = new FileNameMatcher(matcher);\n+\t\tassertEquals(false, matcher.isMatch());\n+\t\tassertEquals(true, matcher.canAppendMatch());\n+\t\tassertEquals(false, copy.isMatch());\n+\t\tassertEquals(true, copy.canAppendMatch());\n+\t\tmatcher.append(\"world\");\n+\t\tassertEquals(true, matcher.isMatch());\n+\t\tassertEquals(false, matcher.canAppendMatch());\n+\t\tassertEquals(false, copy.isMatch());\n+\t\tassertEquals(true, copy.canAppendMatch());\n+\t\tcopy.append(\"world\");\n+\t\tassertEquals(true, matcher.isMatch());\n+\t\tassertEquals(false, matcher.canAppendMatch());\n+\t\tassertEquals(true, copy.isMatch());\n+\t\tassertEquals(false, copy.canAppendMatch());\n+\t\tcopy.reset();\n+\t\tassertEquals(true, matcher.isMatch());\n+\t\tassertEquals(false, matcher.canAppendMatch());\n+\t\tassertEquals(false, copy.isMatch());\n+\t\tassertEquals(true, copy.canAppendMatch());\n+\t\tcopy.append(\"helloworld\");\n+\t\tassertEquals(true, matcher.isMatch());\n+\t\tassertEquals(false, matcher.canAppendMatch());\n+\t\tassertEquals(true, copy.isMatch());\n+\t\tassertEquals(false, copy.canAppendMatch());\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/fnmatch/FileNameMatcher.java b/org.spearce.jgit/src/org/spearce/jgit/fnmatch/FileNameMatcher.java\nindex 9ac1875..702f7b3 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/fnmatch/FileNameMatcher.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/fnmatch/FileNameMatcher.java\n@@ -99,10 +99,23 @@ public class FileNameMatcher {\n \t *            must be a list which will never be modified.\n \t */\n \tprivate FileNameMatcher(final List<Head> headsStartValue) {\n+\t\tthis(headsStartValue, headsStartValue);\n+\t}\n+\n+\t/**\n+\t *\n+\t * @param headsStartValue\n+\t *            must be a list which will never be modified.\n+\t * @param heads\n+\t *            a list which will be cloned and then used as current head\n+\t *            list.\n+\t */\n+\tprivate FileNameMatcher(final List<Head> headsStartValue,\n+\t\t\tfinal List<Head> heads) {\n \t\tthis.headsStartValue = headsStartValue;\n-\t\tthis.heads = new ArrayList<Head>(headsStartValue.size());\n-\t\tthis.heads.addAll(this.headsStartValue);\n-\t\tthis.listForLocalUseage = new ArrayList<Head>(headsStartValue.size());\n+\t\tthis.heads = new ArrayList<Head>(heads.size());\n+\t\tthis.heads.addAll(heads);\n+\t\tthis.listForLocalUseage = new ArrayList<Head>(heads.size());\n \t}\n \n \t/**\n@@ -120,6 +133,17 @@ public class FileNameMatcher {\n \t\tthis(createHeadsStartValues(patternString, invalidWildgetCharacter));\n \t}\n \n+\t/**\n+\t * A Copy Constructor which creates a new {@link FileNameMatcher} with the\n+\t * same state and reset point like <code>other</code>.\n+\t *\n+\t * @param other\n+\t *            another {@link FileNameMatcher} instance.\n+\t */\n+\tpublic FileNameMatcher(FileNameMatcher other) {\n+\t\tthis(other.headsStartValue, other.heads);\n+\t}\n+\n \tprivate static List<Head> createHeadsStartValues(\n \t\t\tfinal String patternString, final Character invalidWildgetCharacter)\n \t\t\tthrows InvalidPatternException {\n-- \n1.5.4.3\n"}]}