git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules.
@ 2008-05-12 20:13 Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 01/24] Start of an implementation of a git like command line tool Florian Koeberle
                   ` (24 more replies)
  0 siblings, 25 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git


Hi

I improved the patches from last time.

That are the changes to the previos patches:
* Removed @author javadoc
* Moved iteration code into the treewalk package
* Moved code around the Rules class into a new treewalk.rules package
* Added newlines to some files
* Removed (hopefully) the trailing whitespaces using the eclipse save actions.
* Renamed Project into WorkTree
* Moved the methods from ProjectSeeker and ProjectFactory into Repository and made them static.
* Moved the constants into the Constants class.
* Renamed my FileTreeIterator into LightFileTreeIterator in order to avoid nameconflict, as they are now in th
e same package.
* Renamed StarPattern into FNMatchPattern, improved it, and moved it into the lib package.
* Improved the javadoc.
* 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.

Maybe I missed something... I would need some patch-tree version control system which tracks changes in the patch tree ;).

Best regards,
Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 01/24] Start of an implementation of a git like command line tool.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 02/24] Formatted Repository class Florian Koeberle
                   ` (23 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Only the "help" command is currenly supported, but it is extendable.

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/pgm/Command.java          |   44 ++++++++
 .../src/org/spearce/jgit/pgm/MainProgram.java      |  114 ++++++++++++++++++++
 2 files changed, 158 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java
new file mode 100644
index 0000000..a05f707
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Command.java
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.pgm;
+
+import java.io.IOException;
+
+/**
+ * A command have tasks like the "git-add", "git-help" or "git-init" console
+ * commands. Instances of ${link Command} must be immutable.
+ * 
+ */
+public interface Command {
+	/**
+	 * Executes the specified Command.
+	 * 
+	 * @param args
+	 *            the arguments which you would pass to the console equivalent
+	 *            of the command.
+	 * @throws IOException
+	 *             for some undefined reasons.
+	 */
+	public void execute(String... args) throws IOException;
+
+	/**
+	 * 
+	 * @return a short description about what the command does. Short means in
+	 *         this context 5 - 10 words.
+	 */
+	public String getShortDescription();
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
new file mode 100644
index 0000000..c9af51c
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
@@ -0,0 +1,114 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.pgm;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * A program which works similar like the command git, except that very view
+ * arguments are supported jet.
+ * 
+ */
+public class MainProgram {
+	private final static Map<String, Command> commandNameToObjectMap;
+
+	static {
+		final Map<String, Command> commands = new HashMap<String, Command>();
+		commands.put("help", HelpCommand.INSTANCE);
+		commandNameToObjectMap = Collections.unmodifiableMap(commands);
+	}
+
+	/**
+	 * Executes a command with some arguments. There are commands for creating
+	 * git repositories, tracking files, etc.
+	 * 
+	 * @param args
+	 *            The first argument specifies the command which should be
+	 *            executed. The other arguments are passed to the command.
+	 * @throws IOException
+	 *             for some reasons.
+	 */
+	public static void main(String[] args) throws IOException {
+		try {
+			if (args.length == 0) {
+				throw new WrongCallException("Require one argument!");
+			}
+			final Command command = commandNameToObjectMap.get(args[0]);
+			if (command == null) {
+				throw new WrongCallException("Require one argument!");
+			}
+
+			final String[] commandArguments = new String[args.length - 1];
+			System.arraycopy(args, 1, commandArguments, 0,
+					commandArguments.length);
+
+			command.execute(commandArguments);
+
+		} catch (WrongCallException e) {
+			System.err.println(e.getMessage());
+			System.err.println();
+			HelpCommand.INSTANCE.execute();
+			System.exit(1);
+		}
+	}
+
+	private static class WrongCallException extends Exception {
+		private static final long serialVersionUID = 3643362832429311084L;
+
+		WrongCallException(String message) {
+			super(message);
+		}
+	}
+
+	private static class HelpCommand implements Command {
+		/**
+		 * Use this instance instead of creating a new ${link HelpCommand}. You
+		 * don't need to create an instance of this class as it is immutable and
+		 * not configurable.
+		 */
+		public static HelpCommand INSTANCE = new HelpCommand();
+
+		public void execute(String... args) throws IOException {
+			System.out
+					.println("Call this program with the following arguments:");
+			System.out
+					.println("commandName commandArgument0 commandArgument1 ...");
+			System.out.println();
+			System.out
+					.println("Currently the following commands are supported:");
+			final SortedMap<String, Command> sortedCommandMap = new TreeMap<String, Command>(
+					MainProgram.commandNameToObjectMap);
+			for (Map.Entry<String, Command> commandEntry : sortedCommandMap
+					.entrySet()) {
+				final String commandName = commandEntry.getKey();
+				final String commandDescription = commandEntry.getValue()
+						.getShortDescription();
+				System.out.printf("%#10s - %s%n", commandName,
+						commandDescription);
+			}
+		}
+
+		public String getShortDescription() {
+			return "Displays some text about how to use this program.";
+		}
+	}
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 02/24] Formatted Repository class.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 01/24] Start of an implementation of a git like command line tool Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 03/24] Formatted Constats class Florian Koeberle
                   ` (22 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/lib/Repository.java       |  372 +++++++++++---------
 1 files changed, 208 insertions(+), 164 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 455a68e..44fd81b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -38,28 +38,30 @@ import org.spearce.jgit.util.FS;
  * Represents a Git repository. A repository holds all objects and refs used for
  * managing source code (could by any type of file, but source code is what
  * SCM's are typically used for).
- *
+ * 
  * In Git terms all data is stored in GIT_DIR, typically a directory called
  * .git. A work tree is maintained unless the repository is a bare repository.
  * Typically the .git directory is located at the root of the work dir.
- *
+ * 
  * <ul>
  * <li>GIT_DIR
- * 	<ul>
- * 		<li>objects/ - objects</li>
- * 		<li>refs/ - tags and heads</li>
- * 		<li>config - configuration</li>
- * 		<li>info/ - more configurations</li>
- * 	</ul>
+ * <ul>
+ * <li>objects/ - objects</li>
+ * <li>refs/ - tags and heads</li>
+ * <li>config - configuration</li>
+ * <li>info/ - more configurations</li>
+ * </ul>
  * </li>
  * </ul>
- *
- * This implementation only handles a subtly undocumented subset of git features.
- *
+ * 
+ * This implementation only handles a subtly undocumented subset of git
+ * features.
+ * 
  */
 public class Repository {
 	private static final String[] refSearchPaths = { "", "refs/", "refs/tags/",
-		Constants.HEADS_PREFIX + "/", "refs/" + Constants.REMOTES_PREFIX + "/" };
+			Constants.HEADS_PREFIX + "/",
+			"refs/" + Constants.REMOTES_PREFIX + "/" };
 
 	private final File gitDir;
 
@@ -79,7 +81,7 @@ public class Repository {
 
 	/**
 	 * Construct a representation of this git repo managing a Git repository.
-	 *
+	 * 
 	 * @param d
 	 *            GIT_DIR
 	 * @throws IOException
@@ -108,7 +110,8 @@ public class Repository {
 			objectsDirs = readObjectsDirs(FS.resolve(gitDir, "objects"),
 					new ArrayList<File>()).toArray(new File[0]);
 		} catch (IOException e) {
-			IOException ex = new IOException("Cannot find all object dirs for " + gitDir);
+			IOException ex = new IOException("Cannot find all object dirs for "
+					+ gitDir);
 			ex.initCause(e);
 			throw ex;
 		}
@@ -134,12 +137,13 @@ public class Repository {
 			scanForPacks();
 	}
 
-	private Collection<File> readObjectsDirs(File objectsDir, Collection<File> ret) throws IOException {
+	private Collection<File> readObjectsDirs(File objectsDir,
+			Collection<File> ret) throws IOException {
 		ret.add(objectsDir);
 		final File altFile = FS.resolve(objectsDir, "info/alternates");
 		if (altFile.exists()) {
 			BufferedReader ar = new BufferedReader(new FileReader(altFile));
-			for (String alt=ar.readLine(); alt!=null; alt=ar.readLine()) {
+			for (String alt = ar.readLine(); alt != null; alt = ar.readLine()) {
 				readObjectsDirs(FS.resolve(objectsDir, alt), ret);
 			}
 			ar.close();
@@ -150,7 +154,7 @@ public class Repository {
 	/**
 	 * Create a new Git repository initializing the necessary files and
 	 * directories.
-	 *
+	 * 
 	 * @throws IOException
 	 */
 	public void create() throws IOException {
@@ -211,15 +215,15 @@ public class Repository {
 	 * to the alternative repo will be returned. If the object is not yet store
 	 * a usable path in this repo will be returned. It is assumed that callers
 	 * will look for objects in a pack first.
-	 *
+	 * 
 	 * @param objectId
 	 * @return suggested file name
 	 */
 	public File toFile(final AnyObjectId objectId) {
 		final String n = objectId.toString();
-		String d=n.substring(0, 2);
-		String f=n.substring(2);
-		for (int i=0; i<objectsDirs.length; ++i) {
+		String d = n.substring(0, 2);
+		String f = n.substring(2);
+		for (int i = 0; i < objectsDirs.length; ++i) {
 			File ret = new File(new File(objectsDirs[i], d), f);
 			if (ret.exists())
 				return ret;
@@ -251,9 +255,8 @@ public class Repository {
 	 *         object, or null if the object does not exist.
 	 * @throws IOException
 	 */
-	public ObjectLoader openObject(final AnyObjectId id)
-			throws IOException {
-		return openObject(new WindowCursor(),id);
+	public ObjectLoader openObject(final AnyObjectId id) throws IOException {
+		return openObject(new WindowCursor(), id);
 	}
 
 	/**
@@ -279,7 +282,8 @@ public class Repository {
 					// This shouldn't happen unless the pack was corrupted
 					// after we opened it or the VM runs out of memory. This is
 					// a know problem with memory mapped I/O in java and have
-					// been noticed with JDK < 1.6. Tell the gc that now is a good
+					// been noticed with JDK < 1.6. Tell the gc that now is a
+					// good
 					// time to collect and try once more.
 					try {
 						curs.release();
@@ -325,14 +329,16 @@ public class Repository {
 	}
 
 	/**
-	 * Access a Commit object using a symbolic reference. This reference may
-	 * be a SHA-1 or ref in combination with a number of symbols translating
-	 * from one ref or SHA1-1 to another, such as HEAD^ etc.
-	 *
-	 * @param revstr a reference to a git commit object
+	 * Access a Commit object using a symbolic reference. This reference may be
+	 * a SHA-1 or ref in combination with a number of symbols translating from
+	 * one ref or SHA1-1 to another, such as HEAD^ etc.
+	 * 
+	 * @param revstr
+	 *            a reference to a git commit object
 	 * @return a Commit named by the specified string
-	 * @throws IOException for I/O error or unexpected object type.
-	 *
+	 * @throws IOException
+	 *             for I/O error or unexpected object type.
+	 * 
 	 * @see #resolve(String)
 	 */
 	public Commit mapCommit(final String revstr) throws IOException {
@@ -342,14 +348,16 @@ public class Repository {
 
 	/**
 	 * Access any type of Git object by id and
-	 *
+	 * 
 	 * @param id
 	 *            SHA-1 of object to read
-	 * @param refName optional, only relevant for simple tags
+	 * @param refName
+	 *            optional, only relevant for simple tags
 	 * @return The Git object if found or null
 	 * @throws IOException
 	 */
-	public Object mapObject(final ObjectId id, final String refName) throws IOException {
+	public Object mapObject(final ObjectId id, final String refName)
+			throws IOException {
 		final ObjectLoader or = openObject(id);
 		final byte[] raw = or.getBytes();
 		if (or.getType() == Constants.OBJ_TREE)
@@ -365,9 +373,11 @@ public class Repository {
 
 	/**
 	 * Access a Commit by SHA'1 id.
+	 * 
 	 * @param id
 	 * @return Commit or null
-	 * @throws IOException for I/O error or unexpected object type.
+	 * @throws IOException
+	 *             for I/O error or unexpected object type.
 	 */
 	public Commit mapCommit(final ObjectId id) throws IOException {
 		final ObjectLoader or = openObject(id);
@@ -385,14 +395,15 @@ public class Repository {
 	}
 
 	/**
-	 * Access a Tree object using a symbolic reference. This reference may
-	 * be a SHA-1 or ref in combination with a number of symbols translating
-	 * from one ref or SHA1-1 to another, such as HEAD^{tree} etc.
-	 *
-	 * @param revstr a reference to a git commit object
+	 * Access a Tree object using a symbolic reference. This reference may be a
+	 * SHA-1 or ref in combination with a number of symbols translating from one
+	 * ref or SHA1-1 to another, such as HEAD^{tree} etc.
+	 * 
+	 * @param revstr
+	 *            a reference to a git commit object
 	 * @return a Tree named by the specified string
 	 * @throws IOException
-	 *
+	 * 
 	 * @see #resolve(String)
 	 */
 	public Tree mapTree(final String revstr) throws IOException {
@@ -402,9 +413,11 @@ public class Repository {
 
 	/**
 	 * Access a Tree by SHA'1 id.
+	 * 
 	 * @param id
 	 * @return Tree or null
-	 * @throws IOException for I/O error or unexpected object type.
+	 * @throws IOException
+	 *             for I/O error or unexpected object type.
 	 */
 	public Tree mapTree(final ObjectId id) throws IOException {
 		final ObjectLoader or = openObject(id);
@@ -419,22 +432,25 @@ public class Repository {
 		throw new IncorrectObjectTypeException(id, Constants.TYPE_TREE);
 	}
 
-	private Tree makeTree(final ObjectId id, final byte[] raw) throws IOException {
+	private Tree makeTree(final ObjectId id, final byte[] raw)
+			throws IOException {
 		Tree ret = new Tree(this, id, raw);
 		return ret;
 	}
 
-	private Tag makeTag(final ObjectId id, final String refName, final byte[] raw) {
+	private Tag makeTag(final ObjectId id, final String refName,
+			final byte[] raw) {
 		Tag ret = new Tag(this, id, refName, raw);
 		return ret;
 	}
 
 	/**
 	 * Access a tag by symbolic name.
-	 *
+	 * 
 	 * @param revstr
 	 * @return a Tag or null
-	 * @throws IOException on I/O error or unexpected type
+	 * @throws IOException
+	 *             on I/O error or unexpected type
 	 */
 	public Tag mapTag(String revstr) throws IOException {
 		final ObjectId id = resolve(revstr);
@@ -443,12 +459,15 @@ public class Repository {
 
 	/**
 	 * Access a Tag by SHA'1 id
+	 * 
 	 * @param refName
 	 * @param id
 	 * @return Commit or null
-	 * @throws IOException for I/O error or unexpected object type.
+	 * @throws IOException
+	 *             for I/O error or unexpected object type.
 	 */
-	public Tag mapTag(final String refName, final ObjectId id) throws IOException {
+	public Tag mapTag(final String refName, final ObjectId id)
+			throws IOException {
 		final ObjectLoader or = openObject(id);
 		if (or == null)
 			return null;
@@ -460,8 +479,9 @@ public class Repository {
 
 	/**
 	 * Get a locked handle to a ref suitable for updating or creating.
-	 *
-	 * @param ref name to lock
+	 * 
+	 * @param ref
+	 *            name to lock
 	 * @return a locked ref
 	 * @throws IOException
 	 */
@@ -473,27 +493,29 @@ public class Repository {
 
 	/**
 	 * Parse a git revision string and return an object id.
-	 *
+	 * 
 	 * Currently supported is combinations of these.
 	 * <ul>
-	 *  <li>SHA-1 - a SHA-1</li>
-	 *  <li>refs/... - a ref name</li>
-	 *  <li>ref^n - nth parent reference</li>
-	 *  <li>ref~n - distance via parent reference</li>
-	 *  <li>ref@{n} - nth version of ref</li>
-	 *  <li>ref^{tree} - tree references by ref</li>
-	 *  <li>ref^{commit} - commit references by ref</li>
+	 * <li>SHA-1 - a SHA-1</li>
+	 * <li>refs/... - a ref name</li>
+	 * <li>ref^n - nth parent reference</li>
+	 * <li>ref~n - distance via parent reference</li>
+	 * <li>ref@{n} - nth version of ref</li>
+	 * <li>ref^{tree} - tree references by ref</li>
+	 * <li>ref^{commit} - commit references by ref</li>
 	 * </ul>
-	 *
+	 * 
 	 * Not supported is
 	 * <ul>
 	 * <li>timestamps in reflogs, ref@{full or relative timestamp}</li>
 	 * <li>abbreviated SHA-1's</li>
 	 * </ul>
-	 *
-	 * @param revstr A git object references expression
+	 * 
+	 * @param revstr
+	 *            A git object references expression
 	 * @return an ObjectId
-	 * @throws IOException on serious errors
+	 * @throws IOException
+	 *             on serious errors
 	 */
 	public ObjectId resolve(final String revstr) throws IOException {
 		char[] rev = revstr.toCharArray();
@@ -503,7 +525,7 @@ public class Repository {
 			switch (rev[i]) {
 			case '^':
 				if (refId == null) {
-					String refstr = new String(rev,0,i);
+					String refstr = new String(rev, 0, i);
 					refId = resolveSimple(refstr);
 					if (refId == null)
 						return null;
@@ -523,23 +545,24 @@ public class Repository {
 						int j;
 						ref = mapObject(refId, null);
 						if (!(ref instanceof Commit))
-							throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
-						for (j=i+1; j<rev.length; ++j) {
+							throw new IncorrectObjectTypeException(refId,
+									Constants.TYPE_COMMIT);
+						for (j = i + 1; j < rev.length; ++j) {
 							if (!Character.isDigit(rev[j]))
 								break;
 						}
-						String parentnum = new String(rev, i+1, j-i-1);
+						String parentnum = new String(rev, i + 1, j - i - 1);
 						int pnum = Integer.parseInt(parentnum);
 						if (pnum != 0)
-							refId = ((Commit)ref).getParentIds()[pnum - 1];
+							refId = ((Commit) ref).getParentIds()[pnum - 1];
 						i = j - 1;
 						break;
 					case '{':
 						int k;
 						String item = null;
-						for (k=i+2; k<rev.length; ++k) {
+						for (k = i + 2; k < rev.length; ++k) {
 							if (rev[k] == '}') {
-								item = new String(rev, i+2, k-i-2);
+								item = new String(rev, i + 2, k - i - 2);
 								break;
 							}
 						}
@@ -548,44 +571,43 @@ public class Repository {
 							if (item.equals("tree")) {
 								ref = mapObject(refId, null);
 								while (ref instanceof Tag) {
-									Tag t = (Tag)ref;
+									Tag t = (Tag) ref;
 									refId = t.getObjId();
 									ref = mapObject(refId, null);
 								}
 								if (ref instanceof Treeish)
-									refId = ((Treeish)ref).getTreeId();
+									refId = ((Treeish) ref).getTreeId();
 								else
-									throw new IncorrectObjectTypeException(refId,  Constants.TYPE_TREE);
-							}
-							else if (item.equals("commit")) {
+									throw new IncorrectObjectTypeException(
+											refId, Constants.TYPE_TREE);
+							} else if (item.equals("commit")) {
 								ref = mapObject(refId, null);
 								while (ref instanceof Tag) {
-									Tag t = (Tag)ref;
+									Tag t = (Tag) ref;
 									refId = t.getObjId();
 									ref = mapObject(refId, null);
 								}
 								if (!(ref instanceof Commit))
-									throw new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);
-							}
-							else if (item.equals("blob")) {
+									throw new IncorrectObjectTypeException(
+											refId, Constants.TYPE_COMMIT);
+							} else if (item.equals("blob")) {
 								ref = mapObject(refId, null);
 								while (ref instanceof Tag) {
-									Tag t = (Tag)ref;
+									Tag t = (Tag) ref;
 									refId = t.getObjId();
 									ref = mapObject(refId, null);
 								}
 								if (!(ref instanceof byte[]))
-									throw new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);
-							}
-							else if (item.equals("")) {
+									throw new IncorrectObjectTypeException(
+											refId, Constants.TYPE_COMMIT);
+							} else if (item.equals("")) {
 								ref = mapObject(refId, null);
 								if (ref instanceof Tag)
-									refId = ((Tag)ref).getObjId();
+									refId = ((Tag) ref).getObjId();
 								else {
 									// self
 								}
-							}
-							else
+							} else
 								throw new RevisionSyntaxException(revstr);
 						else
 							throw new RevisionSyntaxException(revstr);
@@ -593,22 +615,24 @@ public class Repository {
 					default:
 						ref = mapObject(refId, null);
 						if (ref instanceof Commit)
-							refId = ((Commit)ref).getParentIds()[0];
+							refId = ((Commit) ref).getParentIds()[0];
 						else
-							throw new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);
-						
+							throw new IncorrectObjectTypeException(refId,
+									Constants.TYPE_COMMIT);
+
 					}
 				} else {
 					ref = mapObject(refId, null);
 					if (ref instanceof Commit)
-						refId = ((Commit)ref).getParentIds()[0];
+						refId = ((Commit) ref).getParentIds()[0];
 					else
-						throw new IncorrectObjectTypeException(refId,  Constants.TYPE_COMMIT);
+						throw new IncorrectObjectTypeException(refId,
+								Constants.TYPE_COMMIT);
 				}
 				break;
 			case '~':
 				if (ref == null) {
-					String refstr = new String(rev,0,i);
+					String refstr = new String(rev, 0, i);
 					refId = resolveSimple(refstr);
 					ref = mapCommit(refId);
 				}
@@ -617,10 +641,10 @@ public class Repository {
 					if (!Character.isDigit(rev[l]))
 						break;
 				}
-				String distnum = new String(rev, i+1, l-i-1);
+				String distnum = new String(rev, i + 1, l - i - 1);
 				int dist = Integer.parseInt(distnum);
 				while (dist >= 0) {
-					refId = ((Commit)ref).getParentIds()[0];
+					refId = ((Commit) ref).getParentIds()[0];
 					ref = mapCommit(refId);
 					--dist;
 				}
@@ -629,14 +653,16 @@ public class Repository {
 			case '@':
 				int m;
 				String time = null;
-				for (m=i+2; m<rev.length; ++m) {
+				for (m = i + 2; m < rev.length; ++m) {
 					if (rev[m] == '}') {
-						time = new String(rev, i+2, m-i-2);
+						time = new String(rev, i + 2, m - i - 2);
 						break;
 					}
 				}
 				if (time != null)
-					throw new RevisionSyntaxException("reflogs not yet supported by revision parser yet", revstr);
+					throw new RevisionSyntaxException(
+							"reflogs not yet supported by revision parser yet",
+							revstr);
 				i = m - 1;
 				break;
 			default:
@@ -674,12 +700,11 @@ public class Repository {
 	}
 
 	/**
-	 * Scan the object dirs, including alternates for packs
-	 * to use.
+	 * Scan the object dirs, including alternates for packs to use.
 	 */
 	public void scanForPacks() {
 		final ArrayList<PackFile> p = new ArrayList<PackFile>();
-		for (int i=0; i<objectsDirs.length; ++i)
+		for (int i = 0; i < objectsDirs.length; ++i)
 			scanForPacks(new File(objectsDirs[i], "pack"), p);
 		final PackFile[] arr = new PackFile[p.size()];
 		p.toArray(arr);
@@ -710,14 +735,16 @@ public class Repository {
 		}
 	}
 
-    /**
-     * Writes a symref (e.g. HEAD) to disk
-     *
-     * @param name symref name
-     * @param target pointed to ref
-     * @throws IOException
-     */
-    public void writeSymref(final String name, final String target)
+	/**
+	 * Writes a symref (e.g. HEAD) to disk
+	 * 
+	 * @param name
+	 *            symref name
+	 * @param target
+	 *            pointed to ref
+	 * @throws IOException
+	 */
+	public void writeSymref(final String name, final String target)
 			throws IOException {
 		final byte[] content = ("ref: " + target + "\n").getBytes("UTF-8");
 		final LockFile lck = new LockFile(fileForRef(name));
@@ -754,7 +781,7 @@ public class Repository {
 				ObjectId id = packedRefs.get(name);
 				if (id != null)
 					return new Ref(name, id);
-				
+
 				// no packed ref found, return blank one
 				return new Ref(name, null);
 			}
@@ -792,12 +819,13 @@ public class Repository {
 	 * @throws IOException
 	 */
 	public String getPatch() throws IOException {
-		final File ptr = new File(getDirectory(),"patches/"+getBranch()+"/applied");
+		final File ptr = new File(getDirectory(), "patches/" + getBranch()
+				+ "/applied");
 		final BufferedReader br = new BufferedReader(new FileReader(ptr));
-		String last=null;
+		String last = null;
 		try {
 			String line;
-			while ((line=br.readLine())!=null) {
+			while ((line = br.readLine()) != null) {
 				last = line;
 			}
 		} finally {
@@ -811,7 +839,7 @@ public class Repository {
 	 * @throws IOException
 	 */
 	public String getFullBranch() throws IOException {
-		final File ptr = new File(getDirectory(),"HEAD");
+		final File ptr = new File(getDirectory(), "HEAD");
 		final BufferedReader br = new BufferedReader(new FileReader(ptr));
 		String ref;
 		try {
@@ -823,14 +851,14 @@ public class Repository {
 			ref = ref.substring(5);
 		return ref;
 	}
-	
+
 	/**
 	 * @return name of current branch.
 	 * @throws IOException
 	 */
 	public String getBranch() throws IOException {
 		try {
-			final File ptr = new File(getDirectory(),"HEAD");
+			final File ptr = new File(getDirectory(), "HEAD");
 			final BufferedReader br = new BufferedReader(new FileReader(ptr));
 			String ref;
 			try {
@@ -844,7 +872,7 @@ public class Repository {
 				ref = ref.substring(11);
 			return ref;
 		} catch (FileNotFoundException e) {
-			final File ptr = new File(getDirectory(),"head-name");
+			final File ptr = new File(getDirectory(), "head-name");
 			final BufferedReader br = new BufferedReader(new FileReader(ptr));
 			String ref;
 			try {
@@ -862,25 +890,27 @@ public class Repository {
 	public Collection<String> getBranches() {
 		return listRefs("heads");
 	}
-	
+
 	/**
 	 * @return the names of all refs (local and remotes branches, tags)
 	 */
 	public Collection<String> getAllRefs() {
 		return listRefs("");
 	}
-	
+
 	private Collection<String> listRefs(String refSubDir) {
 		// add / to end, unless empty
-		if (refSubDir.length() > 0 && refSubDir.charAt(refSubDir.length() -1 ) != '/')
+		if (refSubDir.length() > 0
+				&& refSubDir.charAt(refSubDir.length() - 1) != '/')
 			refSubDir += "/";
-		
-		Collection<String> branchesRaw = listFilesRecursively(new File(refsDir, refSubDir), null);
+
+		Collection<String> branchesRaw = listFilesRecursively(new File(refsDir,
+				refSubDir), null);
 		ArrayList<String> branches = new ArrayList<String>();
 		for (String b : branchesRaw) {
 			branches.add("refs/" + refSubDir + b);
 		}
-		
+
 		refreshPackedRefsCache();
 		Set<String> keySet = packedRefs.keySet();
 		for (String s : keySet)
@@ -896,22 +926,23 @@ public class Repository {
 		return listRefs("tags");
 	}
 
-	private Map<String,ObjectId> packedRefs = new HashMap<String,ObjectId>();
+	private Map<String, ObjectId> packedRefs = new HashMap<String, ObjectId>();
+
 	private long packedrefstime = 0;
 
 	private void refreshPackedRefsCache() {
 		if (!packedRefsFile.exists()) {
 			if (packedRefs.size() > 0)
-				packedRefs = new HashMap<String,ObjectId>();
+				packedRefs = new HashMap<String, ObjectId>();
 			return;
 		}
 		if (packedRefsFile.lastModified() == packedrefstime)
 			return;
-		Map<String,ObjectId> newPackedRefs = new HashMap<String,ObjectId>();
+		Map<String, ObjectId> newPackedRefs = new HashMap<String, ObjectId>();
 		FileReader fileReader = null;
 		try {
 			fileReader = new FileReader(packedRefsFile);
-			BufferedReader b=new BufferedReader(fileReader);
+			BufferedReader b = new BufferedReader(fileReader);
 			String p;
 			while ((p = b.readLine()) != null) {
 				if (p.charAt(0) == '#')
@@ -920,12 +951,12 @@ public class Repository {
 					continue;
 				}
 				int spos = p.indexOf(' ');
-				ObjectId id = ObjectId.fromString(p.substring(0,spos));
-				String name = p.substring(spos+1);
+				ObjectId id = ObjectId.fromString(p.substring(0, spos));
+				String name = p.substring(spos + 1);
 				newPackedRefs.put(name, id);
 			}
 		} catch (IOException e) {
-			throw new Error("Cannot read packed refs",e);
+			throw new Error("Cannot read packed refs", e);
 		} finally {
 			if (fileReader != null) {
 				try {
@@ -968,13 +999,17 @@ public class Repository {
 	 * @return applied patches in a map indexed on current commit id
 	 * @throws IOException
 	 */
-	public Map<ObjectId,StGitPatch> getAppliedPatches() throws IOException {
-		Map<ObjectId,StGitPatch> ret = new HashMap<ObjectId,StGitPatch>();
+	public Map<ObjectId, StGitPatch> getAppliedPatches() throws IOException {
+		Map<ObjectId, StGitPatch> ret = new HashMap<ObjectId, StGitPatch>();
 		if (isStGitMode()) {
-			File patchDir = new File(new File(getDirectory(),"patches"),getBranch());
-			BufferedReader apr = new BufferedReader(new FileReader(new File(patchDir,"applied")));
-			for (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {
-				File topFile = new File(new File(new File(patchDir,"patches"), patchName), "top");
+			File patchDir = new File(new File(getDirectory(), "patches"),
+					getBranch());
+			BufferedReader apr = new BufferedReader(new FileReader(new File(
+					patchDir, "applied")));
+			for (String patchName = apr.readLine(); patchName != null; patchName = apr
+					.readLine()) {
+				File topFile = new File(new File(new File(patchDir, "patches"),
+						patchName), "top");
 				BufferedReader tfr = new BufferedReader(new FileReader(topFile));
 				String objectId = tfr.readLine();
 				ObjectId id = ObjectId.fromString(objectId);
@@ -1004,7 +1039,7 @@ public class Repository {
 		}
 		return ret;
 	}
-	
+
 	/** Clean up stale caches */
 	public void refreshFromDisk() {
 		packedRefs = null;
@@ -1027,7 +1062,7 @@ public class Repository {
 	static byte[] gitInternalSlash(byte[] bytes) {
 		if (File.separatorChar == '/')
 			return bytes;
-		for (int i=0; i<bytes.length; ++i)
+		for (int i = 0; i < bytes.length; ++i)
 			if (bytes[i] == File.separatorChar)
 				bytes[i] = '/';
 		return bytes;
@@ -1039,32 +1074,32 @@ public class Repository {
 	public RepositoryState getRepositoryState() {
 		if (new File(getWorkDir(), ".dotest").exists())
 			return RepositoryState.REBASING;
-		if (new File(gitDir,".dotest-merge").exists())
+		if (new File(gitDir, ".dotest-merge").exists())
 			return RepositoryState.REBASING_INTERACTIVE;
-		if (new File(gitDir,"MERGE_HEAD").exists())
+		if (new File(gitDir, "MERGE_HEAD").exists())
 			return RepositoryState.MERGING;
-		if (new File(gitDir,"BISECT_LOG").exists())
+		if (new File(gitDir, "BISECT_LOG").exists())
 			return RepositoryState.BISECTING;
 		return RepositoryState.SAFE;
 	}
 
 	/**
-	 * Check validty of a ref name. It must not contain character that has
-	 * a special meaning in a Git object reference expression. Some other
+	 * Check validty of a ref name. It must not contain character that has a
+	 * special meaning in a Git object reference expression. Some other
 	 * dangerous characters are also excluded.
-	 *
+	 * 
 	 * @param refName
-	 *
+	 * 
 	 * @return true if refName is a valid ref name
 	 */
 	public static boolean isValidRefName(final String refName) {
 		final int len = refName.length();
 		char p = '\0';
-		for (int i=0; i<len; ++i) {
+		for (int i = 0; i < len; ++i) {
 			char c = refName.charAt(i);
 			if (c <= ' ')
 				return false;
-			switch(c) {
+			switch (c) {
 			case '.':
 				if (i == 0)
 					return false;
@@ -1076,11 +1111,14 @@ public class Repository {
 			case '/':
 				if (i == 0)
 					return false;
-				if (i == len -1)
+				if (i == len - 1)
 					return false;
 				break;
-			case '~': case '^': case ':':
-			case '?': case '[':
+			case '~':
+			case '^':
+			case ':':
+			case '?':
+			case '[':
 				return false;
 			case '*':
 				return false;
@@ -1092,9 +1130,11 @@ public class Repository {
 
 	/**
 	 * String work dir and return normalized repository path
-	 *
-	 * @param wd Work dir
-	 * @param f File whose path shall be stripp off it's workdir
+	 * 
+	 * @param wd
+	 *            Work dir
+	 * @param f
+	 *            File whose path shall be stripp off it's workdir
 	 * @return normalized repository relative path
 	 */
 	public static String stripWorkDir(File wd, File f) {
@@ -1109,9 +1149,11 @@ public class Repository {
 	 * @return information about how a remote repository is beging tracked
 	 */
 	public RemoteSpec getRemoteSpec(String name) {
-		String url = getConfig().getString("remote."+name, null, "url");
-		String fetchPattern = getConfig().getString("remote."+name, null, "fetch");
-		String pushPattern = getConfig().getString("remote."+name, null, "push");
+		String url = getConfig().getString("remote." + name, null, "url");
+		String fetchPattern = getConfig().getString("remote." + name, null,
+				"fetch");
+		String pushPattern = getConfig().getString("remote." + name, null,
+				"push");
 		return new RemoteSpec(name, url, fetchPattern, pushPattern);
 	}
 
@@ -1125,15 +1167,16 @@ public class Repository {
 	 * @param branch
 	 *            local branch name, e.g. "master"
 	 */
-	public void configureDefaultBranch(final String remote, final String url, final String branch) {
-		config.putString(RepositoryConfig.REMOTE_SECTION, remote, "url",
-				url);
-		config.putString(RepositoryConfig.REMOTE_SECTION, remote, "fetch",
-				"+" + Constants.HEADS_PREFIX + "/*:" + Constants.REMOTES_PREFIX + "/" + remote + "/*");
+	public void configureDefaultBranch(final String remote, final String url,
+			final String branch) {
+		config.putString(RepositoryConfig.REMOTE_SECTION, remote, "url", url);
+		config.putString(RepositoryConfig.REMOTE_SECTION, remote, "fetch", "+"
+				+ Constants.HEADS_PREFIX + "/*:" + Constants.REMOTES_PREFIX
+				+ "/" + remote + "/*");
 		config.putString(RepositoryConfig.BRANCH_SECTION, branch, "remote",
 				remote);
-		config.putString(RepositoryConfig.BRANCH_SECTION, Constants.MASTER, "merge",
-				Constants.HEADS_PREFIX + "/" + branch);
+		config.putString(RepositoryConfig.BRANCH_SECTION, Constants.MASTER,
+				"merge", Constants.HEADS_PREFIX + "/" + branch);
 	}
 
 	/**
@@ -1145,7 +1188,7 @@ public class Repository {
 
 	/**
 	 * Setup HEAD and "master" refs for a new repository.
-	 *
+	 * 
 	 * @param remoteBranch
 	 *            The remote branch to start with
 	 * @param branch
@@ -1154,7 +1197,8 @@ public class Repository {
 	 * @return the commit references by the new HEAD
 	 * @throws IOException
 	 */
-	public Commit setupHEADRef(final String remoteBranch, final String branch) throws IOException {
+	public Commit setupHEADRef(final String remoteBranch, final String branch)
+			throws IOException {
 		Commit mapCommit = mapCommit(remoteBranch);
 		String refName = Constants.HEADS_PREFIX + "/" + branch;
 		LockFile masterRef = lockRef(refName);
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 03/24] Formatted Constats class.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 01/24] Start of an implementation of a git like command line tool Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 02/24] Formatted Repository class Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 04/24] Added path related constats to " Florian Koeberle
                   ` (21 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/lib/Constants.java        |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java
index b8910e7..169c615 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java
@@ -190,8 +190,9 @@ public final class Constants {
 
 	/**
 	 * Convert an OBJ_* type constant to a TYPE_* type constant.
-	 *
-	 * @param typeCode the type code, from a pack representation.
+	 * 
+	 * @param typeCode
+	 *            the type code, from a pack representation.
 	 * @return the canonical string name of this type.
 	 */
 	public static String typeString(final int typeCode) {
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 04/24] Added path related constats to Constats class.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (2 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 03/24] Formatted Constats class Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 23:54   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository Florian Koeberle
                   ` (20 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/lib/Constants.java        |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java
index 169c615..13e09d8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Constants.java
@@ -171,6 +171,26 @@ public final class Constants {
 	public static String REMOTES_PREFIX = "refs/remotes";
 
 	/**
+	 * The name of the repository directory in the project directory.
+	 */
+	public static final String REPOSITORY_DIRECTORY_NAME = ".git";
+
+	/**
+	 * Contains the name of the objects directory in the repository directory.
+	 */
+	public static final String OBJECTS_DIRECTORY_NAME = "objects";
+
+	/**
+	 * Contains the name of the refs directory in the repository directory.
+	 */
+	public static final String REFS_DIRECTORY_NAME = "refs";
+
+	/**
+	 * Contains the name of the HEAD file in the repository directory.
+	 */
+	public static final String HEAD_FILE_NAME = "HEAD";
+
+	/**
 	 * Create a new digest function for objects.
 	 * 
 	 * @return a new digest object.
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (3 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 04/24] Added path related constats to " Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-13  0:04   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 06/24] Added a "init" command to the git like command line tool Florian Koeberle
                   ` (19 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

---
 .../src/org/spearce/jgit/lib/Repository.java       |   30 +++++++++
 .../src/org/spearce/jgit/lib/WorkTree.java         |   67 ++++++++++++++++++++
 2 files changed, 97 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 44fd81b..3186fe2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -1212,4 +1212,34 @@ public class Repository {
 		return mapCommit;
 	}
 
+	/**
+	 * Creates a new {@link WorkTree} and initialize a repository for it.
+	 * 
+	 * @param workTreeDirectory
+	 *            the directory with the project files.
+	 * @return a new {@link WorkTree} with a new and open {@link Repository}.
+	 * @throws IOException
+	 *             thrown by {@link Repository#create()}
+	 */
+	public static WorkTree createWorkTree(File workTreeDirectory)
+			throws IOException {
+		final File gitDirectory = new File(workTreeDirectory,
+				Constants.REPOSITORY_DIRECTORY_NAME);
+		if (gitDirectory.exists()) {
+			throw new IllegalArgumentException(
+					"Repository exists in given project directory.");
+		}
+		final Repository repository = new Repository(gitDirectory);
+		try {
+			repository.create();
+			return new WorkTree(workTreeDirectory, repository);
+		} catch (RuntimeException e) {
+			repository.close();
+			throw e;
+		} catch (IOException e) {
+			repository.close();
+			throw e;
+		}
+	}
+
 }
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java b/org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java
new file mode 100644
index 0000000..14bdda0
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/WorkTree.java
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.lib;
+
+import java.io.File;
+
+/**
+ * Represents a work tree controlled by git. Use {@link Repository} in order to
+ * create an object of this class.
+ * 
+ */
+public class WorkTree {
+	private final File directory;
+
+	private final Repository repository;
+
+	/**
+	 * This constructor should be only used by the class {@link Repository}.
+	 * 
+	 * @param directory
+	 *            defines the value of the directory field.
+	 * @param repository
+	 *            defines the value of the repository field.
+	 */
+	WorkTree(File directory, Repository repository) {
+		this.directory = directory;
+		this.repository = repository;
+	}
+
+	/**
+	 * 
+	 * @return the directory which contains the files of the project. Usually
+	 *         this directory contain a .git directory with the repository.
+	 */
+	public File getDirectory() {
+		return directory;
+	}
+
+	/**
+	 * @return the {@link Repository} object of the project.
+	 */
+	public Repository getRepository() {
+		return repository;
+	}
+
+	/**
+	 * Closes the git repository of this project.
+	 */
+	public void closeRepository() {
+		repository.close();
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 06/24] Added a "init" command to the git like command line tool.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (4 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class Florian Koeberle
                   ` (18 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/pgm/InitCommand.java      |   67 ++++++++++++++++++++
 .../src/org/spearce/jgit/pgm/MainProgram.java      |    1 +
 2 files changed, 68 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java
new file mode 100644
index 0000000..e87e777
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/InitCommand.java
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.pgm;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.spearce.jgit.lib.Repository.createWorkTree;
+import org.spearce.jgit.lib.WorkTree;
+
+import static java.lang.String.format;
+
+/**
+ * The {@link #execute} method of this class is used to create git repositories.
+ * This class is immutable.
+ * 
+ */
+public class InitCommand implements Command {
+	/**
+	 * Use this instance instead of creating a new ${link InitCommand}. You
+	 * don't need to create an instance of this class as it is immutable and not
+	 * configurable.
+	 */
+	public static InitCommand INSTANCE = new InitCommand();
+
+	public void execute(String... args) throws IOException {
+		final String currentDirectoryPathString = System
+				.getProperty("user.dir");
+		if (currentDirectoryPathString == null) {
+			throw new IOException("Unable to get current working directory");
+		}
+		final File currentDirectoryPath = new File(currentDirectoryPathString);
+		if (!currentDirectoryPath.isDirectory()) {
+			final String message = format(
+					"No directory found at \"%s\". It was the current working directory at program start.",
+					currentDirectoryPathString);
+			throw new IOException(message);
+		}
+
+		final WorkTree workTree = createWorkTree(currentDirectoryPath);
+		try {
+			System.out.printf("Created a git repository at: %s%n", workTree
+					.getRepository().getDirectory());
+		} finally {
+			workTree.closeRepository();
+		}
+
+	}
+
+	public String getShortDescription() {
+		return "Creates an empty git repository.";
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
index c9af51c..1ade91b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
@@ -33,6 +33,7 @@ public class MainProgram {
 
 	static {
 		final Map<String, Command> commands = new HashMap<String, Command>();
+		commands.put("init", InitCommand.INSTANCE);
 		commands.put("help", HelpCommand.INSTANCE);
 		commandNameToObjectMap = Collections.unmodifiableMap(commands);
 	}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (5 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 06/24] Added a "init" command to the git like command line tool Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-13  0:24   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 08/24] Added the interface FilePattern Florian Koeberle
                   ` (17 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/lib/Repository.java       |   90 ++++++++++++++++++++
 1 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 3186fe2..ed5bd89 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -16,6 +16,11 @@
  */
 package org.spearce.jgit.lib;
 
+import static org.spearce.jgit.lib.Constants.HEAD_FILE_NAME;
+import static org.spearce.jgit.lib.Constants.OBJECTS_DIRECTORY_NAME;
+import static org.spearce.jgit.lib.Constants.REFS_DIRECTORY_NAME;
+import static org.spearce.jgit.lib.Constants.REPOSITORY_DIRECTORY_NAME;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -1242,4 +1247,89 @@ public class Repository {
 		}
 	}
 
+	/**
+	 * Find the git repository for the current working directory.
+	 * 
+	 * @return a {@link Repository}.
+	 * @throws IOException
+	 *             if the system property user.dir isn't set or if it is
+	 *             invalid.
+	 */
+	public static WorkTree findWorkTree() throws IOException {
+		final String workingDirectoryPath = System.getProperty("user.dir");
+		if (workingDirectoryPath == null) {
+			throw new IOException("unable to get working directory");
+		}
+		final File workingDirectoryFile = new File(workingDirectoryPath);
+		if (!workingDirectoryFile.exists()) {
+			throw new IOException("Working directory path is invalid");
+		}
+		return findWorkTree(workingDirectoryFile);
+	}
+
+	/**
+	 * Checks if a path is a valid git repository. Works similar like the method
+	 * is_git_directory from the original setup.c file.
+	 * 
+	 * @param directory
+	 *            the path which should be checked.
+	 * @return true if the path is a valid git repository.
+	 */
+	private static boolean isRepository(File directory) {
+		if (!directory.isDirectory()) {
+			return false;
+		}
+
+		final File objectDirectory = new File(directory, OBJECTS_DIRECTORY_NAME);
+		if (!objectDirectory.isDirectory()) {
+			return false;
+		}
+
+		final File refsDirectory = new File(directory, REFS_DIRECTORY_NAME);
+		if (!refsDirectory.isDirectory()) {
+			return false;
+		}
+
+		final File head = new File(directory, HEAD_FILE_NAME);
+		if (!hasValidateHeadRef(head)) {
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Checks for example if a path is a valid HEAD file. Should do the same
+	 * like validate_headref from path.c.
+	 * 
+	 * @param path
+	 *            is the path of the HEAD file.
+	 * @return true if it has a valid head reference.
+	 */
+	private static final boolean hasValidateHeadRef(File path) {
+		return true; // TODO stub. view int validate_headref(const char
+		// *path) at path.c
+	}
+
+	private static WorkTree findWorkTree(File directory) throws IOException {
+		File currentDirectory = directory.getAbsoluteFile();
+		while (true) {
+			final File commonGitDirectory = new File(directory,
+					REPOSITORY_DIRECTORY_NAME);
+			if (isRepository(commonGitDirectory)) {
+				return new WorkTree(currentDirectory, new Repository(
+						commonGitDirectory));
+			}
+
+			if (isRepository(currentDirectory)) {
+				return new WorkTree(null, new Repository(currentDirectory));
+			}
+			currentDirectory = currentDirectory.getParentFile();
+			if (currentDirectory == null) {
+				throw new IOException("Can't find git repository");
+			}
+		}
+
+	}
+
 }
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 08/24] Added the interface FilePattern.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (6 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 09/24] Added the class Rule Florian Koeberle
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../spearce/jgit/treewalk/rules/FilePattern.java   |  105 ++++++++++++++++++++
 1 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/FilePattern.java

diff --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
new file mode 100644
index 0000000..666ff08
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/FilePattern.java
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+/**
+ * A {@link FilePattern} can be used to check if files in a directory matches a
+ * pattern. It provides with the {@link #getPatternForSubDirectory(String)}
+ * method {@link FilePattern}s for sub directories.
+ * 
+ * Implementations of this interface should be immutable.
+ * 
+ */
+interface FilePattern {
+	/**
+	 * This pattern instance matches always.
+	 */
+	public static final FilePattern MATCH_ALWAYS = new FilePattern() {
+
+		public FilePattern getPatternForSubDirectory(String directoryName) {
+			return MATCH_ALWAYS;
+		}
+
+		public boolean match(String fileName, boolean fileIsDirectory) {
+			return true;
+		}
+
+		public boolean canMatchAtThisDirectoryLevel() {
+			return true;
+		}
+
+		public boolean isSameForSubDirectories() {
+			return true;
+		}
+	};
+
+	/**
+	 * This pattern instance matches never.
+	 */
+	public static final FilePattern MATCH_NEVER = new FilePattern() {
+
+		public FilePattern getPatternForSubDirectory(String directoryName) {
+			return MATCH_NEVER;
+		}
+
+		public boolean match(String fileName, boolean fileIsDirectory) {
+			return false;
+		}
+
+		public boolean canMatchAtThisDirectoryLevel() {
+			return false;
+		}
+
+		public boolean isSameForSubDirectories() {
+			return true;
+		}
+	};
+
+	/**
+	 * @param fileName
+	 *            the name of the file or directory
+	 * @param fileIsDirectory
+	 *            determines if the file is a directory.
+	 * @return true if the pattern matches.
+	 */
+	boolean match(String fileName, boolean fileIsDirectory);
+
+	/**
+	 * 
+	 * @param directoryName
+	 *            the name of a subdirectory.
+	 * @return a pattern which can be used to match files in sub directories. A
+	 *         user may check if the returned value is {@link #MATCH_NEVER} in
+	 *         order to do some performance optimizations.
+	 * 
+	 */
+	FilePattern getPatternForSubDirectory(String directoryName);
+
+	/**
+	 * This method can be used to generate an smaller list of rules, which can
+	 * match.
+	 * 
+	 * @return true if {@link #match(String, boolean)} returns always false.
+	 */
+	boolean canMatchAtThisDirectoryLevel();
+
+	/**
+	 * @return true if {@link #getPatternForSubDirectory(String)} returns true
+	 *         for every value.
+	 */
+	boolean isSameForSubDirectories();
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 09/24] Added the class Rule.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (7 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 08/24] Added the interface FilePattern Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 10/24] Added the iterface Rules Florian Koeberle
                   ` (15 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/treewalk/rules/Rule.java  |   65 ++++++++++++++++++++
 1 files changed, 65 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rule.java

diff --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
new file mode 100644
index 0000000..fe3b45c
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rule.java
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+/**
+ * A Rule defines what to do with a files which match a specified
+ * {@link FilePattern}.
+ */
+public class Rule {
+	private boolean ignoreAtMatch;
+
+	private FilePattern pattern;
+
+	/**
+	 * 
+	 * @param ignoreAtMatch
+	 *            defines if the rules ignores or accepts at a match.
+	 * @param pattern
+	 *            the pattern used to test if a file matches.
+	 */
+	Rule(boolean ignoreAtMatch, FilePattern pattern) {
+		this.ignoreAtMatch = ignoreAtMatch;
+		this.pattern = pattern;
+	}
+
+	FilePattern getPattern() {
+		return pattern;
+	}
+
+	boolean isIgnoreAtMatch() {
+		return ignoreAtMatch;
+	}
+
+	Rule getRuleForSubDirectory(String directoryName) {
+		final FilePattern subPattern = pattern
+				.getPatternForSubDirectory(directoryName);
+		if (subPattern == pattern) {
+			return this;
+		}
+		return new Rule(ignoreAtMatch, subPattern);
+	}
+
+	boolean canMatchAtThisDirectoryLevel() {
+		return pattern.canMatchAtThisDirectoryLevel();
+	}
+
+	boolean isSameForSubDirectories() {
+		return pattern.isSameForSubDirectories();
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 10/24] Added the iterface Rules.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (8 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 09/24] Added the class Rule Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 11/24] Added the class FNMatchPattern Florian Koeberle
                   ` (14 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/treewalk/rules/Rules.java |   99 ++++++++++++++++++++
 1 files changed, 99 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rules.java

diff --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
new file mode 100644
index 0000000..627d974
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/Rules.java
@@ -0,0 +1,99 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+/**
+ * A {@link Rules} instances defines ignore or do not ignore rules for files in
+ * a directory. It can't directly be used to match files in sub directories, but
+ * provides a method {@link #getRulesForSubDirectory}.
+ * 
+ */
+public interface Rules {
+
+	/**
+	 * Provides the instance of {@link IgnoreAllRules}.
+	 */
+	public static final Rules IGNORE_ALL = new IgnoreAllRules();
+
+	/**
+	 * Provides the instance of {@link IgnoreNothingRules}.
+	 */
+	public static final Rules IGNORE_NOTHING = new IgnoreNothingRules();
+
+	/**
+	 * @param fileName
+	 *            the name of the file or directory.
+	 * @param fileIsDirectory
+	 *            should be true if the file is a directory.
+	 * @return true if the file or directory should be ignored.
+	 */
+	public abstract boolean toIgnore(String fileName, boolean fileIsDirectory);
+
+	/**
+	 * @param directoryName
+	 *            the sub directory for which you want an {@link Rules}
+	 *            instance.
+	 * @return an {@link Rules} instance, which can be used to check files in
+	 *         the specified sub directory.
+	 */
+	public abstract Rules getRulesForSubDirectory(String directoryName);
+
+	/**
+	 * This implementation ignores everything.
+	 */
+	public static final class IgnoreAllRules implements Rules {
+		private IgnoreAllRules() {
+			// declared to make the constructor private
+		}
+
+		public Rules getRulesForSubDirectory(String directoryName) {
+			return this;
+		}
+
+		public boolean toIgnore(String fileName, boolean fileIsDirectory) {
+			return true;
+		}
+
+		@Override
+		public String toString() {
+			return "ignore all rules";
+		}
+	}
+
+	/**
+	 * This implementation ignores nothing.
+	 */
+	public static final class IgnoreNothingRules implements Rules {
+		private IgnoreNothingRules() {
+			// declared to make the constructor private
+		}
+
+		public Rules getRulesForSubDirectory(String directoryName) {
+			return this;
+		}
+
+		public boolean toIgnore(String fileName, boolean fileIsDirectory) {
+			return false;
+		}
+
+		@Override
+		public String toString() {
+			return "ignore nothing rules";
+		}
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 11/24] Added the class FNMatchPattern.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (9 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 10/24] Added the iterface Rules Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-13  0:38   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 12/24] Added the class GlobalFilePattern Florian Koeberle
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/lib/FNMatchPattern.java   |   81 ++++++++++++++++++++
 1 files changed, 81 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java b/org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java
new file mode 100644
index 0000000..005659e
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/FNMatchPattern.java
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.lib;
+
+import java.util.regex.Pattern;
+
+/**
+ * This class represents a pattern which should work like the fnmatch method.
+ * <code>new FNMatchPattern(exp).matches(input)</code> should do the same like
+ * <code>fnmatch(exp, input, 0) == 0</code>
+ * 
+ * As this isn't a one to one code port, but written based on the documentation
+ * of fnmatch it can be that the behavior of this class differ in some corner
+ * cases from the behavior of the fnmatch function.
+ */
+public class FNMatchPattern {
+
+	private final Pattern regexPattern;
+
+	private static String toRegexString(String fnmatchPattern) {
+		final StringBuilder regexStringBuilder = new StringBuilder();
+		char perviosCharacter = 0;
+		for (int i = 0; i < fnmatchPattern.length(); i++) {
+			final char c = fnmatchPattern.charAt(i);
+			switch (c) {
+			case '^':
+				if (perviosCharacter == '[') {
+					regexStringBuilder.append('!');
+				} else {
+					regexStringBuilder.append("\\x5E");
+				}
+				break;
+			case '.':
+				regexStringBuilder.append("\\x2E");
+				break;
+			case '*':
+				regexStringBuilder.append(".*");
+				break;
+			default:
+				regexStringBuilder.append(c);
+			}
+			perviosCharacter = c;
+		}
+		return regexStringBuilder.toString();
+	}
+
+	/**
+	 * 
+	 * @param fnmatchPattern
+	 *            must be a valid fnmatch pattern string.
+	 */
+	public FNMatchPattern(String fnmatchPattern) {
+		final String regularExpression = toRegexString(fnmatchPattern);
+		this.regexPattern = Pattern.compile(regularExpression);
+	}
+
+	/**
+	 * 
+	 * @param stringToMatch
+	 *            the string to match.
+	 * @return true when this pattern matches.
+	 */
+	public boolean matches(String stringToMatch) {
+		return regexPattern.matcher(stringToMatch).matches();
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 12/24] Added the class GlobalFilePattern
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (10 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 11/24] Added the class FNMatchPattern Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 13/24] Added the class ComplexFilePattern Florian Koeberle
                   ` (12 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/rules/GlobalFilePattern.java     |   58 ++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/GlobalFilePattern.java

diff --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
new file mode 100644
index 0000000..ec1f38a
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/GlobalFilePattern.java
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import org.spearce.jgit.lib.FNMatchPattern;
+
+/**
+ * A {@link GlobalFilePattern} defines a pattern for all files in a tree. A
+ * typical example would be "*.txt", which would match at any file or subtree
+ * which ends with ".txt" like "a/b/c.txt" and "a.txt/a.c".
+ * 
+ */
+class GlobalFilePattern implements FilePattern {
+	private final FNMatchPattern fnMatchPattern;
+
+	private final boolean matchDirectoriesOnly;
+
+	GlobalFilePattern(String fnMatchPatternString, boolean matchDirectoriesOnly) {
+		this.fnMatchPattern = new FNMatchPattern(fnMatchPatternString);
+		this.matchDirectoriesOnly = matchDirectoriesOnly;
+	}
+
+	public boolean canMatchAtThisDirectoryLevel() {
+		return true;
+	}
+
+	public FilePattern getPatternForSubDirectory(String directoryName) {
+		if (match(directoryName, true)) {
+			return MATCH_ALWAYS;
+		}
+		return this;
+	}
+
+	public boolean match(String fileName, boolean fileIsDirectory) {
+		if (matchDirectoriesOnly && !fileIsDirectory) {
+			return false;
+		}
+		return fnMatchPattern.matches(fileName);
+	}
+
+	public boolean isSameForSubDirectories() {
+		return false;
+	}
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 13/24] Added the class ComplexFilePattern.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (11 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 12/24] Added the class GlobalFilePattern Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory Florian Koeberle
                   ` (11 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/rules/ComplexFilePattern.java    |   97 ++++++++++++++++++++
 1 files changed, 97 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/ComplexFilePattern.java

diff --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
new file mode 100644
index 0000000..7c2aba0
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/ComplexFilePattern.java
@@ -0,0 +1,97 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.spearce.jgit.lib.FNMatchPattern;
+
+/**
+ * A {@link ComplexFilePattern} defines for some components of a file path
+ * fnmatch like patterns. For example could such a pattern be that the first
+ * directory must start with an a and that the second directory must end with
+ * and b. In the example the pathes axx/xxb/hello.txt and ayy/yyb would match,
+ * but axx would not match.
+ * 
+ */
+class ComplexFilePattern implements FilePattern {
+	private final List<FNMatchPattern> usedPatternList;
+
+	private final boolean matchDirectoriesOnly;
+
+	private final int offset;
+
+	private ComplexFilePattern(List<FNMatchPattern> List,
+			boolean matchDirectoriesOnly, int offset) {
+		this.usedPatternList = List;
+		this.matchDirectoriesOnly = matchDirectoriesOnly;
+		this.offset = offset;
+	}
+
+	ComplexFilePattern(List<String> patternStrings, boolean matchDirectoriesOnly) {
+		this.usedPatternList = new ArrayList<FNMatchPattern>(patternStrings
+				.size());
+		for (String patternString : patternStrings) {
+			this.usedPatternList.add(new FNMatchPattern(patternString));
+		}
+		this.offset = 0;
+		this.matchDirectoriesOnly = matchDirectoriesOnly;
+	}
+
+	int getActualPathSize() {
+		return usedPatternList.size() - offset;
+	}
+
+	private FNMatchPattern getPatternOfCurrentLevel() {
+		return usedPatternList.get(offset);
+	}
+
+	public boolean canMatchAtThisDirectoryLevel() {
+		return getActualPathSize() == 1;
+	}
+
+	public FilePattern getPatternForSubDirectory(String directoryName) {
+
+		if (getActualPathSize() > 1) {
+			if (getPatternOfCurrentLevel().matches(directoryName)) {
+				return new ComplexFilePattern(usedPatternList,
+						matchDirectoriesOnly, offset + 1);
+			} else {
+				return FilePattern.MATCH_NEVER;
+			}
+		}
+		assert (getActualPathSize() == 1);
+		if (match(directoryName, true)) {
+			return FilePattern.MATCH_ALWAYS;
+		} else {
+			return FilePattern.MATCH_NEVER;
+		}
+	}
+
+	public boolean match(String fileName, boolean fileIsDirectory) {
+		if (!fileIsDirectory && matchDirectoriesOnly) {
+			return false;
+		}
+		return getPatternOfCurrentLevel().matches(fileName);
+	}
+
+	public boolean isSameForSubDirectories() {
+		return false;
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (12 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 13/24] Added the class ComplexFilePattern Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-13  1:08   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 15/24] Added a Rules interface implementation and a factory for it Florian Koeberle
                   ` (10 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/rules/IgnoreRuleListFactory.java |  104 ++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/IgnoreRuleListFactory.java

diff --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
new file mode 100644
index 0000000..6634098
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/IgnoreRuleListFactory.java
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Scanner;
+import java.util.StringTokenizer;
+
+/**
+ * This class can be used to create lists of {@link Rule} objects from lines of
+ * .gitignore like files.
+ * 
+ */
+class IgnoreRuleListFactory {
+
+	List<Rule> createIgnoreRuleList(Iterable<String> lineIterable) {
+		LinkedList<Rule> rules = new LinkedList<Rule>();
+		for (String line : lineIterable) {
+			final String trimmedLine = line.trim();
+			if (trimmedLine.startsWith("#")) {
+				continue;
+			}
+			if (trimmedLine.length() == 0) {
+				continue;
+			}
+			rules.add(0, createRule(trimmedLine));
+		}
+		return rules;
+	}
+
+	List<Rule> createIgnoreRuleList(List<File> files)
+			throws FileNotFoundException {
+		final List<String> lines = new ArrayList<String>();
+		for (File file : files) {
+			Scanner scanner = new Scanner(file);
+			try {
+				while (scanner.hasNextLine()) {
+					lines.add(scanner.nextLine());
+				}
+			} finally {
+				scanner.close();
+			}
+		}
+		return createIgnoreRuleList(lines);
+	}
+
+	private Rule createRule(String trimmedLine) {
+		final boolean exclude;
+		String patternString;
+		if (trimmedLine.startsWith("!")) {
+			exclude = false;
+			patternString = trimmedLine.substring(1);
+		} else {
+			exclude = true;
+			patternString = trimmedLine;
+		}
+
+		final boolean matchDirectoriesOnly;
+		if (patternString.endsWith("/")) {
+			matchDirectoriesOnly = true;
+			patternString = patternString.substring(0,
+					patternString.length() - 1);
+		} else {
+			matchDirectoriesOnly = false;
+		}
+
+		final FilePattern pattern;
+		if (patternString.contains("/")) {
+			if (patternString.startsWith("/")) {
+				patternString = patternString.substring(1);
+			}
+			final StringTokenizer stringTokenizer = new StringTokenizer(
+					patternString, "/");
+			final List<String> patternList = new ArrayList<String>();
+			while (stringTokenizer.hasMoreTokens()) {
+				final String token = stringTokenizer.nextToken();
+				patternList.add(token);
+			}
+			pattern = new ComplexFilePattern(patternList, matchDirectoriesOnly);
+		} else {
+			pattern = new GlobalFilePattern(patternString, matchDirectoriesOnly);
+		}
+		return new Rule(exclude, pattern);
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 15/24] Added a Rules interface implementation and a factory for it.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (13 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 16/24] Added test class OverallIgnoreRulestest Florian Koeberle
                   ` (9 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../treewalk/rules/RuleListToObjectConverter.java  |  130 ++++++++++++++++++++
 .../jgit/treewalk/rules/RulesImplementation.java   |   86 +++++++++++++
 2 files changed, 216 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RuleListToObjectConverter.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RulesImplementation.java

diff --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
new file mode 100644
index 0000000..b67beff
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RuleListToObjectConverter.java
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This class converts a list of {@link Rule} objects into a {@Rules} object.
+ * During the conversion some optimizations are done:
+ * <ul>
+ * <li>Rules which can never match are removed. e.g. There is no need to check
+ * the rule "/a" in the directory b.</li>
+ * <li>The list is cut at the first rule which match always. *.txt\n/a for
+ * example would result in an internal list "ignore all, ignore *.txt" which is
+ * then reduced to "ignore all".</li>
+ * <li>Ignore rules which are direcly before an "ignore all" all rule are
+ * removed. /a\n*.txt for example would result in an intern "ignore *.txt,
+ * ignore all" list which is then reduced to "ignore all",</li>
+ * <li>"do not ignore" rules at the bottom of the intern list are removed. This
+ * optimization would remove !a from "!a\n/b" as it is in the inversed list at
+ * the bottom.</li>
+ * </ul>
+ */
+class RuleListToObjectConverter {
+	protected Rules createIgnoreRules(Iterator<Rule> ruleIterator) {
+		final List<Rule> rules = getNessesaryRulesFromIterator(ruleIterator);
+		removeUnnecessaryDoNotIgnoreRulesAtTheEndOfTheList(rules);
+		removeUnnecessaryIgnoreRulesNearTheEndOfTheList(rules);
+
+		if (rules.size() == 1) {
+			final Rule rule = rules.get(0);
+			if (rule.getPattern() == FilePattern.MATCH_ALWAYS) {
+				if (rule.isIgnoreAtMatch()) {
+					return Rules.IGNORE_ALL;
+				} else {
+					return Rules.IGNORE_NOTHING;
+				}
+			}
+		} else if (rules.isEmpty()) {
+			return Rules.IGNORE_NOTHING;
+		}
+		return new RulesImplementation(rules, this);
+	}
+
+	private List<Rule> getNessesaryRulesFromIterator(Iterator<Rule> ruleIterator) {
+		final List<Rule> rules = new ArrayList<Rule>();
+		while (ruleIterator.hasNext()) {
+			final Rule subRule = ruleIterator.next();
+			if (subRule.getPattern() == FilePattern.MATCH_NEVER) {
+				continue;
+			}
+			rules.add(subRule);
+			// There is no need for rules after a rule witch match always,
+			// as such a rule would never be the first rule which matches.
+			if (subRule.getPattern() == FilePattern.MATCH_ALWAYS) {
+				break;
+			}
+		}
+		return rules;
+	}
+
+	/**
+	 * Expects that
+	 * {@link #removeUnnecessaryDoNotIgnoreRulesAtTheEndOfTheList(List)} has
+	 * been executed first.
+	 * 
+	 * @param rules
+	 *            rule list to reduce.
+	 */
+	private void removeUnnecessaryIgnoreRulesNearTheEndOfTheList(
+			final List<Rule> rules) {
+		// Why the following optimization makes only sense for the end of the
+		// list:
+		// If there is a "ignore all"- rule,
+		// then it is located at the end of the list
+		// See how the list is filled to prove this statement.
+		if (rules.size() >= 2) {
+			final Rule lastRule = rules.get(rules.size() - 1);
+			assert lastRule.isIgnoreAtMatch() : "Expected that no 'not ignore'-rule is at the end of the list any more";
+			final boolean ignoreAllAtEnd = lastRule.getPattern().equals(
+					FilePattern.MATCH_ALWAYS);
+			if (ignoreAllAtEnd) {
+				while (rules.size() >= 2) {
+					final int ruleBeforeLastIndex = rules.size() - 2;
+					final Rule ruleBeforeLast = rules.get(ruleBeforeLastIndex);
+					if (ruleBeforeLast.isIgnoreAtMatch()) {
+						rules.remove(ruleBeforeLastIndex);
+					} else {
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	private void removeUnnecessaryDoNotIgnoreRulesAtTheEndOfTheList(
+			final List<Rule> rules) {
+		// Why it is save to remove "don't ignore rules" at the end of the list
+		// if there is no "ignore rule" below a "don't ignore rule" then
+		// the path which haven't match jet will never be ignored:
+		// -> if another "don't ignore rule" match then the patch will not be
+		// ignored
+		// -> if no "don't ignore rule" match then the path will not be ignored.
+		while (!rules.isEmpty()) {
+			final int indexOfLastRule = rules.size() - 1;
+			final Rule lastRule = rules.get(indexOfLastRule);
+			if (lastRule.isIgnoreAtMatch()) {
+				break;
+			} else {
+				rules.remove(indexOfLastRule);
+			}
+		}
+	}
+}
diff --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
new file mode 100644
index 0000000..e98a57e
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/RulesImplementation.java
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+class RulesImplementation implements Rules {
+	/**
+	 * Complete list of rules. Note that order is: determining rule first.
+	 */
+	private final List<Rule> rulesForTree;
+
+	/**
+	 * {@link Rule} objects which return true at a call of
+	 * {@link Rule#canMatchAtThisDirectoryLevel}.
+	 */
+	private final List<Rule> rulesForThisLevel;
+
+	/**
+	 * Factory used to create {@link Rules} for sub directories.
+	 */
+	private RuleListToObjectConverter factory;
+
+	RulesImplementation(List<Rule> rules, RuleListToObjectConverter factory) {
+		this.rulesForTree = rules;
+		this.factory = factory;
+		this.rulesForThisLevel = new ArrayList<Rule>();
+		for (Rule rule : rules) {
+			if (rule.canMatchAtThisDirectoryLevel()) {
+				this.rulesForThisLevel.add(rule);
+			}
+		}
+	}
+
+	/**
+	 * @see Rules#toIgnore(java.lang.String, boolean)
+	 */
+	public boolean toIgnore(String fileName, boolean fileIsDirectory) {
+		for (Rule rule : rulesForThisLevel) {
+			if (rule.getPattern().match(fileName, fileIsDirectory)) {
+				return rule.isIgnoreAtMatch();
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * @see Rules#getRulesForSubDirectory(java.lang.String)
+	 */
+	public Rules getRulesForSubDirectory(final String directoryName) {
+		final Iterator<Rule> subRuleIterator = new Iterator<Rule>() {
+			final Iterator<Rule> ruleIterator = rulesForTree.iterator();
+
+			public boolean hasNext() {
+				return ruleIterator.hasNext();
+			}
+
+			public Rule next() {
+				return ruleIterator.next()
+						.getRuleForSubDirectory(directoryName);
+			}
+
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+
+		};
+		return factory.createIgnoreRules(subRuleIterator);
+	}
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 16/24] Added test class OverallIgnoreRulestest.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (14 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 15/24] Added a Rules interface implementation and a factory for it Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 17/24] Added the class TreeFilePattern Florian Koeberle
                   ` (8 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../treewalk/rules/OverallIgnoreRulesTest.java     |  371 ++++++++++++++++++++
 1 files changed, 371 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/OverallIgnoreRulesTest.java

diff --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
new file mode 100644
index 0000000..60e1bdc
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/OverallIgnoreRulesTest.java
@@ -0,0 +1,371 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class OverallIgnoreRulesTest extends TestCase {
+	private IgnoreRulesFactory factory;
+
+	@Override
+	protected void setUp() throws Exception {
+		factory = new IgnoreRulesFactory();
+	}
+
+	public void testSimpleGlobalPattern() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("ab");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertTrue(ignoreRules.toIgnore("ab", false));
+		assertTrue(ignoreRules.toIgnore("ab", true));
+		assertFalse(ignoreRules.toIgnore("abc", false));
+		assertFalse(ignoreRules.toIgnore("abc", true));
+	}
+
+	public void testGlobalPatternWithOneStar() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("a*c");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+
+		assertTrue(ignoreRules.toIgnore("ac", false));
+		assertTrue(ignoreRules.toIgnore("ac", true));
+
+		assertTrue(ignoreRules.toIgnore("abc", false));
+		assertTrue(ignoreRules.toIgnore("abc", true));
+
+		assertTrue(ignoreRules.toIgnore("abbc", false));
+		assertTrue(ignoreRules.toIgnore("abbc", true));
+
+		assertTrue(ignoreRules.toIgnore("aabc", false));
+		assertTrue(ignoreRules.toIgnore("aabc", true));
+
+		assertFalse(ignoreRules.toIgnore("cab", false));
+		assertFalse(ignoreRules.toIgnore("cab", true));
+	}
+
+	public void testGlobalPatternWithTwoStars() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("a*c*e");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+
+		assertTrue(ignoreRules.toIgnore("ace", false));
+		assertTrue(ignoreRules.toIgnore("ace", true));
+
+		assertTrue(ignoreRules.toIgnore("abcde", false));
+		assertTrue(ignoreRules.toIgnore("abcde", true));
+
+		assertTrue(ignoreRules.toIgnore("aHellocWorlde", false));
+		assertTrue(ignoreRules.toIgnore("aHellocWorlde", true));
+
+		assertFalse(ignoreRules.toIgnore("ae", false));
+		assertFalse(ignoreRules.toIgnore("ae", true));
+	}
+
+	public void testGlobalPatternWithDots() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("*.tar.gz");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+
+		assertTrue(ignoreRules.toIgnore("test.tar.gz", false));
+		assertTrue(ignoreRules.toIgnore("test.tar.gz", true));
+
+		assertTrue(ignoreRules.toIgnore(".tar.gz", false));
+		assertTrue(ignoreRules.toIgnore(".tar.gz", true));
+
+		assertFalse(ignoreRules.toIgnore("test", false));
+		assertFalse(ignoreRules.toIgnore("test", true));
+
+		// test that "." isn't handled as "any character"
+		assertFalse(ignoreRules.toIgnore(".tarogz", false));
+		assertFalse(ignoreRules.toIgnore(".tarogz", true));
+	}
+
+	public void testGlobalPatternDirectoryOnlyRule() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("a/");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+
+		assertTrue(ignoreRules.toIgnore("a", true));
+		assertFalse(ignoreRules.toIgnore("a", false));
+
+		final Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory("a");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesA);
+
+		final Rules ignoreRulesB = ignoreRules.getRulesForSubDirectory("b");
+		assertTrue(ignoreRulesB.toIgnore("a", true));
+		assertFalse(ignoreRulesB.toIgnore("a", false));
+
+		final Rules ignoreRulesBA = ignoreRulesB.getRulesForSubDirectory("a");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesBA);
+
+	}
+
+	public void testSimpleFilePathPattern() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("a/b/c");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertFalse(ignoreRules.toIgnore("a", true));
+		assertFalse(ignoreRules.toIgnore("a", false));
+		assertFalse(ignoreRules.toIgnore("b", true));
+		assertFalse(ignoreRules.toIgnore("b", false));
+		assertFalse(ignoreRules.toIgnore("c", true));
+		assertFalse(ignoreRules.toIgnore("c", false));
+
+		final Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory("a");
+		assertFalse(ignoreRulesA.toIgnore("a", true));
+		assertFalse(ignoreRulesA.toIgnore("a", false));
+		assertFalse(ignoreRulesA.toIgnore("b", true));
+		assertFalse(ignoreRulesA.toIgnore("b", false));
+		assertFalse(ignoreRulesA.toIgnore("c", true));
+		assertFalse(ignoreRulesA.toIgnore("c", false));
+
+		final Rules ignoreRulesAB = ignoreRulesA.getRulesForSubDirectory("b");
+		assertFalse(ignoreRulesAB.toIgnore("a", true));
+		assertFalse(ignoreRulesAB.toIgnore("a", false));
+		assertFalse(ignoreRulesAB.toIgnore("b", true));
+		assertFalse(ignoreRulesAB.toIgnore("b", false));
+		assertTrue(ignoreRulesAB.toIgnore("c", true));
+		assertTrue(ignoreRulesAB.toIgnore("c", false));
+
+		final Rules ignoreRulesABA = ignoreRulesAB.getRulesForSubDirectory("a");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesABA);
+
+		final Rules ignoreRulesABB = ignoreRulesAB.getRulesForSubDirectory("b");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesABB);
+
+		final Rules ignoreRulesABC = ignoreRulesAB.getRulesForSubDirectory("c");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesABC);
+	}
+
+	public void testFilePathPatternDirectoryOnlyRule() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("a/b/c/");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertFalse(ignoreRules.toIgnore("a", true));
+		assertFalse(ignoreRules.toIgnore("a", false));
+		assertFalse(ignoreRules.toIgnore("b", true));
+		assertFalse(ignoreRules.toIgnore("b", false));
+		assertFalse(ignoreRules.toIgnore("c", true));
+		assertFalse(ignoreRules.toIgnore("c", false));
+
+		final Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory("a");
+		assertFalse(ignoreRulesA.toIgnore("a", true));
+		assertFalse(ignoreRulesA.toIgnore("a", false));
+		assertFalse(ignoreRulesA.toIgnore("b", true));
+		assertFalse(ignoreRulesA.toIgnore("b", false));
+		assertFalse(ignoreRulesA.toIgnore("c", true));
+		assertFalse(ignoreRulesA.toIgnore("c", false));
+
+		final Rules ignoreRulesAB = ignoreRulesA.getRulesForSubDirectory("b");
+		assertFalse(ignoreRulesAB.toIgnore("a", true));
+		assertFalse(ignoreRulesAB.toIgnore("a", false));
+		assertFalse(ignoreRulesAB.toIgnore("b", true));
+		assertFalse(ignoreRulesAB.toIgnore("b", false));
+		assertTrue(ignoreRulesAB.toIgnore("c", true));
+		assertFalse(ignoreRulesAB.toIgnore("c", false));
+
+		final Rules ignoreRulesABA = ignoreRulesAB.getRulesForSubDirectory("a");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesABA);
+
+		final Rules ignoreRulesABB = ignoreRulesAB.getRulesForSubDirectory("b");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesABB);
+
+		final Rules ignoreRulesABC = ignoreRulesAB.getRulesForSubDirectory("c");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesABC);
+	}
+
+	public void testShortPathPattern() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("/alpha");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertTrue(ignoreRules.toIgnore("alpha", true));
+		assertTrue(ignoreRules.toIgnore("alpha", false));
+
+		final Rules ignoreRulesAlpha = ignoreRules
+				.getRulesForSubDirectory("alpha");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesAlpha);
+
+		final Rules ignoreRulesBeta = ignoreRules
+				.getRulesForSubDirectory("beta");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesBeta);
+	}
+
+	public void testShortDirectoryPathPattern() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("/alpha/");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertTrue(ignoreRules.toIgnore("alpha", true));
+		assertFalse(ignoreRules.toIgnore("alpha", false));
+
+		final Rules ignoreRulesAlpha = ignoreRules
+				.getRulesForSubDirectory("alpha");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesAlpha);
+
+		final Rules ignoreRulesBeta = ignoreRules
+				.getRulesForSubDirectory("beta");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesBeta);
+	}
+
+	public void testShortPathPatternWithStar() {
+		List<String> lines = new ArrayList<String>();
+		lines.add("/.*");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+
+		assertTrue(ignoreRules.toIgnore(".test", true));
+		assertTrue(ignoreRules.toIgnore(".test", false));
+
+		assertFalse(ignoreRules.toIgnore("test", true));
+		assertFalse(ignoreRules.toIgnore("test", false));
+
+		final Rules ignoreRulesDotTest = ignoreRules
+				.getRulesForSubDirectory(".test");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesDotTest);
+
+		final Rules ignoreRulesTest = ignoreRules
+				.getRulesForSubDirectory("test");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesTest);
+	}
+
+	public void testPathPatternWith2Times2Stars() {
+		final List<String> lines = new ArrayList<String>();
+		lines.add("he*wor*d/*.*");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+
+		assertFalse(ignoreRules.toIgnore("hello", true));
+		assertFalse(ignoreRules.toIgnore("hello", false));
+		final Rules ignoreRulesHello = ignoreRules
+				.getRulesForSubDirectory("hello");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesHello);
+
+		assertFalse(ignoreRules.toIgnore("helloworld", true));
+		assertFalse(ignoreRules.toIgnore("helloworld", false));
+		final Rules ignoreRulesHelloWorld = ignoreRules
+				.getRulesForSubDirectory("helloworld");
+		assertNotSame(Rules.IGNORE_NOTHING, ignoreRulesHelloWorld);
+
+		assertTrue(ignoreRulesHelloWorld.toIgnore("test.txt", true));
+		assertTrue(ignoreRulesHelloWorld.toIgnore("test.txt", false));
+
+		assertFalse(ignoreRulesHelloWorld.toIgnore("test", true));
+		assertFalse(ignoreRulesHelloWorld.toIgnore("test", false));
+
+		final Rules ignoreRulesTestTxt = ignoreRulesHelloWorld
+				.getRulesForSubDirectory("test.txt");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesTestTxt);
+
+		final Rules ignoreRulesTest = ignoreRulesHelloWorld
+				.getRulesForSubDirectory("test");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesTest);
+	}
+
+	public void testEmptyIgnoreList() {
+		final List<String> lines = Collections.emptyList();
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertSame(Rules.IGNORE_NOTHING, ignoreRules);
+	}
+
+	public void testOnlyOneNegatedIgnore() {
+		final List<String> lines = new ArrayList<String>();
+		lines.add("!a");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertSame(Rules.IGNORE_NOTHING, ignoreRules);
+	}
+
+	public void testOnlyThreeNegatedIgnores() {
+		final List<String> lines = new ArrayList<String>();
+		lines.add("!a");
+		lines.add("!a/b/c");
+		lines.add("!b*");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertSame(Rules.IGNORE_NOTHING, ignoreRules);
+	}
+
+	public void testNegatedIgnoreCase1() {
+		final List<String> lines = new ArrayList<String>();
+		lines.add("/a");
+		lines.add("!b");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		final Rules ignoreRulesA = ignoreRules.getRulesForSubDirectory("a");
+		final Rules ignoreRulesAB = ignoreRulesA.getRulesForSubDirectory("b");
+		final Rules ignoreRulesB = ignoreRules.getRulesForSubDirectory("b");
+		final Rules ignoreRulesC = ignoreRules.getRulesForSubDirectory("c");
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesB);
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesAB);
+		assertSame(Rules.IGNORE_NOTHING, ignoreRulesC);
+		assertTrue(ignoreRules.toIgnore("a", true));
+		assertTrue(ignoreRules.toIgnore("a", false));
+		assertTrue(ignoreRulesA.toIgnore("c", true));
+		assertTrue(ignoreRulesA.toIgnore("c", false));
+	}
+
+	public void testExceptionOfException() {
+		final List<String> lines = new ArrayList<String>();
+		lines.add("*.*");
+		lines.add("!*.c");
+		lines.add("a.c");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertTrue(ignoreRules.toIgnore("b.txt", false));
+		assertTrue(ignoreRules.toIgnore("b.txt", true));
+		assertTrue(ignoreRules.toIgnore("a.c", false));
+		assertTrue(ignoreRules.toIgnore("a.c", true));
+		assertFalse(ignoreRules.toIgnore("b.c", false));
+		assertFalse(ignoreRules.toIgnore("b.c", true));
+	}
+
+	public void testComplexCase() {
+		final List<String> lines = new ArrayList<String>();
+		lines.add("*");
+		lines.add("!/alpha/src");
+		lines.add("*~");
+		final Rules ignoreRules = factory.createIgnoreRulesFromLines(lines);
+		assertTrue(ignoreRules.toIgnore("beta", true));
+		assertTrue(ignoreRules.toIgnore("alpha", true));
+		final Rules ignoreRulesAlpha = ignoreRules
+				.getRulesForSubDirectory("alpha");
+		final Rules ignoreRulesAlphaBin = ignoreRulesAlpha
+				.getRulesForSubDirectory("bin");
+		final Rules ignoreRulesAlphaSrc = ignoreRulesAlpha
+				.getRulesForSubDirectory("src");
+		assertSame(Rules.IGNORE_ALL, ignoreRulesAlphaBin);
+		assertFalse(ignoreRulesAlphaSrc.toIgnore("com", true));
+		assertFalse(ignoreRulesAlphaSrc.toIgnore("b.java", false));
+		assertTrue(ignoreRulesAlphaSrc.toIgnore("b.java~", true));
+	}
+
+	private class IgnoreRulesFactory {
+		private RuleListToObjectConverter converter = new RuleListToObjectConverter();
+
+		private IgnoreRuleListFactory listFactory = new IgnoreRuleListFactory();
+
+		/**
+		 * @param ignoreFileLines
+		 *            the lines of a ignore file like .gitignore.
+		 * @return a immutable IgnoreRules object.
+		 */
+		public Rules createIgnoreRulesFromLines(Iterable<String> ignoreFileLines) {
+			final List<Rule> rules = listFactory
+					.createIgnoreRuleList(ignoreFileLines);
+			return converter.createIgnoreRules(rules.iterator());
+		}
+
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 17/24] Added the class TreeFilePattern.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (15 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 16/24] Added test class OverallIgnoreRulestest Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-13  1:22   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 18/24] Added InvalidPatternException and PathNotInProjectDirectoryException Florian Koeberle
                   ` (7 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/rules/TreeFilePattern.java       |   75 ++++++++++++++++++++
 1 files changed, 75 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/TreeFilePattern.java

diff --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
new file mode 100644
index 0000000..9234c95
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/TreeFilePattern.java
@@ -0,0 +1,75 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.util.List;
+
+/**
+ * Represents a pattern like "documents/*.txt" which matches all *.txt files in
+ * the tree documents.
+ * 
+ */
+class TreeFilePattern implements FilePattern {
+
+	private final List<String> path;
+
+	private final int offset;
+
+	private final GlobalFilePattern globalFilePattern;
+
+	public boolean canMatchAtThisDirectoryLevel() {
+		return false;
+	}
+
+	TreeFilePattern(List<String> path, GlobalFilePattern globalFilePattern) {
+		this.path = path;
+		this.offset = 0;
+		this.globalFilePattern = globalFilePattern;
+	}
+
+	private TreeFilePattern(List<String> path, int offset,
+			GlobalFilePattern globalFilePattern) {
+		this.path = path;
+		this.offset = offset;
+		this.globalFilePattern = globalFilePattern;
+	}
+
+	public FilePattern getPatternForSubDirectory(String directoryName) {
+		try {
+			if (!path.get(offset).equals(directoryName)) {
+				return FilePattern.MATCH_NEVER;
+			}
+		} catch (IndexOutOfBoundsException e) {
+			throw new IllegalStateException(
+					"The offset of this class doesn't refer to a valid position in path");
+		}
+		if (offset == path.size() - 1) {
+			return globalFilePattern;
+		} else {
+			return new TreeFilePattern(path, offset + 1, globalFilePattern);
+		}
+	}
+
+	public boolean isSameForSubDirectories() {
+		return false;
+	}
+
+	public boolean match(String fileName, boolean fileIsDirectory) {
+		return false;
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 18/24] Added InvalidPatternException and PathNotInProjectDirectoryException
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (16 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 17/24] Added the class TreeFilePattern Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 19/24] Added the class AddRuleListFactory Florian Koeberle
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/errors/InvalidPatternException.java       |   44 ++++++++++++++++++++
 .../errors/PathNotInProjectDirectoryException.java |   25 +++++++++++
 2 files changed, 69 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java
new file mode 100644
index 0000000..d09f0c9
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidPatternException.java
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.errors;
+
+/**
+ * Thrown when a pattern passed in an argument was wrong.
+ * 
+ */
+public class InvalidPatternException extends Exception {
+	private final String pattern;
+
+	/**
+	 * @param message
+	 *            explains what was wrong with the pattern.
+	 * @param pattern
+	 *            the invalid pattern.
+	 */
+	public InvalidPatternException(String message, String pattern) {
+		super(message);
+		this.pattern = pattern;
+	}
+
+	/**
+	 * @return the invalid pattern.
+	 */
+	public String getPattern() {
+		return pattern;
+	}
+
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java
new file mode 100644
index 0000000..a406aef
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/PathNotInProjectDirectoryException.java
@@ -0,0 +1,25 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.errors;
+
+/**
+ * Thrown when a path wasn't in the project directory, but expected to be.
+ * 
+ */
+public class PathNotInProjectDirectoryException extends
+		IllegalArgumentException {
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (17 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 18/24] Added InvalidPatternException and PathNotInProjectDirectoryException Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-13  1:29   ` Shawn O. Pearce
  2008-05-12 20:13 ` [JGIT PATCH v2 20/24] Added class AddRulesFactory Florian Koeberle
                   ` (5 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/rules/AddRuleListFactory.java    |  128 ++++++++++++++++++++
 1 files changed, 128 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRuleListFactory.java

diff --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
new file mode 100644
index 0000000..0cb700f
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRuleListFactory.java
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.spearce.jgit.errors.InvalidPatternException;
+import org.spearce.jgit.errors.PathNotInProjectDirectoryException;
+
+class AddRuleListFactory {
+	/*
+	 * The add command of git 1.5.2.5 behaves a little bit stange: "git add
+	 * a/\*z" adds the file "a/b/xyz" but "git add a/x\*" does not.
+	 * 
+	 * The first is parsed as pattern "*z" for whole directory tree "a". The
+	 * second is parsed as an path.
+	 * 
+	 */
+
+	private static List<String> getRelativePath(File projectDirectory, File file)
+			throws PathNotInProjectDirectoryException, IOException {
+		File currentFile = file.getCanonicalFile();
+		final LinkedList<String> relativePath = new LinkedList<String>();
+		while (!currentFile.equals(projectDirectory)) {
+			relativePath.addFirst(currentFile.getName());
+			currentFile = currentFile.getParentFile();
+			if (currentFile == null) {
+				throw new PathNotInProjectDirectoryException();
+			}
+		}
+		return relativePath;
+	}
+
+	List<Rule> createRuleList(File projectDirectory, File workingDirectory,
+			List<String> filePatternsOfAddCommand)
+			throws InvalidPatternException, PathNotInProjectDirectoryException,
+			IOException {
+
+		final List<String> pathPrefix = getRelativePath(projectDirectory,
+				workingDirectory);
+
+		final List<Rule> ruleList = new ArrayList<Rule>(
+				filePatternsOfAddCommand.size());
+		for (String pattern : filePatternsOfAddCommand) {
+			final boolean matchDirectoriesOnly;
+			if (pattern.endsWith(File.separator)) {
+				pattern = pattern.substring(0, pattern.length() - 1);
+				matchDirectoriesOnly = true;
+			} else {
+				matchDirectoriesOnly = false;
+			}
+
+			final String[] relativePath = pattern.split("[" + File.separator
+					+ "]");
+			final List<String> path = new ArrayList<String>();
+			path.addAll(pathPrefix);
+			path.addAll(Arrays.asList(relativePath));
+			assert (!path.isEmpty());
+
+			final FilePattern filePattern = createFilePattern(pattern,
+					matchDirectoriesOnly, path);
+			final Rule rule = new Rule(false, filePattern);
+			ruleList.add(rule);
+
+		}
+		return ruleList;
+	}
+
+	private static FilePattern createFilePattern(String pattern,
+			boolean matchDirectoriesOnly, List<String> path)
+			throws InvalidPatternException {
+		/*
+		 * I did several tests with the git-add command, and it seems that it
+		 * handles a pattern as a fileGlob, if it has only one star at the
+		 * beginning of the latest part of the path. Otherwise it handle it as
+		 * file pattern.
+		 */
+
+		final String lastPathElement = path.get(path.size() - 1);
+		final boolean isFileGlob = lastPathElement.startsWith("*");
+		final FilePattern filePattern;
+		if (isFileGlob) {
+			filePattern = createGlobalOrTreeFilePattern(matchDirectoriesOnly,
+					path, lastPathElement);
+		} else {
+			for (String pathElement : path) {
+				if (pathElement.contains("*")) {
+					throw new InvalidPatternException(
+							"Stars are not allowed here", pattern);
+				}
+			}
+			filePattern = new ComplexFilePattern(path, matchDirectoriesOnly);
+		}
+		return filePattern;
+	}
+
+	private static FilePattern createGlobalOrTreeFilePattern(
+			final boolean matchDirectoriesOnly, final List<String> path,
+			final String lastPathElement) {
+		final GlobalFilePattern globalFilePatternForTree = new GlobalFilePattern(
+				lastPathElement, matchDirectoriesOnly);
+		final List<String> targetTree = path.subList(0, path.size() - 1);
+		if (targetTree.isEmpty()) {
+			return globalFilePatternForTree;
+		} else {
+			return new TreeFilePattern(targetTree, globalFilePatternForTree);
+		}
+	}
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 20/24] Added class AddRulesFactory.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (18 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 19/24] Added the class AddRuleListFactory Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it Florian Koeberle
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/rules/AddRulesFactory.java       |   91 ++++++++++++++++++++
 1 files changed, 91 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRulesFactory.java

diff --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
new file mode 100644
index 0000000..c1f9a6f
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/rules/AddRulesFactory.java
@@ -0,0 +1,91 @@
+package org.spearce.jgit.treewalk.rules;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.spearce.jgit.errors.InvalidPatternException;
+import org.spearce.jgit.errors.PathNotInProjectDirectoryException;
+import static org.spearce.jgit.lib.Constants.REPOSITORY_DIRECTORY_NAME;
+
+/**
+ * This class is designed to serve the needs of someone who want to implement a
+ * git-add command and needs to determine the files to add.
+ * 
+ */
+public class AddRulesFactory {
+	private final RuleListToObjectConverter converter = new RuleListToObjectConverter();
+
+	private final IgnoreRuleListFactory ignoreRuleListFactory = new IgnoreRuleListFactory();
+
+	private final AddRuleListFactory addRuleListFactory = new AddRuleListFactory();
+
+	/**
+	 * @param workTreeDirectory
+	 *            The directory with the files of the project under version
+	 *            control.
+	 * @param workingDirectory
+	 *            a directory within the workTreeDirectory.
+	 * @param filePatternsOfAddCommand
+	 *            the file patterns passed to the add command.
+	 * @return a {@link Rules} containing the specified rules, the .gitignore
+	 *         and the .git/info/exclude rules.
+	 * @throws InvalidPatternException
+	 *             if a pattern is invalid.
+	 * @throws PathNotInProjectDirectoryException
+	 *             if the directory workingDirectory is not in workTreeDirectory
+	 * @throws IOException
+	 *             for some reasons.
+	 */
+	public Rules createRules(File workTreeDirectory, File workingDirectory,
+			List<String> filePatternsOfAddCommand)
+			throws InvalidPatternException, PathNotInProjectDirectoryException,
+			IOException {
+		final Rule gitDirectoryIgnoreRule = createGitDirectoryIgnoreRule();
+		final File gitDirectory = new File(workTreeDirectory,
+				REPOSITORY_DIRECTORY_NAME);
+		final List<Rule> ignoreRuleListFromFiles = createExcludeRules(
+				workTreeDirectory, gitDirectory);
+		final List<Rule> includeRules = addRuleListFactory.createRuleList(
+				workTreeDirectory, workingDirectory, filePatternsOfAddCommand);
+		final List<Rule> ruleList = new ArrayList<Rule>();
+
+		ruleList.add(gitDirectoryIgnoreRule);
+		ruleList.addAll(ignoreRuleListFromFiles);
+		ruleList.addAll(includeRules);
+		ruleList.add(new Rule(true, FilePattern.MATCH_ALWAYS));
+
+		return converter.createIgnoreRules(ruleList.iterator());
+	}
+
+	private List<Rule> createExcludeRules(File projectDirectory,
+			File gitDirectory) {
+		final List<File> possibleIgnoreFiles = new ArrayList<File>(2);
+		possibleIgnoreFiles.add(new File(projectDirectory, ".gitignore"));
+		possibleIgnoreFiles.add(new File(new File(gitDirectory, "info"),
+				"exclude"));
+
+		final List<File> ignoreFiles = new ArrayList<File>();
+		for (File possibleIgnoreFile : possibleIgnoreFiles) {
+			if (possibleIgnoreFile.isFile()) {
+				ignoreFiles.add(possibleIgnoreFile);
+			}
+		}
+
+		try {
+			return ignoreRuleListFactory.createIgnoreRuleList(ignoreFiles);
+		} catch (FileNotFoundException e) {
+			throw new RuntimeException("unexpected removal of ignore files", e);
+		}
+	}
+
+	private Rule createGitDirectoryIgnoreRule() {
+		final FilePattern gitDirectoryPattern = new ComplexFilePattern(Arrays
+				.asList(REPOSITORY_DIRECTORY_NAME), true);
+		final Rule gitDirectoryIgnoreRule = new Rule(true, gitDirectoryPattern);
+		return gitDirectoryIgnoreRule;
+	}
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (19 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 20/24] Added class AddRulesFactory Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-14 14:27   ` Paolo Bonzini
  2008-05-12 20:13 ` [JGIT PATCH v2 22/24] Added class LightFileTreeIterable Florian Koeberle
                   ` (3 subsequent siblings)
  24 siblings, 1 reply; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/LightFileTreeIteratorTest.java   |  114 ++++++++++++++++++++
 .../jgit/treewalk/LightFileTreeIterator.java       |  112 +++++++++++++++++++
 2 files changed, 226 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/LightFileTreeIteratorTest.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java

diff --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
new file mode 100644
index 0000000..f937182
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/LightFileTreeIteratorTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spearce.jgit.treewalk.rules.Rules;
+
+import junit.framework.TestCase;
+
+public class LightFileTreeIteratorTest extends TestCase {
+	private String DIRECTORY_A_NAME = "a";
+
+	private String DIRECTORY_AB_NAME = "b";
+
+	private File projectDirectory;
+
+	private File fileB;
+
+	private File directoryA;
+
+	private File directoryAB;
+
+	private File fileABA;
+
+	private File directoryAC;
+
+	private File fileACA;
+
+	private File fileACB;
+
+	@Override
+	protected void setUp() throws Exception {
+		this.projectDirectory = File.createTempFile("FileTreeIteratorTest", "");
+		projectDirectory.delete();
+		projectDirectory.mkdir();
+		projectDirectory.deleteOnExit();
+
+		this.directoryA = new File(projectDirectory, DIRECTORY_A_NAME);
+		directoryA.mkdir();
+
+		this.directoryAB = new File(directoryA, DIRECTORY_AB_NAME);
+		directoryAB.mkdir();
+
+		this.fileABA = new File(directoryAB, "a.y");
+		fileABA.createNewFile();
+
+		this.directoryAC = new File(directoryA, "c");
+		this.directoryAC.mkdir();
+
+		this.fileACA = new File(directoryAC, "a.x");
+		fileACA.createNewFile();
+
+		this.fileACB = new File(directoryAC, "b.y");
+		fileACB.createNewFile();
+
+		this.fileB = new File(projectDirectory, "b.x");
+		fileB.createNewFile();
+	}
+
+	public void testFileTreeIterator() {
+		final Iterator<File> iterator = new LightFileTreeIterator(
+				projectDirectory, Rules.IGNORE_NOTHING, false);
+		final Set<File> actualPathes = new HashSet<File>();
+		while (iterator.hasNext()) {
+			final File next = iterator.next();
+			assertFalse(actualPathes.contains(next));
+			actualPathes.add(next);
+		}
+
+		final Set<File> expectedPathes = new HashSet<File>();
+		expectedPathes.add(directoryA);
+		expectedPathes.add(fileB);
+		expectedPathes.add(directoryAB);
+		expectedPathes.add(fileABA);
+		expectedPathes.add(directoryAC);
+		expectedPathes.add(fileACA);
+		expectedPathes.add(fileACB);
+		assertEquals(expectedPathes, actualPathes);
+
+	}
+
+	public void testFileTreeIteratorWithIgnoreAllRules() {
+		final Iterator<File> iterator = new LightFileTreeIterator(
+				projectDirectory, Rules.IGNORE_ALL, false);
+		final Set<File> actualPathes = new HashSet<File>();
+		while (iterator.hasNext()) {
+			final File next = iterator.next();
+			assertFalse(actualPathes.contains(next));
+			actualPathes.add(next);
+		}
+
+		assertEquals(0, actualPathes.size());
+
+	}
+
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java
new file mode 100644
index 0000000..45fb167
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterator.java
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk;
+
+import java.io.File;
+import java.util.EmptyStackException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+import org.spearce.jgit.treewalk.rules.Rules;
+
+class LightFileTreeIterator implements Iterator<File> {
+	private final Stack<File> remainingPathes;
+
+	private final Stack<Directory> remainingDirectories;
+
+	/**
+	 * Creates a new Iterator which allows to iterate over the content of the
+	 * specified rootDirectory. The rootDirectory itself is never included.
+	 * 
+	 * @param rootDirectory
+	 *            the directory tree to iterate over.
+	 * @param ignoreRules
+	 *            defines which paths are included and which aren't.
+	 * @param includeRootDirectory
+	 *            the iterator will return the rootDirectory if this is flag is
+	 *            true.
+	 */
+	LightFileTreeIterator(File rootDirectory, Rules ignoreRules,
+			boolean includeRootDirectory) {
+		remainingPathes = new Stack<File>();
+		if (includeRootDirectory) {
+			remainingPathes.add(rootDirectory);
+		}
+		remainingDirectories = new Stack<Directory>();
+		remainingDirectories.add(new Directory(rootDirectory, ignoreRules));
+	}
+
+	public boolean hasNext() {
+		findMorePathesIfNessesary();
+		return !remainingPathes.empty();
+	}
+
+	void findMorePathesIfNessesary() {
+		if (remainingPathes.isEmpty()) {
+			findMorePathes();
+		}
+	}
+
+	void findMorePathes() {
+		while (!remainingDirectories.isEmpty() && remainingPathes.isEmpty()) {
+			final Directory directory = remainingDirectories.pop();
+			final File[] pathes = directory.path.listFiles();
+			for (File path : pathes) {
+				final boolean fileIsDirectory = path.isDirectory();
+				if (fileIsDirectory) {
+					final Rules subDirectoryIgnoreRules = directory.ignoreRules
+							.getRulesForSubDirectory(path.getName());
+					if (subDirectoryIgnoreRules != Rules.IGNORE_ALL) {
+						final Directory subDirectory = new Directory(path,
+								subDirectoryIgnoreRules);
+						remainingDirectories.add(subDirectory);
+					}
+				}
+				if (!directory.ignoreRules.toIgnore(path.getName(),
+						fileIsDirectory)) {
+					remainingPathes.add(path);
+				}
+			}
+		}
+	}
+
+	public File next() {
+		findMorePathesIfNessesary();
+		try {
+			return remainingPathes.pop();
+		} catch (EmptyStackException e) {
+			throw new NoSuchElementException();
+		}
+	}
+
+	public void remove() {
+		throw new UnsupportedOperationException();
+	}
+
+	private class Directory {
+		final File path;
+
+		final Rules ignoreRules;
+
+		Directory(File path, Rules ignoreRules) {
+			this.path = path;
+			this.ignoreRules = ignoreRules;
+		}
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 22/24] Added class LightFileTreeIterable.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (20 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 23/24] Added the test class AddCommandIterationTest Florian Koeberle
                   ` (2 subsequent siblings)
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../jgit/treewalk/LightFileTreeIterable.java       |   59 ++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java
new file mode 100644
index 0000000..5768f78
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/LightFileTreeIterable.java
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk;
+
+import java.io.File;
+import java.util.Iterator;
+
+import org.spearce.jgit.treewalk.rules.Rules;
+
+/**
+ * Use this class to iterate over some by rules determined files in a project
+ * directory.
+ * 
+ */
+public class LightFileTreeIterable implements Iterable<File> {
+	private final File projectDirectory;
+
+	private final Rules ignoreRules;
+
+	private final boolean includeRootDirectory;
+
+	/**
+	 * 
+	 * @param workTreeDirectory
+	 *            directory with the files which are under version control.
+	 * @param rules
+	 *            a {@link Rules} instance which is used to determine which file
+	 *            are included and which not.
+	 * @param includeWorkTreeDirectory
+	 *            determines if the iterators should return the
+	 *            workTreeDirectory
+	 */
+	public LightFileTreeIterable(File workTreeDirectory, Rules rules,
+			boolean includeWorkTreeDirectory) {
+		this.projectDirectory = workTreeDirectory;
+		this.ignoreRules = rules;
+		this.includeRootDirectory = includeWorkTreeDirectory;
+	}
+
+	public Iterator<File> iterator() {
+		return new LightFileTreeIterator(projectDirectory, ignoreRules,
+				includeRootDirectory);
+	}
+
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 23/24] Added the test class AddCommandIterationTest.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (21 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 22/24] Added class LightFileTreeIterable Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:13 ` [JGIT PATCH v2 24/24] Added a "add" command to the git like command line tool Florian Koeberle
  2008-05-12 20:43 ` [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Miklos Vajna
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../treewalk/rules/AddCommandIterationTest.java    |  321 ++++++++++++++++++++
 1 files changed, 321 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/AddCommandIterationTest.java

diff --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
new file mode 100644
index 0000000..a96c880
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/treewalk/rules/AddCommandIterationTest.java
@@ -0,0 +1,321 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.treewalk.rules;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.spearce.jgit.errors.InvalidPatternException;
+import org.spearce.jgit.errors.PathNotInProjectDirectoryException;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.WorkTree;
+import org.spearce.jgit.treewalk.LightFileTreeIterable;
+
+public class AddCommandIterationTest extends TestCase {
+
+	private WorkTree workTree;
+
+	private AddRulesFactory factory;
+
+	private Iterable<File> createIterable(File workingDirectory,
+			List<String> filePatternsOfAddCommand)
+			throws PathNotInProjectDirectoryException, InvalidPatternException,
+			IOException {
+		final Rules rules = factory.createRules(workTree.getDirectory(),
+				workingDirectory, filePatternsOfAddCommand);
+		return new LightFileTreeIterable(workTree.getDirectory(), rules, false);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		final File projectDirectory = File.createTempFile("test", "");
+		projectDirectory.delete();
+		projectDirectory.mkdir();
+		projectDirectory.deleteOnExit();
+		this.workTree = Repository.createWorkTree(projectDirectory);
+		this.factory = new AddRulesFactory();
+	}
+
+	public void testNoPattern() throws Exception {
+		createFile("a.txt");
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				Collections.<String> emptyList());
+		final Set<File> expectedPathes = Collections.emptySet();
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedPathes, iterable);
+	}
+
+	public void testTreePattern1() throws Exception {
+		final Set<File> expectedFiles = new HashSet<File>();
+		createFile("a.txt");
+		expectedFiles.add(createFile("a", "a.txt"));
+		expectedFiles.add(createFile("a", "a", "a.txt"));
+		expectedFiles.add(createFile("a", "b", "a.txt"));
+		createFile("a", "b", "a.c");
+
+		final File directoryA = new File(workTree.getDirectory(), "a");
+
+		final Iterable<File> iterable = createIterable(directoryA, Arrays
+				.asList("*.txt"));
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedFiles, iterable);
+	}
+
+	public void testTreePattern2() throws Exception {
+		final Set<File> expectedFiles = new HashSet<File>();
+		createFile("a.txt");
+		expectedFiles.add(createFile("a", "a.txt"));
+		expectedFiles.add(createFile("a", "a", "a.txt"));
+		expectedFiles.add(createFile("a", "b", "a.txt"));
+		createFile("a", "b", "a.c");
+
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				Arrays.asList("a" + File.separator + "*.txt"));
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedFiles, iterable);
+	}
+
+	public void testSelectCompleteSubdirectory() throws Exception {
+		final Set<File> expectedPathes = new HashSet<File>();
+		final File directoryA = new File(workTree.getDirectory(), "a");
+		final File directoryAA = new File(directoryA, "a");
+		final File directoryAB = new File(directoryA, "b");
+		createFile("a.txt");
+		expectedPathes.add(directoryA);
+		expectedPathes.add(directoryAA);
+		expectedPathes.add(createFile("a", "a.txt"));
+		expectedPathes.add(createFile("a", "a", "a.txt"));
+		expectedPathes.add(directoryAB);
+		expectedPathes.add(createFile("a", "b", "a.txt"));
+		expectedPathes.add(createFile("a", "b", "a.c"));
+
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				Arrays.asList("a"));
+
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedPathes, iterable);
+	}
+
+	public void testSelectTwoSubdirectories() throws Exception {
+		final Set<File> expectedPathes = new HashSet<File>();
+		final File directoryA = new File(workTree.getDirectory(), "a");
+		final File directoryAA = new File(directoryA, "a");
+		final File directoryAB = new File(directoryA, "b");
+		createFile("a.txt");
+		createFile("a", "a.txt");
+		expectedPathes.add(directoryAA);
+		expectedPathes.add(createFile("a", "a", "a.txt"));
+		expectedPathes.add(directoryAB);
+		expectedPathes.add(createFile("a", "b", "a.txt"));
+		expectedPathes.add(createFile("a", "b", "a.c"));
+
+		final List<String> patternList = new ArrayList<String>(2);
+		patternList.add("a" + File.separator + "a");
+		patternList.add("a" + File.separator + "b");
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				patternList);
+
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedPathes, iterable);
+	}
+
+	public void testTwoDifferentSelects() throws Exception {
+		final Set<File> expectedPathes = new HashSet<File>();
+		final File directoryA = new File(workTree.getDirectory(), "a");
+		final File directoryAA = new File(directoryA, "a");
+		createFile("a.txt");
+		createFile("a", "a.txt");
+		expectedPathes.add(directoryAA);
+		expectedPathes.add(createFile("a", "a", "a.txt"));
+		expectedPathes.add(createFile("a", "b", "a.txt"));
+		expectedPathes.add(createFile("a", "b", "c", "a.txt"));
+		createFile("a", "b", "a.c");
+
+		final List<String> patternList = new ArrayList<String>(2);
+		patternList.add("a" + File.separator + "a");
+		patternList.add("a" + File.separator + "b" + File.separator + "*.txt");
+
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				patternList);
+
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedPathes, iterable);
+	}
+
+	public void testRealisticExample() throws Exception {
+		final Set<File> expectedPathes = new HashSet<File>();
+
+		// write the .gitignore file
+		final File dotGitIgnoreFile = createFile(".gitignore");
+		final PrintWriter dotGitIgnoreFilePrinter = new PrintWriter(
+				dotGitIgnoreFile);
+		try {
+			dotGitIgnoreFilePrinter.println("/alpha/config.xml");
+			dotGitIgnoreFilePrinter.println("*.class");
+			dotGitIgnoreFilePrinter.println("!/alpha/test/ressources/");
+			dotGitIgnoreFilePrinter.println("*~");
+		} finally {
+			dotGitIgnoreFilePrinter.close();
+		}
+
+		// write the .git/info/exclude file
+		final File repositoryDirectory = workTree.getRepository()
+				.getDirectory();
+		final File infoDirectory = new File(repositoryDirectory, "info");
+		infoDirectory.mkdir();
+		final File infoExcludeFile = new File(infoDirectory, "exclude");
+		final PrintWriter infoExcludeFilePrinter = new PrintWriter(
+				infoExcludeFile);
+		try {
+			infoExcludeFilePrinter.println("/alpha/test/ressources/mytest.txt");
+		} finally {
+			infoExcludeFilePrinter.close();
+		}
+
+		createFile("alpha", "config.xml");
+		expectedPathes.add(createFile("alpha", "src", "Main.java"));
+		createFile("alpha", "src", "Main.class");
+		expectedPathes.add(createFile("alpha", "test", "ressources",
+				"Example.class"));
+		expectedPathes.add(createFile("alpha", "test", "ressources",
+				"input.txt"));
+		createFile("alpha", "test", "ressources", "input.txt~");
+		createFile("alpha", "test", "ressources", "mytest.txt");
+
+		final File alphaDirectory = new File(workTree.getDirectory(), "alpha");
+		final File srcDirectory = new File(alphaDirectory, "src");
+		final File testDirectory = new File(alphaDirectory, "test");
+		final File ressources = new File(testDirectory, "ressources");
+
+		expectedPathes.add(alphaDirectory);
+		expectedPathes.add(srcDirectory);
+		expectedPathes.add(testDirectory);
+		expectedPathes.add(ressources);
+
+		final List<String> patternList = new ArrayList<String>(2);
+		patternList.add("alpha");
+
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				patternList);
+
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedPathes, iterable);
+	}
+
+	public void testSingleFile() throws Exception {
+		createFile("a.txt");
+		createFile("a", "a.txt");
+		createFile("a", "a", "a.txt");
+		final File expectedFile = createFile("a", "b", "a.txt");
+		createFile("a", "b", "a.c");
+
+		final String pattern = "a" + File.separator + "b" + File.separator
+				+ "a.txt";
+		final Iterable<File> iterable = createIterable(workTree.getDirectory(),
+				Arrays.asList(pattern));
+		final Set<File> expectedPathes = Collections.singleton(expectedFile);
+		assertIsValidIterable(iterable);
+		assertIterableReturnsSet(expectedPathes, iterable);
+	}
+
+	/**
+	 * Tests if the specified {@link Iterable} returns the specified set of
+	 * {@link File}s. The assertion will fail if the {@link Iterable} returns
+	 * to much, to less files. It will also fail if the {@link Iterable} returns
+	 * a file twice.
+	 * 
+	 * @param expectedContent
+	 *            the expected set of files.
+	 * @param iterable
+	 *            the {@link Iterable} to test.
+	 */
+	private void assertIterableReturnsSet(Set<File> expectedContent,
+			Iterable<File> iterable) {
+		final Set<File> returnedFiles = new HashSet<File>();
+		final List<File> doubleReturnedFiles = new ArrayList<File>();
+
+		final Iterator<File> iterator = iterable.iterator();
+		while (iterator.hasNext()) {
+			final File file = iterator.next();
+			if (!returnedFiles.add(file)) {
+				doubleReturnedFiles.add(file);
+			}
+		}
+		final Set<File> missingFiles = new HashSet<File>();
+		for (File file : expectedContent) {
+			if (!returnedFiles.contains(file)) {
+				missingFiles.add(file);
+			}
+		}
+		if (!missingFiles.isEmpty()) {
+			fail(String.format("missing pathes: %s", missingFiles));
+		}
+
+		final Set<File> unexpectedFiles = new HashSet<File>();
+		for (File file : returnedFiles) {
+			if (!expectedContent.contains(file)) {
+				unexpectedFiles.add(file);
+			}
+		}
+		if (!unexpectedFiles.isEmpty()) {
+			fail(String.format("unexpected pathes: %s", unexpectedFiles));
+		}
+
+		if (!doubleReturnedFiles.isEmpty()) {
+			fail(String.format("multiple times returned pathes: %s",
+					doubleReturnedFiles));
+		}
+
+	}
+
+	private static void assertIsValidIterable(Iterable<File> iterable) {
+		final Iterator<File> iterator = iterable.iterator();
+		while (iterator.hasNext()) {
+			iterator.next();
+		}
+		try {
+			iterator.next();
+			fail();
+		} catch (NoSuchElementException e) {
+			// expected
+		}
+	}
+
+	private File createFile(String... path) throws IOException {
+		File file = workTree.getDirectory();
+		for (int i = 0; i < path.length; i++) {
+			file = new File(file, path[i]);
+			if (i == path.length - 1) {
+				file.getParentFile().mkdirs();
+				file.createNewFile();
+				break;
+			}
+		}
+		return file;
+	}
+}
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [JGIT PATCH v2 24/24] Added a "add" command to the git like command line tool.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (22 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 23/24] Added the test class AddCommandIterationTest Florian Koeberle
@ 2008-05-12 20:13 ` Florian Koeberle
  2008-05-12 20:43 ` [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Miklos Vajna
  24 siblings, 0 replies; 46+ messages in thread
From: Florian Koeberle @ 2008-05-12 20:13 UTC (permalink / raw)
  To: git; +Cc: Florian Koeberle

Signed-off-by: Florian Koeberle <florianskarten@web.de>
---
 .../src/org/spearce/jgit/pgm/AddCommand.java       |   97 ++++++++++++++++++++
 .../src/org/spearce/jgit/pgm/MainProgram.java      |    1 +
 2 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java
new file mode 100644
index 0000000..6d0a0d6
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/AddCommand.java
@@ -0,0 +1,97 @@
+/*
+ *  Copyright (C) 2008 Florian Köberle
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License, version 2, as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ */
+package org.spearce.jgit.pgm;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.spearce.jgit.errors.InvalidPatternException;
+import org.spearce.jgit.lib.GitIndex;
+import org.spearce.jgit.lib.Repository;
+
+import static org.spearce.jgit.lib.Repository.findWorkTree;
+import org.spearce.jgit.lib.WorkTree;
+import org.spearce.jgit.lib.GitIndex.Entry;
+import org.spearce.jgit.treewalk.LightFileTreeIterable;
+import org.spearce.jgit.treewalk.rules.AddRulesFactory;
+import org.spearce.jgit.treewalk.rules.Rules;
+
+/**
+ * The {@link #execute} method of this class is used to add files to the index.
+ * This class is immutable.
+ * 
+ */
+public class AddCommand implements Command {
+	/**
+	 * Use this instance instead of creating a new ${link AddCommand}. You don't
+	 * need to create an instance of this class as it is immutable and not
+	 * configurable.
+	 */
+	public static AddCommand INSTANCE = new AddCommand();
+
+	private AddRulesFactory addRulesFactory = new AddRulesFactory();
+
+	/**
+	 * Adds the specified files to the index.
+	 * 
+	 * @param args
+	 *            can contain "*.Suffix" patterns, files and directories.
+	 */
+	public void execute(String... args) throws IOException {
+		final WorkTree workTree = findWorkTree();
+		final Repository repository = workTree.getRepository();
+		try {
+			final GitIndex gitIndex = repository.getIndex();
+			final File projectDirectory = workTree.getDirectory();
+			final String workingDirectoryString = System
+					.getProperty("user.dir");
+			if (workingDirectoryString == null) {
+				throw new UnableToDetermineWorkingDirectory();
+			}
+			final File workingDirectory = new File(workingDirectoryString);
+			final Rules rules = addRulesFactory.createRules(workTree
+					.getDirectory(), workingDirectory, Arrays.asList(args));
+			final Iterable<File> fileIterable = new LightFileTreeIterable(
+					workTree.getDirectory(), rules, false);
+			for (File path : fileIterable) {
+				if (path.isFile()) {
+					final Entry entry = gitIndex.add(projectDirectory, path);
+					entry.setAssumeValid(false);
+				}
+			}
+			gitIndex.write();
+		} catch (UnableToDetermineWorkingDirectory e) {
+			System.err.println("Unable to determine working directory");
+			System.exit(1);
+		} catch (InvalidPatternException e) {
+			System.err.printf("The pattern '%s' is invalid: %s",
+					e.getMessage(), e.getPattern());
+			System.exit(1);
+		} finally {
+			repository.close();
+		}
+	}
+
+	public String getShortDescription() {
+		return "Adds one or more files to the index.";
+	}
+
+	private static class UnableToDetermineWorkingDirectory extends Exception {
+		private static final long serialVersionUID = -4229647819515644868L;
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
index 1ade91b..d9dafa3 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/MainProgram.java
@@ -33,6 +33,7 @@ public class MainProgram {
 
 	static {
 		final Map<String, Command> commands = new HashMap<String, Command>();
+		commands.put("add", AddCommand.INSTANCE);
 		commands.put("init", InitCommand.INSTANCE);
 		commands.put("help", HelpCommand.INSTANCE);
 		commandNameToObjectMap = Collections.unmodifiableMap(commands);
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules.
  2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
                   ` (23 preceding siblings ...)
  2008-05-12 20:13 ` [JGIT PATCH v2 24/24] Added a "add" command to the git like command line tool Florian Koeberle
@ 2008-05-12 20:43 ` Miklos Vajna
  24 siblings, 0 replies; 46+ messages in thread
From: Miklos Vajna @ 2008-05-12 20:43 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 254 bytes --]

On Mon, May 12, 2008 at 10:13:18PM +0200, Florian Koeberle <florianskarten@web.de> wrote:
> Maybe I missed something... I would need some patch-tree version
> control system which tracks changes in the patch tree ;).

the branch reflog is your friend :)

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 04/24] Added path related constats to Constats class.
  2008-05-12 20:13 ` [JGIT PATCH v2 04/24] Added path related constats to " Florian Koeberle
@ 2008-05-12 23:54   ` Shawn O. Pearce
  2008-05-23 15:46     ` Florian Köberle
  0 siblings, 1 reply; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-12 23:54 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> @@ -171,6 +171,26 @@ public final class Constants {
>  	public static String REMOTES_PREFIX = "refs/remotes";
>  
>  	/**
> +	 * The name of the repository directory in the project directory.
> +	 */
> +	public static final String REPOSITORY_DIRECTORY_NAME = ".git";

What is a project directory?

> +	/**
> +	 * Contains the name of the HEAD file in the repository directory.
> +	 */
> +	public static final String HEAD_FILE_NAME = "HEAD";

Isn't this already declared as just HEAD?  Lets not duplicate
constants if we can avoid it, especially when they are in the
same class.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.
  2008-05-12 20:13 ` [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository Florian Koeberle
@ 2008-05-13  0:04   ` Shawn O. Pearce
  2008-05-13 21:13     ` Robin Rosenberg
  0 siblings, 1 reply; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-13  0:04 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> +	public static WorkTree createWorkTree(File workTreeDirectory)

I'm only going to make this remark once for your series: In general I
prefer to mark any method argument, instance field or local variable
that I do not plan on changing within the method or class final.
This has saved me more than once from stupidly changing a parameter
when I meant to change something else.

Its not a hard and fast rule in either jgit or egit; you don't need
to go back and fix every single site.  Just something I have found
useful over the years and now do almost everywhere.

> +			throws IOException {
> +		final File gitDirectory = new File(workTreeDirectory,
> +				Constants.REPOSITORY_DIRECTORY_NAME);
> +		if (gitDirectory.exists()) {
> +			throw new IllegalArgumentException(
> +					"Repository exists in given project directory.");

When we throw an exception like this we should include the path
we are complaining about already existing as part of the message
(see Repository.create() for example).  This way if the message
makes it as far as the end-user (which it probably should, and
then there's translation issues are currently ignoring in jgit)
the user can at least see what path we were trying to operate on.
It may help them to realize they are in the wrong directory, or
made a typo on an input, etc.


Another thing about this method is we cannot supply the WindowCache
that the Repository should use for object data access, which means
this Repository will have its own WindowCache.  Under Eclipse (or
any other larger GUI/IDE) we really want only a single WindowCache
instance for the entire JVM as the heap must be shared across all
Repository instances.

This is actually making me reconsider how the WindowCache is handled.
Maybe we should have a single WindowCache instance down inside
of jgit, but allow the higher level UI (like Eclipse) to tune it
on the fly.  Then we don't have to worry about passing it down to
utility routines like this anytime we open a Repository.

Hmmmm.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.
  2008-05-12 20:13 ` [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class Florian Koeberle
@ 2008-05-13  0:24   ` Shawn O. Pearce
  2008-05-23 18:12     ` Florian Köberle
  0 siblings, 1 reply; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-13  0:24 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> @@ -1242,4 +1247,89 @@ public class Repository {
>  		}
>  	}
>  
> +	/**
> +	 * Find the git repository for the current working directory.
> +	 * 
> +	 * @return a {@link Repository}.
> +	 * @throws IOException
> +	 *             if the system property user.dir isn't set or if it is
> +	 *             invalid.
> +	 */
> +	public static WorkTree findWorkTree() throws IOException {
> +		final String workingDirectoryPath = System.getProperty("user.dir");
> +		if (workingDirectoryPath == null) {
> +			throw new IOException("unable to get working directory");
> +		}
> +		final File workingDirectoryFile = new File(workingDirectoryPath);

Isn't `final File workingDirectoryFile = new File(".")` easier to write?

And if we are going to throw a checked exception because we cannot
find a repository in ".", maybe that should be a new checked
exception, like NoGitRepositoryFoundException?

> +	/**
> +	 * Checks if a path is a valid git repository. Works similar like the method
> +	 * is_git_directory from the original setup.c file.

References to C Git aren't common in jgit source code.  We aren't
a reference implementation, but that hasn't stopped people from
finding out code a sane description of "how things work".  I'd rather
not describe our code in terms of C Git's code; especially what
happens if C Git refactors one day, this reference might no longer
make sense.  Anyone coming back here to improve jgit or use this
method will be confused about what we are doing.

> +	 * 
> +	 * @param directory
> +	 *            the path which should be checked.
> +	 * @return true if the path is a valid git repository.
> +	 */
> +	private static boolean isRepository(File directory) {
> +		if (!directory.isDirectory()) {
> +			return false;
> +		}

We usually omit { and } on simple conditions like this.  Its a coding
pattern we stole from C Git, which stole it from the Linux kernel.

> +	private static WorkTree findWorkTree(File directory) throws IOException {
> +		File currentDirectory = directory.getAbsoluteFile();
> +		while (true) {
> +			final File commonGitDirectory = new File(directory,
> +					REPOSITORY_DIRECTORY_NAME);
> +			if (isRepository(commonGitDirectory)) {
> +				return new WorkTree(currentDirectory, new Repository(
> +						commonGitDirectory));
> +			}
> +
> +			if (isRepository(currentDirectory)) {
> +				return new WorkTree(null, new Repository(currentDirectory));
> +			}
> +			currentDirectory = currentDirectory.getParentFile();
> +			if (currentDirectory == null) {
> +				throw new IOException("Can't find git repository");
> +			}
> +		}

Would this perhaps be a shorter, easier to follow variant of the
same algorithm?

	directory = directory.getAbsoluteFile();
	File workdir = directory;
	while (workdir != null) {
		final File gitdir = new File(workdir, REPOSITORY_DIRECTORY_NAME);
		if (isRepository(gitdir))
			return new WorkTree(workdir, new Repository(gitdir));
		if (isRepository(workdir))
			return new WorkTree(null, new Repository(workdir));
		workdir = workdir.getParentFile();
	}
	throw new NoGitRepositoryFoundException("No repository for " + directory);

I often do write infinite loops with "for (;;) {", but usually its
because the loop condition is based on an iterator-style method
returning null at the end and I want to store the result in a local
variable scoped to only the body of the loop:

	for (;;) {
		final RevCommit next = walk.next();
		if (next == null)
			break;

		// use next somehow
	}

Otherwise I try to avoid infinite loops in my final version
of something.  Though on a recent job interview the interviewer
noticed I tend to start writing code with an infinite loop, then
go back and correct the loop condition before saying "done".  ;-)

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 11/24] Added the class FNMatchPattern.
  2008-05-12 20:13 ` [JGIT PATCH v2 11/24] Added the class FNMatchPattern Florian Koeberle
@ 2008-05-13  0:38   ` Shawn O. Pearce
  0 siblings, 0 replies; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-13  0:38 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> +/**
> + * This class represents a pattern which should work like the fnmatch method.
> + * <code>new FNMatchPattern(exp).matches(input)</code> should do the same like
> + * <code>fnmatch(exp, input, 0) == 0</code>
> + * 
> + * As this isn't a one to one code port, but written based on the documentation
> + * of fnmatch it can be that the behavior of this class differ in some corner
> + * cases from the behavior of the fnmatch function.
> + */
> +public class FNMatchPattern {
> +
> +	private final Pattern regexPattern;

For what it is worth, I got a performance improvement by declaring
that such classes like FNMatchPattern are _not_ threadsafe and
storing a Matcher rather than a Pattern.  Then on each test you
can just reset the Matcher and evaluate it again.

This was worthwhile enough that I went back into RevFilter and
added a clone() method so you can safely clone a RevFilter graph
to create a new set of instances for another thread.

Consider using a Matcher here.  Ignore rule matching with a lot
of patterns will bottleneck things like working directory status
operations.

> +	private static String toRegexString(String fnmatchPattern) {
> +		final StringBuilder regexStringBuilder = new StringBuilder();
> +		char perviosCharacter = 0;
> +		for (int i = 0; i < fnmatchPattern.length(); i++) {
> +			final char c = fnmatchPattern.charAt(i);
> +			switch (c) {
> +			case '^':
> +				if (perviosCharacter == '[') {
> +					regexStringBuilder.append('!');
> +				} else {
> +					regexStringBuilder.append("\\x5E");
> +				}
> +				break;
> +			case '.':
> +				regexStringBuilder.append("\\x2E");
> +				break;
> +			case '*':
> +				regexStringBuilder.append(".*");
> +				break;
> +			default:
> +				regexStringBuilder.append(c);
> +			}
> +			perviosCharacter = c;
> +		}
> +		return regexStringBuilder.toString();

Huh.  So the fnmatchPattern of "foo?" will match the name "fo"
in this implementation, but it does not in my C library's fnmatch
function:

	$ cat fnmatch.c 
	#include <fnmatch.h>
	#include <stdio.h>

	int main(int argc, char *argv[]) {
		const char *pattern = argv[1];
		const char *name = argv[2];
		printf("%s on %s = %i\n", pattern, name, fnmatch(pattern, name, 0));
		return 0;
	}
	$ ./fnmatch 'foo?' 'fo'
	foo? on fo = 1

There are plenty more cases like that as too many of the regex
operators are leaking through. All of the regex operators need to
be treated as literals in the regex pattern.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.
  2008-05-12 20:13 ` [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory Florian Koeberle
@ 2008-05-13  1:08   ` Shawn O. Pearce
  2008-05-13 10:19     ` Florian Köberle
  0 siblings, 1 reply; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-13  1:08 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> +/**
> + * This class can be used to create lists of {@link Rule} objects from lines of
> + * .gitignore like files.
> + * 
> + */
> +class IgnoreRuleListFactory {
> +
> +	List<Rule> createIgnoreRuleList(Iterable<String> lineIterable) {
> +		LinkedList<Rule> rules = new LinkedList<Rule>();
> +		for (String line : lineIterable) {
> +			final String trimmedLine = line.trim();
> +			if (trimmedLine.startsWith("#")) {
> +				continue;
> +			}
> +			if (trimmedLine.length() == 0) {
> +				continue;
> +			}
> +			rules.add(0, createRule(trimmedLine));
> +		}
> +		return rules;
> +	}
> +
> +	List<Rule> createIgnoreRuleList(List<File> files)
> +			throws FileNotFoundException {
> +		final List<String> lines = new ArrayList<String>();
> +		for (File file : files) {
> +			Scanner scanner = new Scanner(file);
> +			try {
> +				while (scanner.hasNextLine()) {
> +					lines.add(scanner.nextLine());
> +				}
> +			} finally {
> +				scanner.close();
> +			}
> +		}
> +		return createIgnoreRuleList(lines);
> +	}

Why go through all this work to buffer the lines we don't care about
(starting with # or are blank) when we could just discard them in the
inside of createIgnoreRuleList and then create the rule right away?

> +	private Rule createRule(String trimmedLine) {
> +		final boolean exclude;
> +		String patternString;
> +		if (trimmedLine.startsWith("!")) {
> +			exclude = false;
> +			patternString = trimmedLine.substring(1);
> +		} else {
> +			exclude = true;
> +			patternString = trimmedLine;
> +		}

I suspect this code would be easier to follow if you just accepted
changing the method parameter, such as:

	private Rule createRule(String pattern) {
		boolean exclude = true;
		if (pattern.startsWith("!)) {
			pattern = pattern.substring(1);
			exclude = false;
		}

> +		final boolean matchDirectoriesOnly;
> +		if (patternString.endsWith("/")) {
> +			matchDirectoriesOnly = true;
> +			patternString = patternString.substring(0,
> +					patternString.length() - 1);
> +		} else {
> +			matchDirectoriesOnly = false;
> +		}
> +
> +		final FilePattern pattern;
> +		if (patternString.contains("/")) {
> +			if (patternString.startsWith("/")) {
> +				patternString = patternString.substring(1);
> +			}

"foo/bar" will always end up in this code-path and will not match
in all levels of the tree if I follow your code correctly.

An ignore rule in the top level of "foo/bar" should ignore any entry
named "bar" within a directory "foo" at any level of the tree, even
if it is 35 directories down from the root.  Isn't ComplexFilePattern
about the absolute (starts with "/") cases only?

> +			final StringTokenizer stringTokenizer = new StringTokenizer(
> +					patternString, "/");
> +			final List<String> patternList = new ArrayList<String>();
> +			while (stringTokenizer.hasMoreTokens()) {
> +				final String token = stringTokenizer.nextToken();
> +				patternList.add(token);
> +			}

StringTokenizer is more-or-less replaced by String.split("/"), with
the split method being the more preferred method of doing this.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 17/24] Added the class TreeFilePattern.
  2008-05-12 20:13 ` [JGIT PATCH v2 17/24] Added the class TreeFilePattern Florian Koeberle
@ 2008-05-13  1:22   ` Shawn O. Pearce
  0 siblings, 0 replies; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-13  1:22 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> +/**
> + * Represents a pattern like "documents/*.txt" which matches all *.txt files in
> + * the tree documents.
> + * 
> + */
> +class TreeFilePattern implements FilePattern {
> +
> +	private final List<String> path;
> +
> +	private final int offset;
> +
> +	private final GlobalFilePattern globalFilePattern;

Hmm.  This looks a lot like the ComplexFilePattern class to me;
only it has the optimization of avoiding the regex match on the
leading parts of the path.

Wouldn't it be simpler to define ComplexFilePattern taking a
List<FilePattern> and have two implementations of FilePattern;
one that uses FNMatch and one that uses strict String.equals()?
Then this entire class becomes unnecessary as the pattern
"documents/technical/*.txt" can be handled by two ExactMatch
instances followd by an FNMatch instance.

The performance difference is probably not even measurable, but
the code will be less complicated and less special-cased.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.
  2008-05-12 20:13 ` [JGIT PATCH v2 19/24] Added the class AddRuleListFactory Florian Koeberle
@ 2008-05-13  1:29   ` Shawn O. Pearce
  2008-05-13 11:24     ` Florian Köberle
  0 siblings, 1 reply; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-13  1:29 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git

Florian Koeberle <florianskarten@web.de> wrote:
> +class AddRuleListFactory {
> +	/*
> +	 * The add command of git 1.5.2.5 behaves a little bit stange: "git add
> +	 * a/\*z" adds the file "a/b/xyz" but "git add a/x\*" does not.
> +	 * 
> +	 * The first is parsed as pattern "*z" for whole directory tree "a". The
> +	 * second is parsed as an path.
> +	 * 
> +	 */

Its not strange.  C Git expands each file path to its _full_ path
and stores that into a buffer, then runs fnmatch() for each pattern
on the buffer.  If fnmatch() succeeds the path is added to the index.

In the case above we are running a match of "a/\*.z" against
"a/b/xyz" and that passes.  Or we run "a/x\*" on "a/b/xyz" and it
fails as the sequence of characters "a/x" does not appear in the
string "a/b".

You are running into this odd corner case because you are not
treating the pattern passed as something that matches against the
entire path.  This is one reason why TreeFilter's use the entire
path when they process an entry for inclusion or exclusion, and why
TreeWalk has each AbstractTreeIterator append the current entry name
onto the end of the current path buffer, so we can always examine
the full path from the root of the repository/working directory.

Trying to avoid the full path in classes like ComplexFilePattern
is why you are running into this corner case here, and must now do
extra contortions to somewhat match the behavior of C Git.

At this point I think most of the rules package is overcomplicated
and overoptimized, and yet doesn't actually quite match the behavior
of C Git.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.
  2008-05-13  1:08   ` Shawn O. Pearce
@ 2008-05-13 10:19     ` Florian Köberle
  2008-05-14  1:06       ` Shawn O. Pearce
  0 siblings, 1 reply; 46+ messages in thread
From: Florian Köberle @ 2008-05-13 10:19 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

Shawn O. Pearce wrote:
> Florian Koeberle <florianskarten@web.de> wrote:
>> +/**
>> + * This class can be used to create lists of {@link Rule} objects from lines of
>> + * .gitignore like files.
>> + * 
>> + */
>> +class IgnoreRuleListFactory {
>> +
>> +	List<Rule> createIgnoreRuleList(Iterable<String> lineIterable) {
>> +		LinkedList<Rule> rules = new LinkedList<Rule>();
>> +		for (String line : lineIterable) {
>> +			final String trimmedLine = line.trim();
>> +			if (trimmedLine.startsWith("#")) {
>> +				continue;
>> +			}
>> +			if (trimmedLine.length() == 0) {
>> +				continue;
>> +			}
>> +			rules.add(0, createRule(trimmedLine));
>> +		}
>> +		return rules;
>> +	}
>> +
>> +	List<Rule> createIgnoreRuleList(List<File> files)
>> +			throws FileNotFoundException {
>> +		final List<String> lines = new ArrayList<String>();
>> +		for (File file : files) {
>> +			Scanner scanner = new Scanner(file);
>> +			try {
>> +				while (scanner.hasNextLine()) {
>> +					lines.add(scanner.nextLine());
>> +				}
>> +			} finally {
>> +				scanner.close();
>> +			}
>> +		}
>> +		return createIgnoreRuleList(lines);
>> +	}
> 
> Why go through all this work to buffer the lines we don't care about
> (starting with # or are blank) when we could just discard them in the
> inside of createIgnoreRuleList and then create the rule right away?
I did this to reduce complexity and to increase modularity.
The method createIgnoreRuleList(Iterable<String> lineIterable) can now 
be tested without the need to create files. Also it is so possible to 
read the patterns from different sources.

If you worry about memory usuage I could create some kind of 
RulesBuilder class:

public class RulesBuilder {
	private final List<Rule> rules;
	private RuleListToObjectConverter converter;

	// method used by tests:
	public void addIgnoreRule(String ignoreRuleLine) {
		
	}
  	public void addIgnoreRuleFile(File) {
		// reads file and calls addIgnoreRule
	}

	public void addIncludeRuleOfAddCommand(String pattern) {
	}

	public void addIgnoreGitDirectoryRule() {
	}

	public Rules buildRules() {
		return converter.convertToObject(rules);
	}
}

This would have the advantages:
* all Rule creating code at one place.
* There is no need to keep the original lines in memory.
* It's easy to create rules for testing purposes.
* It's easy to create Factories like AddRulesFactory.

> 
>> +	private Rule createRule(String trimmedLine) {
>> +		final boolean exclude;
>> +		String patternString;
>> +		if (trimmedLine.startsWith("!")) {
>> +			exclude = false;
>> +			patternString = trimmedLine.substring(1);
>> +		} else {
>> +			exclude = true;
>> +			patternString = trimmedLine;
>> +		}
> 
> I suspect this code would be easier to follow if you just accepted
> changing the method parameter, such as:
> 
> 	private Rule createRule(String pattern) {
> 		boolean exclude = true;
> 		if (pattern.startsWith("!)) {
> 			pattern = pattern.substring(1);
> 			exclude = false;
> 		}
If I remember correctly Intellij IDEA marks per default cases where you 
change a parameter. So it looks like that there are style guides which 
are against the practice of changing the values of parameters.

That and the fact that you can't make exclude final now where the reason 
why I wrote it the otherway.
> 
>> +		final boolean matchDirectoriesOnly;
>> +		if (patternString.endsWith("/")) {
>> +			matchDirectoriesOnly = true;
>> +			patternString = patternString.substring(0,
>> +					patternString.length() - 1);
>> +		} else {
>> +			matchDirectoriesOnly = false;
>> +		}
>> +
>> +		final FilePattern pattern;
>> +		if (patternString.contains("/")) {
>> +			if (patternString.startsWith("/")) {
>> +				patternString = patternString.substring(1);
>> +			}
> 
> "foo/bar" will always end up in this code-path and will not match
> in all levels of the tree if I follow your code correctly.
> 
> An ignore rule in the top level of "foo/bar" should ignore any entry
> named "bar" within a directory "foo" at any level of the tree, even
> if it is 35 directories down from the root.  Isn't ComplexFilePattern
> about the absolute (starts with "/") cases only?
Yes, ComplexFilePattern is about that cases only.

I implemented it that way, becasue git behave the same way:
* create the follwing file: a/a/b/test.txt
* add the line "a/b" to .gitignore
* add a and notice that it adds the test.txt file.

> 
>> +			final StringTokenizer stringTokenizer = new StringTokenizer(
>> +					patternString, "/");
>> +			final List<String> patternList = new ArrayList<String>();
>> +			while (stringTokenizer.hasMoreTokens()) {
>> +				final String token = stringTokenizer.nextToken();
>> +				patternList.add(token);
>> +			}
> 
> StringTokenizer is more-or-less replaced by String.split("/"), with
> the split method being the more preferred method of doing this.
> 
Ok

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.
  2008-05-13  1:29   ` Shawn O. Pearce
@ 2008-05-13 11:24     ` Florian Köberle
  2008-05-13 20:55       ` Robin Rosenberg
  0 siblings, 1 reply; 46+ messages in thread
From: Florian Köberle @ 2008-05-13 11:24 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

Shawn O. Pearce wrote:
> Florian Koeberle <florianskarten@web.de> wrote:
>> +class AddRuleListFactory {
>> +	/*
>> +	 * The add command of git 1.5.2.5 behaves a little bit stange: "git add
>> +	 * a/\*z" adds the file "a/b/xyz" but "git add a/x\*" does not.
>> +	 * 
>> +	 * The first is parsed as pattern "*z" for whole directory tree "a". The
>> +	 * second is parsed as an path.
>> +	 * 
>> +	 */
> 
> Its not strange.  C Git expands each file path to its _full_ path
> and stores that into a buffer, then runs fnmatch() for each pattern
> on the buffer.  If fnmatch() succeeds the path is added to the index.
> 
> In the case above we are running a match of "a/\*.z" against
> "a/b/xyz" and that passes.  Or we run "a/x\*" on "a/b/xyz" and it
> fails as the sequence of characters "a/x" does not appear in the
> string "a/b".
> 
> You are running into this odd corner case because you are not
> treating the pattern passed as something that matches against the
> entire path.  This is one reason why TreeFilter's use the entire
> path when they process an entry for inclusion or exclusion, and why
> TreeWalk has each AbstractTreeIterator append the current entry name
> onto the end of the current path buffer, so we can always examine
> the full path from the root of the repository/working directory.
> 
> Trying to avoid the full path in classes like ComplexFilePattern
> is why you are running into this corner case here, and must now do
> extra contortions to somewhat match the behavior of C Git.
> 
> At this point I think most of the rules package is overcomplicated
> and overoptimized, and yet doesn't actually quite match the behavior
> of C Git.
> 

Still I think that the behavior of git-add is strange:
For example, if you want to add the following file:
a/b/c/test.txt
Then I can do this with "a/\*.txt" or "a/b\*.txt" but not with 
"a/\*/c/test.txt"

I know that I handle "a/b\*.txt" wrong, and I don't know a nice way to 
implement it in the current rules framework.

I see three options:
1.) Let the jgit add command work in another way then git-add does.
2.) Don't use the rules framework to determine if a file is selected by 
the add command.
3.) Completely drop the patches
[4.) Add some evil hacks to make it working] <- I don't like that version

Please tell me which way to go, so that I don't waste even more time on 
patches which will never make it in.

Best regards,
Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.
  2008-05-13 11:24     ` Florian Köberle
@ 2008-05-13 20:55       ` Robin Rosenberg
  2008-05-14  1:49         ` Shawn O. Pearce
  0 siblings, 1 reply; 46+ messages in thread
From: Robin Rosenberg @ 2008-05-13 20:55 UTC (permalink / raw)
  To: Florian Köberle; +Cc: Shawn O. Pearce, git

tisdagen den 13 maj 2008 13.24.56 skrev Florian Köberle:
> Shawn O. Pearce wrote:
> > Florian Koeberle <florianskarten@web.de> wrote:
> >> +class AddRuleListFactory {
> >> +	/*
> >> +	 * The add command of git 1.5.2.5 behaves a little bit stange: "git add
> >> +	 * a/\*z" adds the file "a/b/xyz" but "git add a/x\*" does not.
You mean a/\*/x* does not?
> >> +	 * 
> >> +	 * The first is parsed as pattern "*z" for whole directory tree "a". The
> >> +	 * second is parsed as an path.
> >> +	 * 
> >> +	 */
> > 
> > Its not strange.  C Git expands each file path to its _full_ path
> > and stores that into a buffer, then runs fnmatch() for each pattern
> > on the buffer.  If fnmatch() succeeds the path is added to the index.
> > 
> > In the case above we are running a match of "a/\*.z" against
> > "a/b/xyz" and that passes.  Or we run "a/x\*" on "a/b/xyz" and it
> > fails as the sequence of characters "a/x" does not appear in the
> > string "a/b".
> > 
> > You are running into this odd corner case because you are not
> > treating the pattern passed as something that matches against the
> > entire path.  This is one reason why TreeFilter's use the entire
> > path when they process an entry for inclusion or exclusion, and why
> > TreeWalk has each AbstractTreeIterator append the current entry name
> > onto the end of the current path buffer, so we can always examine
> > the full path from the root of the repository/working directory.
> > 
> > Trying to avoid the full path in classes like ComplexFilePattern
> > is why you are running into this corner case here, and must now do
> > extra contortions to somewhat match the behavior of C Git.
> > 
> > At this point I think most of the rules package is overcomplicated
> > and overoptimized, and yet doesn't actually quite match the behavior
> > of C Git.
> > 
> 
> Still I think that the behavior of git-add is strange:
> For example, if you want to add the following file:
> a/b/c/test.txt
> Then I can do this with "a/\*.txt" or "a/b\*.txt" but not with 
> "a/\*/c/test.txt"
> 
> I know that I handle "a/b\*.txt" wrong, and I don't know a nice way to 
> implement it in the current rules framework.
> 
> I see three options:
> 1.) Let the jgit add command work in another way then git-add does.
> 2.) Don't use the rules framework to determine if a file is selected by 
> the add command.
> 3.) Completely drop the patches
> [4.) Add some evil hacks to make it working] <- I don't like that version
> 
> Please tell me which way to go, so that I don't waste even more time on 
> patches which will never make it in.

Correctness is very important. Obviously we will slip bugs trough, but
not intentionally in a part where legacy behaviour may play an important
role. With these options available I'd select number 2.

I think your observations are interesting, especially the one you make
here about a/*/c/test.txt not matching because I don't see from the git
add manual why it shouldn't. I does not look like a recent git bug either. 

btw, I should you can use the ö in your name in mail and too. It'll make
for some interesting testing of non-ascii handling that we need to take
on (another argument for not complicating handling of names too much).
I'm sure it will get pretty hairy regardless.

-- robin

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.
  2008-05-13  0:04   ` Shawn O. Pearce
@ 2008-05-13 21:13     ` Robin Rosenberg
  2008-05-14  0:35       ` Shawn O. Pearce
  0 siblings, 1 reply; 46+ messages in thread
From: Robin Rosenberg @ 2008-05-13 21:13 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Florian Koeberle, git

tisdagen den 13 maj 2008 02.04.05 skrev Shawn O. Pearce:
> This is actually making me reconsider how the WindowCache is handled.
> Maybe we should have a single WindowCache instance down inside
> of jgit, but allow the higher level UI (like Eclipse) to tune it
> on the fly.  Then we don't have to worry about passing it down to
> utility routines like this anytime we open a Repository.

A singleton WindowCache makes more sense yes.

-- robin

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository.
  2008-05-13 21:13     ` Robin Rosenberg
@ 2008-05-14  0:35       ` Shawn O. Pearce
  0 siblings, 0 replies; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-14  0:35 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: Florian Koeberle, git

Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:
> tisdagen den 13 maj 2008 02.04.05 skrev Shawn O. Pearce:
> > This is actually making me reconsider how the WindowCache is handled.
> > Maybe we should have a single WindowCache instance down inside
> > of jgit, but allow the higher level UI (like Eclipse) to tune it
> > on the fly.  Then we don't have to worry about passing it down to
> > utility routines like this anytime we open a Repository.
> 
> A singleton WindowCache makes more sense yes.

Yea, OK.  I'll add it to my list of things to fix real-soon-now.

Right now I'm trying to finish automated tag following, since it
is not implemented.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory.
  2008-05-13 10:19     ` Florian Köberle
@ 2008-05-14  1:06       ` Shawn O. Pearce
  0 siblings, 0 replies; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-14  1:06 UTC (permalink / raw)
  To: Florian Köberle; +Cc: git

Florian Kberle <FloriansKarten@web.de> wrote:
> Shawn O. Pearce wrote:
> >
> >Why go through all this work to buffer the lines we don't care about
> >(starting with # or are blank) when we could just discard them in the
> >inside of createIgnoreRuleList and then create the rule right away?
>
> I did this to reduce complexity and to increase modularity.
> The method createIgnoreRuleList(Iterable<String> lineIterable) can now 
> be tested without the need to create files. Also it is so possible to 
> read the patterns from different sources.
> 
> If you worry about memory usuage I could create some kind of 
> RulesBuilder class:

OK.  I guess I can see that.  I wasn't worried about memory, it just
seemed odd to me that the "parser" (splitting the file into lines)
was also not skipping the lines that were not interesting.

Given your explanation I don't see a reason to change it, it just
struck me as odd.
 
> >I suspect this code would be easier to follow if you just accepted
> >changing the method parameter, such as:
> >
> >	private Rule createRule(String pattern) {
> >		boolean exclude = true;
> >		if (pattern.startsWith("!)) {
> >			pattern = pattern.substring(1);
> >			exclude = false;
> >		}
>
> If I remember correctly Intellij IDEA marks per default cases where you 
> change a parameter. So it looks like that there are style guides which 
> are against the practice of changing the values of parameters.

Yes, there are style guides floating around that say "do not
modify parameters".  There is also a Java keyword that means
"do not modify this variable in scope", its called "final".

Personally I think whether or not something should be final in
a scope depends on the size of the scope and what is clearer to
read to modify the existing variable, or to introduce a copy with a
different name and a potentially different value.  Forcing everything
to not modify parameters by compiler edict is nuts.

In the code I was talking about you had two different variables
for the pattern, just to avoid not modifying the parameter.
Yet within the scope of the method once the "!" is cut off the
original pattern string is worthless.  In my very humble opinion
it is more risky to have two different variables (one whose scope
has expired the moment the method starts and one that is useful)
then to have a mutable parameter.

But as I said, its only my humble opinion.  Since I'm American my
$0.02 is worth what, 0.00000002 rupees these days?  ;-)
 
> I implemented it that way, becasue git behave the same way:
> * create the follwing file: a/a/b/test.txt
> * add the line "a/b" to .gitignore
> * add a and notice that it adds the test.txt file.

OK.  You are correct.  If the ignore rule contains "/" it appears
to only apply from the top level of the repository.  That wasn't
my understanding of how it worked, but I stand corrected.  Thank you.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 19/24] Added the class AddRuleListFactory.
  2008-05-13 20:55       ` Robin Rosenberg
@ 2008-05-14  1:49         ` Shawn O. Pearce
  0 siblings, 0 replies; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-14  1:49 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: Florian Köberle, git

Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:
> tisdagen den 13 maj 2008 13.24.56 skrev Florian Köberle:
> > 
> > Still I think that the behavior of git-add is strange:
> > For example, if you want to add the following file:
> > a/b/c/test.txt
> > Then I can do this with "a/\*.txt" or "a/b\*.txt" but not with 
> > "a/\*/c/test.txt"
...
> Correctness is very important. Obviously we will slip bugs trough, but
> not intentionally in a part where legacy behaviour may play an important
> role. With these options available I'd select number 2.
> 
> I think your observations are interesting, especially the one you make
> here about a/*/c/test.txt not matching because I don't see from the git
> add manual why it shouldn't. I does not look like a recent git bug either. 

Wow.  The behavior of git-add makes _no_ sense to me.

  $ git init
  $ mkdir -p a/b/c; touch a/b/c/test.txt
  $ find a
  a
  a/b
  a/b/c
  a/b/c/test.txt

  $ git add 'a/*/test.txt'
  fatal: pathspec 'a/*/test.txt' did not match any files

(sure, ok, even my shell agrees)

  $ git add 'a/*/c/test.txt'
  fatal: pathspec 'a/*/c/test.txt' did not match any files

  $ ls a/*/c/test.txt
  a/b/c/test.txt

(hmm, now my shell says otherwise)

  $ git add 'a/b*/c/test.txt'
  fatal: pathspec 'a/b*/c/test.txt' did not match any files

  $ ls a/b*/c/test.txt
  a/b/c/test.txt

(also odd)

This last case does match with fnmatch:

  $ cat fnmatch.c 
  #include <fnmatch.h>
  #include <stdio.h>
  
  int main (int argc, char *argv[]) {
  	const char *name = argv[1];
  	const char *patt = argv[2];
  	printf("\"%s\" matches \"%s\" = %d\n",
  		name, patt,
  		fnmatch(patt, name, 0));
  	return 0;
  }

  $ gcc -o fnmatch fnmatch.c
  $ ./fnmatch a/b/c/test.txt 'a/b*/c/test.txt'
  "a/b/c/test.txt" matches "a/b*/c/test.txt" = 0

So I find it odd that git-add does not match this name, but fnmatch
does.  I suspect the problem here is git-add has pruned away the
subdirectory "a/b" and did not enter into it, so the pattern was
never even given a chance to look at test.txt.  This sounds like
a bug to me in git's working directory filter.

Even if Linus says matching names incorrectly is not a bug, I'm
not sure its an implementation detail we should mirror in jgit.

Where does that leave us?  I'm not sure.  But treating git-add as
a black box and replicating its behavior looks loony to me right now.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it.
  2008-05-12 20:13 ` [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it Florian Koeberle
@ 2008-05-14 14:27   ` Paolo Bonzini
  0 siblings, 0 replies; 46+ messages in thread
From: Paolo Bonzini @ 2008-05-14 14:27 UTC (permalink / raw)
  To: Florian Koeberle; +Cc: git


> +	void findMorePathesIfNessesary() {
> +	void findMorePathes

findMorePaths. :-)

Paolo

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 04/24] Added path related constats to Constats class.
  2008-05-12 23:54   ` Shawn O. Pearce
@ 2008-05-23 15:46     ` Florian Köberle
  0 siblings, 0 replies; 46+ messages in thread
From: Florian Köberle @ 2008-05-23 15:46 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

Shawn O. Pearce wrote:
> Florian Koeberle <florianskarten@web.de> wrote:
>> @@ -171,6 +171,26 @@ public final class Constants {
>>  	public static String REMOTES_PREFIX = "refs/remotes";
>>  
>>  	/**
>> +	 * The name of the repository directory in the project directory.
>> +	 */
>> +	public static final String REPOSITORY_DIRECTORY_NAME = ".git";
> 
> What is a project directory?
I will add a sentence describing what I meant with project directory here.



>> +	/**
>> +	 * Contains the name of the HEAD file in the repository directory.
>> +	 */
>> +	public static final String HEAD_FILE_NAME = "HEAD";
> 
> Isn't this already declared as just HEAD?  Lets not duplicate
> constants if we can avoid it, especially when they are in the
> same class.
>
current HEAD constant definition:
 > 	/** Special name for the "HEAD" symbolic-ref. */
 >	public static final String HEAD = "HEAD";
I didn't expect that this constant is a file name.

Looks like the constant is used in the same way I do, so It makes sense 
to use the existing HEAD constant.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.
  2008-05-13  0:24   ` Shawn O. Pearce
@ 2008-05-23 18:12     ` Florian Köberle
  2008-05-23 18:31       ` Miklos Vajna
  2008-05-23 21:28       ` Robin Rosenberg
  0 siblings, 2 replies; 46+ messages in thread
From: Florian Köberle @ 2008-05-23 18:12 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

>> +	 * 
>> +	 * @param directory
>> +	 *            the path which should be checked.
>> +	 * @return true if the path is a valid git repository.
>> +	 */
>> +	private static boolean isRepository(File directory) {
>> +		if (!directory.isDirectory()) {
>> +			return false;
>> +		}
> 
> We usually omit { and } on simple conditions like this.  Its a coding
> pattern we stole from C Git, which stole it from the Linux kernel.

I used this style once too, but was convinced that it dangerous to do so.

The following looks correct at the first look, but it's not:

	if (a)
		if (b)
			something;
	else
		something;

this can't happen if you use { and }:
	if (a) {
		if (b) {
			something0();
		}
	} else {
		something1();
	}


Also it is better extenable:

if (a) {
	something0();
}

if (a) {
	something0():
+	something1();
}

compared too:

-if (a)
+if (a) {
	something0();
+	something1();
+ }


it's even possible that someone does it wrong:
if (a)
	something0():
	something1();

I changed it at placed I edited to the short form, but if it is ok for 
you then I would write it the long way.

> 
>> +	private static WorkTree findWorkTree(File directory) throws IOException {
>> +		File currentDirectory = directory.getAbsoluteFile();
>> +		while (true) {
>> +			final File commonGitDirectory = new File(directory,
>> +					REPOSITORY_DIRECTORY_NAME);
>> +			if (isRepository(commonGitDirectory)) {
>> +				return new WorkTree(currentDirectory, new Repository(
>> +						commonGitDirectory));
>> +			}
>> +
>> +			if (isRepository(currentDirectory)) {
>> +				return new WorkTree(null, new Repository(currentDirectory));
>> +			}
>> +			currentDirectory = currentDirectory.getParentFile();
>> +			if (currentDirectory == null) {
>> +				throw new IOException("Can't find git repository");
>> +			}
>> +		}
> 
> Would this perhaps be a shorter, easier to follow variant of the
> same algorithm?
> 
> 	directory = directory.getAbsoluteFile();
> 	File workdir = directory;
> 	while (workdir != null) {
> 		final File gitdir = new File(workdir, REPOSITORY_DIRECTORY_NAME);
> 		if (isRepository(gitdir))
> 			return new WorkTree(workdir, new Repository(gitdir));
> 		if (isRepository(workdir))
> 			return new WorkTree(null, new Repository(workdir));
> 		workdir = workdir.getParentFile();
> 	}
> 	throw new NoGitRepositoryFoundException("No repository for " + directory);
> 

I did it this way now, but the line length limit makes it harder to read 
then my first version.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.
  2008-05-23 18:12     ` Florian Köberle
@ 2008-05-23 18:31       ` Miklos Vajna
  2008-05-23 20:39         ` Shawn O. Pearce
  2008-05-23 21:28       ` Robin Rosenberg
  1 sibling, 1 reply; 46+ messages in thread
From: Miklos Vajna @ 2008-05-23 18:31 UTC (permalink / raw)
  To: Florian Köberle; +Cc: Shawn O. Pearce, git

[-- Attachment #1: Type: text/plain, Size: 853 bytes --]

On Fri, May 23, 2008 at 08:12:31PM +0200, Florian Köberle <FloriansKarten@web.de> wrote:
> Also it is better extenable:
> 
> if (a) {
> 	something0();
> }
> 
> if (a) {
> 	something0():
> +	something1();
> }
> 
> compared too:
> 
> -if (a)
> +if (a) {
> 	something0();
> +	something1();
> + }
> 
> 
> it's even possible that someone does it wrong:
> if (a)
> 	something0():
> 	something1();

Different programmers have different coding style. A standard is needed,
otherwise different parts of the code will have different style. It's
quite normal if a contributor has to code in the project's coding style,
rather than his own one, I think.

Also I don't think "but this style is confusing for newbies" is a valid
argument, newbies should learn to read code, rather than others need to
write newbie-friendly code. ;-)

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.
  2008-05-23 18:31       ` Miklos Vajna
@ 2008-05-23 20:39         ` Shawn O. Pearce
  0 siblings, 0 replies; 46+ messages in thread
From: Shawn O. Pearce @ 2008-05-23 20:39 UTC (permalink / raw)
  To: Miklos Vajna; +Cc: Florian Köberle, git

Miklos Vajna <vmiklos@frugalware.org> wrote:
> On Fri, May 23, 2008 at 08:12:31PM +0200, Florian Köberle <FloriansKarten@web.de> wrote:
> > Also it is better extenable:
...
> > if (a) {
> > 	something0():
> > +	something1();
> > }
> > 
> > compared too:
> > 
> > -if (a)
> > +if (a) {
> > 	something0();
> > +	something1();
> > + }
> 
> Different programmers have different coding style. A standard is needed,
> otherwise different parts of the code will have different style. It's
> quite normal if a contributor has to code in the project's coding style,
> rather than his own one, I think.
> 
> Also I don't think "but this style is confusing for newbies" is a valid
> argument, newbies should learn to read code, rather than others need to
> write newbie-friendly code. ;-)

Right.

Basically Robin and I have settled on a style not too far from the
one that git.git itself uses, at least where they could pertain to
Java and its semi-C syntax rules.  Part of the reason is because
we (and others in the git community) are just used to this style.

Its shorter vertically, allowing more room for code and comments in
a single screen full.  It also minimizes the number of places where
"\t\t}\n" appear on a line by itself in the context of a patch,
reducing errors from patch hunks applying in the wrong position.

In a little over a month and a half I start a new job.  My new
employer apparently has really strict rules about how code should
be formatted, and everyone in the company has to adhere to them.
No exceptions.  The rules are supposedly quite strange, but the
entire code is at least consistent, and thus easier to follow.
So yea, I get to also go through some strange style thing soon.

When in Rome, do as the Romans do... :-|

-- 
Shawn.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class.
  2008-05-23 18:12     ` Florian Köberle
  2008-05-23 18:31       ` Miklos Vajna
@ 2008-05-23 21:28       ` Robin Rosenberg
  1 sibling, 0 replies; 46+ messages in thread
From: Robin Rosenberg @ 2008-05-23 21:28 UTC (permalink / raw)
  To: Florian Köberle; +Cc: Shawn O. Pearce, git

fredagen den 23 maj 2008 20.12.31 skrev Florian Köberle:
> >> +	 * 
> >> +	 * @param directory
> >> +	 *            the path which should be checked.
> >> +	 * @return true if the path is a valid git repository.
> >> +	 */
> >> +	private static boolean isRepository(File directory) {
> >> +		if (!directory.isDirectory()) {
> >> +			return false;
> >> +		}
> > 
> > We usually omit { and } on simple conditions like this.  Its a coding
> > pattern we stole from C Git, which stole it from the Linux kernel.
> 
> I used this style once too, but was convinced that it dangerous to do so.
As Shawn said, usually. Sometimes we slip too.  But it is unnecessary and
anything unnecessary usually makes code harder to read. It is not a big
deal to me. 

> The following looks correct at the first look, but it's not:
> 
> 	if (a)
> 		if (b)
> 			something;
> 	else
> 		something;
> 
> this can't happen if you use { and }:
> 	if (a) {
> 		if (b) {
> 			something0();
> 		}
> 	} else {
> 		something1();
> 	}

This 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).

> Also it is better extenable:
> 
> if (a) {
> 	something0();
> }
> 
> if (a) {
> 	something0():
> +	something1();
> }

Which 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.

-- robin

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2008-05-23 21:31 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-12 20:13 [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 01/24] Start of an implementation of a git like command line tool Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 02/24] Formatted Repository class Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 03/24] Formatted Constats class Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 04/24] Added path related constats to " Florian Koeberle
2008-05-12 23:54   ` Shawn O. Pearce
2008-05-23 15:46     ` Florian Köberle
2008-05-12 20:13 ` [JGIT PATCH v2 05/24] Added WorkTree class which can be constructed over Repository Florian Koeberle
2008-05-13  0:04   ` Shawn O. Pearce
2008-05-13 21:13     ` Robin Rosenberg
2008-05-14  0:35       ` Shawn O. Pearce
2008-05-12 20:13 ` [JGIT PATCH v2 06/24] Added a "init" command to the git like command line tool Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 07/24] Added findWorkTree method to Repository class Florian Koeberle
2008-05-13  0:24   ` Shawn O. Pearce
2008-05-23 18:12     ` Florian Köberle
2008-05-23 18:31       ` Miklos Vajna
2008-05-23 20:39         ` Shawn O. Pearce
2008-05-23 21:28       ` Robin Rosenberg
2008-05-12 20:13 ` [JGIT PATCH v2 08/24] Added the interface FilePattern Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 09/24] Added the class Rule Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 10/24] Added the iterface Rules Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 11/24] Added the class FNMatchPattern Florian Koeberle
2008-05-13  0:38   ` Shawn O. Pearce
2008-05-12 20:13 ` [JGIT PATCH v2 12/24] Added the class GlobalFilePattern Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 13/24] Added the class ComplexFilePattern Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 14/24] Added the class IgnoreRuleListFactory Florian Koeberle
2008-05-13  1:08   ` Shawn O. Pearce
2008-05-13 10:19     ` Florian Köberle
2008-05-14  1:06       ` Shawn O. Pearce
2008-05-12 20:13 ` [JGIT PATCH v2 15/24] Added a Rules interface implementation and a factory for it Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 16/24] Added test class OverallIgnoreRulestest Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 17/24] Added the class TreeFilePattern Florian Koeberle
2008-05-13  1:22   ` Shawn O. Pearce
2008-05-12 20:13 ` [JGIT PATCH v2 18/24] Added InvalidPatternException and PathNotInProjectDirectoryException Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 19/24] Added the class AddRuleListFactory Florian Koeberle
2008-05-13  1:29   ` Shawn O. Pearce
2008-05-13 11:24     ` Florian Köberle
2008-05-13 20:55       ` Robin Rosenberg
2008-05-14  1:49         ` Shawn O. Pearce
2008-05-12 20:13 ` [JGIT PATCH v2 20/24] Added class AddRulesFactory Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 21/24] Added the class LightFileTreeIterator and a test for it Florian Koeberle
2008-05-14 14:27   ` Paolo Bonzini
2008-05-12 20:13 ` [JGIT PATCH v2 22/24] Added class LightFileTreeIterable Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 23/24] Added the test class AddCommandIterationTest Florian Koeberle
2008-05-12 20:13 ` [JGIT PATCH v2 24/24] Added a "add" command to the git like command line tool Florian Koeberle
2008-05-12 20:43 ` [JGIT PATCH v2 0/24] Implementation of a file tree iteration using ignore rules Miklos Vajna

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).