[522495] Setup archiver could better handle bad server behavior
https://bugs.eclipse.org/bugs/show_bug.cgi?id=522495
diff --git a/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupArchiver.java b/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupArchiver.java
index 06da03c..825991a 100644
--- a/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupArchiver.java
+++ b/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupArchiver.java
@@ -25,19 +25,26 @@
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
+import org.eclipse.emf.ecore.resource.URIHandler;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
@@ -55,6 +62,90 @@
// The default target file is the cache location of the local setup archive.
final ResourceSet resourceSet = SetupCoreUtil.createResourceSet();
final URIConverter uriConverter = resourceSet.getURIConverter();
+
+ for (ListIterator<URIHandler> it = uriConverter.getURIHandlers().listIterator(); it.hasNext();)
+ {
+ // Create a delegating handling for ECFURIHandler...
+ // The GITC is serving bytes that randomly have trailing garbage.
+ final URIHandler uriHandler = it.next();
+ if (uriHandler instanceof ECFURIHandlerImpl)
+ {
+ it.set(new URIHandler()
+ {
+ public void setAttributes(URI uri, Map<String, ?> attributes, Map<?, ?> options) throws IOException
+ {
+ uriHandler.setAttributes(uri, attributes, options);
+ }
+
+ public Map<String, ?> getAttributes(URI uri, Map<?, ?> options)
+ {
+ return uriHandler.getAttributes(uri, options);
+ }
+
+ public boolean exists(URI uri, Map<?, ?> options)
+ {
+ return uriHandler.exists(uri, options);
+ }
+
+ public void delete(URI uri, Map<?, ?> options) throws IOException
+ {
+ uriHandler.delete(uri, options);
+ }
+
+ public OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException
+ {
+ return uriHandler.createOutputStream(uri, options);
+ }
+
+ public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException
+ {
+ InputStream result = uriHandler.createInputStream(uri, options);
+ try
+ {
+ // Copy the bytes out of the stream.
+ ByteArrayOutputStream initialOut = new ByteArrayOutputStream();
+ IOUtil.copy(result, initialOut);
+ byte[] initialBytes = initialOut.toByteArray();
+
+ // Create yet another stream.
+ result = uriHandler.createInputStream(uri, options);
+
+ // Read this one too, and check if the bytes are the same.
+ ByteArrayOutputStream secondaryOut = new ByteArrayOutputStream();
+ IOUtil.copy(result, secondaryOut);
+ byte[] secondaryBytes = secondaryOut.toByteArray();
+ if (Arrays.equals(initialBytes, secondaryBytes))
+ {
+ // If so we can return a stream for those bytes.
+ return new ByteArrayInputStream(initialBytes);
+ }
+ else
+ {
+ // If not, we fail early so we don't even try to load the resource.
+ // This way we don't end up with a resource with what's likely to be bad contents.
+ // At least for XML parsing fails, but with images, we can't check if the image is valid.
+ throw new IOException("The server is delivering inconsistent results for " + uri);
+ }
+ }
+ catch (IORuntimeException ex)
+ {
+ throw new IOException(ex);
+ }
+ }
+
+ public Map<String, ?> contentDescription(URI uri, Map<?, ?> options) throws IOException
+ {
+ return uriHandler.contentDescription(uri, options);
+ }
+
+ public boolean canHandle(URI uri)
+ {
+ return uriHandler.canHandle(uri);
+ }
+ });
+ }
+ }
+
URI archiveLocation = uriConverter.normalize(SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI);
File file = new File(ECFURIHandlerImpl.getCacheFile(archiveLocation).toFileString());
@@ -213,71 +304,92 @@
uriMap.remove(SetupContext.INDEX_ROOT_LOCATION_URI);
- boolean hasFailures = false;
+ // If Ecore models fail to load correct, the org.eclipse.setup will resolve the package proxies incorrectly and will look changed.
+ // We don't want that, so terminate early.
+ boolean hasEcoreFailures = false;
for (Resource resource : resourceSet.getResources())
{
URI uri = resource.getURI();
-
URI normalizedURI = uriConverter.normalize(uri);
- String scheme = normalizedURI.scheme();
- if (normalizedURI.query() == null && ("http".equals(scheme) || "https".equals(scheme)))
+ if ("ecore".equals(uri.fileExtension()) && (resource.getContents().isEmpty() || !resource.getErrors().isEmpty()))
{
- URI path = URI.createURI(scheme);
- path = path.appendSegment(normalizedURI.authority());
- path = path.appendSegments(normalizedURI.segments());
- System.out.println("Mirroring " + normalizedURI);
+ System.err.println("FAILED to load " + normalizedURI);
+ printDiagnostics(resource.getErrors());
+ System.err.println("Aborting");
+ hasEcoreFailures = true;
+ break;
+ }
+ }
- URI output = path.resolve(outputLocation);
- entryNames.remove(path.toString());
- uriMap.put(uri, output);
+ if (!hasEcoreFailures)
+ {
+ boolean hasFailures = false;
+ for (Resource resource : resourceSet.getResources())
+ {
+ URI uri = resource.getURI();
- if (resource.getContents().isEmpty())
+ URI normalizedURI = uriConverter.normalize(uri);
+ String scheme = normalizedURI.scheme();
+ if (normalizedURI.query() == null && ("http".equals(scheme) || "https".equals(scheme)))
{
- System.err.println("FAILED to load " + normalizedURI);
- hasFailures = true;
+ URI path = URI.createURI(scheme);
+ path = path.appendSegment(normalizedURI.authority());
+ path = path.appendSegments(normalizedURI.segments());
+ System.out.println("Mirroring " + normalizedURI);
+
+ URI output = path.resolve(outputLocation);
+ entryNames.remove(path.toString());
+ uriMap.put(uri, output);
+
+ if (resource.getContents().isEmpty() || !resource.getErrors().isEmpty())
+ {
+ System.err.println("FAILED to load " + normalizedURI);
+ printDiagnostics(resource.getErrors());
+ hasFailures = true;
+ }
+ else
+ {
+ try
+ {
+ long before = resource.getTimeStamp();
+ resource.save(options);
+ long after = resource.getTimeStamp();
+
+ if (after - before > 0)
+ {
+ System.err.println("CHANGED! " + normalizedURI);
+ }
+ }
+ catch (IOException ex)
+ {
+ System.err.println("FAILED to save " + normalizedURI);
+ ex.printStackTrace();
+ }
+ }
}
else
{
- try
- {
- long before = resource.getTimeStamp();
- resource.save(options);
- long after = resource.getTimeStamp();
-
- if (after - before > 0)
- {
- System.err.println("CHANGED! " + normalizedURI);
- }
- }
- catch (IOException ex)
- {
- System.err.println("FAILED to save " + normalizedURI);
- ex.printStackTrace();
- }
+ System.out.println("Ignoring " + normalizedURI);
}
}
+
+ if (hasFailures)
+ {
+ System.err.println("There were failures so no entries will be deleted from the archive");
+ }
else
{
- System.out.println("Ignoring " + normalizedURI);
- }
- }
-
- if (hasFailures)
- {
- System.err.println("There were failures so no entries will be deleted from the archive");
- }
- else
- {
- for (String entryName : entryNames)
- {
- URI archiveEntry = URI.createURI(outputLocation + entryName);
- try
+ for (String entryName : entryNames)
{
- uriConverter.delete(archiveEntry, null);
- }
- catch (IOException ex)
- {
- ex.printStackTrace();
+ URI archiveEntry = URI.createURI(outputLocation + entryName);
+ try
+ {
+ uriConverter.delete(archiveEntry, null);
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
}
}
}
@@ -411,6 +523,14 @@
return false;
}
+ private void printDiagnostics(List<Resource.Diagnostic> diagnostics)
+ {
+ for (Resource.Diagnostic diagnostic : diagnostics)
+ {
+ System.err.println(" ERROR: " + diagnostic.getMessage() + " " + diagnostic.getLine() + " " + diagnostic.getLine() + " " + diagnostic.getColumn());
+ }
+ }
+
public void stop()
{
}