From 34dd64f6fe36ace1a90b0b503e2e37d877b7c621 Mon Sep 17 00:00:00 2001 From: Yuxuan 'fishy' Wang Date: Wed, 6 Aug 2014 22:01:08 -0700 Subject: [PATCH] Add support to tag in repo manifest xml. Change-Id: I32d468f92e24701ea680435bf3417e3850857303 Signed-off-by: Yuxuan 'fishy' Wang --- .../eclipse/jgit/gitrepo/RepoCommandTest.java | 40 ++++++++++ .../jgit/gitrepo/internal/RepoText.properties | 2 + .../org/eclipse/jgit/gitrepo/RepoCommand.java | 79 +++++++++++++++++-- .../jgit/gitrepo/internal/RepoText.java | 2 + 4 files changed, 117 insertions(+), 6 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 3e5ef0273..41a086f6b 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 @@ -571,6 +571,46 @@ public void testRemoveOverlappingBare() throws Exception { assertTrue("The a submodule should exist", a); } + @Test + public void testIncludeTag() throws Exception { + Repository localDb = createWorkRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("\n") + .append("") + .append("") + .append("") + .append(""); + JGitTestUtil.writeTrashFile( + tempDb, "manifest.xml", xmlContent.toString()); + + xmlContent = new StringBuilder(); + xmlContent.append("\n") + .append("") + .append("") + .append("") + .append("") + .append(""); + JGitTestUtil.writeTrashFile( + tempDb, "_include.xml", xmlContent.toString()); + + RepoCommand command = new RepoCommand(localDb); + command + .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri) + .call(); + File hello = new File(localDb.getWorkTree(), "foo/hello.txt"); + assertTrue("submodule should be checked out", hello.exists()); + BufferedReader reader = new BufferedReader(new FileReader(hello)); + String content = reader.readLine(); + reader.close(); + assertEquals("submodule content should be as expected", + "master 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 256dd7f08..7443ad32f 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,4 +1,6 @@ copyFileFailed=Error occurred during execution of copyfile rule. +errorIncludeFile=Error: unable to read include file {0} +errorIncludeNotImplemented=Error: tag not supported as no callback defined. errorNoDefault=Error: no default remote in manifest file. errorNoDefaultFilename=Error: no default remote in manifest file {0}. errorParsingManifestFile=Error occurred during parsing manifest file. 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 57514a203..52710d1d6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -123,6 +123,7 @@ public class RepoCommand extends GitCommand { private PersonIdent author; private RemoteReader callback; private InputStream inputStream; + private IncludedFileReader includedReader; private List bareProjects; private Git git; @@ -163,6 +164,7 @@ public interface RemoteReader { * @return the file content. * @throws GitAPIException * @throws IOException + * @since 3.5 */ public byte[] readFile(String uri, String ref, String path) throws GitAPIException, IOException; @@ -224,6 +226,25 @@ protected byte[] readFileFromRepo(Repository repo, } } + /** + * A callback to read included xml files. + * + * @since 3.5 + */ + public interface IncludedFileReader { + /** + * Read a file from the same base dir of the manifest xml file. + * + * @param path + * The relative path to the file to read + * @return the {@code InputStream} of the file. + * @throws GitAPIException + * @throws IOException + */ + public InputStream readIncludeFile(String path) + throws GitAPIException, IOException; + } + private static class CopyFile { final Repository repo; final String path; @@ -309,7 +330,6 @@ public int compareTo(Project that) { private static class XmlManifest extends DefaultHandler { private final RepoCommand command; - private final InputStream inputStream; private final String filename; private final String baseUrl; private final Map remotes; @@ -318,12 +338,14 @@ private static class XmlManifest extends DefaultHandler { private List projects; private String defaultRemote; private String defaultRevision; + private IncludedFileReader includedReader; + private int xmlInRead; private Project currentProject; - XmlManifest(RepoCommand command, InputStream inputStream, + XmlManifest(RepoCommand command, IncludedFileReader includedReader, String filename, String baseUrl, String groups) { this.command = command; - this.inputStream = inputStream; + this.includedReader = includedReader; this.filename = filename; // Strip trailing /s to match repo behavior. @@ -349,7 +371,8 @@ private static class XmlManifest extends DefaultHandler { } } - void read() throws IOException { + void read(InputStream inputStream) throws IOException { + xmlInRead++; final XMLReader xr; try { xr = XMLReaderFactory.createXMLReader(); @@ -395,6 +418,35 @@ public void startElement( currentProject.path, attributes.getValue("src"), //$NON-NLS-1$ attributes.getValue("dest"))); //$NON-NLS-1$ + } else if ("include".equals(qName)) { //$NON_NLS-1$ + String name = attributes.getValue("name"); + InputStream is = null; + if (includedReader != null) { + try { + is = includedReader.readIncludeFile(name); + } catch (Exception e) { + throw new SAXException(MessageFormat.format( + RepoText.get().errorIncludeFile, name), e); + } + } else if (filename != null) { + int index = filename.lastIndexOf('/'); + String path = filename.substring(0, index + 1) + name; + try { + is = new FileInputStream(path); + } catch (IOException e) { + throw new SAXException(MessageFormat.format( + RepoText.get().errorIncludeFile, path), e); + } + } + if (is == null) { + throw new SAXException( + RepoText.get().errorIncludeNotImplemented); + } + try { + read(is); + } catch (IOException e) { + throw new SAXException(e); + } } } @@ -411,6 +463,10 @@ public void endElement( @Override public void endDocument() throws SAXException { + xmlInRead--; + if (xmlInRead != 0) + return; + // Only do the following after we finished reading everything. if (defaultRemote == null) { if (filename != null) throw new SAXException(MessageFormat.format( @@ -606,6 +662,17 @@ public RepoCommand setRemoteReader(final RemoteReader callback) { return this; } + /** + * Set the IncludedFileReader callback. + * + * @param reader + * @return this command + */ + public RepoCommand setIncludedFileReader(IncludedFileReader reader) { + this.includedReader = reader; + return this; + } + @Override public RevCommit call() throws GitAPIException { try { @@ -635,9 +702,9 @@ public RevCommit call() throws GitAPIException { git = new Git(repo); XmlManifest manifest = new XmlManifest( - this, inputStream, path, uri, groups); + this, includedReader, path, uri, groups); try { - manifest.read(); + manifest.read(inputStream); } catch (IOException e) { throw new ManifestErrorException(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 1f9d5d863..36b6e3aac 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 @@ -60,6 +60,8 @@ public static RepoText get() { // @formatter:off /***/ public String copyFileFailed; + /***/ public String errorIncludeFile; + /***/ public String errorIncludeNotImplemented; /***/ public String errorNoDefault; /***/ public String errorNoDefaultFilename; /***/ public String errorParsingManifestFile;