Java tutorial
/******************************************************************************* * 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 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.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.resources.IWorkspaceRoot; import org.eclipse.core.runtime.CoreException; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.util.FS; import org.eclipse.team.core.Team; /** * 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.eclipse.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); //$NON-NLS-1$ return rm.getRepoRelativePath(base); } private final IContainer node; /** * Construct a new iterator from a container in 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 repository * repository the given base is mapped to * @param base * the part of the workspace the iterator will walk over. */ public ContainerTreeIterator(final Repository repository, final IContainer base) { super(computePrefix(base), repository.getConfig().get(WorkingTreeOptions.KEY)); node = base; init(entries()); } /** * Construct a new iterator from the workspace root. * <p> * The iterator will support traversal over workspace projects that have * a Git repository provider connected and 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 repository * repository the given base is mapped to * @param root * the workspace root to walk over. */ public ContainerTreeIterator(final Repository repository, final IWorkspaceRoot root) { super("", repository.getConfig().get(WorkingTreeOptions.KEY)); //$NON-NLS-1$ node = root; init(entries()); } /** * Construct a new iterator from a container in the workspace, with a given * parent iterator. * <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 p * the parent iterator we were created from. * @param base * the part of the workspace the iterator will walk over. */ public ContainerTreeIterator(final WorkingTreeIterator p, final IContainer base) { super(p); node = base; init(entries()); } @Override public AbstractTreeIterator createSubtreeIterator(ObjectReader reader) 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); } /** * Get the ResourceEntry for the current entry. * * @return the current entry */ public ResourceEntry getResourceEntry() { return (ResourceEntry) current(); } private Entry[] entries() { final IResource[] all; try { all = node.members(IContainer.INCLUDE_HIDDEN); } catch (CoreException err) { return EOF; } final Entry[] r = new Entry[all.length]; for (int i = 0; i < r.length; i++) r[i] = new ResourceEntry(all[i]); return r; } @Override public boolean isEntryIgnored() throws IOException { return super.isEntryIgnored() || isEntryIgnoredByTeamProvider(getResourceEntry().getResource()); } private boolean isEntryIgnoredByTeamProvider(IResource resource) { if (resource instanceof IWorkspaceRoot) return false; if (Team.isIgnoredHint(resource)) return true; return isEntryIgnoredByTeamProvider(resource.getParent()); } /** * Wrapper for a resource in the Eclipse workspace */ static public 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.DETECTED.canExecute(asFile())) mode = FileMode.EXECUTABLE_FILE; else mode = FileMode.REGULAR_FILE; break; case IResource.PROJECT: case IResource.FOLDER: { final IContainer c = (IContainer) f; if (c.findMember(Constants.DOT_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() { if (rsrc.getType() == IResource.PROJECT) return rsrc.getLocation().lastSegment(); else 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); //$NON-NLS-1$ } /** * Get the underlying resource of this entry. * * @return the underlying resource */ public IResource getResource() { return rsrc; } private File asFile() { return ((IFile) rsrc).getLocation().toFile(); } } }