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 9fc59c578..27d322079 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 @@ -178,6 +178,41 @@ public class RepoCommandTest extends RepositoryTestCase { assertTrue("\"all,-a\" has have b", file.exists()); } + @Test + public void testRepoManifestCopyfile() throws Exception { + 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 + File hello = new File(localDb.getWorkTree(), "foo/hello.txt"); + assertTrue("The original file exists", hello.exists()); + BufferedReader reader = new BufferedReader(new FileReader(hello)); + String content = reader.readLine(); + reader.close(); + assertEquals("The original file has expected content", "world", content); + // The dest file should also exist + hello = new File(localDb.getWorkTree(), "Hello"); + assertTrue("The destination file exists", hello.exists()); + reader = new BufferedReader(new FileReader(hello)); + content = reader.readLine(); + reader.close(); + assertEquals("The destination file has expected content", "world", content); + } + private void resolveRelativeUris() { // Find the longest common prefix ends with "/" as rootUri. defaultUri = defaultDb.getDirectory().toURI().toString(); diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/gitrepo/internal/RepoText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/gitrepo/internal/RepoText.properties index fb158399b..64d754de8 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/gitrepo/internal/RepoText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/gitrepo/internal/RepoText.properties @@ -1,3 +1,4 @@ +copyFileFailed=Error occurred during execution of copyfile rule. errorNoDefault=Error: no default remote in file {0}. errorParsingManifestFile=Error occurred during parsing manifest file {0}. invalidManifest=Invalid manifest. 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 a7467c83d..a05dc11da 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -43,9 +43,11 @@ package org.eclipse.jgit.gitrepo; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.channels.FileChannel; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -55,6 +57,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.eclipse.jgit.api.AddCommand; import org.eclipse.jgit.api.GitCommand; import org.eclipse.jgit.api.SubmoduleAddCommand; import org.eclipse.jgit.api.errors.GitAPIException; @@ -87,10 +90,38 @@ public class RepoCommand extends GitCommand { private ProgressMonitor monitor; + private static class CopyFile { + final String src; + final String dest; + final String relativeDest; + + CopyFile(Repository repo, String path, String src, String dest) { + this.src = repo.getWorkTree() + "/" + path + "/" + src; //$NON-NLS-1$ //$NON-NLS-2$ + this.relativeDest = dest; + this.dest = repo.getWorkTree() + "/" + dest; //$NON-NLS-1$ + } + + void copy() throws IOException { + FileInputStream input = new FileInputStream(src); + try { + FileOutputStream output = new FileOutputStream(dest); + try { + FileChannel channel = input.getChannel(); + output.getChannel().transferFrom(channel, 0, channel.size()); + } finally { + output.close(); + } + } finally { + input.close(); + } + } + } + private static class Project { final String name; final String path; final Set groups; + final List copyfiles; Project(String name, String path, String groups) { this.name = name; @@ -98,6 +129,11 @@ public class RepoCommand extends GitCommand { this.groups = new HashSet(); if (groups != null && groups.length() > 0) this.groups.addAll(Arrays.asList(groups.split(","))); //$NON-NLS-1$ + copyfiles = new ArrayList(); + } + + void addCopyFile(CopyFile copyfile) { + copyfiles.add(copyfile); } } @@ -110,6 +146,7 @@ public class RepoCommand extends GitCommand { private final Set plusGroups; private final Set minusGroups; private String defaultRemote; + private Project currentProject; XmlManifest(RepoCommand command, String filename, String baseUrl, String groups) { this.command = command; @@ -160,17 +197,34 @@ public class RepoCommand extends GitCommand { String qName, Attributes attributes) throws SAXException { if ("project".equals(qName)) { //$NON-NLS-1$ - projects.add(new Project( //$NON-NLS-1$ - attributes.getValue("name"), //$NON-NLS-1$ - attributes.getValue("path"), //$NON-NLS-1$ - attributes.getValue("groups"))); //$NON-NLS-1$ + currentProject = new Project( //$NON-NLS-1$ + attributes.getValue("name"), //$NON-NLS-1$ + attributes.getValue("path"), //$NON-NLS-1$ + attributes.getValue("groups")); //$NON-NLS-1$ } else if ("remote".equals(qName)) { //$NON-NLS-1$ remotes.put(attributes.getValue("name"), //$NON-NLS-1$ attributes.getValue("fetch")); //$NON-NLS-1$ } else if ("default".equals(qName)) { //$NON-NLS-1$ defaultRemote = attributes.getValue("remote"); //$NON-NLS-1$ } else if ("copyfile".equals(qName)) { //$NON-NLS-1$ - // TODO(fishywang): Handle copyfile. Do nothing for now. + if (currentProject == null) + throw new SAXException(RepoText.get().invalidManifest); + currentProject.addCopyFile(new CopyFile( + command.repo, + currentProject.path, + attributes.getValue("src"), //$NON-NLS-1$ + attributes.getValue("dest"))); //$NON-NLS-1$ + } + } + + @Override + public void endElement( + String uri, + String localName, + String qName) throws SAXException { + if ("project".equals(qName)) { //$NON-NLS-1$ + projects.add(currentProject); + currentProject = null; } } @@ -191,6 +245,21 @@ public class RepoCommand extends GitCommand { if (inGroups(proj)) { String url = remoteUrl + proj.name; command.addSubmodule(url, proj.path); + for (CopyFile copyfile : proj.copyfiles) { + try { + copyfile.copy(); + } catch (IOException e) { + throw new SAXException( + RepoText.get().copyFileFailed, e); + } + AddCommand add = new AddCommand(command.repo) + .addFilepattern(copyfile.relativeDest); + try { + add.call(); + } catch (GitAPIException e) { + throw new SAXException(e); + } + } } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java index 519c9d156..50fc61d91 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/internal/RepoText.java @@ -59,6 +59,7 @@ public class RepoText extends TranslationBundle { } // @formatter:off + /***/ public String copyFileFailed; /***/ public String errorNoDefault; /***/ public String errorParsingManifestFile; /***/ public String invalidManifest;