]> source.dussan.org Git - pf4j.git/commitdiff
Unzip plugin zip file in loadPluginFromPath() (#140)
authorJan Høydahl <janhoy@users.noreply.github.com>
Thu, 6 Apr 2017 10:54:54 +0000 (12:54 +0200)
committerDecebal Suiu <decebal.suiu@gmail.com>
Thu, 6 Apr 2017 10:54:54 +0000 (13:54 +0300)
pf4j/src/main/java/ro/fortsoft/pf4j/AbstractPluginManager.java
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginRepository.java
pf4j/src/main/java/ro/fortsoft/pf4j/util/FileUtils.java
pf4j/src/test/java/ro/fortsoft/pf4j/util/FileUtilsTest.java [new file with mode: 0644]

index 6014717fa264c498ff7da0f96ad3d8cf761be295..fa0366bf12291d7920dbf580f70f8c40f6f31d51 100644 (file)
@@ -16,7 +16,6 @@
 package ro.fortsoft.pf4j;
 
 import com.github.zafarkhaja.semver.Version;
-import com.github.zafarkhaja.semver.expr.Expression;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import ro.fortsoft.pf4j.util.StringUtils;
index 81bce1b2de95e2c92da4734f0e19c0e283400812..b9d6c67d570448b56da474a9f39d0801a0fd79d6 100644 (file)
@@ -17,6 +17,7 @@ package ro.fortsoft.pf4j;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import ro.fortsoft.pf4j.util.FileUtils;
 
 import java.io.File;
 import java.nio.file.Path;
@@ -106,4 +107,22 @@ public class DefaultPluginManager extends AbstractPluginManager {
         log.info("PF4J version {} in '{}' mode", getVersion(), getRuntimeMode());
        }
 
+    /**
+     * Load a plugin from disk. If the path is a zip file, first unpack
+     * @param pluginPath plugin location on disk
+     * @return PluginWrapper for the loaded plugin or null if not loaded
+     * @throws PluginException if problems during load
+     */
+    @Override
+    protected PluginWrapper loadPluginFromPath(Path pluginPath) throws PluginException {
+        // First unzip any ZIP files
+        try {
+            pluginPath = FileUtils.expandIfZip(pluginPath);
+        } catch (Exception e) {
+            log.warn("Failed to unzip " + pluginPath, e);
+            return null;
+        }
+
+        return super.loadPluginFromPath(pluginPath);
+    }
 }
index f662bc4046a356204e0cd9c56917b8234d929dc3..197ae2275b6a0e6aee68f23135603d42ac64a0cf 100644 (file)
@@ -24,7 +24,6 @@ import ro.fortsoft.pf4j.util.HiddenFilter;
 import ro.fortsoft.pf4j.util.NameFileFilter;
 import ro.fortsoft.pf4j.util.NotFileFilter;
 import ro.fortsoft.pf4j.util.OrFileFilter;
-import ro.fortsoft.pf4j.util.Unzip;
 import ro.fortsoft.pf4j.util.ZipFileFilter;
 
 import java.io.File;
@@ -55,7 +54,7 @@ public class DefaultPluginRepository extends BasePluginRepository {
         if ((pluginZips != null) && pluginZips.length > 0) {
             for (File pluginZip : pluginZips) {
                 try {
-                    expandPluginZip(pluginZip);
+                    FileUtils.expandIfZip(pluginZip.toPath());
                 } catch (IOException e) {
                     log.error("Cannot expand plugin zip '{}'", pluginZip);
                     log.error(e.getMessage(), e);
@@ -81,42 +80,4 @@ public class DefaultPluginRepository extends BasePluginRepository {
 
         return hiddenPluginFilter;
     }
-
-    /**
-     * Unzip a plugin zip file in a directory that has the same name as the zip file
-     * and it's relative to {@code pluginsRoot}.
-     * For example if the zip file is {@code my-plugin.zip} then the resulted directory
-     * is {@code my-plugin}.
-     *
-     * @param pluginZip
-     * @return
-     * @throws IOException
-     */
-    private File expandPluginZip(File pluginZip) throws IOException {
-        String fileName = pluginZip.getName();
-        long pluginZipDate = pluginZip.lastModified();
-        String pluginName = fileName.substring(0, fileName.length() - 4);
-        File pluginDirectory = pluginsRoot.resolve(pluginName).toFile();
-        // check if exists root or the '.zip' file is "newer" than root
-        if (!pluginDirectory.exists() || (pluginZipDate > pluginDirectory.lastModified())) {
-            log.debug("Expand plugin zip '{}' in '{}'", pluginZip, pluginDirectory);
-
-            // do not overwrite an old version, remove it
-            if (pluginDirectory.exists()) {
-                FileUtils.delete(pluginDirectory.toPath());
-            }
-
-            // create root for plugin
-            pluginDirectory.mkdirs();
-
-            // expand '.zip' file
-            Unzip unzip = new Unzip();
-            unzip.setSource(pluginZip);
-            unzip.setDestination(pluginDirectory);
-            unzip.extract();
-        }
-
-        return pluginDirectory;
-    }
-
 }
index 70b4e016dc31296eef47b2e96d3a47df5e601571..ab34a19739daed9f1f4a3afc6b7b5529740fe4bb 100644 (file)
  */
 package ro.fortsoft.pf4j.util;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.io.*;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
@@ -29,8 +34,11 @@ import java.util.List;
  * @author Decebal Suiu
  */
 public class FileUtils {
+    private static final Logger log = LoggerFactory.getLogger(FileUtils.class);
+
+    private static final List<String> ZIP_EXTENSIONS = Arrays.asList(".zip", ".ZIP", ".Zip");
 
-       public static List<String> readLines(File file, boolean ignoreComments) throws IOException {
+    public static List<String> readLines(File file, boolean ignoreComments) throws IOException {
                if (!file.exists() || !file.isFile()) {
                        return new ArrayList<>();
                }
@@ -147,4 +155,41 @@ public class FileUtils {
             Files.delete(path);
         } catch (IOException ignored) { }
     }
+
+    /**
+     * Unzip a zip file in a directory that has the same name as the zip file.
+     * For example if the zip file is {@code my-plugin.zip} then the resulted directory
+     * is {@code my-plugin}.
+     *
+     * @param filePath the file to evaluate
+     * @return Path of unzipped folder or original path if this was not a zip file
+     * @throws IOException on error
+     */
+    public static Path expandIfZip(Path filePath) throws IOException {
+        String fileName = filePath.getFileName().toString();
+        if (!ZIP_EXTENSIONS.contains(fileName.substring(fileName.lastIndexOf(".")))) {
+            return filePath;
+        }
+        FileTime pluginZipDate = Files.getLastModifiedTime(filePath);
+        Path pluginDirectory = filePath.resolveSibling(fileName.substring(0, fileName.lastIndexOf(".")));
+
+        if (!Files.exists(pluginDirectory) || pluginZipDate.compareTo(Files.getLastModifiedTime(pluginDirectory)) > 0) {
+            // do not overwrite an old version, remove it
+            if (Files.exists(pluginDirectory)) {
+                FileUtils.delete(pluginDirectory);
+            }
+
+            // create root for plugin
+            Files.createDirectories(pluginDirectory);
+
+            // expand '.zip' file
+            Unzip unzip = new Unzip();
+            unzip.setSource(filePath.toFile());
+            unzip.setDestination(pluginDirectory.toFile());
+            unzip.extract();
+            log.info("Expanded plugin zip '{}' in '{}'", filePath.getFileName(), pluginDirectory.getFileName());
+        }
+
+        return pluginDirectory;
+    }
 }
diff --git a/pf4j/src/test/java/ro/fortsoft/pf4j/util/FileUtilsTest.java b/pf4j/src/test/java/ro/fortsoft/pf4j/util/FileUtilsTest.java
new file mode 100644 (file)
index 0000000..fec02f8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Decebal Suiu
+ *
+ * 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 ro.fortsoft.pf4j.util;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.*;
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+
+public class FileUtilsTest {
+    private Path zipFile;
+    private Path tmpDir;
+    private Path propsFile;
+
+    @Before
+    public void setup() throws IOException {
+        tmpDir = Files.createTempDirectory("pf4j-test");
+        tmpDir.toFile().deleteOnExit();
+        zipFile = tmpDir.resolve("my.zip").toAbsolutePath();
+        propsFile = tmpDir.resolve("plugin.properties");
+        URI file = URI.create("jar:file:"+zipFile.toString());
+        try (FileSystem zipfs = FileSystems.newFileSystem(file, Collections.singletonMap("create", "true"))) {
+            Path propsInZip = zipfs.getPath("/plugin.properties");
+            BufferedWriter br = new BufferedWriter(new FileWriter(propsFile.toString()));
+            br.write("plugin.id=test");
+            br.newLine();
+            br.write("plugin.version=1.2.3");
+            br.newLine();
+            br.write("plugin.class=foo.bar");
+            br.close();
+            Files.move(propsFile, propsInZip);
+        }
+    }
+
+    @Test
+    public void expandIfZip() throws Exception {
+        Path unzipped = FileUtils.expandIfZip(zipFile);
+        assertEquals(tmpDir.resolve("my"), unzipped);
+        assertTrue(Files.exists(tmpDir.resolve("my/plugin.properties")));
+
+        // Non-zip file remains unchanged
+        assertEquals(propsFile, FileUtils.expandIfZip(propsFile));
+    }
+
+}