tmf: Add support for importing Gzip (non-Tar)
authorMarc-Andre Laperle <marc-andre.laperle@ericsson.com>
Tue, 14 Apr 2015 19:17:47 +0000 (15:17 -0400)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Tue, 26 May 2015 21:44:02 +0000 (17:44 -0400)
Change-Id: I25271514449ecbfb7da2f56ee3036949b077ec07
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/48552
Reviewed-by: Hudson CI
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipEntry.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipFile.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipLeveledStructureProvider.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPage.java

diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipEntry.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipEntry.java
new file mode 100644 (file)
index 0000000..e20fb01
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation. Inspired from TarEntry.
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+/**
+ * GZip entry
+ */
+public class GzipEntry {
+    private static final String ROOT_DIR = "/"; //$NON-NLS-1$
+    private final String fName;
+    private final long fMode;
+    private final long fTime;
+    private final int fType;
+
+    /**
+     * Entry type for normal files. This is the only valid type for Gzip
+     * entries.
+     */
+    public static final int FILE = '0';
+
+    /**
+     * Entry type for directories. This doesn't really exist in a Gzip but it's
+     * useful to represent the root of the archive.
+     */
+    public static final int DIRECTORY = '5';
+
+    /**
+     * Create a new Root GzipEntry
+     */
+    public GzipEntry() {
+        fName = ROOT_DIR;
+        fMode = 0644;
+        fType = DIRECTORY;
+        fTime = System.currentTimeMillis() / 1000;
+    }
+
+    /**
+     * Create a new GzipEntry for a file of the given name at the given position
+     * in the file.
+     *
+     * @param name
+     *            filename
+     */
+    public GzipEntry(String name) {
+        fName = name;
+        fMode = 0644;
+        fType = FILE;
+        fTime = System.currentTimeMillis() / 1000;
+    }
+
+    /**
+     * Returns the type of this file, can only be FILE for a real Gzip entry.
+     * DIRECTORY can be specified to represent a "dummy root" in the archive.
+     *
+     * @return file type
+     */
+    public int getFileType() {
+        return fType;
+    }
+
+    /**
+     * Returns the mode of the file in UNIX permissions format.
+     *
+     * @return file mode
+     */
+    public long getMode() {
+        return fMode;
+    }
+
+    /**
+     * Returns the name of the file.
+     *
+     * @return filename
+     */
+    public String getName() {
+        return fName;
+    }
+
+    /**
+     * Returns the modification time of the file in seconds since January 1st
+     * 1970.
+     *
+     * @return time
+     */
+    public long getTime() {
+        return fTime;
+    }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipFile.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipFile.java
new file mode 100644 (file)
index 0000000..e1fbba9
--- /dev/null
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation.
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Wrapper for a Gzipped file
+ */
+public class GzipFile implements AutoCloseable {
+
+    private static final String GZIP_EXTENSION = ".gz"; //$NON-NLS-1$
+
+    private final File fFile;
+    private final GzipEntry fEntry;
+    private GzipEntry fCurEntry;
+    private boolean fIsClosed = false;
+
+    private final InputStream fInternalEntryStream;
+
+    /**
+     * Create a new GzipFile for the given file.
+     *
+     * @param source the source file
+     * @throws IOException
+     *             File not found and such
+     */
+    public GzipFile(File source) throws IOException {
+        fFile = source;
+
+        InputStream in = new FileInputStream(source);
+        // Check if it's a GZIPInputStream.
+        fInternalEntryStream = new GZIPInputStream(in);
+        String name = source.getName();
+        fEntry = new GzipEntry(name.substring(0, name.lastIndexOf(GZIP_EXTENSION)));
+        fCurEntry = fEntry;
+    }
+
+    /**
+     * Close the tar file input stream.
+     *
+     * @throws IOException if the file cannot be successfully closed
+     */
+    @Override
+    public void close() throws IOException {
+        if (fInternalEntryStream != null && !fIsClosed) {
+            fInternalEntryStream.close();
+            fIsClosed = true;
+
+        }
+    }
+
+    /**
+     * Create a new GzipFile for the given path name.
+     *
+     * @param filename
+     *            the filename of the gzip file
+     * @throws IOException
+     *             if the file cannot be opened
+     */
+    public GzipFile(String filename) throws IOException {
+        this(new File(filename));
+    }
+
+    /**
+     * Returns an enumeration cataloguing the tar archive.
+     *
+     * @return enumeration of all files in the archive
+     */
+    public Enumeration<GzipEntry> entries() {
+        return new Enumeration<GzipEntry>() {
+            @Override
+            public boolean hasMoreElements() {
+                return (fCurEntry != null);
+            }
+
+            @Override
+            public GzipEntry nextElement() {
+                GzipEntry oldEntry = fCurEntry;
+                fCurEntry = null;
+                return oldEntry;
+            }
+        };
+    }
+
+    /**
+     * Returns a new InputStream for the given file in the tar archive.
+     *
+     * @param entry
+     *            the GzipEntry
+     * @return an input stream for the given file
+     */
+    public InputStream getInputStream(GzipEntry entry) {
+        if (entry != fEntry) {
+            throw new IllegalArgumentException();
+        }
+        return fInternalEntryStream;
+    }
+
+    /**
+     * Returns the path name of the file this archive represents.
+     *
+     * @return path
+     */
+    public String getName() {
+        return fFile.getPath();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        close();
+    }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipLeveledStructureProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipLeveledStructureProvider.java
new file mode 100644 (file)
index 0000000..47da8ea
--- /dev/null
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation.
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;
+import org.eclipse.ui.internal.wizards.datatransfer.ILeveledImportStructureProvider;
+
+/**
+ * Leveled Structure provider for Gzip file
+ */
+@SuppressWarnings("restriction")
+public class GzipLeveledStructureProvider implements ILeveledImportStructureProvider {
+
+    private final GzipFile fFile;
+    private final GzipEntry root = new GzipEntry();
+    private final GzipEntry fEntry;
+
+    /**
+     * Creates a <code>GzipFileStructureProvider</code>, which will operate on
+     * the passed Gzip file.
+     *
+     * @param sourceFile
+     *            the source GzipFile
+     */
+    public GzipLeveledStructureProvider(GzipFile sourceFile) {
+        super();
+
+        fFile = sourceFile;
+        fEntry = sourceFile.entries().nextElement();
+    }
+
+    @Override
+    public List getChildren(Object element) {
+        ArrayList<Object> children = new ArrayList<>();
+        if (element == root) {
+            children.add(fEntry);
+        }
+        return children;
+    }
+
+    @Override
+    public InputStream getContents(Object element) {
+        return fFile.getInputStream((GzipEntry) element);
+    }
+
+    @Override
+    public String getFullPath(Object element) {
+        return ((GzipEntry) element).getName();
+    }
+
+    @Override
+    public String getLabel(Object element) {
+        if (element != root && element != fEntry) {
+            throw new IllegalArgumentException();
+        }
+        return ((GzipEntry) element).getName();
+    }
+
+    /**
+     * Returns the entry that this importer uses as the root sentinel.
+     *
+     * @return GzipEntry entry
+     */
+    @Override
+    public GzipEntry getRoot() {
+        return root;
+    }
+
+    @Override
+    public boolean closeArchive() {
+        try {
+            fFile.close();
+        } catch (IOException e) {
+            Activator.getDefault().logError(DataTransferMessages.ZipImport_couldNotClose
+                    + fFile.getName(), e);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isFolder(Object element) {
+        return ((GzipEntry) element).getFileType() == GzipEntry.DIRECTORY;
+    }
+
+    @Override
+    public void setStrip(int level) {
+        // Do nothing
+    }
+
+    @Override
+    public int getStrip() {
+        return 0;
+    }
+}
index 004da394f98357676f72d90e41b29db75f55445d..88ccb1977fbecf25d49e33e7e8bd763bc93e6319 100644 (file)
@@ -16,6 +16,7 @@
  *   Bernd Hufmann - Re-design of trace selection and trace validation
  *   Marc-Andre Laperle - Preserve folder structure on import
  *   Marc-Andre Laperle - Extract archives during import
+ *   Marc-Andre Laperle - Add support for Gzip (non-Tar)
  *******************************************************************************/
 
 package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
@@ -146,7 +147,7 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
     private static final String IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID = ".import_from_directory"; //$NON-NLS-1$
 
     // constant from WizardArchiveFileResourceImportPage1
-    private static final String[] FILE_IMPORT_MASK = { "*.jar;*.zip;*.tar;*.tar.gz;*.tgz", "*.*" }; //$NON-NLS-1$ //$NON-NLS-2$
+    private static final String[] FILE_IMPORT_MASK = { "*.jar;*.zip;*.tar;*.tar.gz;*.tgz;*.gz", "*.*" }; //$NON-NLS-1$ //$NON-NLS-2$
     private static final String TRACE_IMPORT_TEMP_FOLDER = ".traceImport"; //$NON-NLS-1$
 
     /**
@@ -791,6 +792,7 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
         return selectFiles(rootObjectAndProvider.getFirst(), rootObjectAndProvider.getSecond());
     }
 
+    @SuppressWarnings("resource")
     private Pair<IFileSystemObject, FileSystemObjectImportStructureProvider> getRootObjectAndProvider(File sourceFile) {
         if (sourceFile == null) {
             return null;
@@ -817,9 +819,17 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
             } else if (ensureZipSourceIsValid(archivePath)) {
                 // We close the file when we dispose the import provider, see
                 // disposeSelectionGroupRoot
-                @SuppressWarnings("resource")
                 ZipFile zipFile = getSpecifiedZipSourceFile(archivePath);
                 leveledImportStructureProvider = new FileSystemObjectLeveledImportStructureProvider(new ZipLeveledStructureProvider(zipFile), archivePath);
+            } else if (ensureGzipSourceIsValid(archivePath)) {
+                // We close the file when we dispose the import provider, see
+                // disposeSelectionGroupRoot
+                GzipFile zipFile = null;
+                try {
+                    zipFile = new GzipFile(archivePath);
+                } catch (IOException e) {
+                }
+                leveledImportStructureProvider = new FileSystemObjectLeveledImportStructureProvider(new GzipLeveledStructureProvider(zipFile), archivePath);
             }
             if (leveledImportStructureProvider == null) {
                 return null;
@@ -837,7 +847,7 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
 
     /**
      * An import provider that makes use of the IFileSystemObject abstraction
-     * instead of using plain file system objects (File, TarEntry, ZipEntry)
+     * instead of using plain file system objects (File, TarEntry, ZipEntry, etc)
      */
     private static class FileSystemObjectImportStructureProvider implements IImportStructureProvider {
 
@@ -871,6 +881,8 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
                 return new TarFileSystemObject((TarEntry) o, fArchivePath);
             } else if (o instanceof ZipEntry) {
                 return new ZipFileSystemObject((ZipEntry) o, fArchivePath);
+            } else if (o instanceof GzipEntry) {
+                return new GzipFileSystemObject((GzipEntry) o, fArchivePath);
             }
 
             throw new IllegalArgumentException("Object type not handled"); //$NON-NLS-1$
@@ -1008,6 +1020,10 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
         return null;
     }
 
+    private static boolean ensureGzipSourceIsValid(String archivePath) {
+        return isGzipFile(archivePath);
+    }
+
     private TraceFileSystemElement selectFiles(final IFileSystemObject rootFileSystemObject,
             final FileSystemObjectImportStructureProvider structureProvider) {
         final TraceFileSystemElement[] results = new TraceFileSystemElement[1];
@@ -1146,7 +1162,7 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
             return false;
         }
 
-        if (!isImportFromDirectory() && !ensureTarSourceIsValid(source.getAbsolutePath()) && !ensureZipSourceIsValid(source.getAbsolutePath())) {
+        if (!isImportFromDirectory() && !ensureTarSourceIsValid(source.getAbsolutePath()) && !ensureZipSourceIsValid(source.getAbsolutePath()) && !ensureGzipSourceIsValid(source.getAbsolutePath())) {
             setMessage(null);
             setErrorMessage(Messages.ImportTraceWizard_BadArchiveFormat);
             return false;
@@ -1186,7 +1202,17 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
 
     private static boolean isArchiveFile(File sourceFile) {
         String absolutePath = sourceFile.getAbsolutePath();
-        return isTarFile(absolutePath) || ArchiveFileManipulations.isZipFile(absolutePath);
+        return isTarFile(absolutePath) || ArchiveFileManipulations.isZipFile(absolutePath) || isGzipFile(absolutePath);
+    }
+
+    private static boolean isGzipFile(String fileName) {
+        if (!fileName.isEmpty()) {
+            try (GzipFile specifiedTarSourceFile = new GzipFile(fileName);) {
+                return true;
+            } catch (IOException e) {
+            }
+        }
+        return false;
     }
 
     @Override
@@ -1455,7 +1481,6 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
                 SubProgressMonitor monitor = new SubProgressMonitor(subMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
                 destTempFolder.create(IResource.HIDDEN, true, monitor);
 
-
                 subMonitor = SubMonitor.convert(progressMonitor, 2);
                 String baseSourceLocation;
                 if (fImportFromArchive) {
@@ -2046,7 +2071,7 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
 
     /**
      * This interface abstracts the differences between different kinds of
-     * FileSystemObjects such as File, TarEntry and ZipEntry. This allows
+     * FileSystemObjects such as File, TarEntry, ZipEntry, etc. This allows
      * clients (TraceFileSystemElement, TraceValidateAndImportOperation) to
      * handle all the types transparently.
      */
@@ -2134,7 +2159,7 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
     }
 
     /**
-     * The "Tar" implementation of an IFileSystemObject
+     * The "Tar" implementation of an IFileSystemObject, entries can also be Gzipped and are uncompressed transparently.
      */
     private static class TarFileSystemObject implements IFileSystemObject {
 
@@ -2187,6 +2212,60 @@ public class ImportTraceWizardPage extends WizardResourceImportPage {
         }
     }
 
+    /**
+     * The "GZIP" implementation of an IFileSystemObject. For a GZIP file that is not in a tar.
+     */
+    private static class GzipFileSystemObject implements IFileSystemObject {
+
+        private GzipEntry fFileSystemObject;
+        private String fArchivePath;
+
+        private GzipFileSystemObject(GzipEntry fileSystemObject, String archivePath) {
+            fFileSystemObject = fileSystemObject;
+            fArchivePath = archivePath;
+        }
+
+        @Override
+        public String getLabel() {
+            return new Path(fFileSystemObject.getName()).lastSegment();
+        }
+
+        @Override
+        public String getName() {
+            return fFileSystemObject.getName();
+        }
+
+        @Override
+        public String getAbsolutePath(String parentContainerPath) {
+            return new Path(parentContainerPath).append(fFileSystemObject.getName()).toOSString();
+        }
+
+        @Override
+        public boolean exists() {
+            return true;
+        }
+
+        @Override
+        public String getSourceLocation() {
+            File file = new File(fArchivePath);
+            try {
+                file = file.getCanonicalFile();
+            } catch (IOException e) {
+                // Will still work but might have extra ../ in the path
+            }
+            URI uri = file.toURI();
+            IPath entryPath = new Path(fFileSystemObject.getName());
+
+            URI jarURI = entryPath.isRoot() ? URIUtil.toJarURI(uri, Path.EMPTY) : URIUtil.toJarURI(uri, entryPath);
+            return URIUtil.toUnencodedString(jarURI);
+        }
+
+        @Override
+        public Object getRawFileSystemObject() {
+            return fFileSystemObject;
+        }
+    }
+
     /**
      * The "Zip" implementation of an IFileSystemObject
      */
This page took 0.032101 seconds and 5 git commands to generate.