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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
---
 .../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

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux