git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Shawn O. Pearce" <spearce@spearce.org>
To: Robin Rosenberg <robin.rosenberg@dewire.com>,
	Marek Zawirski <marek.zawirski@gmail.com>
Cc: git@vger.kernel.org
Subject: [EGIT PATCH 10/11] Add a TreeWalk iterator implementation for IContainer
Date: Sun, 10 Aug 2008 01:46:25 -0700	[thread overview]
Message-ID: <1218357986-19671-11-git-send-email-spearce@spearce.org> (raw)
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

  reply	other threads:[~2008-08-10  8:48 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-10  8:46 [EGIT PATCH 00/11] Misc. cleanups and improvements Shawn O. Pearce
2008-08-10  8:46 ` [EGIT PATCH 01/11] Fix RawParseUtils.endOfParagraph to work on all corner cases Shawn O. Pearce
2008-08-10  8:46   ` [EGIT PATCH 02/11] Add test case for the RevCommit parsing code Shawn O. Pearce
2008-08-10  8:46     ` [EGIT PATCH 03/11] Notify AbstractTreeIterator implementations of skipped tree entries Shawn O. Pearce
2008-08-10  8:46       ` [EGIT PATCH 04/11] Allow AbstractTreeIterator subclasses to supply their own path array Shawn O. Pearce
2008-08-10  8:46         ` [EGIT PATCH 05/11] Allow WorkingTreeIterators to define their prefix path when created Shawn O. Pearce
2008-08-10  8:46           ` [EGIT PATCH 06/11] Add getTree to TreeWalk for locating the current iterator instance Shawn O. Pearce
2008-08-10  8:46             ` [EGIT PATCH 07/11] Allow WorkingTreeIterator to track last modified time for entries Shawn O. Pearce
2008-08-10  8:46               ` [EGIT PATCH 08/11] Expose the current entry's length, last modified in WorkingTreeIterator Shawn O. Pearce
2008-08-10  8:46                 ` [EGIT PATCH 09/11] Expose idBuffer,idOffset in AbstractTreeIterator to applications Shawn O. Pearce
2008-08-10  8:46                   ` Shawn O. Pearce [this message]
2008-08-10  8:46                     ` [EGIT PATCH 11/11] Teach NB how to encode/decode an unsigned 16 bit integer Shawn O. Pearce
2008-08-13 20:41                     ` [EGIT PATCH 10/11] Add a TreeWalk iterator implementation for IContainer Robin Rosenberg
2008-08-14  4:19                       ` Shawn O. Pearce
2008-08-14  5:20                         ` Robin Rosenberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1218357986-19671-11-git-send-email-spearce@spearce.org \
    --to=spearce@spearce.org \
    --cc=git@vger.kernel.org \
    --cc=marek.zawirski@gmail.com \
    --cc=robin.rosenberg@dewire.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).