git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[EGIT PATCH 10/11] Add a TreeWalk iterator implementation for IContainer

From
Shawn O. Pearce <spearce@spearce.org>
Date
Aug 10, 2008, 08:46 UTC
Message-ID
<1218357986-19671-11-git-send-email-spearce@spearce.org>
In-Reply-To
<1218357986-19671-10-git-send-email-spearce@spearce.org>

Treating the Eclipse workspace as a filesystem backend for TreeWalk can give us some nice caching on the file modification times and on directory contents. We also get nice APIs to open a file and read its contents.

This iterator allows combining a walk over an IContainer with any other sort of directory walk we may do, like against a stored tree object in the object database or against the index file, or even any other IContainer in the workspace (e.g. diff two projects).

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../spearce/egit/core/ContainerTreeIterator.java   |  181 ++++++++++++++++++++
 1 files changed, 181 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.egit.core/src/org/spearce/egit/core/ContainerTreeIterator.java
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/ContainerTreeIterator.java b/org.spearce.egit.core/src/org/spearce/egit/core/ContainerTreeIterator.java
new file mode 100644
index 0000000..17b8414
--- /dev/null
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/ContainerTreeIterator.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+
+package org.spearce.egit.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.spearce.egit.core.project.RepositoryMapping;
+import org.spearce.jgit.errors.IncorrectObjectTypeException;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.FileMode;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.treewalk.AbstractTreeIterator;
+import org.spearce.jgit.treewalk.WorkingTreeIterator;
+import org.spearce.jgit.util.FS;
+
+/**
+ * Adapts an Eclipse {@link IContainer} for use in a <code>TreeWalk</code>.
+ * <p>
+ * This iterator converts an Eclipse IContainer object into something that a
+ * TreeWalk instance can iterate over in parallel with any other Git tree data
+ * structure, such as another working directory tree from outside of the
+ * workspace or a stored tree from a Repository object database.
+ * <p>
+ * Modification times provided by this iterator are obtained from the cache
+ * Eclipse uses to track external resource modification. This can be faster, but
+ * requires the user refresh their workspace when external modifications take
+ * place. This is not really a concern as it is common practice to need to do a
+ * workspace refresh after externally modifying a file.
+ * 
+ * @see org.spearce.jgit.treewalk.TreeWalk
+ */
+public class ContainerTreeIterator extends WorkingTreeIterator {
+	private static String computePrefix(final IContainer base) {
+		final RepositoryMapping rm = RepositoryMapping.getMapping(base);
+		if (rm == null)
+			throw new IllegalArgumentException("Not in a Git project: " + base);
+		return rm.getRepoRelativePath(base);
+	}
+
+	private final IContainer node;
+
+	/**
+	 * Construct a new iterator from the workspace.
+	 * <p>
+	 * The iterator will support traversal over the named container, but only if
+	 * it is contained within a project which has the Git repository provider
+	 * connected and this resource is mapped into a Git repository. During the
+	 * iteration the paths will be automatically generated to match the proper
+	 * repository paths for this container's children.
+	 * 
+	 * @param base
+	 *            the part of the workspace the iterator will walk over.
+	 */
+	public ContainerTreeIterator(final IContainer base) {
+		super(computePrefix(base));
+		node = base;
+	}
+
+	private ContainerTreeIterator(final WorkingTreeIterator p,
+			final IContainer base) {
+		super(p);
+		node = base;
+	}
+
+	@Override
+	public AbstractTreeIterator createSubtreeIterator(final Repository db)
+			throws IncorrectObjectTypeException, IOException {
+		if (FileMode.TREE.equals(mode))
+			return new ContainerTreeIterator(this,
+					(IContainer) ((ResourceEntry) current()).rsrc);
+		else
+			throw new IncorrectObjectTypeException(ObjectId.zeroId(),
+					Constants.TYPE_TREE);
+	}
+
+	@Override
+	protected Entry[] getEntries() throws IOException {
+		final IResource[] all;
+		try {
+			all = node.members(IContainer.INCLUDE_HIDDEN);
+		} catch (CoreException err) {
+			final IOException ioe = new IOException(err.getMessage());
+			ioe.initCause(err);
+			throw ioe;
+		}
+
+		final Entry[] r = new Entry[all.length];
+		for (int i = 0; i < r.length; i++)
+			r[i] = new ResourceEntry(all[i]);
+		return r;
+	}
+
+	static class ResourceEntry extends Entry {
+		final IResource rsrc;
+
+		private final FileMode mode;
+
+		private long length = -1;
+
+		ResourceEntry(final IResource f) {
+			rsrc = f;
+
+			switch (f.getType()) {
+			case IResource.FILE:
+				if (FS.INSTANCE.canExecute(asFile()))
+					mode = FileMode.EXECUTABLE_FILE;
+				else
+					mode = FileMode.REGULAR_FILE;
+				break;
+			case IResource.FOLDER: {
+				final IContainer c = (IContainer) f;
+				if (c.findMember(".git") != null)
+					mode = FileMode.GITLINK;
+				else
+					mode = FileMode.TREE;
+				break;
+			}
+			default:
+				mode = FileMode.MISSING;
+				break;
+			}
+		}
+
+		@Override
+		public FileMode getMode() {
+			return mode;
+		}
+
+		@Override
+		public String getName() {
+			return rsrc.getName();
+		}
+
+		@Override
+		public long getLength() {
+			if (length < 0) {
+				if (rsrc instanceof IFile)
+					length = asFile().length();
+				else
+					length = 0;
+			}
+			return length;
+		}
+
+		@Override
+		public long getLastModified() {
+			return rsrc.getLocalTimeStamp();
+		}
+
+		@Override
+		public InputStream openInputStream() throws IOException {
+			if (rsrc instanceof IFile) {
+				try {
+					return ((IFile) rsrc).getContents(true);
+				} catch (CoreException err) {
+					final IOException ioe = new IOException(err.getMessage());
+					ioe.initCause(err);
+					throw ioe;
+				}
+			}
+			throw new IOException("Not a regular file: " + rsrc);
+		}
+
+		private File asFile() {
+			return ((IFile) rsrc).getLocation().toFile();
+		}
+	}
+}
-- 
1.6.0.rc2.219.g1250ab
Previous: Shawn O. PearceNext: Shawn O. Pearce
Message 11 of 15 in “Misc. cleanups and improvements”
  1. 00/11 Misc. cleanups and improvementsShawn O. Pearce, Aug 10, 2008
  2. 01/11 Fix RawParseUtils.endOfParagraph to work on all corner casesShawn O. Pearce, Aug 10, 2008
  3. 02/11 Add test case for the RevCommit parsing codeShawn O. Pearce, Aug 10, 2008
  4. 03/11 Notify AbstractTreeIterator implementations of skipped tree entriesShawn O. Pearce, Aug 10, 2008
  5. 04/11 Allow AbstractTreeIterator subclasses to supply their own path arrayShawn O. Pearce, Aug 10, 2008
  6. 05/11 Allow WorkingTreeIterators to define their prefix path when createdShawn O. Pearce, Aug 10, 2008
  7. 06/11 Add getTree to TreeWalk for locating the current iterator instanceShawn O. Pearce, Aug 10, 2008
  8. 07/11 Allow WorkingTreeIterator to track last modified time for entriesShawn O. Pearce, Aug 10, 2008
  9. 08/11 Expose the current entry's length, last modified in WorkingTreeIteratorShawn O. Pearce, Aug 10, 2008
  10. 09/11 Expose idBuffer,idOffset in AbstractTreeIterator to applicationsShawn O. Pearce, Aug 10, 2008
  11. 10/11 Add a TreeWalk iterator implementation for IContainerShawn O. Pearce, Aug 10, 2008
  12. 11/11 Teach NB how to encode/decode an unsigned 16 bit integerShawn O. Pearce, Aug 10, 2008
  13. Robin RosenbergAug 13, 2008
  14. Shawn O. PearceAug 14, 2008
  15. Robin RosenbergAug 14, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.