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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ro.fortsoft.pf4j.util.FileUtils;
import java.io.File;
import java.nio.file.Path;
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);
+ }
}
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;
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);
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;
- }
-
}
*/
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;
* @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<>();
}
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;
+ }
}
--- /dev/null
+/*
+ * 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));
+ }
+
+}