JAL-3224 New version of getdown which will cope with unpacking .tgz resources, specif...
[jalview.git] / getdown / src / getdown / core / src / main / java / com / threerings / getdown / util / FileUtil.java
index ec9d887..67d0330 100644 (file)
@@ -6,10 +6,18 @@
 package com.threerings.getdown.util;
 
 import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.*;
 import java.util.jar.*;
 import java.util.zip.GZIPInputStream;
 
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+
+import com.threerings.getdown.util.StreamUtil;
 import com.threerings.getdown.Log;
 import static com.threerings.getdown.Log.log;
 
@@ -156,7 +164,7 @@ public class FileUtil
             }
 
             try (BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(efile));
-                 InputStream jin = jar.getInputStream(entry)) {
+                InputStream jin = jar.getInputStream(entry)) {
                 StreamUtil.copy(jin, fout);
             } catch (Exception e) {
                 throw new IOException(
@@ -166,6 +174,75 @@ public class FileUtil
     }
 
     /**
+     * Unpacks the specified tgz file into the specified target directory.
+     * @param cleanExistingDirs if true, all files in all directories contained in {@code tgz} will
+     * be deleted prior to unpacking the tgz.
+     */
+    public static void unpackTgz (TarArchiveInputStream tgz, File target, boolean cleanExistingDirs)
+        throws IOException
+    {
+               TarArchiveEntry entry;
+               while ((entry = tgz.getNextTarEntry()) != null) {
+            // sanitize the entry name
+                       String entryName = entry.getName();
+                       if (entryName.startsWith(File.separator))
+                       {
+                               entryName = entryName.substring(File.separator.length());
+                       }
+            File efile = new File(target, entryName);
+
+            // if we're unpacking a normal tgz file, it will have special path
+            // entries that allow us to create our directories first
+            if (entry.isDirectory()) {
+               
+                               if (cleanExistingDirs) {
+                    if (efile.exists()) {
+                        for (File f : efile.listFiles()) {
+                            if (!f.isDirectory())
+                            f.delete();
+                        }
+                    }
+                               }
+                               
+                if (!efile.exists() && !efile.mkdir()) {
+                    log.warning("Failed to create tgz entry path", "tgz", tgz, "entry", entry);
+                }
+                continue;
+            }
+
+            // but some do not, so we want to ensure that our directories exist
+            // prior to getting down and funky
+            File parent = new File(efile.getParent());
+            if (!parent.exists() && !parent.mkdirs()) {
+                log.warning("Failed to create tgz entry parent", "tgz", tgz, "parent", parent);
+                continue;
+            }
+
+            if (entry.isLink())
+            {
+               System.out.println("Creating hard link "+efile.getName()+" -> "+entry.getLinkName());
+               Files.createLink(efile.toPath(), Paths.get(entry.getLinkName()));
+               continue;
+            }
+
+            if (entry.isSymbolicLink())
+            {
+               System.out.println("Creating symbolic link "+efile.getName()+" -> "+entry.getLinkName());
+               Files.createSymbolicLink(efile.toPath(), Paths.get(entry.getLinkName()));
+               continue;
+            }
+            
+            try (BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(efile));
+                InputStream tin = tgz;) {
+                StreamUtil.copy(tin, fout);
+            } catch (Exception e) {
+                throw new IOException(
+                    Log.format("Failure unpacking", "tgz", tgz, "entry", efile), e);
+            }
+        }
+    }
+
+    /**
      * Unpacks a pack200 packed jar file from {@code packedJar} into {@code target}. If {@code
      * packedJar} has a {@code .gz} extension, it will be gunzipped first.
      */