From e64ce267f8b318abe1503f5cf0b71065499b1c87 Mon Sep 17 00:00:00 2001 From: Ivan Frade Date: Fri, 26 Oct 2018 17:03:40 -0700 Subject: [PATCH] RepoCommand: Preserve executable bit in The copyfile entry in the manifest file copies the contents of the file but doesn't keep the executable flag. This is inconsistent with repo tool behaviour, plus is natural to expect that the copy of a executable file is executable. Transfer the executable bit when copying the file, aligning the RepoCommand with repo tool and user expectations. Change-Id: I01b24f482d5939e01d496f032388b3a5c02a912a Signed-off-by: Ivan Frade --- .../eclipse/jgit/gitrepo/RepoCommandTest.java | 118 ++++++++++++++++++ .../org/eclipse/jgit/gitrepo/RepoCommand.java | 7 +- .../org/eclipse/jgit/gitrepo/RepoProject.java | 1 + 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index c170ac1b3..1f6861b35 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -577,13 +577,69 @@ public void testRepoManifestCopyFile() throws Exception { // The original file should exist File hello = new File(localDb.getWorkTree(), "foo/hello.txt"); assertTrue("The original file should exist", hello.exists()); + assertFalse("The original file should not be executable", + hello.canExecute()); assertContents(hello.toPath(), "master world"); // The dest file should also exist hello = new File(localDb.getWorkTree(), "Hello"); assertTrue("The destination file should exist", hello.exists()); + assertFalse("The destination file should not be executable", + hello.canExecute()); assertContents(hello.toPath(), "master world"); } + @Test + public void testRepoManifestCopyFile_executable() throws Exception { + try (Git git = new Git(defaultDb)) { + git.checkout().setName("master").call(); + File f = JGitTestUtil.writeTrashFile(defaultDb, "hello.sh", + "content of the executable file"); + f.setExecutable(true); + git.add().addFilepattern("hello.sh").call(); + git.commit().setMessage("Add binary file").call(); + } + + Repository localDb = createWorkRepository(); + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("\n") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("").append(""); + JGitTestUtil.writeTrashFile(localDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(localDb); + command.setPath( + localDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + + // The original file should exist and be an executable + File hello = new File(localDb.getWorkTree(), "foo/hello.sh"); + assertTrue("The original file should exist", hello.exists()); + assertTrue("The original file must be executable", hello.canExecute()); + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { + String content = reader.readLine(); + assertEquals("The original file should have expected content", + "content of the executable file", content); + } + + // The destination file should also exist and be an executable + hello = new File(localDb.getWorkTree(), "copy-hello.sh"); + assertTrue("The destination file should exist", hello.exists()); + assertTrue("The destination file must be executable", + hello.canExecute()); + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { + String content = reader.readLine(); + assertEquals("The destination file should have expected content", + "content of the executable file", content); + } + } + @Test public void testBareRepo() throws Exception { Repository remoteDb = createBareRepository(); @@ -767,6 +823,68 @@ public void testCopyFileBare() throws Exception { } } + @Test + public void testCopyFileBare_executable() throws Exception { + try (Git git = new Git(defaultDb)) { + git.checkout().setName(BRANCH).call(); + File f = JGitTestUtil.writeTrashFile(defaultDb, "hello.sh", + "content of the executable file"); + f.setExecutable(true); + git.add().addFilepattern("hello.sh").call(); + git.commit().setMessage("Add binary file").call(); + } + + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("\n") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("").append(""); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testCopyFileBare"); + try (Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository()) { + // The Hello file should exist + File hello = new File(localDb.getWorkTree(), "Hello"); + assertTrue("The Hello file should exist", hello.exists()); + // The foo/Hello file should be skipped. + File foohello = new File(localDb.getWorkTree(), "foo/Hello"); + assertFalse("The foo/Hello file should be skipped", + foohello.exists()); + // The content of Hello file should be expected + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { + String content = reader.readLine(); + assertEquals("The Hello file should have expected content", + "branch world", content); + } + + // The executable file must be there and preserve the executable bit + File helloSh = new File(localDb.getWorkTree(), "copy-hello.sh"); + assertTrue("Destination file should exist", helloSh.exists()); + assertContents(helloSh.toPath(), "content of the executable file"); + assertTrue("Destination file should be executable", + helloSh.canExecute()); + + } + } + @Test public void testReplaceManifestBare() throws Exception { Repository remoteDb = createBareRepository(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index e01101095..e9d86dfa8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -663,12 +663,13 @@ public RevCommit call() throws GitAPIException { builder.add(dcEntry); for (CopyFile copyfile : proj.getCopyFiles()) { - byte[] src = callback.readFile( + RemoteFile rf = callback.readFileWithMode( url, proj.getRevision(), copyfile.src); - objectId = inserter.insert(Constants.OBJ_BLOB, src); + objectId = inserter.insert(Constants.OBJ_BLOB, + rf.getContents()); dcEntry = new DirCacheEntry(copyfile.dest); dcEntry.setObjectId(objectId); - dcEntry.setFileMode(FileMode.REGULAR_FILE); + dcEntry.setFileMode(rf.getFileMode()); builder.add(dcEntry); } for (LinkFile linkfile : proj.getLinkFiles()) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java index 7ba83c7cb..d79dfa8b2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java @@ -136,6 +136,7 @@ public void copy() throws IOException { FileChannel channel = input.getChannel(); output.getChannel().transferFrom(channel, 0, channel.size()); } + destFile.setExecutable(srcFile.canExecute()); } }