package com.beijunyi.parallelgit.filesystem.io; import java.io.IOException; import java.util.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.beijunyi.parallelgit.filesystem.GfsFileStore; import com.beijunyi.parallelgit.filesystem.GitFileSystem; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeOptions; import static java.lang.System.arraycopy; import static java.util.Collections.*; import static org.eclipse.jgit.lib.Constants.*; public class GfsTreeIterator extends WorkingTreeIterator { private final List<GfsTreeEntry> files; private int index = -1; private ObjectId id; private GfsTreeIterator(List<GfsTreeEntry> files, GfsTreeIterator parent) { super(parent); this.files = files; next(1); } private GfsTreeIterator(List<GfsTreeEntry> files) { super((WorkingTreeOptions) null); this.files = files; next(1); } private GfsTreeIterator(DirectoryNode node) throws IOException { this(GfsTreeEntry.listChildren(node)); } private GfsTreeIterator(GfsFileStore store) throws IOException { this(store.getRoot()); } private GfsTreeIterator(GitFileSystem gfs) throws IOException { this(gfs.getFileStore()); } @Nonnull public static GfsTreeIterator iterateRoot(GitFileSystem gfs) throws IOException { return new GfsTreeIterator(gfs); } @Override public boolean isModified(@Nullable DirCacheEntry entry, boolean forceContentCheck, ObjectReader reader) throws IOException { GfsTreeEntry current = currentEntry(); return entry == null || !current.getId().equals(entry.getObjectId()) || !current.getMode().equals(entry.getFileMode()); } @Override public boolean hasId() { return index >= 0 && index < files.size(); } @Override public byte[] idBuffer() { byte[] ret = new byte[OBJECT_ID_LENGTH]; id.copyRawTo(ret, 0); return ret; } @Override public int idOffset() { return 0; } @Nonnull @Override public AbstractTreeIterator createSubtreeIterator(ObjectReader reader) throws IOException { GfsTreeEntry entry = currentEntry(); return new GfsTreeIterator(entry.listChildren(), this); } @Override public boolean first() { return index == 0; } @Override public boolean eof() { return index == files.size(); } @Override public void next(int delta) { index = Math.min(files.size(), index + delta); if(!eof()) readEntry(); } @Override public void back(int delta) { index = Math.max(0, index - delta); readEntry(); } @Nonnull private GfsTreeEntry currentEntry() { return files.get(index); } private void readEntry() { GfsTreeEntry entry = currentEntry(); mode = entry.getMode().getBits(); id = entry.getId(); byte[] name = encode(entry.getName()); ensurePathCapacity(pathOffset + name.length, pathOffset); arraycopy(name, 0, path, pathOffset, name.length); pathLen = pathOffset + name.length; } private static class GfsTreeEntry { private final String name; private final Node node; private GfsTreeEntry(String name, Node node) { this.name = name; this.node = node; } @Nonnull public static GfsTreeEntry forNode(String name, Node node) { return new GfsTreeEntry(name, node); } @Nonnull public String getName() { return name; } @Nonnull public ObjectId getId() { try { return node.getObjectId(false); } catch(IOException e) { throw new IllegalStateException(e); } } @Nonnull public FileMode getMode() { return node.getMode(); } @Nonnull public List<GfsTreeEntry> listChildren() throws IOException { if(!node.isDirectory()) throw new IllegalStateException(); return listChildren((DirectoryNode) node); } @Nonnull public static List<GfsTreeEntry> listChildren(DirectoryNode dir) throws IOException { List<GfsTreeEntry> ret = new ArrayList<>(); for(Map.Entry<String, Node> child : dir.getData().entrySet()) { Node node = child.getValue(); if(!node.isTrivial()) ret.add(forNode(child.getKey(), node)); } sort(ret, TreeEntryComparator.ASCENDING); return unmodifiableList(ret); } } private static class TreeEntryComparator implements Comparator<GfsTreeEntry> { private static TreeEntryComparator ASCENDING = new TreeEntryComparator(); @Override public int compare(GfsTreeEntry o1, GfsTreeEntry o2) { return o1.getName().compareTo(o2.getName()); } } }