+++ /dev/null
-/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.eclipse.jgit.lib;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
-import org.eclipse.jgit.lib.GitIndex.Entry;
-import org.eclipse.jgit.util.FS;
-import org.junit.Before;
-import org.junit.Test;
-
-public class T0007_GitIndexTest extends LocalDiskRepositoryTestCase {
-
- static boolean canrungitstatus;
- static {
- try {
- canrungitstatus = system(new File("."),"git --version") == 0;
- } catch (IOException e) {
- System.out.println("Warning: cannot invoke native git to validate index");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- private static int system(File dir, String cmd) throws IOException,
- InterruptedException {
- final Process process = Runtime.getRuntime().exec(cmd, null, dir);
- new Thread() {
- public void run() {
- try {
- InputStream s = process.getErrorStream();
- for (int c = s.read(); c != -1; c = s.read()) {
- System.err.print((char) c);
- }
- s.close();
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- }
- }.start();
- final Thread t2 = new Thread() {
- public void run() {
- synchronized (this) {
- try {
- InputStream e = process.getInputStream();
- for (int c = e.read(); c != -1; c = e.read()) {
- System.out.print((char) c);
- }
- e.close();
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- }
- }
- };
- t2.start();
- process.getOutputStream().close();
- int ret = process.waitFor();
- synchronized (t2) {
- return ret;
- }
- }
-
- private Repository db;
-
- private File trash;
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- db = createWorkRepository();
- trash = db.getWorkTree();
- }
-
- @Test
- public void testCreateEmptyIndex() throws Exception {
- GitIndex index = new GitIndex(db);
- index.write();
-// native git doesn't like an empty index
-// assertEquals(0,system(trash,"git status"));
-
- GitIndex indexr = new GitIndex(db);
- indexr.read();
- assertEquals(0, indexr.getMembers().length);
- }
-
- @Test
- public void testReadWithNoIndex() throws Exception {
- GitIndex index = new GitIndex(db);
- index.read();
- assertEquals(0, index.getMembers().length);
- }
-
- @Test
- public void testCreateSimpleSortTestIndex() throws Exception {
- GitIndex index = new GitIndex(db);
- writeTrashFile("a/b", "data:a/b");
- writeTrashFile("a:b", "data:a:b");
- writeTrashFile("a.b", "data:a.b");
- index.add(trash, new File(trash, "a/b"));
- index.add(trash, new File(trash, "a:b"));
- index.add(trash, new File(trash, "a.b"));
- index.write();
-
- assertEquals("a/b", index.getEntry("a/b").getName());
- assertEquals("a:b", index.getEntry("a:b").getName());
- assertEquals("a.b", index.getEntry("a.b").getName());
- assertNull(index.getEntry("a*b"));
-
- // Repeat test for re-read index
- GitIndex indexr = new GitIndex(db);
- indexr.read();
- assertEquals("a/b", indexr.getEntry("a/b").getName());
- assertEquals("a:b", indexr.getEntry("a:b").getName());
- assertEquals("a.b", indexr.getEntry("a.b").getName());
- assertNull(indexr.getEntry("a*b"));
-
- if (canrungitstatus)
- assertEquals(0, system(trash, "git status"));
- }
-
- @Test
- public void testUpdateSimpleSortTestIndex() throws Exception {
- GitIndex index = new GitIndex(db);
- writeTrashFile("a/b", "data:a/b");
- writeTrashFile("a:b", "data:a:b");
- writeTrashFile("a.b", "data:a.b");
- index.add(trash, new File(trash, "a/b"));
- index.add(trash, new File(trash, "a:b"));
- index.add(trash, new File(trash, "a.b"));
- writeTrashFile("a/b", "data:a/b modified");
- index.add(trash, new File(trash, "a/b"));
- index.write();
- if (canrungitstatus)
- assertEquals(0, system(trash, "git status"));
- }
-
- @Test
- public void testWriteTree() throws Exception {
- GitIndex index = new GitIndex(db);
- writeTrashFile("a/b", "data:a/b");
- writeTrashFile("a:b", "data:a:b");
- writeTrashFile("a.b", "data:a.b");
- index.add(trash, new File(trash, "a/b"));
- index.add(trash, new File(trash, "a:b"));
- index.add(trash, new File(trash, "a.b"));
- index.write();
-
- ObjectId id = index.writeTree();
- assertEquals("c696abc3ab8e091c665f49d00eb8919690b3aec3", id.name());
-
- writeTrashFile("a/b", "data:a/b");
- index.add(trash, new File(trash, "a/b"));
-
- if (canrungitstatus)
- assertEquals(0, system(trash, "git status"));
- }
-
- @Test
- public void testReadTree() throws Exception {
- // Prepare tree
- GitIndex index = new GitIndex(db);
- writeTrashFile("a/b", "data:a/b");
- writeTrashFile("a:b", "data:a:b");
- writeTrashFile("a.b", "data:a.b");
- index.add(trash, new File(trash, "a/b"));
- index.add(trash, new File(trash, "a:b"));
- index.add(trash, new File(trash, "a.b"));
- index.write();
-
- ObjectId id = index.writeTree();
- System.out.println("wrote id " + id);
- assertEquals("c696abc3ab8e091c665f49d00eb8919690b3aec3", id.name());
- GitIndex index2 = new GitIndex(db);
-
- index2.readTree(mapTree("c696abc3ab8e091c665f49d00eb8919690b3aec3"));
- Entry[] members = index2.getMembers();
- assertEquals(3, members.length);
- assertEquals("a.b", members[0].getName());
- assertEquals("a/b", members[1].getName());
- assertEquals("a:b", members[2].getName());
- assertEquals(3, members.length);
-
- GitIndex indexr = new GitIndex(db);
- indexr.read();
- Entry[] membersr = indexr.getMembers();
- assertEquals(3, membersr.length);
- assertEquals("a.b", membersr[0].getName());
- assertEquals("a/b", membersr[1].getName());
- assertEquals("a:b", membersr[2].getName());
- assertEquals(3, membersr.length);
-
- if (canrungitstatus)
- assertEquals(0, system(trash, "git status"));
- }
-
- @Test
- public void testReadTree2() throws Exception {
- // Prepare a larger tree to test some odd cases in tree writing
- GitIndex index = new GitIndex(db);
- File f1 = writeTrashFile("a/a/a/a", "data:a/a/a/a");
- File f2 = writeTrashFile("a/c/c", "data:a/c/c");
- File f3 = writeTrashFile("a/b", "data:a/b");
- File f4 = writeTrashFile("a:b", "data:a:b");
- File f5 = writeTrashFile("a/d", "data:a/d");
- File f6 = writeTrashFile("a.b", "data:a.b");
- index.add(trash, f1);
- index.add(trash, f2);
- index.add(trash, f3);
- index.add(trash, f4);
- index.add(trash, f5);
- index.add(trash, f6);
- index.write();
- ObjectId id = index.writeTree();
- System.out.println("wrote id " + id);
- assertEquals("ba78e065e2c261d4f7b8f42107588051e87e18e9", id.name());
- GitIndex index2 = new GitIndex(db);
-
- index2.readTree(mapTree("ba78e065e2c261d4f7b8f42107588051e87e18e9"));
- Entry[] members = index2.getMembers();
- assertEquals(6, members.length);
- assertEquals("a.b", members[0].getName());
- assertEquals("a/a/a/a", members[1].getName());
- assertEquals("a/b", members[2].getName());
- assertEquals("a/c/c", members[3].getName());
- assertEquals("a/d", members[4].getName());
- assertEquals("a:b", members[5].getName());
-
- // reread and test
- GitIndex indexr = new GitIndex(db);
- indexr.read();
- Entry[] membersr = indexr.getMembers();
- assertEquals(6, membersr.length);
- assertEquals("a.b", membersr[0].getName());
- assertEquals("a/a/a/a", membersr[1].getName());
- assertEquals("a/b", membersr[2].getName());
- assertEquals("a/c/c", membersr[3].getName());
- assertEquals("a/d", membersr[4].getName());
- assertEquals("a:b", membersr[5].getName());
- }
-
- @Test
- public void testDelete() throws Exception {
- GitIndex index = new GitIndex(db);
- writeTrashFile("a/b", "data:a/b");
- writeTrashFile("a:b", "data:a:b");
- writeTrashFile("a.b", "data:a.b");
- index.add(trash, new File(trash, "a/b"));
- index.add(trash, new File(trash, "a:b"));
- index.add(trash, new File(trash, "a.b"));
- index.write();
- index.writeTree();
- index.remove(trash, new File(trash, "a:b"));
- index.write();
- assertEquals("a.b", index.getMembers()[0].getName());
- assertEquals("a/b", index.getMembers()[1].getName());
-
- GitIndex indexr = new GitIndex(db);
- indexr.read();
- assertEquals("a.b", indexr.getMembers()[0].getName());
- assertEquals("a/b", indexr.getMembers()[1].getName());
-
- if (canrungitstatus)
- assertEquals(0, system(trash, "git status"));
- }
-
- @Test
- public void testCheckout() throws Exception {
- // Prepare tree, remote it and checkout
- GitIndex index = new GitIndex(db);
- File aslashb = writeTrashFile("a/b", "data:a/b");
- File acolonb = writeTrashFile("a:b", "data:a:b");
- File adotb = writeTrashFile("a.b", "data:a.b");
- index.add(trash, aslashb);
- index.add(trash, acolonb);
- index.add(trash, adotb);
- index.write();
- index.writeTree();
- delete(aslashb);
- delete(acolonb);
- delete(adotb);
- delete(aslashb.getParentFile());
-
- GitIndex index2 = new GitIndex(db);
- assertEquals(0, index2.getMembers().length);
-
- index2.readTree(mapTree("c696abc3ab8e091c665f49d00eb8919690b3aec3"));
-
- index2.checkout(trash);
- assertEquals("data:a/b", read(aslashb));
- assertEquals("data:a:b", read(acolonb));
- assertEquals("data:a.b", read(adotb));
-
- if (canrungitstatus)
- assertEquals(0, system(trash, "git status"));
- }
-
- @Test
- public void test030_executeBit_coreModeTrue() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception {
- if (!FS.DETECTED.supportsExecute()) {
- System.err.println("Test ignored since platform FS does not support the execute permission");
- return;
- }
- try {
- // coremode true is the default, typically set to false
- // by git init (but not jgit!)
- Method canExecute = File.class.getMethod("canExecute", (Class[])null);
- Method setExecute = File.class.getMethod("setExecutable", new Class[] { Boolean.TYPE });
- File execFile = writeTrashFile("exec","exec");
- if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.TRUE })).booleanValue())
- throw new Error("could not set execute bit on "+execFile.getAbsolutePath()+"for test");
- File nonexecFile = writeTrashFile("nonexec","nonexec");
- if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.FALSE })).booleanValue())
- throw new Error("could not clear execute bit on "+nonexecFile.getAbsolutePath()+"for test");
-
- GitIndex index = new GitIndex(db);
- index.filemode = Boolean.TRUE; // TODO: we need a way to set this using config
- index.add(trash, execFile);
- index.add(trash, nonexecFile);
- Tree tree = mapTree(index.writeTree().name());
- assertEquals(FileMode.EXECUTABLE_FILE, tree.findBlobMember(execFile.getName()).getMode());
- assertEquals(FileMode.REGULAR_FILE, tree.findBlobMember(nonexecFile.getName()).getMode());
-
- index.write();
-
- if (!execFile.delete())
- throw new Error("Problem in test, cannot delete test file "+execFile.getAbsolutePath());
- if (!nonexecFile.delete())
- throw new Error("Problem in test, cannot delete test file "+nonexecFile.getAbsolutePath());
- GitIndex index2 = new GitIndex(db);
- index2.filemode = Boolean.TRUE; // TODO: we need a way to set this using config
- index2.read();
- index2.checkout(trash);
- assertTrue(((Boolean)canExecute.invoke(execFile,(Object[])null)).booleanValue());
- assertFalse(((Boolean)canExecute.invoke(nonexecFile,(Object[])null)).booleanValue());
-
- assertFalse(index2.getEntry(execFile.getName()).isModified(trash));
- assertFalse(index2.getEntry(nonexecFile.getName()).isModified(trash));
-
- if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.FALSE })).booleanValue())
- throw new Error("could not clear set execute bit on "+execFile.getAbsolutePath()+"for test");
- if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.TRUE })).booleanValue())
- throw new Error("could set execute bit on "+nonexecFile.getAbsolutePath()+"for test");
-
- assertTrue(index2.getEntry(execFile.getName()).isModified(trash));
- assertTrue(index2.getEntry(nonexecFile.getName()).isModified(trash));
-
- } catch (NoSuchMethodException e) {
- System.err.println("Test ignored when running under JDK < 1.6");
- return;
- }
- }
-
- @Test
- public void test031_executeBit_coreModeFalse() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception {
- if (!FS.DETECTED.supportsExecute()) {
- System.err.println("Test ignored since platform FS does not support the execute permission");
- return;
- }
- try {
- // coremode true is the default, typically set to false
- // by git init (but not jgit!)
- Method canExecute = File.class.getMethod("canExecute", (Class[])null);
- Method setExecute = File.class.getMethod("setExecutable", new Class[] { Boolean.TYPE });
- File execFile = writeTrashFile("exec","exec");
- if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.TRUE })).booleanValue())
- throw new Error("could not set execute bit on "+execFile.getAbsolutePath()+"for test");
- File nonexecFile = writeTrashFile("nonexec","nonexec");
- if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.FALSE })).booleanValue())
- throw new Error("could not clear execute bit on "+nonexecFile.getAbsolutePath()+"for test");
-
- GitIndex index = new GitIndex(db);
- index.filemode = Boolean.FALSE; // TODO: we need a way to set this using config
- index.add(trash, execFile);
- index.add(trash, nonexecFile);
- Tree tree = mapTree(index.writeTree().name());
- assertEquals(FileMode.REGULAR_FILE, tree.findBlobMember(execFile.getName()).getMode());
- assertEquals(FileMode.REGULAR_FILE, tree.findBlobMember(nonexecFile.getName()).getMode());
-
- index.write();
-
- if (!execFile.delete())
- throw new Error("Problem in test, cannot delete test file "+execFile.getAbsolutePath());
- if (!nonexecFile.delete())
- throw new Error("Problem in test, cannot delete test file "+nonexecFile.getAbsolutePath());
- GitIndex index2 = new GitIndex(db);
- index2.filemode = Boolean.FALSE; // TODO: we need a way to set this using config
- index2.read();
- index2.checkout(trash);
- assertFalse(((Boolean)canExecute.invoke(execFile,(Object[])null)).booleanValue());
- assertFalse(((Boolean)canExecute.invoke(nonexecFile,(Object[])null)).booleanValue());
-
- assertFalse(index2.getEntry(execFile.getName()).isModified(trash));
- assertFalse(index2.getEntry(nonexecFile.getName()).isModified(trash));
-
- if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.FALSE })).booleanValue())
- throw new Error("could not clear set execute bit on "+execFile.getAbsolutePath()+"for test");
- if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.TRUE })).booleanValue())
- throw new Error("could set execute bit on "+nonexecFile.getAbsolutePath()+"for test");
-
- // no change since we ignore the execute bit
- assertFalse(index2.getEntry(execFile.getName()).isModified(trash));
- assertFalse(index2.getEntry(nonexecFile.getName()).isModified(trash));
-
- } catch (NoSuchMethodException e) {
- System.err.println("Test ignored when running under JDK < 1.6");
- return;
- }
- }
-
- private void delete(File f) throws IOException {
- if (!f.delete())
- throw new IOException("Failed to delete f");
- }
-
- private File writeTrashFile(String name, String body) throws IOException {
- final File path = new File(trash, name);
- write(path, body);
- return path;
- }
-
- private Tree mapTree(String name) throws IOException {
- ObjectId id = db.resolve(name + "^{tree}");
- return new Tree(db, id, db.open(id).getCachedBytes());
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
- * Copyright (C) 2007, Robin Rosenberg <me@lathund.dewire.com>
- * Copyright (C) 2007-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.eclipse.jgit.lib;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-import java.security.MessageDigest;
-import java.text.MessageFormat;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Stack;
-import java.util.TreeMap;
-
-import org.eclipse.jgit.JGitText;
-import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.errors.CorruptObjectException;
-import org.eclipse.jgit.errors.NotSupportedException;
-import org.eclipse.jgit.events.IndexChangedEvent;
-import org.eclipse.jgit.util.FileUtils;
-import org.eclipse.jgit.util.RawParseUtils;
-
-/**
- * A representation of the Git index.
- *
- * The index points to the objects currently checked out or in the process of
- * being prepared for committing or objects involved in an unfinished merge.
- *
- * The abstract format is:<br/> path stage flags statdata SHA-1
- * <ul>
- * <li>Path is the relative path in the workdir</li>
- * <li>stage is 0 (normally), but when
- * merging 1 is the common ancestor version, 2 is 'our' version and 3 is 'their'
- * version. A fully resolved merge only contains stage 0.</li>
- * <li>flags is the object type and information of validity</li>
- * <li>statdata is the size of this object and some other file system specifics,
- * some of it ignored by JGit</li>
- * <li>SHA-1 represents the content of the references object</li>
- * </ul>
- *
- * An index can also contain a tree cache which we ignore for now. We drop the
- * tree cache when writing the index.
- *
- * @deprecated Use {@link DirCache} instead.
- */
-public class GitIndex {
-
- /** Stage 0 represents merged entries. */
- public static final int STAGE_0 = 0;
-
- private RandomAccessFile cache;
-
- private File cacheFile;
-
- // Index is modified
- private boolean changed;
-
- // Stat information updated
- private boolean statDirty;
-
- private Header header;
-
- private long lastCacheTime;
-
- private final Repository db;
-
- private Map<byte[], Entry> entries = new TreeMap<byte[], Entry>(new Comparator<byte[]>() {
- public int compare(byte[] o1, byte[] o2) {
- for (int i = 0; i < o1.length && i < o2.length; ++i) {
- int c = (o1[i] & 0xff) - (o2[i] & 0xff);
- if (c != 0)
- return c;
- }
- if (o1.length < o2.length)
- return -1;
- else if (o1.length > o2.length)
- return 1;
- return 0;
- }
- });
-
- /**
- * Construct a Git index representation.
- * @param db
- */
- public GitIndex(Repository db) {
- this.db = db;
- this.cacheFile = db.getIndexFile();
- }
-
- /**
- * @return true if we have modified the index in memory since reading it from disk
- */
- public boolean isChanged() {
- return changed || statDirty;
- }
-
- /**
- * Reread index data from disk if the index file has been changed
- * @throws IOException
- */
- public void rereadIfNecessary() throws IOException {
- if (cacheFile.exists() && cacheFile.lastModified() != lastCacheTime) {
- read();
- db.fireEvent(new IndexChangedEvent());
- }
- }
-
- /**
- * Add the content of a file to the index.
- *
- * @param wd workdir
- * @param f the file
- * @return a new or updated index entry for the path represented by f
- * @throws IOException
- */
- public Entry add(File wd, File f) throws IOException {
- byte[] key = makeKey(wd, f);
- Entry e = entries.get(key);
- if (e == null) {
- e = new Entry(key, f, 0);
- entries.put(key, e);
- } else {
- e.update(f);
- }
- return e;
- }
-
- /**
- * Add the content of a file to the index.
- *
- * @param wd
- * workdir
- * @param f
- * the file
- * @param content
- * content of the file
- * @return a new or updated index entry for the path represented by f
- * @throws IOException
- */
- public Entry add(File wd, File f, byte[] content) throws IOException {
- byte[] key = makeKey(wd, f);
- Entry e = entries.get(key);
- if (e == null) {
- e = new Entry(key, f, 0, content);
- entries.put(key, e);
- } else {
- e.update(f, content);
- }
- return e;
- }
-
- /**
- * Remove a path from the index.
- *
- * @param wd
- * workdir
- * @param f
- * the file whose path shall be removed.
- * @return true if such a path was found (and thus removed)
- * @throws IOException
- */
- public boolean remove(File wd, File f) throws IOException {
- byte[] key = makeKey(wd, f);
- return entries.remove(key) != null;
- }
-
- /**
- * Read the cache file into memory.
- *
- * @throws IOException
- */
- public void read() throws IOException {
- changed = false;
- statDirty = false;
- if (!cacheFile.exists()) {
- header = null;
- entries.clear();
- lastCacheTime = 0;
- return;
- }
- cache = new RandomAccessFile(cacheFile, "r");
- try {
- FileChannel channel = cache.getChannel();
- ByteBuffer buffer = ByteBuffer.allocateDirect((int) cacheFile.length());
- buffer.order(ByteOrder.BIG_ENDIAN);
- int j = channel.read(buffer);
- if (j != buffer.capacity())
- throw new IOException(MessageFormat.format(JGitText.get().couldNotReadIndexInOneGo
- , j, buffer.capacity()));
- buffer.flip();
- header = new Header(buffer);
- entries.clear();
- for (int i = 0; i < header.entries; ++i) {
- Entry entry = new Entry(buffer);
- final GitIndex.Entry existing = entries.get(entry.name);
- entries.put(entry.name, entry);
- if (existing != null) {
- entry.stages |= existing.stages;
- }
- }
- lastCacheTime = cacheFile.lastModified();
- } finally {
- cache.close();
- }
- }
-
- /**
- * Write content of index to disk.
- *
- * @throws IOException
- */
- public void write() throws IOException {
- checkWriteOk();
- File tmpIndex = new File(cacheFile.getAbsoluteFile() + ".tmp");
- File lock = new File(cacheFile.getAbsoluteFile() + ".lock");
- if (!lock.createNewFile())
- throw new IOException(JGitText.get().indexFileIsInUse);
- try {
- FileOutputStream fileOutputStream = new FileOutputStream(tmpIndex);
- FileChannel fc = fileOutputStream.getChannel();
- ByteBuffer buf = ByteBuffer.allocate(4096);
- MessageDigest newMessageDigest = Constants.newMessageDigest();
- header = new Header(entries);
- header.write(buf);
- buf.flip();
- newMessageDigest
- .update(buf.array(), buf.arrayOffset(), buf.limit());
- fc.write(buf);
- buf.flip();
- buf.clear();
- for (Iterator i = entries.values().iterator(); i.hasNext();) {
- Entry e = (Entry) i.next();
- e.write(buf);
- buf.flip();
- newMessageDigest.update(buf.array(), buf.arrayOffset(), buf
- .limit());
- fc.write(buf);
- buf.flip();
- buf.clear();
- }
- buf.put(newMessageDigest.digest());
- buf.flip();
- fc.write(buf);
- fc.close();
- fileOutputStream.close();
- if (cacheFile.exists()) {
- if (db.getFS().retryFailedLockFileCommit()) {
- // file deletion fails on windows if another
- // thread is reading the file concurrently
- // So let's try 10 times...
- boolean deleted = false;
- for (int i = 0; i < 10; i++) {
- if (cacheFile.delete()) {
- deleted = true;
- break;
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // ignore
- }
- }
- if (!deleted)
- throw new IOException(
- JGitText.get().couldNotRenameDeleteOldIndex);
- } else {
- if (!cacheFile.delete())
- throw new IOException(
- JGitText.get().couldNotRenameDeleteOldIndex);
- }
- }
- if (!tmpIndex.renameTo(cacheFile))
- throw new IOException(
- JGitText.get().couldNotRenameTemporaryIndexFileToIndex);
- changed = false;
- statDirty = false;
- lastCacheTime = cacheFile.lastModified();
- db.fireEvent(new IndexChangedEvent());
- } finally {
- if (!lock.delete())
- throw new IOException(
- JGitText.get().couldNotDeleteLockFileShouldNotHappen);
- if (tmpIndex.exists() && !tmpIndex.delete())
- throw new IOException(
- JGitText.get().couldNotDeleteTemporaryIndexFileShouldNotHappen);
- }
- }
-
- private void checkWriteOk() throws IOException {
- for (Iterator i = entries.values().iterator(); i.hasNext();) {
- Entry e = (Entry) i.next();
- if (e.getStage() != 0) {
- throw new NotSupportedException(JGitText.get().cannotWorkWithOtherStagesThanZeroRightNow);
- }
- }
- }
-
- private boolean File_canExecute(File f){
- return db.getFS().canExecute(f);
- }
-
- private boolean File_setExecute(File f, boolean value) {
- return db.getFS().setExecute(f, value);
- }
-
- private boolean File_hasExecute() {
- return db.getFS().supportsExecute();
- }
-
- static byte[] makeKey(File wd, File f) {
- if (!f.getPath().startsWith(wd.getPath()))
- throw new Error(JGitText.get().pathIsNotInWorkingDir);
- String relName = Repository.stripWorkDir(wd, f);
- return Constants.encode(relName);
- }
-
- Boolean filemode;
- private boolean config_filemode() {
- // temporary til we can actually set parameters. We need to be able
- // to change this for testing.
- if (filemode != null)
- return filemode.booleanValue();
- Config config = db.getConfig();
- filemode = Boolean.valueOf(config.getBoolean("core", null, "filemode", true));
- return filemode.booleanValue();
- }
-
- /**
- * An index entry
- *
- * @deprecated Use {@link org.eclipse.jgit.dircache.DirCacheEntry}.
- */
- @Deprecated
- public class Entry {
- private long ctime;
-
- private long mtime;
-
- private int dev;
-
- private int ino;
-
- private int mode;
-
- private int uid;
-
- private int gid;
-
- private int size;
-
- private ObjectId sha1;
-
- private short flags;
-
- private byte[] name;
-
- private int stages;
-
- Entry(byte[] key, File f, int stage)
- throws IOException {
- ctime = f.lastModified() * 1000000L;
- mtime = ctime; // we use same here
- dev = -1;
- ino = -1;
- if (config_filemode() && File_canExecute(f))
- mode = FileMode.EXECUTABLE_FILE.getBits();
- else
- mode = FileMode.REGULAR_FILE.getBits();
- uid = -1;
- gid = -1;
- size = (int) f.length();
- ObjectInserter inserter = db.newObjectInserter();
- try {
- InputStream in = new FileInputStream(f);
- try {
- sha1 = inserter.insert(Constants.OBJ_BLOB, f.length(), in);
- } finally {
- in.close();
- }
- inserter.flush();
- } finally {
- inserter.release();
- }
- name = key;
- flags = (short) ((stage << 12) | name.length); // TODO: fix flags
- stages = (1 >> getStage());
- }
-
- Entry(byte[] key, File f, int stage, byte[] newContent)
- throws IOException {
- ctime = f.lastModified() * 1000000L;
- mtime = ctime; // we use same here
- dev = -1;
- ino = -1;
- if (config_filemode() && File_canExecute(f))
- mode = FileMode.EXECUTABLE_FILE.getBits();
- else
- mode = FileMode.REGULAR_FILE.getBits();
- uid = -1;
- gid = -1;
- size = newContent.length;
- ObjectInserter inserter = db.newObjectInserter();
- try {
- InputStream in = new FileInputStream(f);
- try {
- sha1 = inserter.insert(Constants.OBJ_BLOB, newContent);
- } finally {
- in.close();
- }
- inserter.flush();
- } finally {
- inserter.release();
- }
- name = key;
- flags = (short) ((stage << 12) | name.length); // TODO: fix flags
- stages = (1 >> getStage());
- }
-
- Entry(TreeEntry f, int stage) {
- ctime = -1; // hmm
- mtime = -1;
- dev = -1;
- ino = -1;
- mode = f.getMode().getBits();
- uid = -1;
- gid = -1;
- try {
- size = (int) db.open(f.getId(), Constants.OBJ_BLOB).getSize();
- } catch (IOException e) {
- e.printStackTrace();
- size = -1;
- }
- sha1 = f.getId();
- name = Constants.encode(f.getFullName());
- flags = (short) ((stage << 12) | name.length); // TODO: fix flags
- stages = (1 >> getStage());
- }
-
- Entry(ByteBuffer b) {
- int startposition = b.position();
- ctime = b.getInt() * 1000000000L + (b.getInt() % 1000000000L);
- mtime = b.getInt() * 1000000000L + (b.getInt() % 1000000000L);
- dev = b.getInt();
- ino = b.getInt();
- mode = b.getInt();
- uid = b.getInt();
- gid = b.getInt();
- size = b.getInt();
- byte[] sha1bytes = new byte[Constants.OBJECT_ID_LENGTH];
- b.get(sha1bytes);
- sha1 = ObjectId.fromRaw(sha1bytes);
- flags = b.getShort();
- stages = (1 << getStage());
- name = new byte[flags & 0xFFF];
- b.get(name);
- b
- .position(startposition
- + ((8 + 8 + 4 + 4 + 4 + 4 + 4 + 4 + 20 + 2
- + name.length + 8) & ~7));
- }
-
- /**
- * Update this index entry with stat and SHA-1 information if it looks
- * like the file has been modified in the workdir.
- *
- * @param f
- * file in work dir
- * @return true if a change occurred
- * @throws IOException
- */
- public boolean update(File f) throws IOException {
- long lm = f.lastModified() * 1000000L;
- boolean modified = mtime != lm;
- mtime = lm;
- if (size != f.length())
- modified = true;
- if (config_filemode()) {
- if (File_canExecute(f) != FileMode.EXECUTABLE_FILE.equals(mode)) {
- mode = FileMode.EXECUTABLE_FILE.getBits();
- modified = true;
- }
- }
- if (modified) {
- size = (int) f.length();
- ObjectInserter oi = db.newObjectInserter();
- try {
- InputStream in = new FileInputStream(f);
- try {
- ObjectId newsha1 = oi.insert(Constants.OBJ_BLOB, f
- .length(), in);
- oi.flush();
- if (!newsha1.equals(sha1))
- modified = true;
- sha1 = newsha1;
- } finally {
- in.close();
- }
- } finally {
- oi.release();
- }
- }
- return modified;
- }
-
- /**
- * Update this index entry with stat and SHA-1 information if it looks
- * like the file has been modified in the workdir.
- *
- * @param f
- * file in work dir
- * @param newContent
- * the new content of the file
- * @return true if a change occurred
- * @throws IOException
- */
- public boolean update(File f, byte[] newContent) throws IOException {
- boolean modified = false;
- size = newContent.length;
- ObjectInserter oi = db.newObjectInserter();
- try {
- ObjectId newsha1 = oi.insert(Constants.OBJ_BLOB, newContent);
- oi.flush();
- if (!newsha1.equals(sha1))
- modified = true;
- sha1 = newsha1;
- } finally {
- oi.release();
- }
- return modified;
- }
-
- void write(ByteBuffer buf) {
- int startposition = buf.position();
- buf.putInt((int) (ctime / 1000000000L));
- buf.putInt((int) (ctime % 1000000000L));
- buf.putInt((int) (mtime / 1000000000L));
- buf.putInt((int) (mtime % 1000000000L));
- buf.putInt(dev);
- buf.putInt(ino);
- buf.putInt(mode);
- buf.putInt(uid);
- buf.putInt(gid);
- buf.putInt(size);
- sha1.copyRawTo(buf);
- buf.putShort(flags);
- buf.put(name);
- int end = startposition
- + ((8 + 8 + 4 + 4 + 4 + 4 + 4 + 4 + 20 + 2 + name.length + 8) & ~7);
- int remain = end - buf.position();
- while (remain-- > 0)
- buf.put((byte) 0);
- }
-
- /**
- * Check if an entry's content is different from the cache,
- *
- * File status information is used and status is same we
- * consider the file identical to the state in the working
- * directory. Native git uses more stat fields than we
- * have accessible in Java.
- *
- * @param wd working directory to compare content with
- * @return true if content is most likely different.
- */
- public boolean isModified(File wd) {
- return isModified(wd, false);
- }
-
- /**
- * Check if an entry's content is different from the cache,
- *
- * File status information is used and status is same we
- * consider the file identical to the state in the working
- * directory. Native git uses more stat fields than we
- * have accessible in Java.
- *
- * @param wd working directory to compare content with
- * @param forceContentCheck True if the actual file content
- * should be checked if modification time differs.
- *
- * @return true if content is most likely different.
- */
- public boolean isModified(File wd, boolean forceContentCheck) {
-
- if (isAssumedValid())
- return false;
-
- if (isUpdateNeeded())
- return true;
-
- File file = getFile(wd);
- long length = file.length();
- if (length == 0) {
- if (!file.exists())
- return true;
- }
- if (length != size)
- return true;
-
- // JDK1.6 has file.canExecute
- // if (file.canExecute() != FileMode.EXECUTABLE_FILE.equals(mode))
- // return true;
- final int exebits = FileMode.EXECUTABLE_FILE.getBits()
- ^ FileMode.REGULAR_FILE.getBits();
-
- if (config_filemode() && FileMode.EXECUTABLE_FILE.equals(mode)) {
- if (!File_canExecute(file)&& File_hasExecute())
- return true;
- } else {
- if (FileMode.REGULAR_FILE.equals(mode&~exebits)) {
- if (!file.isFile())
- return true;
- if (config_filemode() && File_canExecute(file) && File_hasExecute())
- return true;
- } else {
- if (FileMode.SYMLINK.equals(mode)) {
- return true;
- } else {
- if (FileMode.TREE.equals(mode)) {
- if (!file.isDirectory())
- return true;
- } else {
- System.out.println(MessageFormat.format(JGitText.get().doesNotHandleMode
- , mode, file));
- return true;
- }
- }
- }
- }
-
- // Git under windows only stores seconds so we round the timestamp
- // Java gives us if it looks like the timestamp in index is seconds
- // only. Otherwise we compare the timestamp at millisecond prevision.
- long javamtime = mtime / 1000000L;
- long lastm = file.lastModified();
- if (javamtime % 1000 == 0)
- lastm = lastm - lastm % 1000;
- if (lastm != javamtime) {
- if (!forceContentCheck)
- return true;
-
- try {
- InputStream is = new FileInputStream(file);
- try {
- ObjectId newId = new ObjectInserter.Formatter().idFor(
- Constants.OBJ_BLOB, file.length(), is);
- return !newId.equals(sha1);
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- // can't happen, but if it does we ignore it
- e.printStackTrace();
- }
- }
- } catch (FileNotFoundException e) {
- // should not happen because we already checked this
- e.printStackTrace();
- throw new Error(e);
- }
- }
- return false;
- }
-
- /**
- * Returns the stages in which the entry's file is recorded in the index.
- * The stages are bit-encoded: bit N is set if the file is present
- * in stage N. In particular, the N-th bit will be set if this entry
- * itself is in stage N (see getStage()).
- *
- * @return flags denoting stages
- * @see #getStage()
- */
- public int getStages() {
- return stages;
- }
-
- // for testing
- void forceRecheck() {
- mtime = -1;
- }
-
- private File getFile(File wd) {
- return new File(wd, getName());
- }
-
- public String toString() {
- return getName() + "/SHA-1(" + sha1.name() + ")/M:"
- + new Date(ctime / 1000000L) + "/C:"
- + new Date(mtime / 1000000L) + "/d" + dev + "/i" + ino
- + "/m" + Integer.toString(mode, 8) + "/u" + uid + "/g"
- + gid + "/s" + size + "/f" + flags + "/@" + getStage();
- }
-
- /**
- * @return path name for this entry
- */
- public String getName() {
- return RawParseUtils.decode(name);
- }
-
- /**
- * @return path name for this entry as byte array, hopefully UTF-8 encoded
- */
- public byte[] getNameUTF8() {
- return name;
- }
-
- /**
- * @return SHA-1 of the entry managed by this index
- */
- public ObjectId getObjectId() {
- return sha1;
- }
-
- /**
- * @return the stage this entry is in
- */
- public int getStage() {
- return (flags & 0x3000) >> 12;
- }
-
- /**
- * @return size of disk object
- */
- public int getSize() {
- return size;
- }
-
- /**
- * @return true if this entry shall be assumed valid
- */
- public boolean isAssumedValid() {
- return (flags & 0x8000) != 0;
- }
-
- /**
- * @return true if this entry should be checked for changes
- */
- public boolean isUpdateNeeded() {
- return (flags & 0x4000) != 0;
- }
-
- /**
- * Set whether to always assume this entry valid
- *
- * @param assumeValid true to ignore changes
- */
- public void setAssumeValid(boolean assumeValid) {
- if (assumeValid)
- flags |= 0x8000;
- else
- flags &= ~0x8000;
- }
-
- /**
- * Set whether this entry must be checked
- *
- * @param updateNeeded
- */
- public void setUpdateNeeded(boolean updateNeeded) {
- if (updateNeeded)
- flags |= 0x4000;
- else
- flags &= ~0x4000;
- }
-
- /**
- * Return raw file mode bits. See {@link FileMode}
- * @return file mode bits
- */
- public int getModeBits() {
- return mode;
- }
- }
-
- static class Header {
- private int signature;
-
- private int version;
-
- int entries;
-
- Header(ByteBuffer map) throws CorruptObjectException {
- read(map);
- }
-
- private void read(ByteBuffer buf) throws CorruptObjectException {
- signature = buf.getInt();
- version = buf.getInt();
- entries = buf.getInt();
- if (signature != 0x44495243)
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().indexSignatureIsInvalid, signature));
- if (version != 2)
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().unknownIndexVersionOrCorruptIndex, version));
- }
-
- void write(ByteBuffer buf) {
- buf.order(ByteOrder.BIG_ENDIAN);
- buf.putInt(signature);
- buf.putInt(version);
- buf.putInt(entries);
- }
-
- Header(Map entryset) {
- signature = 0x44495243;
- version = 2;
- entries = entryset.size();
- }
- }
-
- /**
- * Read a Tree recursively into the index
- *
- * @param t The tree to read
- *
- * @throws IOException
- */
- public void readTree(Tree t) throws IOException {
- entries.clear();
- readTree("", t);
- }
-
- void readTree(String prefix, Tree t) throws IOException {
- TreeEntry[] members = t.members();
- for (int i = 0; i < members.length; ++i) {
- TreeEntry te = members[i];
- String name;
- if (prefix.length() > 0)
- name = prefix + "/" + te.getName();
- else
- name = te.getName();
- if (te instanceof Tree) {
- readTree(name, (Tree) te);
- } else {
- Entry e = new Entry(te, 0);
- entries.put(Constants.encode(name), e);
- }
- }
- }
-
- /**
- * Add tree entry to index
- * @param te tree entry
- * @return new or modified index entry
- * @throws IOException
- */
- public Entry addEntry(TreeEntry te) throws IOException {
- byte[] key = Constants.encode(te.getFullName());
- Entry e = new Entry(te, 0);
- entries.put(key, e);
- return e;
- }
-
- /**
- * Check out content of the content represented by the index
- *
- * @param wd
- * workdir
- * @throws IOException
- */
- public void checkout(File wd) throws IOException {
- for (Entry e : entries.values()) {
- if (e.getStage() != 0)
- continue;
- checkoutEntry(wd, e);
- }
- }
-
- /**
- * Check out content of the specified index entry
- *
- * @param wd workdir
- * @param e index entry
- * @throws IOException
- */
- public void checkoutEntry(File wd, Entry e) throws IOException {
- ObjectLoader ol = db.open(e.sha1, Constants.OBJ_BLOB);
- File file = new File(wd, e.getName());
- file.delete();
- FileUtils.mkdirs(file.getParentFile(), true);
- FileOutputStream dst = new FileOutputStream(file);
- try {
- ol.copyTo(dst);
- } finally {
- dst.close();
- }
- if (config_filemode() && File_hasExecute()) {
- if (FileMode.EXECUTABLE_FILE.equals(e.mode)) {
- if (!File_canExecute(file))
- File_setExecute(file, true);
- } else {
- if (File_canExecute(file))
- File_setExecute(file, false);
- }
- }
- e.mtime = file.lastModified() * 1000000L;
- e.ctime = e.mtime;
- }
-
- /**
- * Construct and write tree out of index.
- *
- * @return SHA-1 of the constructed tree
- *
- * @throws IOException
- */
- public ObjectId writeTree() throws IOException {
- checkWriteOk();
- ObjectInserter inserter = db.newObjectInserter();
- try {
- Tree current = new Tree(db);
- Stack<Tree> trees = new Stack<Tree>();
- trees.push(current);
- String[] prevName = new String[0];
- for (Entry e : entries.values()) {
- if (e.getStage() != 0)
- continue;
- String[] newName = splitDirPath(e.getName());
- int c = longestCommonPath(prevName, newName);
- while (c < trees.size() - 1) {
- current.setId(inserter.insert(Constants.OBJ_TREE, current.format()));
- trees.pop();
- current = trees.isEmpty() ? null : (Tree) trees.peek();
- }
- while (trees.size() < newName.length) {
- if (!current.existsTree(newName[trees.size() - 1])) {
- current = new Tree(current, Constants.encode(newName[trees.size() - 1]));
- current.getParent().addEntry(current);
- trees.push(current);
- } else {
- current = (Tree) current.findTreeMember(newName[trees
- .size() - 1]);
- trees.push(current);
- }
- }
- FileTreeEntry ne = new FileTreeEntry(current, e.sha1,
- Constants.encode(newName[newName.length - 1]),
- (e.mode & FileMode.EXECUTABLE_FILE.getBits()) == FileMode.EXECUTABLE_FILE.getBits());
- current.addEntry(ne);
- }
- while (!trees.isEmpty()) {
- current.setId(inserter.insert(Constants.OBJ_TREE, current.format()));
- trees.pop();
- if (!trees.isEmpty())
- current = trees.peek();
- }
- inserter.flush();
- return current.getId();
- } finally {
- inserter.release();
- }
- }
-
- String[] splitDirPath(String name) {
- String[] tmp = new String[name.length() / 2 + 1];
- int p0 = -1;
- int p1;
- int c = 0;
- while ((p1 = name.indexOf('/', p0 + 1)) != -1) {
- tmp[c++] = name.substring(p0 + 1, p1);
- p0 = p1;
- }
- tmp[c++] = name.substring(p0 + 1);
- String[] ret = new String[c];
- for (int i = 0; i < c; ++i) {
- ret[i] = tmp[i];
- }
- return ret;
- }
-
- int longestCommonPath(String[] a, String[] b) {
- int i;
- for (i = 0; i < a.length && i < b.length; ++i)
- if (!a[i].equals(b[i]))
- return i;
- return i;
- }
-
- /**
- * Return the members of the index sorted by the unsigned byte
- * values of the path names.
- *
- * Small beware: Unaccounted for are unmerged entries. You may want
- * to abort if members with stage != 0 are found if you are doing
- * any updating operations. All stages will be found after one another
- * here later. Currently only one stage per name is returned.
- *
- * @return The index entries sorted
- */
- public Entry[] getMembers() {
- return entries.values().toArray(new Entry[entries.size()]);
- }
-
- /**
- * Look up an entry with the specified path.
- *
- * @param path
- * @return index entry for the path or null if not in index.
- * @throws UnsupportedEncodingException
- */
- public Entry getEntry(String path) throws UnsupportedEncodingException {
- return entries.get(Repository.gitInternalSlash(Constants.encode(path)));
- }
-
- /**
- * @return The repository holding this index.
- */
- public Repository getRepository() {
- return db;
- }
-}