From ec80c9b112f2b2807273382c5bf57ebaefdb368d Mon Sep 17 00:00:00 2001 From: Robin Rosenberg Date: Tue, 21 Aug 2007 23:31:25 +0200 Subject: [PATCH] Obey core.filemode setting This includes ignoring changes and setting the execute bit on checkout. If J2SE 5.0 or earlier is used core.filemode is ignored by jgit anyway. The Eclipse API has suppport for the execute permission but jgit is not dependent on Eclipse. Signed-off-by: Robin Rosenberg --- .../org.spearce.jgit--All-Tests (Java 6).launch | 21 +++++ .../src/org/spearce/jgit/lib/GitIndex.java | 59 ++++++++++-- .../tst/org/spearce/jgit/lib/T0007_Index.java | 105 +++++++++++++++++++++ 3 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 org.spearce.jgit/org.spearce.jgit--All-Tests (Java 6).launch diff --git a/org.spearce.jgit/org.spearce.jgit--All-Tests (Java 6).launch b/org.spearce.jgit/org.spearce.jgit--All-Tests (Java 6).launch new file mode 100644 index 00000000..f2556723 --- /dev/null +++ b/org.spearce.jgit/org.spearce.jgit--All-Tests (Java 6).launch @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java b/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java index c81217ce..fa31314e 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java @@ -182,9 +182,11 @@ public class GitIndex { } static Method canExecute; + static Method setExecute; static { try { canExecute = File.class.getMethod("canExecute", (Class[]) null); + setExecute = File.class.getMethod("setExecutable", new Class[] { Boolean.TYPE }); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { @@ -214,6 +216,25 @@ public class GitIndex { return false; } + /* + * JDK1.6 has file.setExecute + */ + boolean File_setExecute(File f,boolean value) { + if (setExecute != null) { + try { + return ((Boolean) setExecute.invoke(f, + new Object[] { new Boolean(value) })).booleanValue(); + } catch (IllegalArgumentException e) { + throw new Error(e); + } catch (IllegalAccessException e) { + throw new Error(e); + } catch (InvocationTargetException e) { + throw new Error(e); + } + } else + return false; + } + static byte[] makeKey(File wd, File f) { if (!f.getPath().startsWith(wd.getPath())) throw new Error("Path is not in working dir"); @@ -222,6 +243,16 @@ public class GitIndex { return relName.getBytes(); } + 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(); + RepositoryConfig config = db.getConfig(); + return config.getBoolean("core", "filemode", true); + } + public class Entry { private long ctime; @@ -253,7 +284,10 @@ public class GitIndex { mtime = ctime; // we use same here dev = -1; ino = -1; - mode = FileMode.REGULAR_FILE.getBits(); + 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(); @@ -309,9 +343,11 @@ public class GitIndex { mtime = f.lastModified() * 1000000L; if (size != f.length()) modified = true; - if (File_canExecute(f) != FileMode.EXECUTABLE_FILE.equals(mode)) { - mode = FileMode.EXECUTABLE_FILE.getBits(); - 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(); @@ -386,14 +422,14 @@ public class GitIndex { final int exebits = FileMode.EXECUTABLE_FILE.getBits() ^ FileMode.REGULAR_FILE.getBits(); - if (FileMode.EXECUTABLE_FILE.equals(mode)) { + if (config_filemode() && FileMode.EXECUTABLE_FILE.equals(mode)) { if (!File_canExecute(file)&& canExecute != null) return true; } else { if (FileMode.REGULAR_FILE.equals(mode&~exebits)) { if (!file.isFile()) return true; - if (File_canExecute(file) && canExecute != null) + if (config_filemode() && File_canExecute(file) && canExecute != null) return true; } else { if (FileMode.SYMLINK.equals(mode)) { @@ -545,6 +581,17 @@ public class GitIndex { if (j != bytes.length) throw new IOException("Could not write file " + file); channel.close(); + if (config_filemode() && canExecute != null) { + 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; } } diff --git a/org.spearce.jgit/tst/org/spearce/jgit/lib/T0007_Index.java b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0007_Index.java index 4755e953..989c8a49 100644 --- a/org.spearce.jgit/tst/org/spearce/jgit/lib/T0007_Index.java +++ b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0007_Index.java @@ -4,6 +4,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.spearce.jgit.lib.GitIndex.Entry; @@ -272,6 +274,109 @@ public class T0007_Index extends RepositoryTestCase { assertEquals(0, system(trash, "git status")); } + public void test030_executeBit_coreModeTrue() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception { + 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 = db.mapTree(index.writeTree()); + 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; + } + } + + public void test031_executeBit_coreModeFalse() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception { + 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 = db.mapTree(index.writeTree()); + 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 String content(File f) throws IOException { byte[] buf = new byte[(int) f.length()]; FileInputStream is = new FileInputStream(f); -- 2.11.4.GIT