{"thread":{"id":"13496","subject":"[JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules.","startedAt":"2008-05-12T20:13:18Z","lastAt":"2008-05-23T21:28:33Z","messageCount":46,"participants":["Florian Koeberle","Miklos Vajna","Shawn O. Pearce","Florian Köberle","Robin Rosenberg","Paolo Bonzini"],"isPatch":true,"patchVersion":2,"patchTotal":24},"messages":[{"id":"76761","messageId":"1210623222-24908-1-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":null,"subject":"[JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:18Z","receivedAt":"2008-05-12T20:13:18Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"\nHi\n\nI improved the patches from last time.\n\nThat are the changes to the previos patches:\n* Removed @author javadoc\n* Moved iteration code into the treewalk package\n* Moved code around the Rules class into a new treewalk.rules package\n* Added newlines to some files\n* Removed (hopefully) the trailing whitespaces using the eclipse save actions.\n* Renamed Project into WorkTree\n* Moved the methods from ProjectSeeker and ProjectFactory into Repository and made them static.\n* Moved the constants into the Constants class.\n* Renamed my FileTreeIterator into LightFileTreeIterator in order to avoid nameconflict, as they are now in th\ne same package.\n* Renamed StarPattern into FNMatchPattern, improved it, and moved it into the lib package.\n* Improved the javadoc.\n* Replaced the AddCommandFileIterableFactory with a AddRulesFactory which creates Rules instances instead of Iterators. The advantage of this move is that the factory is now iterator independent.\n\nMaybe I missed something... I would need some patch-tree version control system which tracks changes in the patch tree ;).\n\nBest regards,\nFlorian\n"},{"id":"76764","messageId":"1210623222-24908-2-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 01/24] Start of an implementation of a git like command line tool.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:19Z","receivedAt":"2008-05-12T20:13:19Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Only the \"help\" command is currenly supported, but it is extendable.\n\nSigned-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/pgm/Command.java          |   44 ++++++++\n .../src/org/spearce/jgit/pgm/MainProgram.java      |  114 ++++++++++++++++++++\n 2 files changed, 158 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java\nnew file mode 100644\nindex 0000000..a05f707\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java\n@@ -0,0 +1,44 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.pgm;\n+\n+import java.io.IOException;\n+\n+/**\n+ * A command have tasks like the \"git-add\", \"git-help\" or \"git-init\" console\n+ * commands. Instances of ${link Command} must be immutable.\n+ * \n+ */\n+public interface Command {\n+\t/**\n+\t * Executes the specified Command.\n+\t * \n+\t * @param args\n+\t *            the arguments which you would pass to the console equivalent\n+\t *            of the command.\n+\t * @throws IOException\n+\t *             for some undefined reasons.\n+\t */\n+\tpublic void execute(String... args) throws IOException;\n+\n+\t/**\n+\t * \n+\t * @return a short description about what the command does. Short means in\n+\t *         this context 5 - 10 words.\n+\t */\n+\tpublic String getShortDescription();\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\nnew file mode 100644\nindex 0000000..c9af51c\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\n@@ -0,0 +1,114 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.pgm;\n+\n+import java.io.IOException;\n+import java.util.Collections;\n+import java.util.HashMap;\n+import java.util.Map;\n+import java.util.SortedMap;\n+import java.util.TreeMap;\n+\n+/**\n+ * A program which works similar like the command git, except that very view\n+ * arguments are supported jet.\n+ * \n+ */\n+public class MainProgram {\n+\tprivate final static Map<String, Command> commandNameToObjectMap;\n+\n+\tstatic {\n+\t\tfinal Map<String, Command> commands = new HashMap<String, Command>();\n+\t\tcommands.put(\"help\", HelpCommand.INSTANCE);\n+\t\tcommandNameToObjectMap = Collections.unmodifiableMap(commands);\n+\t}\n+\n+\t/**\n+\t * Executes a command with some arguments. There are commands for creating\n+\t * git repositories, tracking files, etc.\n+\t * \n+\t * @param args\n+\t *            The first argument specifies the command which should be\n+\t *            executed. The other arguments are passed to the command.\n+\t * @throws IOException\n+\t *             for some reasons.\n+\t */\n+\tpublic static void main(String[] args) throws IOException {\n+\t\ttry {\n+\t\t\tif (args.length == 0) {\n+\t\t\t\tthrow new WrongCallException(\"Require one argument!\");\n+\t\t\t}\n+\t\t\tfinal Command command = commandNameToObjectMap.get(args[0]);\n+\t\t\tif (command == null) {\n+\t\t\t\tthrow new WrongCallException(\"Require one argument!\");\n+\t\t\t}\n+\n+\t\t\tfinal String[] commandArguments = new String[args.length - 1];\n+\t\t\tSystem.arraycopy(args, 1, commandArguments, 0,\n+\t\t\t\t\tcommandArguments.length);\n+\n+\t\t\tcommand.execute(commandArguments);\n+\n+\t\t} catch (WrongCallException e) {\n+\t\t\tSystem.err.println(e.getMessage());\n+\t\t\tSystem.err.println();\n+\t\t\tHelpCommand.INSTANCE.execute();\n+\t\t\tSystem.exit(1);\n+\t\t}\n+\t}\n+\n+\tprivate static class WrongCallException extends Exception {\n+\t\tprivate static final long serialVersionUID = 3643362832429311084L;\n+\n+\t\tWrongCallException(String message) {\n+\t\t\tsuper(message);\n+\t\t}\n+\t}\n+\n+\tprivate static class HelpCommand implements Command {\n+\t\t/**\n+\t\t * Use this instance instead of creating a new ${link HelpCommand}. You\n+\t\t * don't need to create an instance of this class as it is immutable and\n+\t\t * not configurable.\n+\t\t */\n+\t\tpublic static HelpCommand INSTANCE = new HelpCommand();\n+\n+\t\tpublic void execute(String... args) throws IOException {\n+\t\t\tSystem.out\n+\t\t\t\t\t.println(\"Call this program with the following arguments:\");\n+\t\t\tSystem.out\n+\t\t\t\t\t.println(\"commandName commandArgument0 commandArgument1 ...\");\n+\t\t\tSystem.out.println();\n+\t\t\tSystem.out\n+\t\t\t\t\t.println(\"Currently the following commands are supported:\");\n+\t\t\tfinal SortedMap<String, Command> sortedCommandMap = new TreeMap<String, Command>(\n+\t\t\t\t\tMainProgram.commandNameToObjectMap);\n+\t\t\tfor (Map.Entry<String, Command> commandEntry : sortedCommandMap\n+\t\t\t\t\t.entrySet()) {\n+\t\t\t\tfinal String commandName = commandEntry.getKey();\n+\t\t\t\tfinal String commandDescription = commandEntry.getValue()\n+\t\t\t\t\t\t.getShortDescription();\n+\t\t\t\tSystem.out.printf(\"%#10s - %s%n\", commandName,\n+\t\t\t\t\t\tcommandDescription);\n+\t\t\t}\n+\t\t}\n+\n+\t\tpublic String getShortDescription() {\n+\t\t\treturn \"Displays some text about how to use this program.\";\n+\t\t}\n+\t}\n+}\n-- \n1.5.4.3\n"},{"id":"76784","messageId":"1210623222-24908-3-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 02/24] Formatted Repository class.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:20Z","receivedAt":"2008-05-12T20:13:20Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/lib/Repository.java       |  372 +++++++++++---------\n 1 files changed, 208 insertions(+), 164 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\nindex 455a68e..44fd81b 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n@@ -38,28 +38,30 @@ import org.spearce.jgit.util.FS;\n  * Represents a Git repository. A repository holds all objects and refs used for\n  * managing source code (could by any type of file, but source code is what\n  * SCM's are typically used for).\n- *\n+ * \n  * In Git terms all data is stored in GIT_DIR, typically a directory called\n  * .git. A work tree is maintained unless the repository is a bare repository.\n  * Typically the .git directory is located at the root of the work dir.\n- *\n+ * \n  * <ul>\n  * <li>GIT_DIR\n- * \t<ul>\n- * \t\t<li>objects/ - objects</li>\n- * \t\t<li>refs/ - tags and heads</li>\n- * \t\t<li>config - configuration</li>\n- * \t\t<li>info/ - more configurations</li>\n- * \t</ul>\n+ * <ul>\n+ * <li>objects/ - objects</li>\n+ * <li>refs/ - tags and heads</li>\n+ * <li>config - configuration</li>\n+ * <li>info/ - more configurations</li>\n+ * </ul>\n  * </li>\n  * </ul>\n- *\n- * This implementation only handles a subtly undocumented subset of git features.\n- *\n+ * \n+ * This implementation only handles a subtly undocumented subset of git\n+ * features.\n+ * \n  */\n public class Repository {\n \tprivate static final String[] refSearchPaths = { \"\", \"refs/\", \"refs/tags/\",\n-\t\tConstants.HEADS_PREFIX + \"/\", \"refs/\" + Constants.REMOTES_PREFIX + \"/\" };\n+\t\t\tConstants.HEADS_PREFIX + \"/\",\n+\t\t\t\"refs/\" + Constants.REMOTES_PREFIX + \"/\" };\n \n \tprivate final File gitDir;\n \n@@ -79,7 +81,7 @@ public class Repository {\n \n \t/**\n \t * Construct a representation of this git repo managing a Git repository.\n-\t *\n+\t * \n \t * @param d\n \t *            GIT_DIR\n \t * @throws IOException\n@@ -108,7 +110,8 @@ public class Repository {\n \t\t\tobjectsDirs = readObjectsDirs(FS.resolve(gitDir, \"objects\"),\n \t\t\t\t\tnew ArrayList<File>()).toArray(new File[0]);\n \t\t} catch (IOException e) {\n-\t\t\tIOException ex = new IOException(\"Cannot find all object dirs for \" + gitDir);\n+\t\t\tIOException ex = new IOException(\"Cannot find all object dirs for \"\n+\t\t\t\t\t+ gitDir);\n \t\t\tex.initCause(e);\n \t\t\tthrow ex;\n \t\t}\n@@ -134,12 +137,13 @@ public class Repository {\n \t\t\tscanForPacks();\n \t}\n \n-\tprivate Collection<File> readObjectsDirs(File objectsDir, Collection<File> ret) throws IOException {\n+\tprivate Collection<File> readObjectsDirs(File objectsDir,\n+\t\t\tCollection<File> ret) throws IOException {\n \t\tret.add(objectsDir);\n \t\tfinal File altFile = FS.resolve(objectsDir, \"info/alternates\");\n \t\tif (altFile.exists()) {\n \t\t\tBufferedReader ar = new BufferedReader(new FileReader(altFile));\n-\t\t\tfor (String alt=ar.readLine(); alt!=null; alt=ar.readLine()) {\n+\t\t\tfor (String alt = ar.readLine(); alt != null; alt = ar.readLine()) {\n \t\t\t\treadObjectsDirs(FS.resolve(objectsDir, alt), ret);\n \t\t\t}\n \t\t\tar.close();\n@@ -150,7 +154,7 @@ public class Repository {\n \t/**\n \t * Create a new Git repository initializing the necessary files and\n \t * directories.\n-\t *\n+\t * \n \t * @throws IOException\n \t */\n \tpublic void create() throws IOException {\n@@ -211,15 +215,15 @@ public class Repository {\n \t * to the alternative repo will be returned. If the object is not yet store\n \t * a usable path in this repo will be returned. It is assumed that callers\n \t * will look for objects in a pack first.\n-\t *\n+\t * \n \t * @param objectId\n \t * @return suggested file name\n \t */\n \tpublic File toFile(final AnyObjectId objectId) {\n \t\tfinal String n = objectId.toString();\n-\t\tString d=n.substring(0, 2);\n-\t\tString f=n.substring(2);\n-\t\tfor (int i=0; i<objectsDirs.length; ++i) {\n+\t\tString d = n.substring(0, 2);\n+\t\tString f = n.substring(2);\n+\t\tfor (int i = 0; i < objectsDirs.length; ++i) {\n \t\t\tFile ret = new File(new File(objectsDirs[i], d), f);\n \t\t\tif (ret.exists())\n \t\t\t\treturn ret;\n@@ -251,9 +255,8 @@ public class Repository {\n \t *         object, or null if the object does not exist.\n \t * @throws IOException\n \t */\n-\tpublic ObjectLoader openObject(final AnyObjectId id)\n-\t\t\tthrows IOException {\n-\t\treturn openObject(new WindowCursor(),id);\n+\tpublic ObjectLoader openObject(final AnyObjectId id) throws IOException {\n+\t\treturn openObject(new WindowCursor(), id);\n \t}\n \n \t/**\n@@ -279,7 +282,8 @@ public class Repository {\n \t\t\t\t\t// This shouldn't happen unless the pack was corrupted\n \t\t\t\t\t// after we opened it or the VM runs out of memory. This is\n \t\t\t\t\t// a know problem with memory mapped I/O in java and have\n-\t\t\t\t\t// been noticed with JDK < 1.6. Tell the gc that now is a good\n+\t\t\t\t\t// been noticed with JDK < 1.6. Tell the gc that now is a\n+\t\t\t\t\t// good\n \t\t\t\t\t// time to collect and try once more.\n \t\t\t\t\ttry {\n \t\t\t\t\t\tcurs.release();\n@@ -325,14 +329,16 @@ public class Repository {\n \t}\n \n \t/**\n-\t * Access a Commit object using a symbolic reference. This reference may\n-\t * be a SHA-1 or ref in combination with a number of symbols translating\n-\t * from one ref or SHA1-1 to another, such as HEAD^ etc.\n-\t *\n-\t * @param revstr a reference to a git commit object\n+\t * Access a Commit object using a symbolic reference. This reference may be\n+\t * a SHA-1 or ref in combination with a number of symbols translating from\n+\t * one ref or SHA1-1 to another, such as HEAD^ etc.\n+\t * \n+\t * @param revstr\n+\t *            a reference to a git commit object\n \t * @return a Commit named by the specified string\n-\t * @throws IOException for I/O error or unexpected object type.\n-\t *\n+\t * @throws IOException\n+\t *             for I/O error or unexpected object type.\n+\t * \n \t * @see #resolve(String)\n \t */\n \tpublic Commit mapCommit(final String revstr) throws IOException {\n@@ -342,14 +348,16 @@ public class Repository {\n \n \t/**\n \t * Access any type of Git object by id and\n-\t *\n+\t * \n \t * @param id\n \t *            SHA-1 of object to read\n-\t * @param refName optional, only relevant for simple tags\n+\t * @param refName\n+\t *            optional, only relevant for simple tags\n \t * @return The Git object if found or null\n \t * @throws IOException\n \t */\n-\tpublic Object mapObject(final ObjectId id, final String refName) throws IOException {\n+\tpublic Object mapObject(final ObjectId id, final String refName)\n+\t\t\tthrows IOException {\n \t\tfinal ObjectLoader or = openObject(id);\n \t\tfinal byte[] raw = or.getBytes();\n \t\tif (or.getType() == Constants.OBJ_TREE)\n@@ -365,9 +373,11 @@ public class Repository {\n \n \t/**\n \t * Access a Commit by SHA'1 id.\n+\t * \n \t * @param id\n \t * @return Commit or null\n-\t * @throws IOException for I/O error or unexpected object type.\n+\t * @throws IOException\n+\t *             for I/O error or unexpected object type.\n \t */\n \tpublic Commit mapCommit(final ObjectId id) throws IOException {\n \t\tfinal ObjectLoader or = openObject(id);\n@@ -385,14 +395,15 @@ public class Repository {\n \t}\n \n \t/**\n-\t * Access a Tree object using a symbolic reference. This reference may\n-\t * be a SHA-1 or ref in combination with a number of symbols translating\n-\t * from one ref or SHA1-1 to another, such as HEAD^{tree} etc.\n-\t *\n-\t * @param revstr a reference to a git commit object\n+\t * Access a Tree object using a symbolic reference. This reference may be a\n+\t * SHA-1 or ref in combination with a number of symbols translating from one\n+\t * ref or SHA1-1 to another, such as HEAD^{tree} etc.\n+\t * \n+\t * @param revstr\n+\t *            a reference to a git commit object\n \t * @return a Tree named by the specified string\n \t * @throws IOException\n-\t *\n+\t * \n \t * @see #resolve(String)\n \t */\n \tpublic Tree mapTree(final String revstr) throws IOException {\n@@ -402,9 +413,11 @@ public class Repository {\n \n \t/**\n \t * Access a Tree by SHA'1 id.\n+\t * \n \t * @param id\n \t * @return Tree or null\n-\t * @throws IOException for I/O error or unexpected object type.\n+\t * @throws IOException\n+\t *             for I/O error or unexpected object type.\n \t */\n \tpublic Tree mapTree(final ObjectId id) throws IOException {\n \t\tfinal ObjectLoader or = openObject(id);\n@@ -419,22 +432,25 @@ public class Repository {\n \t\tthrow new IncorrectObjectTypeException(id, Constants.TYPE_TREE);\n \t}\n \n-\tprivate Tree makeTree(final ObjectId id, final byte[] raw) throws IOException {\n+\tprivate Tree makeTree(final ObjectId id, final byte[] raw)\n+\t\t\tthrows IOException {\n \t\tTree ret = new Tree(this, id, raw);\n \t\treturn ret;\n \t}\n \n-\tprivate Tag makeTag(final ObjectId id, final String refName, final byte[] raw) {\n+\tprivate Tag makeTag(final ObjectId id, final String refName,\n+\t\t\tfinal byte[] raw) {\n \t\tTag ret = new Tag(this, id, refName, raw);\n \t\treturn ret;\n \t}\n \n \t/**\n \t * Access a tag by symbolic name.\n-\t *\n+\t * \n \t * @param revstr\n \t * @return a Tag or null\n-\t * @throws IOException on I/O error or unexpected type\n+\t * @throws IOException\n+\t *             on I/O error or unexpected type\n \t */\n \tpublic Tag mapTag(String revstr) throws IOException {\n \t\tfinal ObjectId id = resolve(revstr);\n@@ -443,12 +459,15 @@ public class Repository {\n \n \t/**\n \t * Access a Tag by SHA'1 id\n+\t * \n \t * @param refName\n \t * @param id\n \t * @return Commit or null\n-\t * @throws IOException for I/O error or unexpected object type.\n+\t * @throws IOException\n+\t *             for I/O error or unexpected object type.\n \t */\n-\tpublic Tag mapTag(final String refName, final ObjectId id) throws IOException {\n+\tpublic Tag mapTag(final String refName, final ObjectId id)\n+\t\t\tthrows IOException {\n \t\tfinal ObjectLoader or = openObject(id);\n \t\tif (or == null)\n \t\t\treturn null;\n@@ -460,8 +479,9 @@ public class Repository {\n \n \t/**\n \t * Get a locked handle to a ref suitable for updating or creating.\n-\t *\n-\t * @param ref name to lock\n+\t * \n+\t * @param ref\n+\t *            name to lock\n \t * @return a locked ref\n \t * @throws IOException\n \t */\n@@ -473,27 +493,29 @@ public class Repository {\n \n \t/**\n \t * Parse a git revision string and return an object id.\n-\t *\n+\t * \n \t * Currently supported is combinations of these.\n \t * <ul>\n-\t *  <li>SHA-1 - a SHA-1</li>\n-\t *  <li>refs/... - a ref name</li>\n-\t *  <li>ref^n - nth parent reference</li>\n-\t *  <li>ref~n - distance via parent reference</li>\n-\t *  <li>ref@{n} - nth version of ref</li>\n-\t *  <li>ref^{tree} - tree references by ref</li>\n-\t *  <li>ref^{commit} - commit references by ref</li>\n+\t * <li>SHA-1 - a SHA-1</li>\n+\t * <li>refs/... - a ref name</li>\n+\t * <li>ref^n - nth parent reference</li>\n+\t * <li>ref~n - distance via parent reference</li>\n+\t * <li>ref@{n} - nth version of ref</li>\n+\t * <li>ref^{tree} - tree references by ref</li>\n+\t * <li>ref^{commit} - commit references by ref</li>\n \t * </ul>\n-\t *\n+\t * \n \t * Not supported is\n \t * <ul>\n \t * <li>timestamps in reflogs, ref@{full or relative timestamp}</li>\n \t * <li>abbreviated SHA-1's</li>\n \t * </ul>\n-\t *\n-\t * @param revstr A git object references expression\n+\t * \n+\t * @param revstr\n+\t *            A git object references expression\n \t * @return an ObjectId\n-\t * @throws IOException on serious errors\n+\t * @throws IOException\n+\t *             on serious errors\n \t */\n \tpublic ObjectId resolve(final String revstr) throws IOException {\n \t\tchar[] rev = revstr.toCharArray();\n@@ -503,7 +525,7 @@ public class Repository {\n \t\t\tswitch (rev[i]) {\n \t\t\tcase '^':\n \t\t\t\tif (refId == null) {\n-\t\t\t\t\tString refstr = new String(rev,0,i);\n+\t\t\t\t\tString refstr = new String(rev, 0, i);\n \t\t\t\t\trefId = resolveSimple(refstr);\n \t\t\t\t\tif (refId == null)\n \t\t\t\t\t\treturn null;\n@@ -523,23 +545,24 @@ public class Repository {\n \t\t\t\t\t\tint j;\n \t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\tif (!(ref instanceof Commit))\n-\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);\n-\t\t\t\t\t\tfor (j=i+1; j<rev.length; ++j) {\n+\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,\n+\t\t\t\t\t\t\t\t\tConstants.TYPE_COMMIT);\n+\t\t\t\t\t\tfor (j = i + 1; j < rev.length; ++j) {\n \t\t\t\t\t\t\tif (!Character.isDigit(rev[j]))\n \t\t\t\t\t\t\t\tbreak;\n \t\t\t\t\t\t}\n-\t\t\t\t\t\tString parentnum = new String(rev, i+1, j-i-1);\n+\t\t\t\t\t\tString parentnum = new String(rev, i + 1, j - i - 1);\n \t\t\t\t\t\tint pnum = Integer.parseInt(parentnum);\n \t\t\t\t\t\tif (pnum != 0)\n-\t\t\t\t\t\t\trefId = ((Commit)ref).getParentIds()[pnum - 1];\n+\t\t\t\t\t\t\trefId = ((Commit) ref).getParentIds()[pnum - 1];\n \t\t\t\t\t\ti = j - 1;\n \t\t\t\t\t\tbreak;\n \t\t\t\t\tcase '{':\n \t\t\t\t\t\tint k;\n \t\t\t\t\t\tString item = null;\n-\t\t\t\t\t\tfor (k=i+2; k<rev.length; ++k) {\n+\t\t\t\t\t\tfor (k = i + 2; k < rev.length; ++k) {\n \t\t\t\t\t\t\tif (rev[k] == '}') {\n-\t\t\t\t\t\t\t\titem = new String(rev, i+2, k-i-2);\n+\t\t\t\t\t\t\t\titem = new String(rev, i + 2, k - i - 2);\n \t\t\t\t\t\t\t\tbreak;\n \t\t\t\t\t\t\t}\n \t\t\t\t\t\t}\n@@ -548,44 +571,43 @@ public class Repository {\n \t\t\t\t\t\t\tif (item.equals(\"tree\")) {\n \t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\twhile (ref instanceof Tag) {\n-\t\t\t\t\t\t\t\t\tTag t = (Tag)ref;\n+\t\t\t\t\t\t\t\t\tTag t = (Tag) ref;\n \t\t\t\t\t\t\t\t\trefId = t.getObjId();\n \t\t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\t}\n \t\t\t\t\t\t\t\tif (ref instanceof Treeish)\n-\t\t\t\t\t\t\t\t\trefId = ((Treeish)ref).getTreeId();\n+\t\t\t\t\t\t\t\t\trefId = ((Treeish) ref).getTreeId();\n \t\t\t\t\t\t\t\telse\n-\t\t\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,  Constants.TYPE_TREE);\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\telse if (item.equals(\"commit\")) {\n+\t\t\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(\n+\t\t\t\t\t\t\t\t\t\t\trefId, Constants.TYPE_TREE);\n+\t\t\t\t\t\t\t} else if (item.equals(\"commit\")) {\n \t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\twhile (ref instanceof Tag) {\n-\t\t\t\t\t\t\t\t\tTag t = (Tag)ref;\n+\t\t\t\t\t\t\t\t\tTag t = (Tag) ref;\n \t\t\t\t\t\t\t\t\trefId = t.getObjId();\n \t\t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\t}\n \t\t\t\t\t\t\t\tif (!(ref instanceof Commit))\n-\t\t\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\telse if (item.equals(\"blob\")) {\n+\t\t\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(\n+\t\t\t\t\t\t\t\t\t\t\trefId, Constants.TYPE_COMMIT);\n+\t\t\t\t\t\t\t} else if (item.equals(\"blob\")) {\n \t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\twhile (ref instanceof Tag) {\n-\t\t\t\t\t\t\t\t\tTag t = (Tag)ref;\n+\t\t\t\t\t\t\t\t\tTag t = (Tag) ref;\n \t\t\t\t\t\t\t\t\trefId = t.getObjId();\n \t\t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\t}\n \t\t\t\t\t\t\t\tif (!(ref instanceof byte[]))\n-\t\t\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\telse if (item.equals(\"\")) {\n+\t\t\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(\n+\t\t\t\t\t\t\t\t\t\t\trefId, Constants.TYPE_COMMIT);\n+\t\t\t\t\t\t\t} else if (item.equals(\"\")) {\n \t\t\t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\t\t\tif (ref instanceof Tag)\n-\t\t\t\t\t\t\t\t\trefId = ((Tag)ref).getObjId();\n+\t\t\t\t\t\t\t\t\trefId = ((Tag) ref).getObjId();\n \t\t\t\t\t\t\t\telse {\n \t\t\t\t\t\t\t\t\t// self\n \t\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\t}\n-\t\t\t\t\t\t\telse\n+\t\t\t\t\t\t\t} else\n \t\t\t\t\t\t\t\tthrow new RevisionSyntaxException(revstr);\n \t\t\t\t\t\telse\n \t\t\t\t\t\t\tthrow new RevisionSyntaxException(revstr);\n@@ -593,22 +615,24 @@ public class Repository {\n \t\t\t\t\tdefault:\n \t\t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\t\tif (ref instanceof Commit)\n-\t\t\t\t\t\t\trefId = ((Commit)ref).getParentIds()[0];\n+\t\t\t\t\t\t\trefId = ((Commit) ref).getParentIds()[0];\n \t\t\t\t\t\telse\n-\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);\n-\t\t\t\t\t\t\n+\t\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,\n+\t\t\t\t\t\t\t\t\tConstants.TYPE_COMMIT);\n+\n \t\t\t\t\t}\n \t\t\t\t} else {\n \t\t\t\t\tref = mapObject(refId, null);\n \t\t\t\t\tif (ref instanceof Commit)\n-\t\t\t\t\t\trefId = ((Commit)ref).getParentIds()[0];\n+\t\t\t\t\t\trefId = ((Commit) ref).getParentIds()[0];\n \t\t\t\t\telse\n-\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);\n+\t\t\t\t\t\tthrow new IncorrectObjectTypeException(refId,\n+\t\t\t\t\t\t\t\tConstants.TYPE_COMMIT);\n \t\t\t\t}\n \t\t\t\tbreak;\n \t\t\tcase '~':\n \t\t\t\tif (ref == null) {\n-\t\t\t\t\tString refstr = new String(rev,0,i);\n+\t\t\t\t\tString refstr = new String(rev, 0, i);\n \t\t\t\t\trefId = resolveSimple(refstr);\n \t\t\t\t\tref = mapCommit(refId);\n \t\t\t\t}\n@@ -617,10 +641,10 @@ public class Repository {\n \t\t\t\t\tif (!Character.isDigit(rev[l]))\n \t\t\t\t\t\tbreak;\n \t\t\t\t}\n-\t\t\t\tString distnum = new String(rev, i+1, l-i-1);\n+\t\t\t\tString distnum = new String(rev, i + 1, l - i - 1);\n \t\t\t\tint dist = Integer.parseInt(distnum);\n \t\t\t\twhile (dist >= 0) {\n-\t\t\t\t\trefId = ((Commit)ref).getParentIds()[0];\n+\t\t\t\t\trefId = ((Commit) ref).getParentIds()[0];\n \t\t\t\t\tref = mapCommit(refId);\n \t\t\t\t\t--dist;\n \t\t\t\t}\n@@ -629,14 +653,16 @@ public class Repository {\n \t\t\tcase '@':\n \t\t\t\tint m;\n \t\t\t\tString time = null;\n-\t\t\t\tfor (m=i+2; m<rev.length; ++m) {\n+\t\t\t\tfor (m = i + 2; m < rev.length; ++m) {\n \t\t\t\t\tif (rev[m] == '}') {\n-\t\t\t\t\t\ttime = new String(rev, i+2, m-i-2);\n+\t\t\t\t\t\ttime = new String(rev, i + 2, m - i - 2);\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n \t\t\t\t}\n \t\t\t\tif (time != null)\n-\t\t\t\t\tthrow new RevisionSyntaxException(\"reflogs not yet supported by revision parser yet\", revstr);\n+\t\t\t\t\tthrow new RevisionSyntaxException(\n+\t\t\t\t\t\t\t\"reflogs not yet supported by revision parser yet\",\n+\t\t\t\t\t\t\trevstr);\n \t\t\t\ti = m - 1;\n \t\t\t\tbreak;\n \t\t\tdefault:\n@@ -674,12 +700,11 @@ public class Repository {\n \t}\n \n \t/**\n-\t * Scan the object dirs, including alternates for packs\n-\t * to use.\n+\t * Scan the object dirs, including alternates for packs to use.\n \t */\n \tpublic void scanForPacks() {\n \t\tfinal ArrayList<PackFile> p = new ArrayList<PackFile>();\n-\t\tfor (int i=0; i<objectsDirs.length; ++i)\n+\t\tfor (int i = 0; i < objectsDirs.length; ++i)\n \t\t\tscanForPacks(new File(objectsDirs[i], \"pack\"), p);\n \t\tfinal PackFile[] arr = new PackFile[p.size()];\n \t\tp.toArray(arr);\n@@ -710,14 +735,16 @@ public class Repository {\n \t\t}\n \t}\n \n-    /**\n-     * Writes a symref (e.g. HEAD) to disk\n-     *\n-     * @param name symref name\n-     * @param target pointed to ref\n-     * @throws IOException\n-     */\n-    public void writeSymref(final String name, final String target)\n+\t/**\n+\t * Writes a symref (e.g. HEAD) to disk\n+\t * \n+\t * @param name\n+\t *            symref name\n+\t * @param target\n+\t *            pointed to ref\n+\t * @throws IOException\n+\t */\n+\tpublic void writeSymref(final String name, final String target)\n \t\t\tthrows IOException {\n \t\tfinal byte[] content = (\"ref: \" + target + \"\\n\").getBytes(\"UTF-8\");\n \t\tfinal LockFile lck = new LockFile(fileForRef(name));\n@@ -754,7 +781,7 @@ public class Repository {\n \t\t\t\tObjectId id = packedRefs.get(name);\n \t\t\t\tif (id != null)\n \t\t\t\t\treturn new Ref(name, id);\n-\t\t\t\t\n+\n \t\t\t\t// no packed ref found, return blank one\n \t\t\t\treturn new Ref(name, null);\n \t\t\t}\n@@ -792,12 +819,13 @@ public class Repository {\n \t * @throws IOException\n \t */\n \tpublic String getPatch() throws IOException {\n-\t\tfinal File ptr = new File(getDirectory(),\"patches/\"+getBranch()+\"/applied\");\n+\t\tfinal File ptr = new File(getDirectory(), \"patches/\" + getBranch()\n+\t\t\t\t+ \"/applied\");\n \t\tfinal BufferedReader br = new BufferedReader(new FileReader(ptr));\n-\t\tString last=null;\n+\t\tString last = null;\n \t\ttry {\n \t\t\tString line;\n-\t\t\twhile ((line=br.readLine())!=null) {\n+\t\t\twhile ((line = br.readLine()) != null) {\n \t\t\t\tlast = line;\n \t\t\t}\n \t\t} finally {\n@@ -811,7 +839,7 @@ public class Repository {\n \t * @throws IOException\n \t */\n \tpublic String getFullBranch() throws IOException {\n-\t\tfinal File ptr = new File(getDirectory(),\"HEAD\");\n+\t\tfinal File ptr = new File(getDirectory(), \"HEAD\");\n \t\tfinal BufferedReader br = new BufferedReader(new FileReader(ptr));\n \t\tString ref;\n \t\ttry {\n@@ -823,14 +851,14 @@ public class Repository {\n \t\t\tref = ref.substring(5);\n \t\treturn ref;\n \t}\n-\t\n+\n \t/**\n \t * @return name of current branch.\n \t * @throws IOException\n \t */\n \tpublic String getBranch() throws IOException {\n \t\ttry {\n-\t\t\tfinal File ptr = new File(getDirectory(),\"HEAD\");\n+\t\t\tfinal File ptr = new File(getDirectory(), \"HEAD\");\n \t\t\tfinal BufferedReader br = new BufferedReader(new FileReader(ptr));\n \t\t\tString ref;\n \t\t\ttry {\n@@ -844,7 +872,7 @@ public class Repository {\n \t\t\t\tref = ref.substring(11);\n \t\t\treturn ref;\n \t\t} catch (FileNotFoundException e) {\n-\t\t\tfinal File ptr = new File(getDirectory(),\"head-name\");\n+\t\t\tfinal File ptr = new File(getDirectory(), \"head-name\");\n \t\t\tfinal BufferedReader br = new BufferedReader(new FileReader(ptr));\n \t\t\tString ref;\n \t\t\ttry {\n@@ -862,25 +890,27 @@ public class Repository {\n \tpublic Collection<String> getBranches() {\n \t\treturn listRefs(\"heads\");\n \t}\n-\t\n+\n \t/**\n \t * @return the names of all refs (local and remotes branches, tags)\n \t */\n \tpublic Collection<String> getAllRefs() {\n \t\treturn listRefs(\"\");\n \t}\n-\t\n+\n \tprivate Collection<String> listRefs(String refSubDir) {\n \t\t// add / to end, unless empty\n-\t\tif (refSubDir.length() > 0 && refSubDir.charAt(refSubDir.length() -1 ) != '/')\n+\t\tif (refSubDir.length() > 0\n+\t\t\t\t&& refSubDir.charAt(refSubDir.length() - 1) != '/')\n \t\t\trefSubDir += \"/\";\n-\t\t\n-\t\tCollection<String> branchesRaw = listFilesRecursively(new File(refsDir, refSubDir), null);\n+\n+\t\tCollection<String> branchesRaw = listFilesRecursively(new File(refsDir,\n+\t\t\t\trefSubDir), null);\n \t\tArrayList<String> branches = new ArrayList<String>();\n \t\tfor (String b : branchesRaw) {\n \t\t\tbranches.add(\"refs/\" + refSubDir + b);\n \t\t}\n-\t\t\n+\n \t\trefreshPackedRefsCache();\n \t\tSet<String> keySet = packedRefs.keySet();\n \t\tfor (String s : keySet)\n@@ -896,22 +926,23 @@ public class Repository {\n \t\treturn listRefs(\"tags\");\n \t}\n \n-\tprivate Map<String,ObjectId> packedRefs = new HashMap<String,ObjectId>();\n+\tprivate Map<String, ObjectId> packedRefs = new HashMap<String, ObjectId>();\n+\n \tprivate long packedrefstime = 0;\n \n \tprivate void refreshPackedRefsCache() {\n \t\tif (!packedRefsFile.exists()) {\n \t\t\tif (packedRefs.size() > 0)\n-\t\t\t\tpackedRefs = new HashMap<String,ObjectId>();\n+\t\t\t\tpackedRefs = new HashMap<String, ObjectId>();\n \t\t\treturn;\n \t\t}\n \t\tif (packedRefsFile.lastModified() == packedrefstime)\n \t\t\treturn;\n-\t\tMap<String,ObjectId> newPackedRefs = new HashMap<String,ObjectId>();\n+\t\tMap<String, ObjectId> newPackedRefs = new HashMap<String, ObjectId>();\n \t\tFileReader fileReader = null;\n \t\ttry {\n \t\t\tfileReader = new FileReader(packedRefsFile);\n-\t\t\tBufferedReader b=new BufferedReader(fileReader);\n+\t\t\tBufferedReader b = new BufferedReader(fileReader);\n \t\t\tString p;\n \t\t\twhile ((p = b.readLine()) != null) {\n \t\t\t\tif (p.charAt(0) == '#')\n@@ -920,12 +951,12 @@ public class Repository {\n \t\t\t\t\tcontinue;\n \t\t\t\t}\n \t\t\t\tint spos = p.indexOf(' ');\n-\t\t\t\tObjectId id = ObjectId.fromString(p.substring(0,spos));\n-\t\t\t\tString name = p.substring(spos+1);\n+\t\t\t\tObjectId id = ObjectId.fromString(p.substring(0, spos));\n+\t\t\t\tString name = p.substring(spos + 1);\n \t\t\t\tnewPackedRefs.put(name, id);\n \t\t\t}\n \t\t} catch (IOException e) {\n-\t\t\tthrow new Error(\"Cannot read packed refs\",e);\n+\t\t\tthrow new Error(\"Cannot read packed refs\", e);\n \t\t} finally {\n \t\t\tif (fileReader != null) {\n \t\t\t\ttry {\n@@ -968,13 +999,17 @@ public class Repository {\n \t * @return applied patches in a map indexed on current commit id\n \t * @throws IOException\n \t */\n-\tpublic Map<ObjectId,StGitPatch> getAppliedPatches() throws IOException {\n-\t\tMap<ObjectId,StGitPatch> ret = new HashMap<ObjectId,StGitPatch>();\n+\tpublic Map<ObjectId, StGitPatch> getAppliedPatches() throws IOException {\n+\t\tMap<ObjectId, StGitPatch> ret = new HashMap<ObjectId, StGitPatch>();\n \t\tif (isStGitMode()) {\n-\t\t\tFile patchDir = new File(new File(getDirectory(),\"patches\"),getBranch());\n-\t\t\tBufferedReader apr = new BufferedReader(new FileReader(new File(patchDir,\"applied\")));\n-\t\t\tfor (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {\n-\t\t\t\tFile topFile = new File(new File(new File(patchDir,\"patches\"), patchName), \"top\");\n+\t\t\tFile patchDir = new File(new File(getDirectory(), \"patches\"),\n+\t\t\t\t\tgetBranch());\n+\t\t\tBufferedReader apr = new BufferedReader(new FileReader(new File(\n+\t\t\t\t\tpatchDir, \"applied\")));\n+\t\t\tfor (String patchName = apr.readLine(); patchName != null; patchName = apr\n+\t\t\t\t\t.readLine()) {\n+\t\t\t\tFile topFile = new File(new File(new File(patchDir, \"patches\"),\n+\t\t\t\t\t\tpatchName), \"top\");\n \t\t\t\tBufferedReader tfr = new BufferedReader(new FileReader(topFile));\n \t\t\t\tString objectId = tfr.readLine();\n \t\t\t\tObjectId id = ObjectId.fromString(objectId);\n@@ -1004,7 +1039,7 @@ public class Repository {\n \t\t}\n \t\treturn ret;\n \t}\n-\t\n+\n \t/** Clean up stale caches */\n \tpublic void refreshFromDisk() {\n \t\tpackedRefs = null;\n@@ -1027,7 +1062,7 @@ public class Repository {\n \tstatic byte[] gitInternalSlash(byte[] bytes) {\n \t\tif (File.separatorChar == '/')\n \t\t\treturn bytes;\n-\t\tfor (int i=0; i<bytes.length; ++i)\n+\t\tfor (int i = 0; i < bytes.length; ++i)\n \t\t\tif (bytes[i] == File.separatorChar)\n \t\t\t\tbytes[i] = '/';\n \t\treturn bytes;\n@@ -1039,32 +1074,32 @@ public class Repository {\n \tpublic RepositoryState getRepositoryState() {\n \t\tif (new File(getWorkDir(), \".dotest\").exists())\n \t\t\treturn RepositoryState.REBASING;\n-\t\tif (new File(gitDir,\".dotest-merge\").exists())\n+\t\tif (new File(gitDir, \".dotest-merge\").exists())\n \t\t\treturn RepositoryState.REBASING_INTERACTIVE;\n-\t\tif (new File(gitDir,\"MERGE_HEAD\").exists())\n+\t\tif (new File(gitDir, \"MERGE_HEAD\").exists())\n \t\t\treturn RepositoryState.MERGING;\n-\t\tif (new File(gitDir,\"BISECT_LOG\").exists())\n+\t\tif (new File(gitDir, \"BISECT_LOG\").exists())\n \t\t\treturn RepositoryState.BISECTING;\n \t\treturn RepositoryState.SAFE;\n \t}\n \n \t/**\n-\t * Check validty of a ref name. It must not contain character that has\n-\t * a special meaning in a Git object reference expression. Some other\n+\t * Check validty of a ref name. It must not contain character that has a\n+\t * special meaning in a Git object reference expression. Some other\n \t * dangerous characters are also excluded.\n-\t *\n+\t * \n \t * @param refName\n-\t *\n+\t * \n \t * @return true if refName is a valid ref name\n \t */\n \tpublic static boolean isValidRefName(final String refName) {\n \t\tfinal int len = refName.length();\n \t\tchar p = '\\0';\n-\t\tfor (int i=0; i<len; ++i) {\n+\t\tfor (int i = 0; i < len; ++i) {\n \t\t\tchar c = refName.charAt(i);\n \t\t\tif (c <= ' ')\n \t\t\t\treturn false;\n-\t\t\tswitch(c) {\n+\t\t\tswitch (c) {\n \t\t\tcase '.':\n \t\t\t\tif (i == 0)\n \t\t\t\t\treturn false;\n@@ -1076,11 +1111,14 @@ public class Repository {\n \t\t\tcase '/':\n \t\t\t\tif (i == 0)\n \t\t\t\t\treturn false;\n-\t\t\t\tif (i == len -1)\n+\t\t\t\tif (i == len - 1)\n \t\t\t\t\treturn false;\n \t\t\t\tbreak;\n-\t\t\tcase '~': case '^': case ':':\n-\t\t\tcase '?': case '[':\n+\t\t\tcase '~':\n+\t\t\tcase '^':\n+\t\t\tcase ':':\n+\t\t\tcase '?':\n+\t\t\tcase '[':\n \t\t\t\treturn false;\n \t\t\tcase '*':\n \t\t\t\treturn false;\n@@ -1092,9 +1130,11 @@ public class Repository {\n \n \t/**\n \t * String work dir and return normalized repository path\n-\t *\n-\t * @param wd Work dir\n-\t * @param f File whose path shall be stripp off it's workdir\n+\t * \n+\t * @param wd\n+\t *            Work dir\n+\t * @param f\n+\t *            File whose path shall be stripp off it's workdir\n \t * @return normalized repository relative path\n \t */\n \tpublic static String stripWorkDir(File wd, File f) {\n@@ -1109,9 +1149,11 @@ public class Repository {\n \t * @return information about how a remote repository is beging tracked\n \t */\n \tpublic RemoteSpec getRemoteSpec(String name) {\n-\t\tString url = getConfig().getString(\"remote.\"+name, null, \"url\");\n-\t\tString fetchPattern = getConfig().getString(\"remote.\"+name, null, \"fetch\");\n-\t\tString pushPattern = getConfig().getString(\"remote.\"+name, null, \"push\");\n+\t\tString url = getConfig().getString(\"remote.\" + name, null, \"url\");\n+\t\tString fetchPattern = getConfig().getString(\"remote.\" + name, null,\n+\t\t\t\t\"fetch\");\n+\t\tString pushPattern = getConfig().getString(\"remote.\" + name, null,\n+\t\t\t\t\"push\");\n \t\treturn new RemoteSpec(name, url, fetchPattern, pushPattern);\n \t}\n \n@@ -1125,15 +1167,16 @@ public class Repository {\n \t * @param branch\n \t *            local branch name, e.g. \"master\"\n \t */\n-\tpublic void configureDefaultBranch(final String remote, final String url, final String branch) {\n-\t\tconfig.putString(RepositoryConfig.REMOTE_SECTION, remote, \"url\",\n-\t\t\t\turl);\n-\t\tconfig.putString(RepositoryConfig.REMOTE_SECTION, remote, \"fetch\",\n-\t\t\t\t\"+\" + Constants.HEADS_PREFIX + \"/*:\" + Constants.REMOTES_PREFIX + \"/\" + remote + \"/*\");\n+\tpublic void configureDefaultBranch(final String remote, final String url,\n+\t\t\tfinal String branch) {\n+\t\tconfig.putString(RepositoryConfig.REMOTE_SECTION, remote, \"url\", url);\n+\t\tconfig.putString(RepositoryConfig.REMOTE_SECTION, remote, \"fetch\", \"+\"\n+\t\t\t\t+ Constants.HEADS_PREFIX + \"/*:\" + Constants.REMOTES_PREFIX\n+\t\t\t\t+ \"/\" + remote + \"/*\");\n \t\tconfig.putString(RepositoryConfig.BRANCH_SECTION, branch, \"remote\",\n \t\t\t\tremote);\n-\t\tconfig.putString(RepositoryConfig.BRANCH_SECTION, Constants.MASTER, \"merge\",\n-\t\t\t\tConstants.HEADS_PREFIX + \"/\" + branch);\n+\t\tconfig.putString(RepositoryConfig.BRANCH_SECTION, Constants.MASTER,\n+\t\t\t\t\"merge\", Constants.HEADS_PREFIX + \"/\" + branch);\n \t}\n \n \t/**\n@@ -1145,7 +1188,7 @@ public class Repository {\n \n \t/**\n \t * Setup HEAD and \"master\" refs for a new repository.\n-\t *\n+\t * \n \t * @param remoteBranch\n \t *            The remote branch to start with\n \t * @param branch\n@@ -1154,7 +1197,8 @@ public class Repository {\n \t * @return the commit references by the new HEAD\n \t * @throws IOException\n \t */\n-\tpublic Commit setupHEADRef(final String remoteBranch, final String branch) throws IOException {\n+\tpublic Commit setupHEADRef(final String remoteBranch, final String branch)\n+\t\t\tthrows IOException {\n \t\tCommit mapCommit = mapCommit(remoteBranch);\n \t\tString refName = Constants.HEADS_PREFIX + \"/\" + branch;\n \t\tLockFile masterRef = lockRef(refName);\n-- \n1.5.4.3\n"},{"id":"76763","messageId":"1210623222-24908-4-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 03/24] Formatted Constats class.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:21Z","receivedAt":"2008-05-12T20:13:21Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/lib/Constants.java        |    5 +++--\n 1 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java\nindex b8910e7..169c615 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java\n@@ -190,8 +190,9 @@ public final class Constants {\n \n \t/**\n \t * Convert an OBJ_* type constant to a TYPE_* type constant.\n-\t *\n-\t * @param typeCode the type code, from a pack representation.\n+\t * \n+\t * @param typeCode\n+\t *            the type code, from a pack representation.\n \t * @return the canonical string name of this type.\n \t */\n \tpublic static String typeString(final int typeCode) {\n-- \n1.5.4.3\n"},{"id":"76782","messageId":"1210623222-24908-5-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 04/24] Added path related constats to Constats class.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:22Z","receivedAt":"2008-05-12T20:13:22Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/lib/Constants.java        |   20 ++++++++++++++++++++\n 1 files changed, 20 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java\nindex 169c615..13e09d8 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java\n@@ -171,6 +171,26 @@ public final class Constants {\n \tpublic static String REMOTES_PREFIX = \"refs/remotes\";\n \n \t/**\n+\t * The name of the repository directory in the project directory.\n+\t */\n+\tpublic static final String REPOSITORY_DIRECTORY_NAME = \".git\";\n+\n+\t/**\n+\t * Contains the name of the objects directory in the repository directory.\n+\t */\n+\tpublic static final String OBJECTS_DIRECTORY_NAME = \"objects\";\n+\n+\t/**\n+\t * Contains the name of the refs directory in the repository directory.\n+\t */\n+\tpublic static final String REFS_DIRECTORY_NAME = \"refs\";\n+\n+\t/**\n+\t * Contains the name of the HEAD file in the repository directory.\n+\t */\n+\tpublic static final String HEAD_FILE_NAME = \"HEAD\";\n+\n+\t/**\n \t * Create a new digest function for objects.\n \t * \n \t * @return a new digest object.\n-- \n1.5.4.3\n"},{"id":"76770","messageId":"1210623222-24908-6-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:23Z","receivedAt":"2008-05-12T20:13:23Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"---\n .../src/org/spearce/jgit/lib/Repository.java       |   30 +++++++++\n .../src/org/spearce/jgit/lib/WorkTree.java         |   67 ++++++++++++++++++++\n 2 files changed, 97 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\nindex 44fd81b..3186fe2 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n@@ -1212,4 +1212,34 @@ public class Repository {\n \t\treturn mapCommit;\n \t}\n \n+\t/**\n+\t * Creates a new {@link WorkTree} and initialize a repository for it.\n+\t * \n+\t * @param workTreeDirectory\n+\t *            the directory with the project files.\n+\t * @return a new {@link WorkTree} with a new and open {@link Repository}.\n+\t * @throws IOException\n+\t *             thrown by {@link Repository#create()}\n+\t */\n+\tpublic static WorkTree createWorkTree(File workTreeDirectory)\n+\t\t\tthrows IOException {\n+\t\tfinal File gitDirectory = new File(workTreeDirectory,\n+\t\t\t\tConstants.REPOSITORY_DIRECTORY_NAME);\n+\t\tif (gitDirectory.exists()) {\n+\t\t\tthrow new IllegalArgumentException(\n+\t\t\t\t\t\"Repository exists in given project directory.\");\n+\t\t}\n+\t\tfinal Repository repository = new Repository(gitDirectory);\n+\t\ttry {\n+\t\t\trepository.create();\n+\t\t\treturn new WorkTree(workTreeDirectory, repository);\n+\t\t} catch (RuntimeException e) {\n+\t\t\trepository.close();\n+\t\t\tthrow e;\n+\t\t} catch (IOException e) {\n+\t\t\trepository.close();\n+\t\t\tthrow e;\n+\t\t}\n+\t}\n+\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java b/org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java\nnew file mode 100644\nindex 0000000..14bdda0\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java\n@@ -0,0 +1,67 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.lib;\n+\n+import java.io.File;\n+\n+/**\n+ * Represents a work tree controlled by git. Use {@link Repository} in order to\n+ * create an object of this class.\n+ * \n+ */\n+public class WorkTree {\n+\tprivate final File directory;\n+\n+\tprivate final Repository repository;\n+\n+\t/**\n+\t * This constructor should be only used by the class {@link Repository}.\n+\t * \n+\t * @param directory\n+\t *            defines the value of the directory field.\n+\t * @param repository\n+\t *            defines the value of the repository field.\n+\t */\n+\tWorkTree(File directory, Repository repository) {\n+\t\tthis.directory = directory;\n+\t\tthis.repository = repository;\n+\t}\n+\n+\t/**\n+\t * \n+\t * @return the directory which contains the files of the project. Usually\n+\t *         this directory contain a .git directory with the repository.\n+\t */\n+\tpublic File getDirectory() {\n+\t\treturn directory;\n+\t}\n+\n+\t/**\n+\t * @return the {@link Repository} object of the project.\n+\t */\n+\tpublic Repository getRepository() {\n+\t\treturn repository;\n+\t}\n+\n+\t/**\n+\t * Closes the git repository of this project.\n+\t */\n+\tpublic void closeRepository() {\n+\t\trepository.close();\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76769","messageId":"1210623222-24908-7-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 06/24] Added a \"init\" command to the git like command line tool.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:24Z","receivedAt":"2008-05-12T20:13:24Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/pgm/InitCommand.java      |   67 ++++++++++++++++++++\n .../src/org/spearce/jgit/pgm/MainProgram.java      |    1 +\n 2 files changed, 68 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java\nnew file mode 100644\nindex 0000000..e87e777\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java\n@@ -0,0 +1,67 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.pgm;\n+\n+import java.io.File;\n+import java.io.IOException;\n+\n+import static org.spearce.jgit.lib.Repository.createWorkTree;\n+import org.spearce.jgit.lib.WorkTree;\n+\n+import static java.lang.String.format;\n+\n+/**\n+ * The {@link #execute} method of this class is used to create git repositories.\n+ * This class is immutable.\n+ * \n+ */\n+public class InitCommand implements Command {\n+\t/**\n+\t * Use this instance instead of creating a new ${link InitCommand}. You\n+\t * don't need to create an instance of this class as it is immutable and not\n+\t * configurable.\n+\t */\n+\tpublic static InitCommand INSTANCE = new InitCommand();\n+\n+\tpublic void execute(String... args) throws IOException {\n+\t\tfinal String currentDirectoryPathString = System\n+\t\t\t\t.getProperty(\"user.dir\");\n+\t\tif (currentDirectoryPathString == null) {\n+\t\t\tthrow new IOException(\"Unable to get current working directory\");\n+\t\t}\n+\t\tfinal File currentDirectoryPath = new File(currentDirectoryPathString);\n+\t\tif (!currentDirectoryPath.isDirectory()) {\n+\t\t\tfinal String message = format(\n+\t\t\t\t\t\"No directory found at \\\"%s\\\". It was the current working directory at program start.\",\n+\t\t\t\t\tcurrentDirectoryPathString);\n+\t\t\tthrow new IOException(message);\n+\t\t}\n+\n+\t\tfinal WorkTree workTree = createWorkTree(currentDirectoryPath);\n+\t\ttry {\n+\t\t\tSystem.out.printf(\"Created a git repository at: %s%n\", workTree\n+\t\t\t\t\t.getRepository().getDirectory());\n+\t\t} finally {\n+\t\t\tworkTree.closeRepository();\n+\t\t}\n+\n+\t}\n+\n+\tpublic String getShortDescription() {\n+\t\treturn \"Creates an empty git repository.\";\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\nindex c9af51c..1ade91b 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\n@@ -33,6 +33,7 @@ public class MainProgram {\n \n \tstatic {\n \t\tfinal Map<String, Command> commands = new HashMap<String, Command>();\n+\t\tcommands.put(\"init\", InitCommand.INSTANCE);\n \t\tcommands.put(\"help\", HelpCommand.INSTANCE);\n \t\tcommandNameToObjectMap = Collections.unmodifiableMap(commands);\n \t}\n-- \n1.5.4.3\n"},{"id":"76772","messageId":"1210623222-24908-8-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:25Z","receivedAt":"2008-05-12T20:13:25Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/lib/Repository.java       |   90 ++++++++++++++++++++\n 1 files changed, 90 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\nindex 3186fe2..ed5bd89 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n@@ -16,6 +16,11 @@\n  */\n package org.spearce.jgit.lib;\n \n+import static org.spearce.jgit.lib.Constants.HEAD_FILE_NAME;\n+import static org.spearce.jgit.lib.Constants.OBJECTS_DIRECTORY_NAME;\n+import static org.spearce.jgit.lib.Constants.REFS_DIRECTORY_NAME;\n+import static org.spearce.jgit.lib.Constants.REPOSITORY_DIRECTORY_NAME;\n+\n import java.io.BufferedReader;\n import java.io.File;\n import java.io.FileNotFoundException;\n@@ -1242,4 +1247,89 @@ public class Repository {\n \t\t}\n \t}\n \n+\t/**\n+\t * Find the git repository for the current working directory.\n+\t * \n+\t * @return a {@link Repository}.\n+\t * @throws IOException\n+\t *             if the system property user.dir isn't set or if it is\n+\t *             invalid.\n+\t */\n+\tpublic static WorkTree findWorkTree() throws IOException {\n+\t\tfinal String workingDirectoryPath = System.getProperty(\"user.dir\");\n+\t\tif (workingDirectoryPath == null) {\n+\t\t\tthrow new IOException(\"unable to get working directory\");\n+\t\t}\n+\t\tfinal File workingDirectoryFile = new File(workingDirectoryPath);\n+\t\tif (!workingDirectoryFile.exists()) {\n+\t\t\tthrow new IOException(\"Working directory path is invalid\");\n+\t\t}\n+\t\treturn findWorkTree(workingDirectoryFile);\n+\t}\n+\n+\t/**\n+\t * Checks if a path is a valid git repository. Works similar like the method\n+\t * is_git_directory from the original setup.c file.\n+\t * \n+\t * @param directory\n+\t *            the path which should be checked.\n+\t * @return true if the path is a valid git repository.\n+\t */\n+\tprivate static boolean isRepository(File directory) {\n+\t\tif (!directory.isDirectory()) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\tfinal File objectDirectory = new File(directory, OBJECTS_DIRECTORY_NAME);\n+\t\tif (!objectDirectory.isDirectory()) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\tfinal File refsDirectory = new File(directory, REFS_DIRECTORY_NAME);\n+\t\tif (!refsDirectory.isDirectory()) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\tfinal File head = new File(directory, HEAD_FILE_NAME);\n+\t\tif (!hasValidateHeadRef(head)) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\treturn true;\n+\t}\n+\n+\t/**\n+\t * Checks for example if a path is a valid HEAD file. Should do the same\n+\t * like validate_headref from path.c.\n+\t * \n+\t * @param path\n+\t *            is the path of the HEAD file.\n+\t * @return true if it has a valid head reference.\n+\t */\n+\tprivate static final boolean hasValidateHeadRef(File path) {\n+\t\treturn true; // TODO stub. view int validate_headref(const char\n+\t\t// *path) at path.c\n+\t}\n+\n+\tprivate static WorkTree findWorkTree(File directory) throws IOException {\n+\t\tFile currentDirectory = directory.getAbsoluteFile();\n+\t\twhile (true) {\n+\t\t\tfinal File commonGitDirectory = new File(directory,\n+\t\t\t\t\tREPOSITORY_DIRECTORY_NAME);\n+\t\t\tif (isRepository(commonGitDirectory)) {\n+\t\t\t\treturn new WorkTree(currentDirectory, new Repository(\n+\t\t\t\t\t\tcommonGitDirectory));\n+\t\t\t}\n+\n+\t\t\tif (isRepository(currentDirectory)) {\n+\t\t\t\treturn new WorkTree(null, new Repository(currentDirectory));\n+\t\t\t}\n+\t\t\tcurrentDirectory = currentDirectory.getParentFile();\n+\t\t\tif (currentDirectory == null) {\n+\t\t\t\tthrow new IOException(\"Can't find git repository\");\n+\t\t\t}\n+\t\t}\n+\n+\t}\n+\n }\n-- \n1.5.4.3\n"},{"id":"76778","messageId":"1210623222-24908-9-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 08/24] Added the interface FilePattern.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:26Z","receivedAt":"2008-05-12T20:13:26Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../spearce/jgit/treewalk/rules/FilePattern.java   |  105 ++++++++++++++++++++\n 1 files changed, 105 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/FilePattern.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/FilePattern.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/FilePattern.java\nnew file mode 100644\nindex 0000000..666ff08\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/FilePattern.java\n@@ -0,0 +1,105 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+/**\n+ * A {@link FilePattern} can be used to check if files in a directory matches a\n+ * pattern. It provides with the {@link #getPatternForSubDirectory(String)}\n+ * method {@link FilePattern}s for sub directories.\n+ * \n+ * Implementations of this interface should be immutable.\n+ * \n+ */\n+interface FilePattern {\n+\t/**\n+\t * This pattern instance matches always.\n+\t */\n+\tpublic static final FilePattern MATCH_ALWAYS = new FilePattern() {\n+\n+\t\tpublic FilePattern getPatternForSubDirectory(String directoryName) {\n+\t\t\treturn MATCH_ALWAYS;\n+\t\t}\n+\n+\t\tpublic boolean match(String fileName, boolean fileIsDirectory) {\n+\t\t\treturn true;\n+\t\t}\n+\n+\t\tpublic boolean canMatchAtThisDirectoryLevel() {\n+\t\t\treturn true;\n+\t\t}\n+\n+\t\tpublic boolean isSameForSubDirectories() {\n+\t\t\treturn true;\n+\t\t}\n+\t};\n+\n+\t/**\n+\t * This pattern instance matches never.\n+\t */\n+\tpublic static final FilePattern MATCH_NEVER = new FilePattern() {\n+\n+\t\tpublic FilePattern getPatternForSubDirectory(String directoryName) {\n+\t\t\treturn MATCH_NEVER;\n+\t\t}\n+\n+\t\tpublic boolean match(String fileName, boolean fileIsDirectory) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\tpublic boolean canMatchAtThisDirectoryLevel() {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\tpublic boolean isSameForSubDirectories() {\n+\t\t\treturn true;\n+\t\t}\n+\t};\n+\n+\t/**\n+\t * @param fileName\n+\t *            the name of the file or directory\n+\t * @param fileIsDirectory\n+\t *            determines if the file is a directory.\n+\t * @return true if the pattern matches.\n+\t */\n+\tboolean match(String fileName, boolean fileIsDirectory);\n+\n+\t/**\n+\t * \n+\t * @param directoryName\n+\t *            the name of a subdirectory.\n+\t * @return a pattern which can be used to match files in sub directories. A\n+\t *         user may check if the returned value is {@link #MATCH_NEVER} in\n+\t *         order to do some performance optimizations.\n+\t * \n+\t */\n+\tFilePattern getPatternForSubDirectory(String directoryName);\n+\n+\t/**\n+\t * This method can be used to generate an smaller list of rules, which can\n+\t * match.\n+\t * \n+\t * @return true if {@link #match(String, boolean)} returns always false.\n+\t */\n+\tboolean canMatchAtThisDirectoryLevel();\n+\n+\t/**\n+\t * @return true if {@link #getPatternForSubDirectory(String)} returns true\n+\t *         for every value.\n+\t */\n+\tboolean isSameForSubDirectories();\n+}\n-- \n1.5.4.3\n"},{"id":"76780","messageId":"1210623222-24908-10-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 09/24] Added the class Rule.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:27Z","receivedAt":"2008-05-12T20:13:27Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/treewalk/rules/Rule.java  |   65 ++++++++++++++++++++\n 1 files changed, 65 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rule.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rule.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rule.java\nnew file mode 100644\nindex 0000000..fe3b45c\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rule.java\n@@ -0,0 +1,65 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+/**\n+ * A Rule defines what to do with a files which match a specified\n+ * {@link FilePattern}.\n+ */\n+public class Rule {\n+\tprivate boolean ignoreAtMatch;\n+\n+\tprivate FilePattern pattern;\n+\n+\t/**\n+\t * \n+\t * @param ignoreAtMatch\n+\t *            defines if the rules ignores or accepts at a match.\n+\t * @param pattern\n+\t *            the pattern used to test if a file matches.\n+\t */\n+\tRule(boolean ignoreAtMatch, FilePattern pattern) {\n+\t\tthis.ignoreAtMatch = ignoreAtMatch;\n+\t\tthis.pattern = pattern;\n+\t}\n+\n+\tFilePattern getPattern() {\n+\t\treturn pattern;\n+\t}\n+\n+\tboolean isIgnoreAtMatch() {\n+\t\treturn ignoreAtMatch;\n+\t}\n+\n+\tRule getRuleForSubDirectory(String directoryName) {\n+\t\tfinal FilePattern subPattern = pattern\n+\t\t\t\t.getPatternForSubDirectory(directoryName);\n+\t\tif (subPattern == pattern) {\n+\t\t\treturn this;\n+\t\t}\n+\t\treturn new Rule(ignoreAtMatch, subPattern);\n+\t}\n+\n+\tboolean canMatchAtThisDirectoryLevel() {\n+\t\treturn pattern.canMatchAtThisDirectoryLevel();\n+\t}\n+\n+\tboolean isSameForSubDirectories() {\n+\t\treturn pattern.isSameForSubDirectories();\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76785","messageId":"1210623222-24908-11-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 10/24] Added the iterface Rules.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:28Z","receivedAt":"2008-05-12T20:13:28Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/treewalk/rules/Rules.java |   99 ++++++++++++++++++++\n 1 files changed, 99 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rules.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rules.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rules.java\nnew file mode 100644\nindex 0000000..627d974\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rules.java\n@@ -0,0 +1,99 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+/**\n+ * A {@link Rules} instances defines ignore or do not ignore rules for files in\n+ * a directory. It can't directly be used to match files in sub directories, but\n+ * provides a method {@link #getRulesForSubDirectory}.\n+ * \n+ */\n+public interface Rules {\n+\n+\t/**\n+\t * Provides the instance of {@link IgnoreAllRules}.\n+\t */\n+\tpublic static final Rules IGNORE_ALL = new IgnoreAllRules();\n+\n+\t/**\n+\t * Provides the instance of {@link IgnoreNothingRules}.\n+\t */\n+\tpublic static final Rules IGNORE_NOTHING = new IgnoreNothingRules();\n+\n+\t/**\n+\t * @param fileName\n+\t *            the name of the file or directory.\n+\t * @param fileIsDirectory\n+\t *            should be true if the file is a directory.\n+\t * @return true if the file or directory should be ignored.\n+\t */\n+\tpublic abstract boolean toIgnore(String fileName, boolean fileIsDirectory);\n+\n+\t/**\n+\t * @param directoryName\n+\t *            the sub directory for which you want an {@link Rules}\n+\t *            instance.\n+\t * @return an {@link Rules} instance, which can be used to check files in\n+\t *         the specified sub directory.\n+\t */\n+\tpublic abstract Rules getRulesForSubDirectory(String directoryName);\n+\n+\t/**\n+\t * This implementation ignores everything.\n+\t */\n+\tpublic static final class IgnoreAllRules implements Rules {\n+\t\tprivate IgnoreAllRules() {\n+\t\t\t// declared to make the constructor private\n+\t\t}\n+\n+\t\tpublic Rules getRulesForSubDirectory(String directoryName) {\n+\t\t\treturn this;\n+\t\t}\n+\n+\t\tpublic boolean toIgnore(String fileName, boolean fileIsDirectory) {\n+\t\t\treturn true;\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic String toString() {\n+\t\t\treturn \"ignore all rules\";\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * This implementation ignores nothing.\n+\t */\n+\tpublic static final class IgnoreNothingRules implements Rules {\n+\t\tprivate IgnoreNothingRules() {\n+\t\t\t// declared to make the constructor private\n+\t\t}\n+\n+\t\tpublic Rules getRulesForSubDirectory(String directoryName) {\n+\t\t\treturn this;\n+\t\t}\n+\n+\t\tpublic boolean toIgnore(String fileName, boolean fileIsDirectory) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic String toString() {\n+\t\t\treturn \"ignore nothing rules\";\n+\t\t}\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76773","messageId":"1210623222-24908-12-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 11/24] Added the class FNMatchPattern.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:29Z","receivedAt":"2008-05-12T20:13:29Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/lib/FNMatchPattern.java   |   81 ++++++++++++++++++++\n 1 files changed, 81 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java b/org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java\nnew file mode 100644\nindex 0000000..005659e\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java\n@@ -0,0 +1,81 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.lib;\n+\n+import java.util.regex.Pattern;\n+\n+/**\n+ * This class represents a pattern which should work like the fnmatch method.\n+ * <code>new FNMatchPattern(exp).matches(input)</code> should do the same like\n+ * <code>fnmatch(exp, input, 0) == 0</code>\n+ * \n+ * As this isn't a one to one code port, but written based on the documentation\n+ * of fnmatch it can be that the behavior of this class differ in some corner\n+ * cases from the behavior of the fnmatch function.\n+ */\n+public class FNMatchPattern {\n+\n+\tprivate final Pattern regexPattern;\n+\n+\tprivate static String toRegexString(String fnmatchPattern) {\n+\t\tfinal StringBuilder regexStringBuilder = new StringBuilder();\n+\t\tchar perviosCharacter = 0;\n+\t\tfor (int i = 0; i < fnmatchPattern.length(); i++) {\n+\t\t\tfinal char c = fnmatchPattern.charAt(i);\n+\t\t\tswitch (c) {\n+\t\t\tcase '^':\n+\t\t\t\tif (perviosCharacter == '[') {\n+\t\t\t\t\tregexStringBuilder.append('!');\n+\t\t\t\t} else {\n+\t\t\t\t\tregexStringBuilder.append(\"\\\\x5E\");\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tcase '.':\n+\t\t\t\tregexStringBuilder.append(\"\\\\x2E\");\n+\t\t\t\tbreak;\n+\t\t\tcase '*':\n+\t\t\t\tregexStringBuilder.append(\".*\");\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tregexStringBuilder.append(c);\n+\t\t\t}\n+\t\t\tperviosCharacter = c;\n+\t\t}\n+\t\treturn regexStringBuilder.toString();\n+\t}\n+\n+\t/**\n+\t * \n+\t * @param fnmatchPattern\n+\t *            must be a valid fnmatch pattern string.\n+\t */\n+\tpublic FNMatchPattern(String fnmatchPattern) {\n+\t\tfinal String regularExpression = toRegexString(fnmatchPattern);\n+\t\tthis.regexPattern = Pattern.compile(regularExpression);\n+\t}\n+\n+\t/**\n+\t * \n+\t * @param stringToMatch\n+\t *            the string to match.\n+\t * @return true when this pattern matches.\n+\t */\n+\tpublic boolean matches(String stringToMatch) {\n+\t\treturn regexPattern.matcher(stringToMatch).matches();\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76771","messageId":"1210623222-24908-13-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 12/24] Added the class GlobalFilePattern","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:30Z","receivedAt":"2008-05-12T20:13:30Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/rules/GlobalFilePattern.java     |   58 ++++++++++++++++++++\n 1 files changed, 58 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/GlobalFilePattern.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/GlobalFilePattern.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/GlobalFilePattern.java\nnew file mode 100644\nindex 0000000..ec1f38a\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/GlobalFilePattern.java\n@@ -0,0 +1,58 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import org.spearce.jgit.lib.FNMatchPattern;\n+\n+/**\n+ * A {@link GlobalFilePattern} defines a pattern for all files in a tree. A\n+ * typical example would be \"*.txt\", which would match at any file or subtree\n+ * which ends with \".txt\" like \"a/b/c.txt\" and \"a.txt/a.c\".\n+ * \n+ */\n+class GlobalFilePattern implements FilePattern {\n+\tprivate final FNMatchPattern fnMatchPattern;\n+\n+\tprivate final boolean matchDirectoriesOnly;\n+\n+\tGlobalFilePattern(String fnMatchPatternString, boolean matchDirectoriesOnly) {\n+\t\tthis.fnMatchPattern = new FNMatchPattern(fnMatchPatternString);\n+\t\tthis.matchDirectoriesOnly = matchDirectoriesOnly;\n+\t}\n+\n+\tpublic boolean canMatchAtThisDirectoryLevel() {\n+\t\treturn true;\n+\t}\n+\n+\tpublic FilePattern getPatternForSubDirectory(String directoryName) {\n+\t\tif (match(directoryName, true)) {\n+\t\t\treturn MATCH_ALWAYS;\n+\t\t}\n+\t\treturn this;\n+\t}\n+\n+\tpublic boolean match(String fileName, boolean fileIsDirectory) {\n+\t\tif (matchDirectoriesOnly && !fileIsDirectory) {\n+\t\t\treturn false;\n+\t\t}\n+\t\treturn fnMatchPattern.matches(fileName);\n+\t}\n+\n+\tpublic boolean isSameForSubDirectories() {\n+\t\treturn false;\n+\t}\n+}\n-- \n1.5.4.3\n"},{"id":"76765","messageId":"1210623222-24908-14-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 13/24] Added the class ComplexFilePattern.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:31Z","receivedAt":"2008-05-12T20:13:31Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/rules/ComplexFilePattern.java    |   97 ++++++++++++++++++++\n 1 files changed, 97 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/ComplexFilePattern.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/ComplexFilePattern.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/ComplexFilePattern.java\nnew file mode 100644\nindex 0000000..7c2aba0\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/ComplexFilePattern.java\n@@ -0,0 +1,97 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.util.List;\n+import java.util.ArrayList;\n+\n+import org.spearce.jgit.lib.FNMatchPattern;\n+\n+/**\n+ * A {@link ComplexFilePattern} defines for some components of a file path\n+ * fnmatch like patterns. For example could such a pattern be that the first\n+ * directory must start with an a and that the second directory must end with\n+ * and b. In the example the pathes axx/xxb/hello.txt and ayy/yyb would match,\n+ * but axx would not match.\n+ * \n+ */\n+class ComplexFilePattern implements FilePattern {\n+\tprivate final List<FNMatchPattern> usedPatternList;\n+\n+\tprivate final boolean matchDirectoriesOnly;\n+\n+\tprivate final int offset;\n+\n+\tprivate ComplexFilePattern(List<FNMatchPattern> List,\n+\t\t\tboolean matchDirectoriesOnly, int offset) {\n+\t\tthis.usedPatternList = List;\n+\t\tthis.matchDirectoriesOnly = matchDirectoriesOnly;\n+\t\tthis.offset = offset;\n+\t}\n+\n+\tComplexFilePattern(List<String> patternStrings, boolean matchDirectoriesOnly) {\n+\t\tthis.usedPatternList = new ArrayList<FNMatchPattern>(patternStrings\n+\t\t\t\t.size());\n+\t\tfor (String patternString : patternStrings) {\n+\t\t\tthis.usedPatternList.add(new FNMatchPattern(patternString));\n+\t\t}\n+\t\tthis.offset = 0;\n+\t\tthis.matchDirectoriesOnly = matchDirectoriesOnly;\n+\t}\n+\n+\tint getActualPathSize() {\n+\t\treturn usedPatternList.size() - offset;\n+\t}\n+\n+\tprivate FNMatchPattern getPatternOfCurrentLevel() {\n+\t\treturn usedPatternList.get(offset);\n+\t}\n+\n+\tpublic boolean canMatchAtThisDirectoryLevel() {\n+\t\treturn getActualPathSize() == 1;\n+\t}\n+\n+\tpublic FilePattern getPatternForSubDirectory(String directoryName) {\n+\n+\t\tif (getActualPathSize() > 1) {\n+\t\t\tif (getPatternOfCurrentLevel().matches(directoryName)) {\n+\t\t\t\treturn new ComplexFilePattern(usedPatternList,\n+\t\t\t\t\t\tmatchDirectoriesOnly, offset + 1);\n+\t\t\t} else {\n+\t\t\t\treturn FilePattern.MATCH_NEVER;\n+\t\t\t}\n+\t\t}\n+\t\tassert (getActualPathSize() == 1);\n+\t\tif (match(directoryName, true)) {\n+\t\t\treturn FilePattern.MATCH_ALWAYS;\n+\t\t} else {\n+\t\t\treturn FilePattern.MATCH_NEVER;\n+\t\t}\n+\t}\n+\n+\tpublic boolean match(String fileName, boolean fileIsDirectory) {\n+\t\tif (!fileIsDirectory && matchDirectoriesOnly) {\n+\t\t\treturn false;\n+\t\t}\n+\t\treturn getPatternOfCurrentLevel().matches(fileName);\n+\t}\n+\n+\tpublic boolean isSameForSubDirectories() {\n+\t\treturn false;\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76762","messageId":"1210623222-24908-15-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:32Z","receivedAt":"2008-05-12T20:13:32Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/rules/IgnoreRuleListFactory.java |  104 ++++++++++++++++++++\n 1 files changed, 104 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/IgnoreRuleListFactory.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/IgnoreRuleListFactory.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/IgnoreRuleListFactory.java\nnew file mode 100644\nindex 0000000..6634098\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/IgnoreRuleListFactory.java\n@@ -0,0 +1,104 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.io.File;\n+import java.io.FileNotFoundException;\n+import java.util.ArrayList;\n+import java.util.LinkedList;\n+import java.util.List;\n+import java.util.Scanner;\n+import java.util.StringTokenizer;\n+\n+/**\n+ * This class can be used to create lists of {@link Rule} objects from lines of\n+ * .gitignore like files.\n+ * \n+ */\n+class IgnoreRuleListFactory {\n+\n+\tList<Rule> createIgnoreRuleList(Iterable<String> lineIterable) {\n+\t\tLinkedList<Rule> rules = new LinkedList<Rule>();\n+\t\tfor (String line : lineIterable) {\n+\t\t\tfinal String trimmedLine = line.trim();\n+\t\t\tif (trimmedLine.startsWith(\"#\")) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (trimmedLine.length() == 0) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\trules.add(0, createRule(trimmedLine));\n+\t\t}\n+\t\treturn rules;\n+\t}\n+\n+\tList<Rule> createIgnoreRuleList(List<File> files)\n+\t\t\tthrows FileNotFoundException {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tfor (File file : files) {\n+\t\t\tScanner scanner = new Scanner(file);\n+\t\t\ttry {\n+\t\t\t\twhile (scanner.hasNextLine()) {\n+\t\t\t\t\tlines.add(scanner.nextLine());\n+\t\t\t\t}\n+\t\t\t} finally {\n+\t\t\t\tscanner.close();\n+\t\t\t}\n+\t\t}\n+\t\treturn createIgnoreRuleList(lines);\n+\t}\n+\n+\tprivate Rule createRule(String trimmedLine) {\n+\t\tfinal boolean exclude;\n+\t\tString patternString;\n+\t\tif (trimmedLine.startsWith(\"!\")) {\n+\t\t\texclude = false;\n+\t\t\tpatternString = trimmedLine.substring(1);\n+\t\t} else {\n+\t\t\texclude = true;\n+\t\t\tpatternString = trimmedLine;\n+\t\t}\n+\n+\t\tfinal boolean matchDirectoriesOnly;\n+\t\tif (patternString.endsWith(\"/\")) {\n+\t\t\tmatchDirectoriesOnly = true;\n+\t\t\tpatternString = patternString.substring(0,\n+\t\t\t\t\tpatternString.length() - 1);\n+\t\t} else {\n+\t\t\tmatchDirectoriesOnly = false;\n+\t\t}\n+\n+\t\tfinal FilePattern pattern;\n+\t\tif (patternString.contains(\"/\")) {\n+\t\t\tif (patternString.startsWith(\"/\")) {\n+\t\t\t\tpatternString = patternString.substring(1);\n+\t\t\t}\n+\t\t\tfinal StringTokenizer stringTokenizer = new StringTokenizer(\n+\t\t\t\t\tpatternString, \"/\");\n+\t\t\tfinal List<String> patternList = new ArrayList<String>();\n+\t\t\twhile (stringTokenizer.hasMoreTokens()) {\n+\t\t\t\tfinal String token = stringTokenizer.nextToken();\n+\t\t\t\tpatternList.add(token);\n+\t\t\t}\n+\t\t\tpattern = new ComplexFilePattern(patternList, matchDirectoriesOnly);\n+\t\t} else {\n+\t\t\tpattern = new GlobalFilePattern(patternString, matchDirectoriesOnly);\n+\t\t}\n+\t\treturn new Rule(exclude, pattern);\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76767","messageId":"1210623222-24908-16-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 15/24] Added a Rules interface implementation and a factory for it.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:33Z","receivedAt":"2008-05-12T20:13:33Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../treewalk/rules/RuleListToObjectConverter.java  |  130 ++++++++++++++++++++\n .../jgit/treewalk/rules/RulesImplementation.java   |   86 +++++++++++++\n 2 files changed, 216 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RuleListToObjectConverter.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RulesImplementation.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RuleListToObjectConverter.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RuleListToObjectConverter.java\nnew file mode 100644\nindex 0000000..b67beff\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RuleListToObjectConverter.java\n@@ -0,0 +1,130 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.util.ArrayList;\n+import java.util.Iterator;\n+import java.util.List;\n+\n+/**\n+ * This class converts a list of {@link Rule} objects into a {@Rules} object.\n+ * During the conversion some optimizations are done:\n+ * <ul>\n+ * <li>Rules which can never match are removed. e.g. There is no need to check\n+ * the rule \"/a\" in the directory b.</li>\n+ * <li>The list is cut at the first rule which match always. *.txt\\n/a for\n+ * example would result in an internal list \"ignore all, ignore *.txt\" which is\n+ * then reduced to \"ignore all\".</li>\n+ * <li>Ignore rules which are direcly before an \"ignore all\" all rule are\n+ * removed. /a\\n*.txt for example would result in an intern \"ignore *.txt,\n+ * ignore all\" list which is then reduced to \"ignore all\",</li>\n+ * <li>\"do not ignore\" rules at the bottom of the intern list are removed. This\n+ * optimization would remove !a from \"!a\\n/b\" as it is in the inversed list at\n+ * the bottom.</li>\n+ * </ul>\n+ */\n+class RuleListToObjectConverter {\n+\tprotected Rules createIgnoreRules(Iterator<Rule> ruleIterator) {\n+\t\tfinal List<Rule> rules = getNessesaryRulesFromIterator(ruleIterator);\n+\t\tremoveUnnecessaryDoNotIgnoreRulesAtTheEndOfTheList(rules);\n+\t\tremoveUnnecessaryIgnoreRulesNearTheEndOfTheList(rules);\n+\n+\t\tif (rules.size() == 1) {\n+\t\t\tfinal Rule rule = rules.get(0);\n+\t\t\tif (rule.getPattern() == FilePattern.MATCH_ALWAYS) {\n+\t\t\t\tif (rule.isIgnoreAtMatch()) {\n+\t\t\t\t\treturn Rules.IGNORE_ALL;\n+\t\t\t\t} else {\n+\t\t\t\t\treturn Rules.IGNORE_NOTHING;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else if (rules.isEmpty()) {\n+\t\t\treturn Rules.IGNORE_NOTHING;\n+\t\t}\n+\t\treturn new RulesImplementation(rules, this);\n+\t}\n+\n+\tprivate List<Rule> getNessesaryRulesFromIterator(Iterator<Rule> ruleIterator) {\n+\t\tfinal List<Rule> rules = new ArrayList<Rule>();\n+\t\twhile (ruleIterator.hasNext()) {\n+\t\t\tfinal Rule subRule = ruleIterator.next();\n+\t\t\tif (subRule.getPattern() == FilePattern.MATCH_NEVER) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\trules.add(subRule);\n+\t\t\t// There is no need for rules after a rule witch match always,\n+\t\t\t// as such a rule would never be the first rule which matches.\n+\t\t\tif (subRule.getPattern() == FilePattern.MATCH_ALWAYS) {\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\treturn rules;\n+\t}\n+\n+\t/**\n+\t * Expects that\n+\t * {@link #removeUnnecessaryDoNotIgnoreRulesAtTheEndOfTheList(List)} has\n+\t * been executed first.\n+\t * \n+\t * @param rules\n+\t *            rule list to reduce.\n+\t */\n+\tprivate void removeUnnecessaryIgnoreRulesNearTheEndOfTheList(\n+\t\t\tfinal List<Rule> rules) {\n+\t\t// Why the following optimization makes only sense for the end of the\n+\t\t// list:\n+\t\t// If there is a \"ignore all\"- rule,\n+\t\t// then it is located at the end of the list\n+\t\t// See how the list is filled to prove this statement.\n+\t\tif (rules.size() >= 2) {\n+\t\t\tfinal Rule lastRule = rules.get(rules.size() - 1);\n+\t\t\tassert lastRule.isIgnoreAtMatch() : \"Expected that no 'not ignore'-rule is at the end of the list any more\";\n+\t\t\tfinal boolean ignoreAllAtEnd = lastRule.getPattern().equals(\n+\t\t\t\t\tFilePattern.MATCH_ALWAYS);\n+\t\t\tif (ignoreAllAtEnd) {\n+\t\t\t\twhile (rules.size() >= 2) {\n+\t\t\t\t\tfinal int ruleBeforeLastIndex = rules.size() - 2;\n+\t\t\t\t\tfinal Rule ruleBeforeLast = rules.get(ruleBeforeLastIndex);\n+\t\t\t\t\tif (ruleBeforeLast.isIgnoreAtMatch()) {\n+\t\t\t\t\t\trules.remove(ruleBeforeLastIndex);\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate void removeUnnecessaryDoNotIgnoreRulesAtTheEndOfTheList(\n+\t\t\tfinal List<Rule> rules) {\n+\t\t// Why it is save to remove \"don't ignore rules\" at the end of the list\n+\t\t// if there is no \"ignore rule\" below a \"don't ignore rule\" then\n+\t\t// the path which haven't match jet will never be ignored:\n+\t\t// -> if another \"don't ignore rule\" match then the patch will not be\n+\t\t// ignored\n+\t\t// -> if no \"don't ignore rule\" match then the path will not be ignored.\n+\t\twhile (!rules.isEmpty()) {\n+\t\t\tfinal int indexOfLastRule = rules.size() - 1;\n+\t\t\tfinal Rule lastRule = rules.get(indexOfLastRule);\n+\t\t\tif (lastRule.isIgnoreAtMatch()) {\n+\t\t\t\tbreak;\n+\t\t\t} else {\n+\t\t\t\trules.remove(indexOfLastRule);\n+\t\t\t}\n+\t\t}\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RulesImplementation.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RulesImplementation.java\nnew file mode 100644\nindex 0000000..e98a57e\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RulesImplementation.java\n@@ -0,0 +1,86 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.util.ArrayList;\n+import java.util.Iterator;\n+import java.util.List;\n+\n+class RulesImplementation implements Rules {\n+\t/**\n+\t * Complete list of rules. Note that order is: determining rule first.\n+\t */\n+\tprivate final List<Rule> rulesForTree;\n+\n+\t/**\n+\t * {@link Rule} objects which return true at a call of\n+\t * {@link Rule#canMatchAtThisDirectoryLevel}.\n+\t */\n+\tprivate final List<Rule> rulesForThisLevel;\n+\n+\t/**\n+\t * Factory used to create {@link Rules} for sub directories.\n+\t */\n+\tprivate RuleListToObjectConverter factory;\n+\n+\tRulesImplementation(List<Rule> rules, RuleListToObjectConverter factory) {\n+\t\tthis.rulesForTree = rules;\n+\t\tthis.factory = factory;\n+\t\tthis.rulesForThisLevel = new ArrayList<Rule>();\n+\t\tfor (Rule rule : rules) {\n+\t\t\tif (rule.canMatchAtThisDirectoryLevel()) {\n+\t\t\t\tthis.rulesForThisLevel.add(rule);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * @see Rules#toIgnore(java.lang.String, boolean)\n+\t */\n+\tpublic boolean toIgnore(String fileName, boolean fileIsDirectory) {\n+\t\tfor (Rule rule : rulesForThisLevel) {\n+\t\t\tif (rule.getPattern().match(fileName, fileIsDirectory)) {\n+\t\t\t\treturn rule.isIgnoreAtMatch();\n+\t\t\t}\n+\t\t}\n+\t\treturn false;\n+\t}\n+\n+\t/**\n+\t * @see Rules#getRulesForSubDirectory(java.lang.String)\n+\t */\n+\tpublic Rules getRulesForSubDirectory(final String directoryName) {\n+\t\tfinal Iterator<Rule> subRuleIterator = new Iterator<Rule>() {\n+\t\t\tfinal Iterator<Rule> ruleIterator = rulesForTree.iterator();\n+\n+\t\t\tpublic boolean hasNext() {\n+\t\t\t\treturn ruleIterator.hasNext();\n+\t\t\t}\n+\n+\t\t\tpublic Rule next() {\n+\t\t\t\treturn ruleIterator.next()\n+\t\t\t\t\t\t.getRuleForSubDirectory(directoryName);\n+\t\t\t}\n+\n+\t\t\tpublic void remove() {\n+\t\t\t\tthrow new UnsupportedOperationException();\n+\t\t\t}\n+\n+\t\t};\n+\t\treturn factory.createIgnoreRules(subRuleIterator);\n+\t}\n+}\n-- \n1.5.4.3\n"},{"id":"76781","messageId":"1210623222-24908-17-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 16/24] Added test class OverallIgnoreRulestest.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:34Z","receivedAt":"2008-05-12T20:13:34Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../treewalk/rules/OverallIgnoreRulesTest.java     |  371 ++++++++++++++++++++\n 1 files changed, 371 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/OverallIgnoreRulesTest.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/OverallIgnoreRulesTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/OverallIgnoreRulesTest.java\nnew file mode 100644\nindex 0000000..60e1bdc\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/OverallIgnoreRulesTest.java\n@@ -0,0 +1,371 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.util.ArrayList;\n+import java.util.Collections;\n+import java.util.List;\n+\n+import junit.framework.TestCase;\n+\n+public class OverallIgnoreRulesTest extends TestCase {\n+\tprivate IgnoreRulesFactory factory;\n+\n+\t@Override\n+\tprotected void setUp() throws Exception {\n+\t\tfactory = new IgnoreRulesFactory();\n+\t}\n+\n+\tpublic void testSimpleGlobalPattern() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"ab\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertTrue(ignoreRules.toIgnore(\"ab\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"ab\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"abc\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"abc\", true));\n+\t}\n+\n+\tpublic void testGlobalPatternWithOneStar() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"a*c\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"ac\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"ac\", true));\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"abc\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"abc\", true));\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"abbc\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"abbc\", true));\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"aabc\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"aabc\", true));\n+\n+\t\tassertFalse(ignoreRules.toIgnore(\"cab\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"cab\", true));\n+\t}\n+\n+\tpublic void testGlobalPatternWithTwoStars() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"a*c*e\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"ace\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"ace\", true));\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"abcde\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"abcde\", true));\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"aHellocWorlde\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"aHellocWorlde\", true));\n+\n+\t\tassertFalse(ignoreRules.toIgnore(\"ae\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"ae\", true));\n+\t}\n+\n+\tpublic void testGlobalPatternWithDots() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"*.tar.gz\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"test.tar.gz\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"test.tar.gz\", true));\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\".tar.gz\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\".tar.gz\", true));\n+\n+\t\tassertFalse(ignoreRules.toIgnore(\"test\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"test\", true));\n+\n+\t\t// test that \".\" isn't handled as \"any character\"\n+\t\tassertFalse(ignoreRules.toIgnore(\".tarogz\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\".tarogz\", true));\n+\t}\n+\n+\tpublic void testGlobalPatternDirectoryOnlyRule() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"a/\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"a\", false));\n+\n+\t\tfinal Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory(\"a\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesA);\n+\n+\t\tfinal Rules ignoreRulesB = ignoreRules.getRulesForSubDirectory(\"b\");\n+\t\tassertTrue(ignoreRulesB.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRulesB.toIgnore(\"a\", false));\n+\n+\t\tfinal Rules ignoreRulesBA = ignoreRulesB.getRulesForSubDirectory(\"a\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesBA);\n+\n+\t}\n+\n+\tpublic void testSimpleFilePathPattern() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"a/b/c\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertFalse(ignoreRules.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"a\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"b\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"b\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"c\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"c\", false));\n+\n+\t\tfinal Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory(\"a\");\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"a\", false));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"b\", true));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"b\", false));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"c\", true));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"c\", false));\n+\n+\t\tfinal Rules ignoreRulesAB = ignoreRulesA.getRulesForSubDirectory(\"b\");\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"a\", false));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"b\", true));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"b\", false));\n+\t\tassertTrue(ignoreRulesAB.toIgnore(\"c\", true));\n+\t\tassertTrue(ignoreRulesAB.toIgnore(\"c\", false));\n+\n+\t\tfinal Rules ignoreRulesABA = ignoreRulesAB.getRulesForSubDirectory(\"a\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesABA);\n+\n+\t\tfinal Rules ignoreRulesABB = ignoreRulesAB.getRulesForSubDirectory(\"b\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesABB);\n+\n+\t\tfinal Rules ignoreRulesABC = ignoreRulesAB.getRulesForSubDirectory(\"c\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesABC);\n+\t}\n+\n+\tpublic void testFilePathPatternDirectoryOnlyRule() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"a/b/c/\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertFalse(ignoreRules.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"a\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"b\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"b\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"c\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"c\", false));\n+\n+\t\tfinal Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory(\"a\");\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"a\", false));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"b\", true));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"b\", false));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"c\", true));\n+\t\tassertFalse(ignoreRulesA.toIgnore(\"c\", false));\n+\n+\t\tfinal Rules ignoreRulesAB = ignoreRulesA.getRulesForSubDirectory(\"b\");\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"a\", true));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"a\", false));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"b\", true));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"b\", false));\n+\t\tassertTrue(ignoreRulesAB.toIgnore(\"c\", true));\n+\t\tassertFalse(ignoreRulesAB.toIgnore(\"c\", false));\n+\n+\t\tfinal Rules ignoreRulesABA = ignoreRulesAB.getRulesForSubDirectory(\"a\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesABA);\n+\n+\t\tfinal Rules ignoreRulesABB = ignoreRulesAB.getRulesForSubDirectory(\"b\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesABB);\n+\n+\t\tfinal Rules ignoreRulesABC = ignoreRulesAB.getRulesForSubDirectory(\"c\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesABC);\n+\t}\n+\n+\tpublic void testShortPathPattern() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"/alpha\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertTrue(ignoreRules.toIgnore(\"alpha\", true));\n+\t\tassertTrue(ignoreRules.toIgnore(\"alpha\", false));\n+\n+\t\tfinal Rules ignoreRulesAlpha = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"alpha\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesAlpha);\n+\n+\t\tfinal Rules ignoreRulesBeta = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"beta\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesBeta);\n+\t}\n+\n+\tpublic void testShortDirectoryPathPattern() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"/alpha/\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertTrue(ignoreRules.toIgnore(\"alpha\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"alpha\", false));\n+\n+\t\tfinal Rules ignoreRulesAlpha = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"alpha\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesAlpha);\n+\n+\t\tfinal Rules ignoreRulesBeta = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"beta\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesBeta);\n+\t}\n+\n+\tpublic void testShortPathPatternWithStar() {\n+\t\tList<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"/.*\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\n+\t\tassertTrue(ignoreRules.toIgnore(\".test\", true));\n+\t\tassertTrue(ignoreRules.toIgnore(\".test\", false));\n+\n+\t\tassertFalse(ignoreRules.toIgnore(\"test\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"test\", false));\n+\n+\t\tfinal Rules ignoreRulesDotTest = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\".test\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesDotTest);\n+\n+\t\tfinal Rules ignoreRulesTest = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"test\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesTest);\n+\t}\n+\n+\tpublic void testPathPatternWith2Times2Stars() {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"he*wor*d/*.*\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\n+\t\tassertFalse(ignoreRules.toIgnore(\"hello\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"hello\", false));\n+\t\tfinal Rules ignoreRulesHello = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"hello\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesHello);\n+\n+\t\tassertFalse(ignoreRules.toIgnore(\"helloworld\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"helloworld\", false));\n+\t\tfinal Rules ignoreRulesHelloWorld = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"helloworld\");\n+\t\tassertNotSame(Rules.IGNORE_NOTHING, ignoreRulesHelloWorld);\n+\n+\t\tassertTrue(ignoreRulesHelloWorld.toIgnore(\"test.txt\", true));\n+\t\tassertTrue(ignoreRulesHelloWorld.toIgnore(\"test.txt\", false));\n+\n+\t\tassertFalse(ignoreRulesHelloWorld.toIgnore(\"test\", true));\n+\t\tassertFalse(ignoreRulesHelloWorld.toIgnore(\"test\", false));\n+\n+\t\tfinal Rules ignoreRulesTestTxt = ignoreRulesHelloWorld\n+\t\t\t\t.getRulesForSubDirectory(\"test.txt\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesTestTxt);\n+\n+\t\tfinal Rules ignoreRulesTest = ignoreRulesHelloWorld\n+\t\t\t\t.getRulesForSubDirectory(\"test\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesTest);\n+\t}\n+\n+\tpublic void testEmptyIgnoreList() {\n+\t\tfinal List<String> lines = Collections.emptyList();\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRules);\n+\t}\n+\n+\tpublic void testOnlyOneNegatedIgnore() {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"!a\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRules);\n+\t}\n+\n+\tpublic void testOnlyThreeNegatedIgnores() {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"!a\");\n+\t\tlines.add(\"!a/b/c\");\n+\t\tlines.add(\"!b*\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRules);\n+\t}\n+\n+\tpublic void testNegatedIgnoreCase1() {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"/a\");\n+\t\tlines.add(\"!b\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tfinal Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory(\"a\");\n+\t\tfinal Rules ignoreRulesAB = ignoreRulesA.getRulesForSubDirectory(\"b\");\n+\t\tfinal Rules ignoreRulesB = ignoreRules.getRulesForSubDirectory(\"b\");\n+\t\tfinal Rules ignoreRulesC = ignoreRules.getRulesForSubDirectory(\"c\");\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesB);\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesAB);\n+\t\tassertSame(Rules.IGNORE_NOTHING, ignoreRulesC);\n+\t\tassertTrue(ignoreRules.toIgnore(\"a\", true));\n+\t\tassertTrue(ignoreRules.toIgnore(\"a\", false));\n+\t\tassertTrue(ignoreRulesA.toIgnore(\"c\", true));\n+\t\tassertTrue(ignoreRulesA.toIgnore(\"c\", false));\n+\t}\n+\n+\tpublic void testExceptionOfException() {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"*.*\");\n+\t\tlines.add(\"!*.c\");\n+\t\tlines.add(\"a.c\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertTrue(ignoreRules.toIgnore(\"b.txt\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"b.txt\", true));\n+\t\tassertTrue(ignoreRules.toIgnore(\"a.c\", false));\n+\t\tassertTrue(ignoreRules.toIgnore(\"a.c\", true));\n+\t\tassertFalse(ignoreRules.toIgnore(\"b.c\", false));\n+\t\tassertFalse(ignoreRules.toIgnore(\"b.c\", true));\n+\t}\n+\n+\tpublic void testComplexCase() {\n+\t\tfinal List<String> lines = new ArrayList<String>();\n+\t\tlines.add(\"*\");\n+\t\tlines.add(\"!/alpha/src\");\n+\t\tlines.add(\"*~\");\n+\t\tfinal Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);\n+\t\tassertTrue(ignoreRules.toIgnore(\"beta\", true));\n+\t\tassertTrue(ignoreRules.toIgnore(\"alpha\", true));\n+\t\tfinal Rules ignoreRulesAlpha = ignoreRules\n+\t\t\t\t.getRulesForSubDirectory(\"alpha\");\n+\t\tfinal Rules ignoreRulesAlphaBin = ignoreRulesAlpha\n+\t\t\t\t.getRulesForSubDirectory(\"bin\");\n+\t\tfinal Rules ignoreRulesAlphaSrc = ignoreRulesAlpha\n+\t\t\t\t.getRulesForSubDirectory(\"src\");\n+\t\tassertSame(Rules.IGNORE_ALL, ignoreRulesAlphaBin);\n+\t\tassertFalse(ignoreRulesAlphaSrc.toIgnore(\"com\", true));\n+\t\tassertFalse(ignoreRulesAlphaSrc.toIgnore(\"b.java\", false));\n+\t\tassertTrue(ignoreRulesAlphaSrc.toIgnore(\"b.java~\", true));\n+\t}\n+\n+\tprivate class IgnoreRulesFactory {\n+\t\tprivate RuleListToObjectConverter converter = new RuleListToObjectConverter();\n+\n+\t\tprivate IgnoreRuleListFactory listFactory = new IgnoreRuleListFactory();\n+\n+\t\t/**\n+\t\t * @param ignoreFileLines\n+\t\t *            the lines of a ignore file like .gitignore.\n+\t\t * @return a immutable IgnoreRules object.\n+\t\t */\n+\t\tpublic Rules createIgnoreRulesFromLines(Iterable<String> ignoreFileLines) {\n+\t\t\tfinal List<Rule> rules = listFactory\n+\t\t\t\t\t.createIgnoreRuleList(ignoreFileLines);\n+\t\t\treturn converter.createIgnoreRules(rules.iterator());\n+\t\t}\n+\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76774","messageId":"1210623222-24908-18-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 17/24] Added the class TreeFilePattern.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:35Z","receivedAt":"2008-05-12T20:13:35Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/rules/TreeFilePattern.java       |   75 ++++++++++++++++++++\n 1 files changed, 75 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/TreeFilePattern.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/TreeFilePattern.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/TreeFilePattern.java\nnew file mode 100644\nindex 0000000..9234c95\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/TreeFilePattern.java\n@@ -0,0 +1,75 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.util.List;\n+\n+/**\n+ * Represents a pattern like \"documents/*.txt\" which matches all *.txt files in\n+ * the tree documents.\n+ * \n+ */\n+class TreeFilePattern implements FilePattern {\n+\n+\tprivate final List<String> path;\n+\n+\tprivate final int offset;\n+\n+\tprivate final GlobalFilePattern globalFilePattern;\n+\n+\tpublic boolean canMatchAtThisDirectoryLevel() {\n+\t\treturn false;\n+\t}\n+\n+\tTreeFilePattern(List<String> path, GlobalFilePattern globalFilePattern) {\n+\t\tthis.path = path;\n+\t\tthis.offset = 0;\n+\t\tthis.globalFilePattern = globalFilePattern;\n+\t}\n+\n+\tprivate TreeFilePattern(List<String> path, int offset,\n+\t\t\tGlobalFilePattern globalFilePattern) {\n+\t\tthis.path = path;\n+\t\tthis.offset = offset;\n+\t\tthis.globalFilePattern = globalFilePattern;\n+\t}\n+\n+\tpublic FilePattern getPatternForSubDirectory(String directoryName) {\n+\t\ttry {\n+\t\t\tif (!path.get(offset).equals(directoryName)) {\n+\t\t\t\treturn FilePattern.MATCH_NEVER;\n+\t\t\t}\n+\t\t} catch (IndexOutOfBoundsException e) {\n+\t\t\tthrow new IllegalStateException(\n+\t\t\t\t\t\"The offset of this class doesn't refer to a valid position in path\");\n+\t\t}\n+\t\tif (offset == path.size() - 1) {\n+\t\t\treturn globalFilePattern;\n+\t\t} else {\n+\t\t\treturn new TreeFilePattern(path, offset + 1, globalFilePattern);\n+\t\t}\n+\t}\n+\n+\tpublic boolean isSameForSubDirectories() {\n+\t\treturn false;\n+\t}\n+\n+\tpublic boolean match(String fileName, boolean fileIsDirectory) {\n+\t\treturn false;\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76777","messageId":"1210623222-24908-19-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 18/24] Added InvalidPatternException and PathNotInProjectDirectoryException","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:36Z","receivedAt":"2008-05-12T20:13:36Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/errors/InvalidPatternException.java       |   44 ++++++++++++++++++++\n .../errors/PathNotInProjectDirectoryException.java |   25 +++++++++++\n 2 files changed, 69 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java\nnew file mode 100644\nindex 0000000..d09f0c9\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java\n@@ -0,0 +1,44 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.errors;\n+\n+/**\n+ * Thrown when a pattern passed in an argument was wrong.\n+ * \n+ */\n+public class InvalidPatternException extends Exception {\n+\tprivate final String pattern;\n+\n+\t/**\n+\t * @param message\n+\t *            explains what was wrong with the pattern.\n+\t * @param pattern\n+\t *            the invalid pattern.\n+\t */\n+\tpublic InvalidPatternException(String message, String pattern) {\n+\t\tsuper(message);\n+\t\tthis.pattern = pattern;\n+\t}\n+\n+\t/**\n+\t * @return the invalid pattern.\n+\t */\n+\tpublic String getPattern() {\n+\t\treturn pattern;\n+\t}\n+\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java\nnew file mode 100644\nindex 0000000..a406aef\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java\n@@ -0,0 +1,25 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.errors;\n+\n+/**\n+ * Thrown when a path wasn't in the project directory, but expected to be.\n+ * \n+ */\n+public class PathNotInProjectDirectoryException extends\n+\t\tIllegalArgumentException {\n+}\n-- \n1.5.4.3\n"},{"id":"76779","messageId":"1210623222-24908-20-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 19/24] Added the class AddRuleListFactory.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:37Z","receivedAt":"2008-05-12T20:13:37Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/rules/AddRuleListFactory.java    |  128 ++++++++++++++++++++\n 1 files changed, 128 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRuleListFactory.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRuleListFactory.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRuleListFactory.java\nnew file mode 100644\nindex 0000000..0cb700f\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRuleListFactory.java\n@@ -0,0 +1,128 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.io.File;\n+import java.io.IOException;\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.LinkedList;\n+import java.util.List;\n+\n+import org.spearce.jgit.errors.InvalidPatternException;\n+import org.spearce.jgit.errors.PathNotInProjectDirectoryException;\n+\n+class AddRuleListFactory {\n+\t/*\n+\t * The add command of git 1.5.2.5 behaves a little bit stange: \"git add\n+\t * a/\\*z\" adds the file \"a/b/xyz\" but \"git add a/x\\*\" does not.\n+\t * \n+\t * The first is parsed as pattern \"*z\" for whole directory tree \"a\". The\n+\t * second is parsed as an path.\n+\t * \n+\t */\n+\n+\tprivate static List<String> getRelativePath(File projectDirectory, File file)\n+\t\t\tthrows PathNotInProjectDirectoryException, IOException {\n+\t\tFile currentFile = file.getCanonicalFile();\n+\t\tfinal LinkedList<String> relativePath = new LinkedList<String>();\n+\t\twhile (!currentFile.equals(projectDirectory)) {\n+\t\t\trelativePath.addFirst(currentFile.getName());\n+\t\t\tcurrentFile = currentFile.getParentFile();\n+\t\t\tif (currentFile == null) {\n+\t\t\t\tthrow new PathNotInProjectDirectoryException();\n+\t\t\t}\n+\t\t}\n+\t\treturn relativePath;\n+\t}\n+\n+\tList<Rule> createRuleList(File projectDirectory, File workingDirectory,\n+\t\t\tList<String> filePatternsOfAddCommand)\n+\t\t\tthrows InvalidPatternException, PathNotInProjectDirectoryException,\n+\t\t\tIOException {\n+\n+\t\tfinal List<String> pathPrefix = getRelativePath(projectDirectory,\n+\t\t\t\tworkingDirectory);\n+\n+\t\tfinal List<Rule> ruleList = new ArrayList<Rule>(\n+\t\t\t\tfilePatternsOfAddCommand.size());\n+\t\tfor (String pattern : filePatternsOfAddCommand) {\n+\t\t\tfinal boolean matchDirectoriesOnly;\n+\t\t\tif (pattern.endsWith(File.separator)) {\n+\t\t\t\tpattern = pattern.substring(0, pattern.length() - 1);\n+\t\t\t\tmatchDirectoriesOnly = true;\n+\t\t\t} else {\n+\t\t\t\tmatchDirectoriesOnly = false;\n+\t\t\t}\n+\n+\t\t\tfinal String[] relativePath = pattern.split(\"[\" + File.separator\n+\t\t\t\t\t+ \"]\");\n+\t\t\tfinal List<String> path = new ArrayList<String>();\n+\t\t\tpath.addAll(pathPrefix);\n+\t\t\tpath.addAll(Arrays.asList(relativePath));\n+\t\t\tassert (!path.isEmpty());\n+\n+\t\t\tfinal FilePattern filePattern = createFilePattern(pattern,\n+\t\t\t\t\tmatchDirectoriesOnly, path);\n+\t\t\tfinal Rule rule = new Rule(false, filePattern);\n+\t\t\truleList.add(rule);\n+\n+\t\t}\n+\t\treturn ruleList;\n+\t}\n+\n+\tprivate static FilePattern createFilePattern(String pattern,\n+\t\t\tboolean matchDirectoriesOnly, List<String> path)\n+\t\t\tthrows InvalidPatternException {\n+\t\t/*\n+\t\t * I did several tests with the git-add command, and it seems that it\n+\t\t * handles a pattern as a fileGlob, if it has only one star at the\n+\t\t * beginning of the latest part of the path. Otherwise it handle it as\n+\t\t * file pattern.\n+\t\t */\n+\n+\t\tfinal String lastPathElement = path.get(path.size() - 1);\n+\t\tfinal boolean isFileGlob = lastPathElement.startsWith(\"*\");\n+\t\tfinal FilePattern filePattern;\n+\t\tif (isFileGlob) {\n+\t\t\tfilePattern = createGlobalOrTreeFilePattern(matchDirectoriesOnly,\n+\t\t\t\t\tpath, lastPathElement);\n+\t\t} else {\n+\t\t\tfor (String pathElement : path) {\n+\t\t\t\tif (pathElement.contains(\"*\")) {\n+\t\t\t\t\tthrow new InvalidPatternException(\n+\t\t\t\t\t\t\t\"Stars are not allowed here\", pattern);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tfilePattern = new ComplexFilePattern(path, matchDirectoriesOnly);\n+\t\t}\n+\t\treturn filePattern;\n+\t}\n+\n+\tprivate static FilePattern createGlobalOrTreeFilePattern(\n+\t\t\tfinal boolean matchDirectoriesOnly, final List<String> path,\n+\t\t\tfinal String lastPathElement) {\n+\t\tfinal GlobalFilePattern globalFilePatternForTree = new GlobalFilePattern(\n+\t\t\t\tlastPathElement, matchDirectoriesOnly);\n+\t\tfinal List<String> targetTree = path.subList(0, path.size() - 1);\n+\t\tif (targetTree.isEmpty()) {\n+\t\t\treturn globalFilePatternForTree;\n+\t\t} else {\n+\t\t\treturn new TreeFilePattern(targetTree, globalFilePatternForTree);\n+\t\t}\n+\t}\n+}\n-- \n1.5.4.3\n"},{"id":"76775","messageId":"1210623222-24908-21-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 20/24] Added class AddRulesFactory.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:38Z","receivedAt":"2008-05-12T20:13:38Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/rules/AddRulesFactory.java       |   91 ++++++++++++++++++++\n 1 files changed, 91 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRulesFactory.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRulesFactory.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRulesFactory.java\nnew file mode 100644\nindex 0000000..c1f9a6f\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRulesFactory.java\n@@ -0,0 +1,91 @@\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.io.File;\n+import java.io.FileNotFoundException;\n+import java.io.IOException;\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.List;\n+\n+import org.spearce.jgit.errors.InvalidPatternException;\n+import org.spearce.jgit.errors.PathNotInProjectDirectoryException;\n+import static org.spearce.jgit.lib.Constants.REPOSITORY_DIRECTORY_NAME;\n+\n+/**\n+ * This class is designed to serve the needs of someone who want to implement a\n+ * git-add command and needs to determine the files to add.\n+ * \n+ */\n+public class AddRulesFactory {\n+\tprivate final RuleListToObjectConverter converter = new RuleListToObjectConverter();\n+\n+\tprivate final IgnoreRuleListFactory ignoreRuleListFactory = new IgnoreRuleListFactory();\n+\n+\tprivate final AddRuleListFactory addRuleListFactory = new AddRuleListFactory();\n+\n+\t/**\n+\t * @param workTreeDirectory\n+\t *            The directory with the files of the project under version\n+\t *            control.\n+\t * @param workingDirectory\n+\t *            a directory within the workTreeDirectory.\n+\t * @param filePatternsOfAddCommand\n+\t *            the file patterns passed to the add command.\n+\t * @return a {@link Rules} containing the specified rules, the .gitignore\n+\t *         and the .git/info/exclude rules.\n+\t * @throws InvalidPatternException\n+\t *             if a pattern is invalid.\n+\t * @throws PathNotInProjectDirectoryException\n+\t *             if the directory workingDirectory is not in workTreeDirectory\n+\t * @throws IOException\n+\t *             for some reasons.\n+\t */\n+\tpublic Rules createRules(File workTreeDirectory, File workingDirectory,\n+\t\t\tList<String> filePatternsOfAddCommand)\n+\t\t\tthrows InvalidPatternException, PathNotInProjectDirectoryException,\n+\t\t\tIOException {\n+\t\tfinal Rule gitDirectoryIgnoreRule = createGitDirectoryIgnoreRule();\n+\t\tfinal File gitDirectory = new File(workTreeDirectory,\n+\t\t\t\tREPOSITORY_DIRECTORY_NAME);\n+\t\tfinal List<Rule> ignoreRuleListFromFiles = createExcludeRules(\n+\t\t\t\tworkTreeDirectory, gitDirectory);\n+\t\tfinal List<Rule> includeRules = addRuleListFactory.createRuleList(\n+\t\t\t\tworkTreeDirectory, workingDirectory, filePatternsOfAddCommand);\n+\t\tfinal List<Rule> ruleList = new ArrayList<Rule>();\n+\n+\t\truleList.add(gitDirectoryIgnoreRule);\n+\t\truleList.addAll(ignoreRuleListFromFiles);\n+\t\truleList.addAll(includeRules);\n+\t\truleList.add(new Rule(true, FilePattern.MATCH_ALWAYS));\n+\n+\t\treturn converter.createIgnoreRules(ruleList.iterator());\n+\t}\n+\n+\tprivate List<Rule> createExcludeRules(File projectDirectory,\n+\t\t\tFile gitDirectory) {\n+\t\tfinal List<File> possibleIgnoreFiles = new ArrayList<File>(2);\n+\t\tpossibleIgnoreFiles.add(new File(projectDirectory, \".gitignore\"));\n+\t\tpossibleIgnoreFiles.add(new File(new File(gitDirectory, \"info\"),\n+\t\t\t\t\"exclude\"));\n+\n+\t\tfinal List<File> ignoreFiles = new ArrayList<File>();\n+\t\tfor (File possibleIgnoreFile : possibleIgnoreFiles) {\n+\t\t\tif (possibleIgnoreFile.isFile()) {\n+\t\t\t\tignoreFiles.add(possibleIgnoreFile);\n+\t\t\t}\n+\t\t}\n+\n+\t\ttry {\n+\t\t\treturn ignoreRuleListFactory.createIgnoreRuleList(ignoreFiles);\n+\t\t} catch (FileNotFoundException e) {\n+\t\t\tthrow new RuntimeException(\"unexpected removal of ignore files\", e);\n+\t\t}\n+\t}\n+\n+\tprivate Rule createGitDirectoryIgnoreRule() {\n+\t\tfinal FilePattern gitDirectoryPattern = new ComplexFilePattern(Arrays\n+\t\t\t\t.asList(REPOSITORY_DIRECTORY_NAME), true);\n+\t\tfinal Rule gitDirectoryIgnoreRule = new Rule(true, gitDirectoryPattern);\n+\t\treturn gitDirectoryIgnoreRule;\n+\t}\n+}\n-- \n1.5.4.3\n"},{"id":"76783","messageId":"1210623222-24908-22-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:39Z","receivedAt":"2008-05-12T20:13:39Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/LightFileTreeIteratorTest.java   |  114 ++++++++++++++++++++\n .../jgit/treewalk/LightFileTreeIterator.java       |  112 +++++++++++++++++++\n 2 files changed, 226 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/LightFileTreeIteratorTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/LightFileTreeIteratorTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/LightFileTreeIteratorTest.java\nnew file mode 100644\nindex 0000000..f937182\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/LightFileTreeIteratorTest.java\n@@ -0,0 +1,114 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk;\n+\n+import java.io.File;\n+import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.Set;\n+\n+import org.spearce.jgit.treewalk.rules.Rules;\n+\n+import junit.framework.TestCase;\n+\n+public class LightFileTreeIteratorTest extends TestCase {\n+\tprivate String DIRECTORY_A_NAME = \"a\";\n+\n+\tprivate String DIRECTORY_AB_NAME = \"b\";\n+\n+\tprivate File projectDirectory;\n+\n+\tprivate File fileB;\n+\n+\tprivate File directoryA;\n+\n+\tprivate File directoryAB;\n+\n+\tprivate File fileABA;\n+\n+\tprivate File directoryAC;\n+\n+\tprivate File fileACA;\n+\n+\tprivate File fileACB;\n+\n+\t@Override\n+\tprotected void setUp() throws Exception {\n+\t\tthis.projectDirectory = File.createTempFile(\"FileTreeIteratorTest\", \"\");\n+\t\tprojectDirectory.delete();\n+\t\tprojectDirectory.mkdir();\n+\t\tprojectDirectory.deleteOnExit();\n+\n+\t\tthis.directoryA = new File(projectDirectory, DIRECTORY_A_NAME);\n+\t\tdirectoryA.mkdir();\n+\n+\t\tthis.directoryAB = new File(directoryA, DIRECTORY_AB_NAME);\n+\t\tdirectoryAB.mkdir();\n+\n+\t\tthis.fileABA = new File(directoryAB, \"a.y\");\n+\t\tfileABA.createNewFile();\n+\n+\t\tthis.directoryAC = new File(directoryA, \"c\");\n+\t\tthis.directoryAC.mkdir();\n+\n+\t\tthis.fileACA = new File(directoryAC, \"a.x\");\n+\t\tfileACA.createNewFile();\n+\n+\t\tthis.fileACB = new File(directoryAC, \"b.y\");\n+\t\tfileACB.createNewFile();\n+\n+\t\tthis.fileB = new File(projectDirectory, \"b.x\");\n+\t\tfileB.createNewFile();\n+\t}\n+\n+\tpublic void testFileTreeIterator() {\n+\t\tfinal Iterator<File> iterator = new LightFileTreeIterator(\n+\t\t\t\tprojectDirectory, Rules.IGNORE_NOTHING, false);\n+\t\tfinal Set<File> actualPathes = new HashSet<File>();\n+\t\twhile (iterator.hasNext()) {\n+\t\t\tfinal File next = iterator.next();\n+\t\t\tassertFalse(actualPathes.contains(next));\n+\t\t\tactualPathes.add(next);\n+\t\t}\n+\n+\t\tfinal Set<File> expectedPathes = new HashSet<File>();\n+\t\texpectedPathes.add(directoryA);\n+\t\texpectedPathes.add(fileB);\n+\t\texpectedPathes.add(directoryAB);\n+\t\texpectedPathes.add(fileABA);\n+\t\texpectedPathes.add(directoryAC);\n+\t\texpectedPathes.add(fileACA);\n+\t\texpectedPathes.add(fileACB);\n+\t\tassertEquals(expectedPathes, actualPathes);\n+\n+\t}\n+\n+\tpublic void testFileTreeIteratorWithIgnoreAllRules() {\n+\t\tfinal Iterator<File> iterator = new LightFileTreeIterator(\n+\t\t\t\tprojectDirectory, Rules.IGNORE_ALL, false);\n+\t\tfinal Set<File> actualPathes = new HashSet<File>();\n+\t\twhile (iterator.hasNext()) {\n+\t\t\tfinal File next = iterator.next();\n+\t\t\tassertFalse(actualPathes.contains(next));\n+\t\t\tactualPathes.add(next);\n+\t\t}\n+\n+\t\tassertEquals(0, actualPathes.size());\n+\n+\t}\n+\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java\nnew file mode 100644\nindex 0000000..45fb167\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java\n@@ -0,0 +1,112 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk;\n+\n+import java.io.File;\n+import java.util.EmptyStackException;\n+import java.util.Iterator;\n+import java.util.NoSuchElementException;\n+import java.util.Stack;\n+\n+import org.spearce.jgit.treewalk.rules.Rules;\n+\n+class LightFileTreeIterator implements Iterator<File> {\n+\tprivate final Stack<File> remainingPathes;\n+\n+\tprivate final Stack<Directory> remainingDirectories;\n+\n+\t/**\n+\t * Creates a new Iterator which allows to iterate over the content of the\n+\t * specified rootDirectory. The rootDirectory itself is never included.\n+\t * \n+\t * @param rootDirectory\n+\t *            the directory tree to iterate over.\n+\t * @param ignoreRules\n+\t *            defines which paths are included and which aren't.\n+\t * @param includeRootDirectory\n+\t *            the iterator will return the rootDirectory if this is flag is\n+\t *            true.\n+\t */\n+\tLightFileTreeIterator(File rootDirectory, Rules ignoreRules,\n+\t\t\tboolean includeRootDirectory) {\n+\t\tremainingPathes = new Stack<File>();\n+\t\tif (includeRootDirectory) {\n+\t\t\tremainingPathes.add(rootDirectory);\n+\t\t}\n+\t\tremainingDirectories = new Stack<Directory>();\n+\t\tremainingDirectories.add(new Directory(rootDirectory, ignoreRules));\n+\t}\n+\n+\tpublic boolean hasNext() {\n+\t\tfindMorePathesIfNessesary();\n+\t\treturn !remainingPathes.empty();\n+\t}\n+\n+\tvoid findMorePathesIfNessesary() {\n+\t\tif (remainingPathes.isEmpty()) {\n+\t\t\tfindMorePathes();\n+\t\t}\n+\t}\n+\n+\tvoid findMorePathes() {\n+\t\twhile (!remainingDirectories.isEmpty() && remainingPathes.isEmpty()) {\n+\t\t\tfinal Directory directory = remainingDirectories.pop();\n+\t\t\tfinal File[] pathes = directory.path.listFiles();\n+\t\t\tfor (File path : pathes) {\n+\t\t\t\tfinal boolean fileIsDirectory = path.isDirectory();\n+\t\t\t\tif (fileIsDirectory) {\n+\t\t\t\t\tfinal Rules subDirectoryIgnoreRules = directory.ignoreRules\n+\t\t\t\t\t\t\t.getRulesForSubDirectory(path.getName());\n+\t\t\t\t\tif (subDirectoryIgnoreRules != Rules.IGNORE_ALL) {\n+\t\t\t\t\t\tfinal Directory subDirectory = new Directory(path,\n+\t\t\t\t\t\t\t\tsubDirectoryIgnoreRules);\n+\t\t\t\t\t\tremainingDirectories.add(subDirectory);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\tif (!directory.ignoreRules.toIgnore(path.getName(),\n+\t\t\t\t\t\tfileIsDirectory)) {\n+\t\t\t\t\tremainingPathes.add(path);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tpublic File next() {\n+\t\tfindMorePathesIfNessesary();\n+\t\ttry {\n+\t\t\treturn remainingPathes.pop();\n+\t\t} catch (EmptyStackException e) {\n+\t\t\tthrow new NoSuchElementException();\n+\t\t}\n+\t}\n+\n+\tpublic void remove() {\n+\t\tthrow new UnsupportedOperationException();\n+\t}\n+\n+\tprivate class Directory {\n+\t\tfinal File path;\n+\n+\t\tfinal Rules ignoreRules;\n+\n+\t\tDirectory(File path, Rules ignoreRules) {\n+\t\t\tthis.path = path;\n+\t\t\tthis.ignoreRules = ignoreRules;\n+\t\t}\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76776","messageId":"1210623222-24908-23-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 22/24] Added class LightFileTreeIterable.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:40Z","receivedAt":"2008-05-12T20:13:40Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../jgit/treewalk/LightFileTreeIterable.java       |   59 ++++++++++++++++++++\n 1 files changed, 59 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java\nnew file mode 100644\nindex 0000000..5768f78\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java\n@@ -0,0 +1,59 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk;\n+\n+import java.io.File;\n+import java.util.Iterator;\n+\n+import org.spearce.jgit.treewalk.rules.Rules;\n+\n+/**\n+ * Use this class to iterate over some by rules determined files in a project\n+ * directory.\n+ * \n+ */\n+public class LightFileTreeIterable implements Iterable<File> {\n+\tprivate final File projectDirectory;\n+\n+\tprivate final Rules ignoreRules;\n+\n+\tprivate final boolean includeRootDirectory;\n+\n+\t/**\n+\t * \n+\t * @param workTreeDirectory\n+\t *            directory with the files which are under version control.\n+\t * @param rules\n+\t *            a {@link Rules} instance which is used to determine which file\n+\t *            are included and which not.\n+\t * @param includeWorkTreeDirectory\n+\t *            determines if the iterators should return the\n+\t *            workTreeDirectory\n+\t */\n+\tpublic LightFileTreeIterable(File workTreeDirectory, Rules rules,\n+\t\t\tboolean includeWorkTreeDirectory) {\n+\t\tthis.projectDirectory = workTreeDirectory;\n+\t\tthis.ignoreRules = rules;\n+\t\tthis.includeRootDirectory = includeWorkTreeDirectory;\n+\t}\n+\n+\tpublic Iterator<File> iterator() {\n+\t\treturn new LightFileTreeIterator(projectDirectory, ignoreRules,\n+\t\t\t\tincludeRootDirectory);\n+\t}\n+\n+}\n-- \n1.5.4.3\n"},{"id":"76766","messageId":"1210623222-24908-24-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 23/24] Added the test class AddCommandIterationTest.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:41Z","receivedAt":"2008-05-12T20:13:41Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../treewalk/rules/AddCommandIterationTest.java    |  321 ++++++++++++++++++++\n 1 files changed, 321 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/AddCommandIterationTest.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/AddCommandIterationTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/AddCommandIterationTest.java\nnew file mode 100644\nindex 0000000..a96c880\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/AddCommandIterationTest.java\n@@ -0,0 +1,321 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.treewalk.rules;\n+\n+import java.io.File;\n+import java.io.IOException;\n+import java.io.PrintWriter;\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.Collections;\n+import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.List;\n+import java.util.NoSuchElementException;\n+import java.util.Set;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.errors.InvalidPatternException;\n+import org.spearce.jgit.errors.PathNotInProjectDirectoryException;\n+import org.spearce.jgit.lib.Repository;\n+import org.spearce.jgit.lib.WorkTree;\n+import org.spearce.jgit.treewalk.LightFileTreeIterable;\n+\n+public class AddCommandIterationTest extends TestCase {\n+\n+\tprivate WorkTree workTree;\n+\n+\tprivate AddRulesFactory factory;\n+\n+\tprivate Iterable<File> createIterable(File workingDirectory,\n+\t\t\tList<String> filePatternsOfAddCommand)\n+\t\t\tthrows PathNotInProjectDirectoryException, InvalidPatternException,\n+\t\t\tIOException {\n+\t\tfinal Rules rules = factory.createRules(workTree.getDirectory(),\n+\t\t\t\tworkingDirectory, filePatternsOfAddCommand);\n+\t\treturn new LightFileTreeIterable(workTree.getDirectory(), rules, false);\n+\t}\n+\n+\t@Override\n+\tprotected void setUp() throws Exception {\n+\t\tfinal File projectDirectory = File.createTempFile(\"test\", \"\");\n+\t\tprojectDirectory.delete();\n+\t\tprojectDirectory.mkdir();\n+\t\tprojectDirectory.deleteOnExit();\n+\t\tthis.workTree = Repository.createWorkTree(projectDirectory);\n+\t\tthis.factory = new AddRulesFactory();\n+\t}\n+\n+\tpublic void testNoPattern() throws Exception {\n+\t\tcreateFile(\"a.txt\");\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tCollections.<String> emptyList());\n+\t\tfinal Set<File> expectedPathes = Collections.emptySet();\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedPathes, iterable);\n+\t}\n+\n+\tpublic void testTreePattern1() throws Exception {\n+\t\tfinal Set<File> expectedFiles = new HashSet<File>();\n+\t\tcreateFile(\"a.txt\");\n+\t\texpectedFiles.add(createFile(\"a\", \"a.txt\"));\n+\t\texpectedFiles.add(createFile(\"a\", \"a\", \"a.txt\"));\n+\t\texpectedFiles.add(createFile(\"a\", \"b\", \"a.txt\"));\n+\t\tcreateFile(\"a\", \"b\", \"a.c\");\n+\n+\t\tfinal File directoryA = new File(workTree.getDirectory(), \"a\");\n+\n+\t\tfinal Iterable<File> iterable = createIterable(directoryA, Arrays\n+\t\t\t\t.asList(\"*.txt\"));\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedFiles, iterable);\n+\t}\n+\n+\tpublic void testTreePattern2() throws Exception {\n+\t\tfinal Set<File> expectedFiles = new HashSet<File>();\n+\t\tcreateFile(\"a.txt\");\n+\t\texpectedFiles.add(createFile(\"a\", \"a.txt\"));\n+\t\texpectedFiles.add(createFile(\"a\", \"a\", \"a.txt\"));\n+\t\texpectedFiles.add(createFile(\"a\", \"b\", \"a.txt\"));\n+\t\tcreateFile(\"a\", \"b\", \"a.c\");\n+\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tArrays.asList(\"a\" + File.separator + \"*.txt\"));\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedFiles, iterable);\n+\t}\n+\n+\tpublic void testSelectCompleteSubdirectory() throws Exception {\n+\t\tfinal Set<File> expectedPathes = new HashSet<File>();\n+\t\tfinal File directoryA = new File(workTree.getDirectory(), \"a\");\n+\t\tfinal File directoryAA = new File(directoryA, \"a\");\n+\t\tfinal File directoryAB = new File(directoryA, \"b\");\n+\t\tcreateFile(\"a.txt\");\n+\t\texpectedPathes.add(directoryA);\n+\t\texpectedPathes.add(directoryAA);\n+\t\texpectedPathes.add(createFile(\"a\", \"a.txt\"));\n+\t\texpectedPathes.add(createFile(\"a\", \"a\", \"a.txt\"));\n+\t\texpectedPathes.add(directoryAB);\n+\t\texpectedPathes.add(createFile(\"a\", \"b\", \"a.txt\"));\n+\t\texpectedPathes.add(createFile(\"a\", \"b\", \"a.c\"));\n+\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tArrays.asList(\"a\"));\n+\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedPathes, iterable);\n+\t}\n+\n+\tpublic void testSelectTwoSubdirectories() throws Exception {\n+\t\tfinal Set<File> expectedPathes = new HashSet<File>();\n+\t\tfinal File directoryA = new File(workTree.getDirectory(), \"a\");\n+\t\tfinal File directoryAA = new File(directoryA, \"a\");\n+\t\tfinal File directoryAB = new File(directoryA, \"b\");\n+\t\tcreateFile(\"a.txt\");\n+\t\tcreateFile(\"a\", \"a.txt\");\n+\t\texpectedPathes.add(directoryAA);\n+\t\texpectedPathes.add(createFile(\"a\", \"a\", \"a.txt\"));\n+\t\texpectedPathes.add(directoryAB);\n+\t\texpectedPathes.add(createFile(\"a\", \"b\", \"a.txt\"));\n+\t\texpectedPathes.add(createFile(\"a\", \"b\", \"a.c\"));\n+\n+\t\tfinal List<String> patternList = new ArrayList<String>(2);\n+\t\tpatternList.add(\"a\" + File.separator + \"a\");\n+\t\tpatternList.add(\"a\" + File.separator + \"b\");\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tpatternList);\n+\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedPathes, iterable);\n+\t}\n+\n+\tpublic void testTwoDifferentSelects() throws Exception {\n+\t\tfinal Set<File> expectedPathes = new HashSet<File>();\n+\t\tfinal File directoryA = new File(workTree.getDirectory(), \"a\");\n+\t\tfinal File directoryAA = new File(directoryA, \"a\");\n+\t\tcreateFile(\"a.txt\");\n+\t\tcreateFile(\"a\", \"a.txt\");\n+\t\texpectedPathes.add(directoryAA);\n+\t\texpectedPathes.add(createFile(\"a\", \"a\", \"a.txt\"));\n+\t\texpectedPathes.add(createFile(\"a\", \"b\", \"a.txt\"));\n+\t\texpectedPathes.add(createFile(\"a\", \"b\", \"c\", \"a.txt\"));\n+\t\tcreateFile(\"a\", \"b\", \"a.c\");\n+\n+\t\tfinal List<String> patternList = new ArrayList<String>(2);\n+\t\tpatternList.add(\"a\" + File.separator + \"a\");\n+\t\tpatternList.add(\"a\" + File.separator + \"b\" + File.separator + \"*.txt\");\n+\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tpatternList);\n+\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedPathes, iterable);\n+\t}\n+\n+\tpublic void testRealisticExample() throws Exception {\n+\t\tfinal Set<File> expectedPathes = new HashSet<File>();\n+\n+\t\t// write the .gitignore file\n+\t\tfinal File dotGitIgnoreFile = createFile(\".gitignore\");\n+\t\tfinal PrintWriter dotGitIgnoreFilePrinter = new PrintWriter(\n+\t\t\t\tdotGitIgnoreFile);\n+\t\ttry {\n+\t\t\tdotGitIgnoreFilePrinter.println(\"/alpha/config.xml\");\n+\t\t\tdotGitIgnoreFilePrinter.println(\"*.class\");\n+\t\t\tdotGitIgnoreFilePrinter.println(\"!/alpha/test/ressources/\");\n+\t\t\tdotGitIgnoreFilePrinter.println(\"*~\");\n+\t\t} finally {\n+\t\t\tdotGitIgnoreFilePrinter.close();\n+\t\t}\n+\n+\t\t// write the .git/info/exclude file\n+\t\tfinal File repositoryDirectory = workTree.getRepository()\n+\t\t\t\t.getDirectory();\n+\t\tfinal File infoDirectory = new File(repositoryDirectory, \"info\");\n+\t\tinfoDirectory.mkdir();\n+\t\tfinal File infoExcludeFile = new File(infoDirectory, \"exclude\");\n+\t\tfinal PrintWriter infoExcludeFilePrinter = new PrintWriter(\n+\t\t\t\tinfoExcludeFile);\n+\t\ttry {\n+\t\t\tinfoExcludeFilePrinter.println(\"/alpha/test/ressources/mytest.txt\");\n+\t\t} finally {\n+\t\t\tinfoExcludeFilePrinter.close();\n+\t\t}\n+\n+\t\tcreateFile(\"alpha\", \"config.xml\");\n+\t\texpectedPathes.add(createFile(\"alpha\", \"src\", \"Main.java\"));\n+\t\tcreateFile(\"alpha\", \"src\", \"Main.class\");\n+\t\texpectedPathes.add(createFile(\"alpha\", \"test\", \"ressources\",\n+\t\t\t\t\"Example.class\"));\n+\t\texpectedPathes.add(createFile(\"alpha\", \"test\", \"ressources\",\n+\t\t\t\t\"input.txt\"));\n+\t\tcreateFile(\"alpha\", \"test\", \"ressources\", \"input.txt~\");\n+\t\tcreateFile(\"alpha\", \"test\", \"ressources\", \"mytest.txt\");\n+\n+\t\tfinal File alphaDirectory = new File(workTree.getDirectory(), \"alpha\");\n+\t\tfinal File srcDirectory = new File(alphaDirectory, \"src\");\n+\t\tfinal File testDirectory = new File(alphaDirectory, \"test\");\n+\t\tfinal File ressources = new File(testDirectory, \"ressources\");\n+\n+\t\texpectedPathes.add(alphaDirectory);\n+\t\texpectedPathes.add(srcDirectory);\n+\t\texpectedPathes.add(testDirectory);\n+\t\texpectedPathes.add(ressources);\n+\n+\t\tfinal List<String> patternList = new ArrayList<String>(2);\n+\t\tpatternList.add(\"alpha\");\n+\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tpatternList);\n+\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedPathes, iterable);\n+\t}\n+\n+\tpublic void testSingleFile() throws Exception {\n+\t\tcreateFile(\"a.txt\");\n+\t\tcreateFile(\"a\", \"a.txt\");\n+\t\tcreateFile(\"a\", \"a\", \"a.txt\");\n+\t\tfinal File expectedFile = createFile(\"a\", \"b\", \"a.txt\");\n+\t\tcreateFile(\"a\", \"b\", \"a.c\");\n+\n+\t\tfinal String pattern = \"a\" + File.separator + \"b\" + File.separator\n+\t\t\t\t+ \"a.txt\";\n+\t\tfinal Iterable<File> iterable = createIterable(workTree.getDirectory(),\n+\t\t\t\tArrays.asList(pattern));\n+\t\tfinal Set<File> expectedPathes = Collections.singleton(expectedFile);\n+\t\tassertIsValidIterable(iterable);\n+\t\tassertIterableReturnsSet(expectedPathes, iterable);\n+\t}\n+\n+\t/**\n+\t * Tests if the specified {@link Iterable} returns the specified set of\n+\t * {@link File}s. The assertion will fail if the {@link Iterable} returns\n+\t * to much, to less files. It will also fail if the {@link Iterable} returns\n+\t * a file twice.\n+\t * \n+\t * @param expectedContent\n+\t *            the expected set of files.\n+\t * @param iterable\n+\t *            the {@link Iterable} to test.\n+\t */\n+\tprivate void assertIterableReturnsSet(Set<File> expectedContent,\n+\t\t\tIterable<File> iterable) {\n+\t\tfinal Set<File> returnedFiles = new HashSet<File>();\n+\t\tfinal List<File> doubleReturnedFiles = new ArrayList<File>();\n+\n+\t\tfinal Iterator<File> iterator = iterable.iterator();\n+\t\twhile (iterator.hasNext()) {\n+\t\t\tfinal File file = iterator.next();\n+\t\t\tif (!returnedFiles.add(file)) {\n+\t\t\t\tdoubleReturnedFiles.add(file);\n+\t\t\t}\n+\t\t}\n+\t\tfinal Set<File> missingFiles = new HashSet<File>();\n+\t\tfor (File file : expectedContent) {\n+\t\t\tif (!returnedFiles.contains(file)) {\n+\t\t\t\tmissingFiles.add(file);\n+\t\t\t}\n+\t\t}\n+\t\tif (!missingFiles.isEmpty()) {\n+\t\t\tfail(String.format(\"missing pathes: %s\", missingFiles));\n+\t\t}\n+\n+\t\tfinal Set<File> unexpectedFiles = new HashSet<File>();\n+\t\tfor (File file : returnedFiles) {\n+\t\t\tif (!expectedContent.contains(file)) {\n+\t\t\t\tunexpectedFiles.add(file);\n+\t\t\t}\n+\t\t}\n+\t\tif (!unexpectedFiles.isEmpty()) {\n+\t\t\tfail(String.format(\"unexpected pathes: %s\", unexpectedFiles));\n+\t\t}\n+\n+\t\tif (!doubleReturnedFiles.isEmpty()) {\n+\t\t\tfail(String.format(\"multiple times returned pathes: %s\",\n+\t\t\t\t\tdoubleReturnedFiles));\n+\t\t}\n+\n+\t}\n+\n+\tprivate static void assertIsValidIterable(Iterable<File> iterable) {\n+\t\tfinal Iterator<File> iterator = iterable.iterator();\n+\t\twhile (iterator.hasNext()) {\n+\t\t\titerator.next();\n+\t\t}\n+\t\ttry {\n+\t\t\titerator.next();\n+\t\t\tfail();\n+\t\t} catch (NoSuchElementException e) {\n+\t\t\t// expected\n+\t\t}\n+\t}\n+\n+\tprivate File createFile(String... path) throws IOException {\n+\t\tFile file = workTree.getDirectory();\n+\t\tfor (int i = 0; i < path.length; i++) {\n+\t\t\tfile = new File(file, path[i]);\n+\t\t\tif (i == path.length - 1) {\n+\t\t\t\tfile.getParentFile().mkdirs();\n+\t\t\t\tfile.createNewFile();\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\treturn file;\n+\t}\n+}\n-- \n1.5.4.3\n"},{"id":"76768","messageId":"1210623222-24908-25-git-send-email-florianskarten@web.de","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"[JGIT PATCH v2 24/24] Added a \"add\" command to the git like command line tool.","fromName":"Florian Koeberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-12T20:13:42Z","receivedAt":"2008-05-12T20:13:42Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Signed-off-by: Florian Koeberle <florianskarten@web.de>\n---\n .../src/org/spearce/jgit/pgm/AddCommand.java       |   97 ++++++++++++++++++++\n .../src/org/spearce/jgit/pgm/MainProgram.java      |    1 +\n 2 files changed, 98 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java\nnew file mode 100644\nindex 0000000..6d0a0d6\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java\n@@ -0,0 +1,97 @@\n+/*\n+ *  Copyright (C) 2008 Florian KÃ¶berle\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU General Public\n+ *  License, version 2, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.jgit.pgm;\n+\n+import java.io.File;\n+import java.io.IOException;\n+import java.util.Arrays;\n+\n+import org.spearce.jgit.errors.InvalidPatternException;\n+import org.spearce.jgit.lib.GitIndex;\n+import org.spearce.jgit.lib.Repository;\n+\n+import static org.spearce.jgit.lib.Repository.findWorkTree;\n+import org.spearce.jgit.lib.WorkTree;\n+import org.spearce.jgit.lib.GitIndex.Entry;\n+import org.spearce.jgit.treewalk.LightFileTreeIterable;\n+import org.spearce.jgit.treewalk.rules.AddRulesFactory;\n+import org.spearce.jgit.treewalk.rules.Rules;\n+\n+/**\n+ * The {@link #execute} method of this class is used to add files to the index.\n+ * This class is immutable.\n+ * \n+ */\n+public class AddCommand implements Command {\n+\t/**\n+\t * Use this instance instead of creating a new ${link AddCommand}. You don't\n+\t * need to create an instance of this class as it is immutable and not\n+\t * configurable.\n+\t */\n+\tpublic static AddCommand INSTANCE = new AddCommand();\n+\n+\tprivate AddRulesFactory addRulesFactory = new AddRulesFactory();\n+\n+\t/**\n+\t * Adds the specified files to the index.\n+\t * \n+\t * @param args\n+\t *            can contain \"*.Suffix\" patterns, files and directories.\n+\t */\n+\tpublic void execute(String... args) throws IOException {\n+\t\tfinal WorkTree workTree = findWorkTree();\n+\t\tfinal Repository repository = workTree.getRepository();\n+\t\ttry {\n+\t\t\tfinal GitIndex gitIndex = repository.getIndex();\n+\t\t\tfinal File projectDirectory = workTree.getDirectory();\n+\t\t\tfinal String workingDirectoryString = System\n+\t\t\t\t\t.getProperty(\"user.dir\");\n+\t\t\tif (workingDirectoryString == null) {\n+\t\t\t\tthrow new UnableToDetermineWorkingDirectory();\n+\t\t\t}\n+\t\t\tfinal File workingDirectory = new File(workingDirectoryString);\n+\t\t\tfinal Rules rules = addRulesFactory.createRules(workTree\n+\t\t\t\t\t.getDirectory(), workingDirectory, Arrays.asList(args));\n+\t\t\tfinal Iterable<File> fileIterable = new LightFileTreeIterable(\n+\t\t\t\t\tworkTree.getDirectory(), rules, false);\n+\t\t\tfor (File path : fileIterable) {\n+\t\t\t\tif (path.isFile()) {\n+\t\t\t\t\tfinal Entry entry = gitIndex.add(projectDirectory, path);\n+\t\t\t\t\tentry.setAssumeValid(false);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tgitIndex.write();\n+\t\t} catch (UnableToDetermineWorkingDirectory e) {\n+\t\t\tSystem.err.println(\"Unable to determine working directory\");\n+\t\t\tSystem.exit(1);\n+\t\t} catch (InvalidPatternException e) {\n+\t\t\tSystem.err.printf(\"The pattern '%s' is invalid: %s\",\n+\t\t\t\t\te.getMessage(), e.getPattern());\n+\t\t\tSystem.exit(1);\n+\t\t} finally {\n+\t\t\trepository.close();\n+\t\t}\n+\t}\n+\n+\tpublic String getShortDescription() {\n+\t\treturn \"Adds one or more files to the index.\";\n+\t}\n+\n+\tprivate static class UnableToDetermineWorkingDirectory extends Exception {\n+\t\tprivate static final long serialVersionUID = -4229647819515644868L;\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\nindex 1ade91b..d9dafa3 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java\n@@ -33,6 +33,7 @@ public class MainProgram {\n \n \tstatic {\n \t\tfinal Map<String, Command> commands = new HashMap<String, Command>();\n+\t\tcommands.put(\"add\", AddCommand.INSTANCE);\n \t\tcommands.put(\"init\", InitCommand.INSTANCE);\n \t\tcommands.put(\"help\", HelpCommand.INSTANCE);\n \t\tcommandNameToObjectMap = Collections.unmodifiableMap(commands);\n-- \n1.5.4.3\n"},{"id":"76788","messageId":"20080512204310.GS27724@genesis.frugalware.org","threadId":"13496","inReplyTo":"1210623222-24908-1-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules.","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-12T20:43:10Z","receivedAt":"2008-05-12T20:43:10Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, May 12, 2008 at 10:13:18PM +0200, Florian Koeberle <florianskarten@web.de> wrote:\n> Maybe I missed something... I would need some patch-tree version\n> control system which tracks changes in the patch tree ;).\n\nthe branch reflog is your friend :)\n"},{"id":"76812","messageId":"20080512235431.GY29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-5-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 04/24] Added path related constats to Constats class.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-12T23:54:31Z","receivedAt":"2008-05-12T23:54:31Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> @@ -171,6 +171,26 @@ public final class Constants {\n>  \tpublic static String REMOTES_PREFIX = \"refs/remotes\";\n>  \n>  \t/**\n> +\t * The name of the repository directory in the project directory.\n> +\t */\n> +\tpublic static final String REPOSITORY_DIRECTORY_NAME = \".git\";\n\nWhat is a project directory?\n\n> +\t/**\n> +\t * Contains the name of the HEAD file in the repository directory.\n> +\t */\n> +\tpublic static final String HEAD_FILE_NAME = \"HEAD\";\n\nIsn't this already declared as just HEAD?  Lets not duplicate\nconstants if we can avoid it, especially when they are in the\nsame class.\n\n-- \nShawn.\n"},{"id":"76814","messageId":"20080513000405.GZ29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-6-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-13T00:04:05Z","receivedAt":"2008-05-13T00:04:05Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> +\tpublic static WorkTree createWorkTree(File workTreeDirectory)\n\nI'm only going to make this remark once for your series: In general I\nprefer to mark any method argument, instance field or local variable\nthat I do not plan on changing within the method or class final.\nThis has saved me more than once from stupidly changing a parameter\nwhen I meant to change something else.\n\nIts not a hard and fast rule in either jgit or egit; you don't need\nto go back and fix every single site.  Just something I have found\nuseful over the years and now do almost everywhere.\n\n> +\t\t\tthrows IOException {\n> +\t\tfinal File gitDirectory = new File(workTreeDirectory,\n> +\t\t\t\tConstants.REPOSITORY_DIRECTORY_NAME);\n> +\t\tif (gitDirectory.exists()) {\n> +\t\t\tthrow new IllegalArgumentException(\n> +\t\t\t\t\t\"Repository exists in given project directory.\");\n\nWhen we throw an exception like this we should include the path\nwe are complaining about already existing as part of the message\n(see Repository.create() for example).  This way if the message\nmakes it as far as the end-user (which it probably should, and\nthen there's translation issues are currently ignoring in jgit)\nthe user can at least see what path we were trying to operate on.\nIt may help them to realize they are in the wrong directory, or\nmade a typo on an input, etc.\n\n\nAnother thing about this method is we cannot supply the WindowCache\nthat the Repository should use for object data access, which means\nthis Repository will have its own WindowCache.  Under Eclipse (or\nany other larger GUI/IDE) we really want only a single WindowCache\ninstance for the entire JVM as the heap must be shared across all\nRepository instances.\n\nThis is actually making me reconsider how the WindowCache is handled.\nMaybe we should have a single WindowCache instance down inside\nof jgit, but allow the higher level UI (like Eclipse) to tune it\non the fly.  Then we don't have to worry about passing it down to\nutility routines like this anytime we open a Repository.\n\nHmmmm.\n\n-- \nShawn.\n"},{"id":"76817","messageId":"20080513002409.GC29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-8-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-13T00:24:09Z","receivedAt":"2008-05-13T00:24:09Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> @@ -1242,4 +1247,89 @@ public class Repository {\n>  \t\t}\n>  \t}\n>  \n> +\t/**\n> +\t * Find the git repository for the current working directory.\n> +\t * \n> +\t * @return a {@link Repository}.\n> +\t * @throws IOException\n> +\t *             if the system property user.dir isn't set or if it is\n> +\t *             invalid.\n> +\t */\n> +\tpublic static WorkTree findWorkTree() throws IOException {\n> +\t\tfinal String workingDirectoryPath = System.getProperty(\"user.dir\");\n> +\t\tif (workingDirectoryPath == null) {\n> +\t\t\tthrow new IOException(\"unable to get working directory\");\n> +\t\t}\n> +\t\tfinal File workingDirectoryFile = new File(workingDirectoryPath);\n\nIsn't `final File workingDirectoryFile = new File(\".\")` easier to write?\n\nAnd if we are going to throw a checked exception because we cannot\nfind a repository in \".\", maybe that should be a new checked\nexception, like NoGitRepositoryFoundException?\n\n> +\t/**\n> +\t * Checks if a path is a valid git repository. Works similar like the method\n> +\t * is_git_directory from the original setup.c file.\n\nReferences to C Git aren't common in jgit source code.  We aren't\na reference implementation, but that hasn't stopped people from\nfinding out code a sane description of \"how things work\".  I'd rather\nnot describe our code in terms of C Git's code; especially what\nhappens if C Git refactors one day, this reference might no longer\nmake sense.  Anyone coming back here to improve jgit or use this\nmethod will be confused about what we are doing.\n\n> +\t * \n> +\t * @param directory\n> +\t *            the path which should be checked.\n> +\t * @return true if the path is a valid git repository.\n> +\t */\n> +\tprivate static boolean isRepository(File directory) {\n> +\t\tif (!directory.isDirectory()) {\n> +\t\t\treturn false;\n> +\t\t}\n\nWe usually omit { and } on simple conditions like this.  Its a coding\npattern we stole from C Git, which stole it from the Linux kernel.\n\n> +\tprivate static WorkTree findWorkTree(File directory) throws IOException {\n> +\t\tFile currentDirectory = directory.getAbsoluteFile();\n> +\t\twhile (true) {\n> +\t\t\tfinal File commonGitDirectory = new File(directory,\n> +\t\t\t\t\tREPOSITORY_DIRECTORY_NAME);\n> +\t\t\tif (isRepository(commonGitDirectory)) {\n> +\t\t\t\treturn new WorkTree(currentDirectory, new Repository(\n> +\t\t\t\t\t\tcommonGitDirectory));\n> +\t\t\t}\n> +\n> +\t\t\tif (isRepository(currentDirectory)) {\n> +\t\t\t\treturn new WorkTree(null, new Repository(currentDirectory));\n> +\t\t\t}\n> +\t\t\tcurrentDirectory = currentDirectory.getParentFile();\n> +\t\t\tif (currentDirectory == null) {\n> +\t\t\t\tthrow new IOException(\"Can't find git repository\");\n> +\t\t\t}\n> +\t\t}\n\nWould this perhaps be a shorter, easier to follow variant of the\nsame algorithm?\n\n\tdirectory = directory.getAbsoluteFile();\n\tFile workdir = directory;\n\twhile (workdir != null) {\n\t\tfinal File gitdir = new File(workdir, REPOSITORY_DIRECTORY_NAME);\n\t\tif (isRepository(gitdir))\n\t\t\treturn new WorkTree(workdir, new Repository(gitdir));\n\t\tif (isRepository(workdir))\n\t\t\treturn new WorkTree(null, new Repository(workdir));\n\t\tworkdir = workdir.getParentFile();\n\t}\n\tthrow new NoGitRepositoryFoundException(\"No repository for \" + directory);\n\nI often do write infinite loops with \"for (;;) {\", but usually its\nbecause the loop condition is based on an iterator-style method\nreturning null at the end and I want to store the result in a local\nvariable scoped to only the body of the loop:\n\n\tfor (;;) {\n\t\tfinal RevCommit next = walk.next();\n\t\tif (next == null)\n\t\t\tbreak;\n\n\t\t// use next somehow\n\t}\n\nOtherwise I try to avoid infinite loops in my final version\nof something.  Though on a recent job interview the interviewer\nnoticed I tend to start writing code with an infinite loop, then\ngo back and correct the loop condition before saying \"done\".  ;-)\n\n-- \nShawn.\n"},{"id":"76818","messageId":"20080513003832.GD29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-12-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 11/24] Added the class FNMatchPattern.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-13T00:38:32Z","receivedAt":"2008-05-13T00:38:32Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> +/**\n> + * This class represents a pattern which should work like the fnmatch method.\n> + * <code>new FNMatchPattern(exp).matches(input)</code> should do the same like\n> + * <code>fnmatch(exp, input, 0) == 0</code>\n> + * \n> + * As this isn't a one to one code port, but written based on the documentation\n> + * of fnmatch it can be that the behavior of this class differ in some corner\n> + * cases from the behavior of the fnmatch function.\n> + */\n> +public class FNMatchPattern {\n> +\n> +\tprivate final Pattern regexPattern;\n\nFor what it is worth, I got a performance improvement by declaring\nthat such classes like FNMatchPattern are _not_ threadsafe and\nstoring a Matcher rather than a Pattern.  Then on each test you\ncan just reset the Matcher and evaluate it again.\n\nThis was worthwhile enough that I went back into RevFilter and\nadded a clone() method so you can safely clone a RevFilter graph\nto create a new set of instances for another thread.\n\nConsider using a Matcher here.  Ignore rule matching with a lot\nof patterns will bottleneck things like working directory status\noperations.\n\n> +\tprivate static String toRegexString(String fnmatchPattern) {\n> +\t\tfinal StringBuilder regexStringBuilder = new StringBuilder();\n> +\t\tchar perviosCharacter = 0;\n> +\t\tfor (int i = 0; i < fnmatchPattern.length(); i++) {\n> +\t\t\tfinal char c = fnmatchPattern.charAt(i);\n> +\t\t\tswitch (c) {\n> +\t\t\tcase '^':\n> +\t\t\t\tif (perviosCharacter == '[') {\n> +\t\t\t\t\tregexStringBuilder.append('!');\n> +\t\t\t\t} else {\n> +\t\t\t\t\tregexStringBuilder.append(\"\\\\x5E\");\n> +\t\t\t\t}\n> +\t\t\t\tbreak;\n> +\t\t\tcase '.':\n> +\t\t\t\tregexStringBuilder.append(\"\\\\x2E\");\n> +\t\t\t\tbreak;\n> +\t\t\tcase '*':\n> +\t\t\t\tregexStringBuilder.append(\".*\");\n> +\t\t\t\tbreak;\n> +\t\t\tdefault:\n> +\t\t\t\tregexStringBuilder.append(c);\n> +\t\t\t}\n> +\t\t\tperviosCharacter = c;\n> +\t\t}\n> +\t\treturn regexStringBuilder.toString();\n\nHuh.  So the fnmatchPattern of \"foo?\" will match the name \"fo\"\nin this implementation, but it does not in my C library's fnmatch\nfunction:\n\n\t$ cat fnmatch.c \n\t#include <fnmatch.h>\n\t#include <stdio.h>\n\n\tint main(int argc, char *argv[]) {\n\t\tconst char *pattern = argv[1];\n\t\tconst char *name = argv[2];\n\t\tprintf(\"%s on %s = %i\\n\", pattern, name, fnmatch(pattern, name, 0));\n\t\treturn 0;\n\t}\n\t$ ./fnmatch 'foo?' 'fo'\n\tfoo? on fo = 1\n\nThere are plenty more cases like that as too many of the regex\noperators are leaking through. All of the regex operators need to\nbe treated as literals in the regex pattern.\n\n-- \nShawn.\n"},{"id":"76819","messageId":"20080513010844.GE29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-15-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-13T01:08:44Z","receivedAt":"2008-05-13T01:08:44Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> +/**\n> + * This class can be used to create lists of {@link Rule} objects from lines of\n> + * .gitignore like files.\n> + * \n> + */\n> +class IgnoreRuleListFactory {\n> +\n> +\tList<Rule> createIgnoreRuleList(Iterable<String> lineIterable) {\n> +\t\tLinkedList<Rule> rules = new LinkedList<Rule>();\n> +\t\tfor (String line : lineIterable) {\n> +\t\t\tfinal String trimmedLine = line.trim();\n> +\t\t\tif (trimmedLine.startsWith(\"#\")) {\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\t\t\tif (trimmedLine.length() == 0) {\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\t\t\trules.add(0, createRule(trimmedLine));\n> +\t\t}\n> +\t\treturn rules;\n> +\t}\n> +\n> +\tList<Rule> createIgnoreRuleList(List<File> files)\n> +\t\t\tthrows FileNotFoundException {\n> +\t\tfinal List<String> lines = new ArrayList<String>();\n> +\t\tfor (File file : files) {\n> +\t\t\tScanner scanner = new Scanner(file);\n> +\t\t\ttry {\n> +\t\t\t\twhile (scanner.hasNextLine()) {\n> +\t\t\t\t\tlines.add(scanner.nextLine());\n> +\t\t\t\t}\n> +\t\t\t} finally {\n> +\t\t\t\tscanner.close();\n> +\t\t\t}\n> +\t\t}\n> +\t\treturn createIgnoreRuleList(lines);\n> +\t}\n\nWhy go through all this work to buffer the lines we don't care about\n(starting with # or are blank) when we could just discard them in the\ninside of createIgnoreRuleList and then create the rule right away?\n\n> +\tprivate Rule createRule(String trimmedLine) {\n> +\t\tfinal boolean exclude;\n> +\t\tString patternString;\n> +\t\tif (trimmedLine.startsWith(\"!\")) {\n> +\t\t\texclude = false;\n> +\t\t\tpatternString = trimmedLine.substring(1);\n> +\t\t} else {\n> +\t\t\texclude = true;\n> +\t\t\tpatternString = trimmedLine;\n> +\t\t}\n\nI suspect this code would be easier to follow if you just accepted\nchanging the method parameter, such as:\n\n\tprivate Rule createRule(String pattern) {\n\t\tboolean exclude = true;\n\t\tif (pattern.startsWith(\"!)) {\n\t\t\tpattern = pattern.substring(1);\n\t\t\texclude = false;\n\t\t}\n\n> +\t\tfinal boolean matchDirectoriesOnly;\n> +\t\tif (patternString.endsWith(\"/\")) {\n> +\t\t\tmatchDirectoriesOnly = true;\n> +\t\t\tpatternString = patternString.substring(0,\n> +\t\t\t\t\tpatternString.length() - 1);\n> +\t\t} else {\n> +\t\t\tmatchDirectoriesOnly = false;\n> +\t\t}\n> +\n> +\t\tfinal FilePattern pattern;\n> +\t\tif (patternString.contains(\"/\")) {\n> +\t\t\tif (patternString.startsWith(\"/\")) {\n> +\t\t\t\tpatternString = patternString.substring(1);\n> +\t\t\t}\n\n\"foo/bar\" will always end up in this code-path and will not match\nin all levels of the tree if I follow your code correctly.\n\nAn ignore rule in the top level of \"foo/bar\" should ignore any entry\nnamed \"bar\" within a directory \"foo\" at any level of the tree, even\nif it is 35 directories down from the root.  Isn't ComplexFilePattern\nabout the absolute (starts with \"/\") cases only?\n\n> +\t\t\tfinal StringTokenizer stringTokenizer = new StringTokenizer(\n> +\t\t\t\t\tpatternString, \"/\");\n> +\t\t\tfinal List<String> patternList = new ArrayList<String>();\n> +\t\t\twhile (stringTokenizer.hasMoreTokens()) {\n> +\t\t\t\tfinal String token = stringTokenizer.nextToken();\n> +\t\t\t\tpatternList.add(token);\n> +\t\t\t}\n\nStringTokenizer is more-or-less replaced by String.split(\"/\"), with\nthe split method being the more preferred method of doing this.\n\n-- \nShawn.\n"},{"id":"76820","messageId":"20080513012253.GF29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-18-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 17/24] Added the class TreeFilePattern.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-13T01:22:53Z","receivedAt":"2008-05-13T01:22:53Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> +/**\n> + * Represents a pattern like \"documents/*.txt\" which matches all *.txt files in\n> + * the tree documents.\n> + * \n> + */\n> +class TreeFilePattern implements FilePattern {\n> +\n> +\tprivate final List<String> path;\n> +\n> +\tprivate final int offset;\n> +\n> +\tprivate final GlobalFilePattern globalFilePattern;\n\nHmm.  This looks a lot like the ComplexFilePattern class to me;\nonly it has the optimization of avoiding the regex match on the\nleading parts of the path.\n\nWouldn't it be simpler to define ComplexFilePattern taking a\nList<FilePattern> and have two implementations of FilePattern;\none that uses FNMatch and one that uses strict String.equals()?\nThen this entire class becomes unnecessary as the pattern\n\"documents/technical/*.txt\" can be handled by two ExactMatch\ninstances followd by an FNMatch instance.\n\nThe performance difference is probably not even measurable, but\nthe code will be less complicated and less special-cased.\n\n-- \nShawn.\n"},{"id":"76821","messageId":"20080513012909.GG29038@spearce.org","threadId":"13496","inReplyTo":"1210623222-24908-20-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-13T01:29:09Z","receivedAt":"2008-05-13T01:29:09Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Koeberle <florianskarten@web.de> wrote:\n> +class AddRuleListFactory {\n> +\t/*\n> +\t * The add command of git 1.5.2.5 behaves a little bit stange: \"git add\n> +\t * a/\\*z\" adds the file \"a/b/xyz\" but \"git add a/x\\*\" does not.\n> +\t * \n> +\t * The first is parsed as pattern \"*z\" for whole directory tree \"a\". The\n> +\t * second is parsed as an path.\n> +\t * \n> +\t */\n\nIts not strange.  C Git expands each file path to its _full_ path\nand stores that into a buffer, then runs fnmatch() for each pattern\non the buffer.  If fnmatch() succeeds the path is added to the index.\n\nIn the case above we are running a match of \"a/\\*.z\" against\n\"a/b/xyz\" and that passes.  Or we run \"a/x\\*\" on \"a/b/xyz\" and it\nfails as the sequence of characters \"a/x\" does not appear in the\nstring \"a/b\".\n\nYou are running into this odd corner case because you are not\ntreating the pattern passed as something that matches against the\nentire path.  This is one reason why TreeFilter's use the entire\npath when they process an entry for inclusion or exclusion, and why\nTreeWalk has each AbstractTreeIterator append the current entry name\nonto the end of the current path buffer, so we can always examine\nthe full path from the root of the repository/working directory.\n\nTrying to avoid the full path in classes like ComplexFilePattern\nis why you are running into this corner case here, and must now do\nextra contortions to somewhat match the behavior of C Git.\n\nAt this point I think most of the rules package is overcomplicated\nand overoptimized, and yet doesn't actually quite match the behavior\nof C Git.\n\n-- \nShawn.\n"},{"id":"76856","messageId":"48296B41.9020105@web.de","threadId":"13496","inReplyTo":"20080513010844.GE29038@spearce.org","subject":"Re: [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.","fromName":"Florian Köberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-13T10:19:45Z","receivedAt":"2008-05-13T10:19:45Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Shawn O. Pearce wrote:\n> Florian Koeberle <florianskarten@web.de> wrote:\n>> +/**\n>> + * This class can be used to create lists of {@link Rule} objects from lines of\n>> + * .gitignore like files.\n>> + * \n>> + */\n>> +class IgnoreRuleListFactory {\n>> +\n>> +\tList<Rule> createIgnoreRuleList(Iterable<String> lineIterable) {\n>> +\t\tLinkedList<Rule> rules = new LinkedList<Rule>();\n>> +\t\tfor (String line : lineIterable) {\n>> +\t\t\tfinal String trimmedLine = line.trim();\n>> +\t\t\tif (trimmedLine.startsWith(\"#\")) {\n>> +\t\t\t\tcontinue;\n>> +\t\t\t}\n>> +\t\t\tif (trimmedLine.length() == 0) {\n>> +\t\t\t\tcontinue;\n>> +\t\t\t}\n>> +\t\t\trules.add(0, createRule(trimmedLine));\n>> +\t\t}\n>> +\t\treturn rules;\n>> +\t}\n>> +\n>> +\tList<Rule> createIgnoreRuleList(List<File> files)\n>> +\t\t\tthrows FileNotFoundException {\n>> +\t\tfinal List<String> lines = new ArrayList<String>();\n>> +\t\tfor (File file : files) {\n>> +\t\t\tScanner scanner = new Scanner(file);\n>> +\t\t\ttry {\n>> +\t\t\t\twhile (scanner.hasNextLine()) {\n>> +\t\t\t\t\tlines.add(scanner.nextLine());\n>> +\t\t\t\t}\n>> +\t\t\t} finally {\n>> +\t\t\t\tscanner.close();\n>> +\t\t\t}\n>> +\t\t}\n>> +\t\treturn createIgnoreRuleList(lines);\n>> +\t}\n> \n> Why go through all this work to buffer the lines we don't care about\n> (starting with # or are blank) when we could just discard them in the\n> inside of createIgnoreRuleList and then create the rule right away?\nI did this to reduce complexity and to increase modularity.\nThe method createIgnoreRuleList(Iterable<String> lineIterable) can now \nbe tested without the need to create files. Also it is so possible to \nread the patterns from different sources.\n\nIf you worry about memory usuage I could create some kind of \nRulesBuilder class:\n\npublic class RulesBuilder {\n\tprivate final List<Rule> rules;\n\tprivate RuleListToObjectConverter converter;\n\n\t// method used by tests:\n\tpublic void addIgnoreRule(String ignoreRuleLine) {\n\t\t\n\t}\n  \tpublic void addIgnoreRuleFile(File) {\n\t\t// reads file and calls addIgnoreRule\n\t}\n\n\tpublic void addIncludeRuleOfAddCommand(String pattern) {\n\t}\n\n\tpublic void addIgnoreGitDirectoryRule() {\n\t}\n\n\tpublic Rules buildRules() {\n\t\treturn converter.convertToObject(rules);\n\t}\n}\n\nThis would have the advantages:\n* all Rule creating code at one place.\n* There is no need to keep the original lines in memory.\n* It's easy to create rules for testing purposes.\n* It's easy to create Factories like AddRulesFactory.\n\n> \n>> +\tprivate Rule createRule(String trimmedLine) {\n>> +\t\tfinal boolean exclude;\n>> +\t\tString patternString;\n>> +\t\tif (trimmedLine.startsWith(\"!\")) {\n>> +\t\t\texclude = false;\n>> +\t\t\tpatternString = trimmedLine.substring(1);\n>> +\t\t} else {\n>> +\t\t\texclude = true;\n>> +\t\t\tpatternString = trimmedLine;\n>> +\t\t}\n> \n> I suspect this code would be easier to follow if you just accepted\n> changing the method parameter, such as:\n> \n> \tprivate Rule createRule(String pattern) {\n> \t\tboolean exclude = true;\n> \t\tif (pattern.startsWith(\"!)) {\n> \t\t\tpattern = pattern.substring(1);\n> \t\t\texclude = false;\n> \t\t}\nIf I remember correctly Intellij IDEA marks per default cases where you \nchange a parameter. So it looks like that there are style guides which \nare against the practice of changing the values of parameters.\n\nThat and the fact that you can't make exclude final now where the reason \nwhy I wrote it the otherway.\n> \n>> +\t\tfinal boolean matchDirectoriesOnly;\n>> +\t\tif (patternString.endsWith(\"/\")) {\n>> +\t\t\tmatchDirectoriesOnly = true;\n>> +\t\t\tpatternString = patternString.substring(0,\n>> +\t\t\t\t\tpatternString.length() - 1);\n>> +\t\t} else {\n>> +\t\t\tmatchDirectoriesOnly = false;\n>> +\t\t}\n>> +\n>> +\t\tfinal FilePattern pattern;\n>> +\t\tif (patternString.contains(\"/\")) {\n>> +\t\t\tif (patternString.startsWith(\"/\")) {\n>> +\t\t\t\tpatternString = patternString.substring(1);\n>> +\t\t\t}\n> \n> \"foo/bar\" will always end up in this code-path and will not match\n> in all levels of the tree if I follow your code correctly.\n> \n> An ignore rule in the top level of \"foo/bar\" should ignore any entry\n> named \"bar\" within a directory \"foo\" at any level of the tree, even\n> if it is 35 directories down from the root.  Isn't ComplexFilePattern\n> about the absolute (starts with \"/\") cases only?\nYes, ComplexFilePattern is about that cases only.\n\nI implemented it that way, becasue git behave the same way:\n* create the follwing file: a/a/b/test.txt\n* add the line \"a/b\" to .gitignore\n* add a and notice that it adds the test.txt file.\n\n> \n>> +\t\t\tfinal StringTokenizer stringTokenizer = new StringTokenizer(\n>> +\t\t\t\t\tpatternString, \"/\");\n>> +\t\t\tfinal List<String> patternList = new ArrayList<String>();\n>> +\t\t\twhile (stringTokenizer.hasMoreTokens()) {\n>> +\t\t\t\tfinal String token = stringTokenizer.nextToken();\n>> +\t\t\t\tpatternList.add(token);\n>> +\t\t\t}\n> \n> StringTokenizer is more-or-less replaced by String.split(\"/\"), with\n> the split method being the more preferred method of doing this.\n> \nOk\n"},{"id":"76861","messageId":"48297A88.5040508@web.de","threadId":"13496","inReplyTo":"20080513012909.GG29038@spearce.org","subject":"Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.","fromName":"Florian Köberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-13T11:24:56Z","receivedAt":"2008-05-13T11:24:56Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Shawn O. Pearce wrote:\n> Florian Koeberle <florianskarten@web.de> wrote:\n>> +class AddRuleListFactory {\n>> +\t/*\n>> +\t * The add command of git 1.5.2.5 behaves a little bit stange: \"git add\n>> +\t * a/\\*z\" adds the file \"a/b/xyz\" but \"git add a/x\\*\" does not.\n>> +\t * \n>> +\t * The first is parsed as pattern \"*z\" for whole directory tree \"a\". The\n>> +\t * second is parsed as an path.\n>> +\t * \n>> +\t */\n> \n> Its not strange.  C Git expands each file path to its _full_ path\n> and stores that into a buffer, then runs fnmatch() for each pattern\n> on the buffer.  If fnmatch() succeeds the path is added to the index.\n> \n> In the case above we are running a match of \"a/\\*.z\" against\n> \"a/b/xyz\" and that passes.  Or we run \"a/x\\*\" on \"a/b/xyz\" and it\n> fails as the sequence of characters \"a/x\" does not appear in the\n> string \"a/b\".\n> \n> You are running into this odd corner case because you are not\n> treating the pattern passed as something that matches against the\n> entire path.  This is one reason why TreeFilter's use the entire\n> path when they process an entry for inclusion or exclusion, and why\n> TreeWalk has each AbstractTreeIterator append the current entry name\n> onto the end of the current path buffer, so we can always examine\n> the full path from the root of the repository/working directory.\n> \n> Trying to avoid the full path in classes like ComplexFilePattern\n> is why you are running into this corner case here, and must now do\n> extra contortions to somewhat match the behavior of C Git.\n> \n> At this point I think most of the rules package is overcomplicated\n> and overoptimized, and yet doesn't actually quite match the behavior\n> of C Git.\n> \n\nStill I think that the behavior of git-add is strange:\nFor example, if you want to add the following file:\na/b/c/test.txt\nThen I can do this with \"a/\\*.txt\" or \"a/b\\*.txt\" but not with \n\"a/\\*/c/test.txt\"\n\nI know that I handle \"a/b\\*.txt\" wrong, and I don't know a nice way to \nimplement it in the current rules framework.\n\nI see three options:\n1.) Let the jgit add command work in another way then git-add does.\n2.) Don't use the rules framework to determine if a file is selected by \nthe add command.\n3.) Completely drop the patches\n[4.) Add some evil hacks to make it working] <- I don't like that version\n\nPlease tell me which way to go, so that I don't waste even more time on \npatches which will never make it in.\n\nBest regards,\nFlorian\n"},{"id":"76886","messageId":"200805132255.46363.robin.rosenberg.lists@dewire.com","threadId":"13496","inReplyTo":"48297A88.5040508@web.de","subject":"Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2008-05-13T20:55:45Z","receivedAt":"2008-05-13T20:55:45Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"tisdagen den 13 maj 2008 13.24.56 skrev Florian Köberle:\n> Shawn O. Pearce wrote:\n> > Florian Koeberle <florianskarten@web.de> wrote:\n> >> +class AddRuleListFactory {\n> >> +\t/*\n> >> +\t * The add command of git 1.5.2.5 behaves a little bit stange: \"git add\n> >> +\t * a/\\*z\" adds the file \"a/b/xyz\" but \"git add a/x\\*\" does not.\nYou mean a/\\*/x* does not?\n> >> +\t * \n> >> +\t * The first is parsed as pattern \"*z\" for whole directory tree \"a\". The\n> >> +\t * second is parsed as an path.\n> >> +\t * \n> >> +\t */\n> > \n> > Its not strange.  C Git expands each file path to its _full_ path\n> > and stores that into a buffer, then runs fnmatch() for each pattern\n> > on the buffer.  If fnmatch() succeeds the path is added to the index.\n> > \n> > In the case above we are running a match of \"a/\\*.z\" against\n> > \"a/b/xyz\" and that passes.  Or we run \"a/x\\*\" on \"a/b/xyz\" and it\n> > fails as the sequence of characters \"a/x\" does not appear in the\n> > string \"a/b\".\n> > \n> > You are running into this odd corner case because you are not\n> > treating the pattern passed as something that matches against the\n> > entire path.  This is one reason why TreeFilter's use the entire\n> > path when they process an entry for inclusion or exclusion, and why\n> > TreeWalk has each AbstractTreeIterator append the current entry name\n> > onto the end of the current path buffer, so we can always examine\n> > the full path from the root of the repository/working directory.\n> > \n> > Trying to avoid the full path in classes like ComplexFilePattern\n> > is why you are running into this corner case here, and must now do\n> > extra contortions to somewhat match the behavior of C Git.\n> > \n> > At this point I think most of the rules package is overcomplicated\n> > and overoptimized, and yet doesn't actually quite match the behavior\n> > of C Git.\n> > \n> \n> Still I think that the behavior of git-add is strange:\n> For example, if you want to add the following file:\n> a/b/c/test.txt\n> Then I can do this with \"a/\\*.txt\" or \"a/b\\*.txt\" but not with \n> \"a/\\*/c/test.txt\"\n> \n> I know that I handle \"a/b\\*.txt\" wrong, and I don't know a nice way to \n> implement it in the current rules framework.\n> \n> I see three options:\n> 1.) Let the jgit add command work in another way then git-add does.\n> 2.) Don't use the rules framework to determine if a file is selected by \n> the add command.\n> 3.) Completely drop the patches\n> [4.) Add some evil hacks to make it working] <- I don't like that version\n> \n> Please tell me which way to go, so that I don't waste even more time on \n> patches which will never make it in.\n\nCorrectness is very important. Obviously we will slip bugs trough, but\nnot intentionally in a part where legacy behaviour may play an important\nrole. With these options available I'd select number 2.\n\nI think your observations are interesting, especially the one you make\nhere about a/*/c/test.txt not matching because I don't see from the git\nadd manual why it shouldn't. I does not look like a recent git bug either. \n\nbtw, I should you can use the ö in your name in mail and too. It'll make\nfor some interesting testing of non-ascii handling that we need to take\non (another argument for not complicating handling of names too much).\nI'm sure it will get pretty hairy regardless.\n\n-- robin\n"},{"id":"76887","messageId":"200805132313.33217.robin.rosenberg.lists@dewire.com","threadId":"13496","inReplyTo":"20080513000405.GZ29038@spearce.org","subject":"Re: [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2008-05-13T21:13:33Z","receivedAt":"2008-05-13T21:13:33Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"tisdagen den 13 maj 2008 02.04.05 skrev Shawn O. Pearce:\n> This is actually making me reconsider how the WindowCache is handled.\n> Maybe we should have a single WindowCache instance down inside\n> of jgit, but allow the higher level UI (like Eclipse) to tune it\n> on the fly.  Then we don't have to worry about passing it down to\n> utility routines like this anytime we open a Repository.\n\nA singleton WindowCache makes more sense yes.\n\n-- robin\n"},{"id":"76898","messageId":"20080514003545.GI29038@spearce.org","threadId":"13496","inReplyTo":"200805132313.33217.robin.rosenberg.lists@dewire.com","subject":"Re: [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-14T00:35:45Z","receivedAt":"2008-05-14T00:35:45Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> tisdagen den 13 maj 2008 02.04.05 skrev Shawn O. Pearce:\n> > This is actually making me reconsider how the WindowCache is handled.\n> > Maybe we should have a single WindowCache instance down inside\n> > of jgit, but allow the higher level UI (like Eclipse) to tune it\n> > on the fly.  Then we don't have to worry about passing it down to\n> > utility routines like this anytime we open a Repository.\n> \n> A singleton WindowCache makes more sense yes.\n\nYea, OK.  I'll add it to my list of things to fix real-soon-now.\n\nRight now I'm trying to finish automated tag following, since it\nis not implemented.\n\n-- \nShawn.\n"},{"id":"76900","messageId":"20080514010600.GK29038@spearce.org","threadId":"13496","inReplyTo":"48296B41.9020105@web.de","subject":"Re: [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-14T01:06:00Z","receivedAt":"2008-05-14T01:06:00Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Florian Kberle <FloriansKarten@web.de> wrote:\n> Shawn O. Pearce wrote:\n> >\n> >Why go through all this work to buffer the lines we don't care about\n> >(starting with # or are blank) when we could just discard them in the\n> >inside of createIgnoreRuleList and then create the rule right away?\n>\n> I did this to reduce complexity and to increase modularity.\n> The method createIgnoreRuleList(Iterable<String> lineIterable) can now \n> be tested without the need to create files. Also it is so possible to \n> read the patterns from different sources.\n> \n> If you worry about memory usuage I could create some kind of \n> RulesBuilder class:\n\nOK.  I guess I can see that.  I wasn't worried about memory, it just\nseemed odd to me that the \"parser\" (splitting the file into lines)\nwas also not skipping the lines that were not interesting.\n\nGiven your explanation I don't see a reason to change it, it just\nstruck me as odd.\n \n> >I suspect this code would be easier to follow if you just accepted\n> >changing the method parameter, such as:\n> >\n> >\tprivate Rule createRule(String pattern) {\n> >\t\tboolean exclude = true;\n> >\t\tif (pattern.startsWith(\"!)) {\n> >\t\t\tpattern = pattern.substring(1);\n> >\t\t\texclude = false;\n> >\t\t}\n>\n> If I remember correctly Intellij IDEA marks per default cases where you \n> change a parameter. So it looks like that there are style guides which \n> are against the practice of changing the values of parameters.\n\nYes, there are style guides floating around that say \"do not\nmodify parameters\".  There is also a Java keyword that means\n\"do not modify this variable in scope\", its called \"final\".\n\nPersonally I think whether or not something should be final in\na scope depends on the size of the scope and what is clearer to\nread to modify the existing variable, or to introduce a copy with a\ndifferent name and a potentially different value.  Forcing everything\nto not modify parameters by compiler edict is nuts.\n\nIn the code I was talking about you had two different variables\nfor the pattern, just to avoid not modifying the parameter.\nYet within the scope of the method once the \"!\" is cut off the\noriginal pattern string is worthless.  In my very humble opinion\nit is more risky to have two different variables (one whose scope\nhas expired the moment the method starts and one that is useful)\nthen to have a mutable parameter.\n\nBut as I said, its only my humble opinion.  Since I'm American my\n$0.02 is worth what, 0.00000002 rupees these days?  ;-)\n \n> I implemented it that way, becasue git behave the same way:\n> * create the follwing file: a/a/b/test.txt\n> * add the line \"a/b\" to .gitignore\n> * add a and notice that it adds the test.txt file.\n\nOK.  You are correct.  If the ignore rule contains \"/\" it appears\nto only apply from the top level of the repository.  That wasn't\nmy understanding of how it worked, but I stand corrected.  Thank you.\n\n-- \nShawn.\n"},{"id":"76905","messageId":"20080514014902.GL29038@spearce.org","threadId":"13496","inReplyTo":"200805132255.46363.robin.rosenberg.lists@dewire.com","subject":"Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-14T01:49:02Z","receivedAt":"2008-05-14T01:49:02Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> tisdagen den 13 maj 2008 13.24.56 skrev Florian Köberle:\n> > \n> > Still I think that the behavior of git-add is strange:\n> > For example, if you want to add the following file:\n> > a/b/c/test.txt\n> > Then I can do this with \"a/\\*.txt\" or \"a/b\\*.txt\" but not with \n> > \"a/\\*/c/test.txt\"\n...\n> Correctness is very important. Obviously we will slip bugs trough, but\n> not intentionally in a part where legacy behaviour may play an important\n> role. With these options available I'd select number 2.\n> \n> I think your observations are interesting, especially the one you make\n> here about a/*/c/test.txt not matching because I don't see from the git\n> add manual why it shouldn't. I does not look like a recent git bug either. \n\nWow.  The behavior of git-add makes _no_ sense to me.\n\n  $ git init\n  $ mkdir -p a/b/c; touch a/b/c/test.txt\n  $ find a\n  a\n  a/b\n  a/b/c\n  a/b/c/test.txt\n\n  $ git add 'a/*/test.txt'\n  fatal: pathspec 'a/*/test.txt' did not match any files\n\n(sure, ok, even my shell agrees)\n\n  $ git add 'a/*/c/test.txt'\n  fatal: pathspec 'a/*/c/test.txt' did not match any files\n\n  $ ls a/*/c/test.txt\n  a/b/c/test.txt\n\n(hmm, now my shell says otherwise)\n\n  $ git add 'a/b*/c/test.txt'\n  fatal: pathspec 'a/b*/c/test.txt' did not match any files\n\n  $ ls a/b*/c/test.txt\n  a/b/c/test.txt\n\n(also odd)\n\nThis last case does match with fnmatch:\n\n  $ cat fnmatch.c \n  #include <fnmatch.h>\n  #include <stdio.h>\n  \n  int main (int argc, char *argv[]) {\n  \tconst char *name = argv[1];\n  \tconst char *patt = argv[2];\n  \tprintf(\"\\\"%s\\\" matches \\\"%s\\\" = %d\\n\",\n  \t\tname, patt,\n  \t\tfnmatch(patt, name, 0));\n  \treturn 0;\n  }\n\n  $ gcc -o fnmatch fnmatch.c\n  $ ./fnmatch a/b/c/test.txt 'a/b*/c/test.txt'\n  \"a/b/c/test.txt\" matches \"a/b*/c/test.txt\" = 0\n\nSo I find it odd that git-add does not match this name, but fnmatch\ndoes.  I suspect the problem here is git-add has pruned away the\nsubdirectory \"a/b\" and did not enter into it, so the pattern was\nnever even given a chance to look at test.txt.  This sounds like\na bug to me in git's working directory filter.\n\nEven if Linus says matching names incorrectly is not a bug, I'm\nnot sure its an implementation detail we should mirror in jgit.\n\nWhere does that leave us?  I'm not sure.  But treating git-add as\na black box and replicating its behavior looks loony to me right now.\n\n-- \nShawn.\n"},{"id":"76945","messageId":"482AF6D2.6080800@gnu.org","threadId":"13496","inReplyTo":"1210623222-24908-22-git-send-email-florianskarten@web.de","subject":"Re: [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it.","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2008-05-14T14:27:30Z","receivedAt":"2008-05-14T14:27:30Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> +\tvoid findMorePathesIfNessesary() {\n> +\tvoid findMorePathes\n\nfindMorePaths. :-)\n\nPaolo\n"},{"id":"77559","messageId":"4836E6E2.20406@web.de","threadId":"13496","inReplyTo":"20080512235431.GY29038@spearce.org","subject":"Re: [JGIT PATCH v2 04/24] Added path related constats to Constats class.","fromName":"Florian Köberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-23T15:46:42Z","receivedAt":"2008-05-23T15:46:42Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":"Shawn O. Pearce wrote:\n> Florian Koeberle <florianskarten@web.de> wrote:\n>> @@ -171,6 +171,26 @@ public final class Constants {\n>>  \tpublic static String REMOTES_PREFIX = \"refs/remotes\";\n>>  \n>>  \t/**\n>> +\t * The name of the repository directory in the project directory.\n>> +\t */\n>> +\tpublic static final String REPOSITORY_DIRECTORY_NAME = \".git\";\n> \n> What is a project directory?\nI will add a sentence describing what I meant with project directory here.\n\n\n\n>> +\t/**\n>> +\t * Contains the name of the HEAD file in the repository directory.\n>> +\t */\n>> +\tpublic static final String HEAD_FILE_NAME = \"HEAD\";\n> \n> Isn't this already declared as just HEAD?  Lets not duplicate\n> constants if we can avoid it, especially when they are in the\n> same class.\n>\ncurrent HEAD constant definition:\n > \t/** Special name for the \"HEAD\" symbolic-ref. */\n >\tpublic static final String HEAD = \"HEAD\";\nI didn't expect that this constant is a file name.\n\nLooks like the constant is used in the same way I do, so It makes sense \nto use the existing HEAD constant.\n"},{"id":"77566","messageId":"4837090F.4000307@web.de","threadId":"13496","inReplyTo":"20080513002409.GC29038@spearce.org","subject":"Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.","fromName":"Florian Köberle","fromEmail":"florianskarten@web.de","sentAt":"2008-05-23T18:12:31Z","receivedAt":"2008-05-23T18:12:31Z","isPatch":true,"sender":{"key":"florianskarten@web.de","avatar":null},"body":">> +\t * \n>> +\t * @param directory\n>> +\t *            the path which should be checked.\n>> +\t * @return true if the path is a valid git repository.\n>> +\t */\n>> +\tprivate static boolean isRepository(File directory) {\n>> +\t\tif (!directory.isDirectory()) {\n>> +\t\t\treturn false;\n>> +\t\t}\n> \n> We usually omit { and } on simple conditions like this.  Its a coding\n> pattern we stole from C Git, which stole it from the Linux kernel.\n\nI used this style once too, but was convinced that it dangerous to do so.\n\nThe following looks correct at the first look, but it's not:\n\n\tif (a)\n\t\tif (b)\n\t\t\tsomething;\n\telse\n\t\tsomething;\n\nthis can't happen if you use { and }:\n\tif (a) {\n\t\tif (b) {\n\t\t\tsomething0();\n\t\t}\n\t} else {\n\t\tsomething1();\n\t}\n\n\nAlso it is better extenable:\n\nif (a) {\n\tsomething0();\n}\n\nif (a) {\n\tsomething0():\n+\tsomething1();\n}\n\ncompared too:\n\n-if (a)\n+if (a) {\n\tsomething0();\n+\tsomething1();\n+ }\n\n\nit's even possible that someone does it wrong:\nif (a)\n\tsomething0():\n\tsomething1();\n\nI changed it at placed I edited to the short form, but if it is ok for \nyou then I would write it the long way.\n\n> \n>> +\tprivate static WorkTree findWorkTree(File directory) throws IOException {\n>> +\t\tFile currentDirectory = directory.getAbsoluteFile();\n>> +\t\twhile (true) {\n>> +\t\t\tfinal File commonGitDirectory = new File(directory,\n>> +\t\t\t\t\tREPOSITORY_DIRECTORY_NAME);\n>> +\t\t\tif (isRepository(commonGitDirectory)) {\n>> +\t\t\t\treturn new WorkTree(currentDirectory, new Repository(\n>> +\t\t\t\t\t\tcommonGitDirectory));\n>> +\t\t\t}\n>> +\n>> +\t\t\tif (isRepository(currentDirectory)) {\n>> +\t\t\t\treturn new WorkTree(null, new Repository(currentDirectory));\n>> +\t\t\t}\n>> +\t\t\tcurrentDirectory = currentDirectory.getParentFile();\n>> +\t\t\tif (currentDirectory == null) {\n>> +\t\t\t\tthrow new IOException(\"Can't find git repository\");\n>> +\t\t\t}\n>> +\t\t}\n> \n> Would this perhaps be a shorter, easier to follow variant of the\n> same algorithm?\n> \n> \tdirectory = directory.getAbsoluteFile();\n> \tFile workdir = directory;\n> \twhile (workdir != null) {\n> \t\tfinal File gitdir = new File(workdir, REPOSITORY_DIRECTORY_NAME);\n> \t\tif (isRepository(gitdir))\n> \t\t\treturn new WorkTree(workdir, new Repository(gitdir));\n> \t\tif (isRepository(workdir))\n> \t\t\treturn new WorkTree(null, new Repository(workdir));\n> \t\tworkdir = workdir.getParentFile();\n> \t}\n> \tthrow new NoGitRepositoryFoundException(\"No repository for \" + directory);\n> \n\nI did it this way now, but the line length limit makes it harder to read \nthen my first version.\n"},{"id":"77568","messageId":"20080523183151.GT27724@genesis.frugalware.org","threadId":"13496","inReplyTo":"4837090F.4000307@web.de","subject":"Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-23T18:31:51Z","receivedAt":"2008-05-23T18:31:51Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Fri, May 23, 2008 at 08:12:31PM +0200, Florian Köberle <FloriansKarten@web.de> wrote:\n> Also it is better extenable:\n> \n> if (a) {\n> \tsomething0();\n> }\n> \n> if (a) {\n> \tsomething0():\n> +\tsomething1();\n> }\n> \n> compared too:\n> \n> -if (a)\n> +if (a) {\n> \tsomething0();\n> +\tsomething1();\n> + }\n> \n> \n> it's even possible that someone does it wrong:\n> if (a)\n> \tsomething0():\n> \tsomething1();\n\nDifferent programmers have different coding style. A standard is needed,\notherwise different parts of the code will have different style. It's\nquite normal if a contributor has to code in the project's coding style,\nrather than his own one, I think.\n\nAlso I don't think \"but this style is confusing for newbies\" is a valid\nargument, newbies should learn to read code, rather than others need to\nwrite newbie-friendly code. ;-)\n"},{"id":"77599","messageId":"20080523203930.GV29038@spearce.org","threadId":"13496","inReplyTo":"20080523183151.GT27724@genesis.frugalware.org","subject":"Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-23T20:39:30Z","receivedAt":"2008-05-23T20:39:30Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Miklos Vajna <vmiklos@frugalware.org> wrote:\n> On Fri, May 23, 2008 at 08:12:31PM +0200, Florian Köberle <FloriansKarten@web.de> wrote:\n> > Also it is better extenable:\n...\n> > if (a) {\n> > \tsomething0():\n> > +\tsomething1();\n> > }\n> > \n> > compared too:\n> > \n> > -if (a)\n> > +if (a) {\n> > \tsomething0();\n> > +\tsomething1();\n> > + }\n> \n> Different programmers have different coding style. A standard is needed,\n> otherwise different parts of the code will have different style. It's\n> quite normal if a contributor has to code in the project's coding style,\n> rather than his own one, I think.\n> \n> Also I don't think \"but this style is confusing for newbies\" is a valid\n> argument, newbies should learn to read code, rather than others need to\n> write newbie-friendly code. ;-)\n\nRight.\n\nBasically Robin and I have settled on a style not too far from the\none that git.git itself uses, at least where they could pertain to\nJava and its semi-C syntax rules.  Part of the reason is because\nwe (and others in the git community) are just used to this style.\n\nIts shorter vertically, allowing more room for code and comments in\na single screen full.  It also minimizes the number of places where\n\"\\t\\t}\\n\" appear on a line by itself in the context of a patch,\nreducing errors from patch hunks applying in the wrong position.\n\nIn a little over a month and a half I start a new job.  My new\nemployer apparently has really strict rules about how code should\nbe formatted, and everyone in the company has to adhere to them.\nNo exceptions.  The rules are supposedly quite strange, but the\nentire code is at least consistent, and thus easier to follow.\nSo yea, I get to also go through some strange style thing soon.\n\nWhen in Rome, do as the Romans do... :-|\n\n-- \nShawn.\n"},{"id":"77602","messageId":"200805232328.33666.robin.rosenberg.lists@dewire.com","threadId":"13496","inReplyTo":"4837090F.4000307@web.de","subject":"Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2008-05-23T21:28:33Z","receivedAt":"2008-05-23T21:28:33Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"fredagen den 23 maj 2008 20.12.31 skrev Florian Köberle:\n> >> +\t * \n> >> +\t * @param directory\n> >> +\t *            the path which should be checked.\n> >> +\t * @return true if the path is a valid git repository.\n> >> +\t */\n> >> +\tprivate static boolean isRepository(File directory) {\n> >> +\t\tif (!directory.isDirectory()) {\n> >> +\t\t\treturn false;\n> >> +\t\t}\n> > \n> > We usually omit { and } on simple conditions like this.  Its a coding\n> > pattern we stole from C Git, which stole it from the Linux kernel.\n> \n> I used this style once too, but was convinced that it dangerous to do so.\nAs Shawn said, usually. Sometimes we slip too.  But it is unnecessary and\nanything unnecessary usually makes code harder to read. It is not a big\ndeal to me. \n\n> The following looks correct at the first look, but it's not:\n> \n> \tif (a)\n> \t\tif (b)\n> \t\t\tsomething;\n> \telse\n> \t\tsomething;\n> \n> this can't happen if you use { and }:\n> \tif (a) {\n> \t\tif (b) {\n> \t\t\tsomething0();\n> \t\t}\n> \t} else {\n> \t\tsomething1();\n> \t}\n\nThis isn't the same case, because here we have nested statements, I do think braces should be used here. Java shouldn't even allow \"ambigous\" syntax like this (first case).\n\n> Also it is better extenable:\n> \n> if (a) {\n> \tsomething0();\n> }\n> \n> if (a) {\n> \tsomething0():\n> +\tsomething1();\n> }\n\nWhich is why I think is not that big a deal.  The main reason I may leave braces on a non-nested simple statement is becuase I had a debug statement or something like that there, and I might well want to have one again temporarily. Toggling braces on and off (even with eclipse where it requires two-four keypresses) are annoying.\n\n-- robin\n"}]}