blob: 0f808954f28a030d8ed74559e5830d0cf7d1d7bf [file] [log] [blame]
// Copyright (C) 2017 Google Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlesource.gerrit.plugins.supermanifest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Repository;
class JiriManifestParser {
public static JiriProjects getProjects(Repository repo, String ref, String manifest)
throws ConfigInvalidException, IOException {
Queue<String> q = new LinkedList<>();
q.add(manifest);
HashSet<String> processedFiles = new HashSet<>();
HashMap<String, JiriProjects.Project> projectMap = new HashMap<>();
while (q.size() != 0) {
String file = q.remove();
if (processedFiles.contains(file)) {
continue;
}
processedFiles.add(file);
JiriManifest m;
try {
m = parseManifest(repo, ref, file);
} catch (JAXBException | XMLStreamException e) {
throw new ConfigInvalidException("XML parse error", e);
}
if (m.imports.getImports().length != 0) {
throw new ConfigInvalidException(
String.format("Manifest %s contains remote imports which are not supported", file));
}
for (JiriProjects.Project project : m.projects.getProjects()) {
project.fillDefault();
if (projectMap.containsKey(project.Key())) {
if (!projectMap.get(project.Key()).equals(project))
throw new ConfigInvalidException(
String.format(
"Duplicate conflicting project %s in manifest %s\n%s\n%s",
project.Key(),
file,
project.toString(),
projectMap.get(project.Key()).toString()));
} else {
projectMap.put(project.Key(), project);
}
}
URI parentURI;
try {
parentURI = new URI(file);
} catch (URISyntaxException e) {
throw new ConfigInvalidException("Invalid parent URI", e);
}
for (JiriManifest.LocalImport l : m.imports.getLocalImports()) {
q.add(parentURI.resolve(l.getFile()).getPath());
}
}
return new JiriProjects(projectMap.values().toArray(new JiriProjects.Project[0]));
}
private static JiriManifest parseManifest(Repository repo, String ref, String file)
throws JAXBException, IOException, XMLStreamException {
byte[] b = Utils.readBlob(repo, ref + ":" + file);
JAXBContext jc = JAXBContext.newInstance(JiriManifest.class);
XMLInputFactory inf = XMLInputFactory.newFactory();
inf.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
inf.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader sr = inf.createXMLStreamReader(new StreamSource(new ByteArrayInputStream(b)));
return (JiriManifest) jc.createUnmarshaller().unmarshal(sr);
}
}