From 11e3850a572349f8a5a493010c1fec505ca3850c Mon Sep 17 00:00:00 2001 From: Arthur Poiret Date: Sat, 21 Jan 2023 11:19:21 +0100 Subject: [PATCH 1/2] feat: add multi-archive support --- owlplug-client/pom.xml | 6 + .../com/owlplug/core/utils/ArchiveUtils.java | 129 ++++++++++++++++++ .../com/owlplug/core/utils/FileUtils.java | 48 ------- .../explore/tasks/BundleInstallTask.java | 3 +- 4 files changed, 137 insertions(+), 49 deletions(-) create mode 100644 owlplug-client/src/main/java/com/owlplug/core/utils/ArchiveUtils.java diff --git a/owlplug-client/pom.xml b/owlplug-client/pom.xml index 5653f16c..c697a344 100644 --- a/owlplug-client/pom.xml +++ b/owlplug-client/pom.xml @@ -206,6 +206,12 @@ 3.1.0 + + org.apache.commons + commons-compress + 1.22 + + junit junit diff --git a/owlplug-client/src/main/java/com/owlplug/core/utils/ArchiveUtils.java b/owlplug-client/src/main/java/com/owlplug/core/utils/ArchiveUtils.java new file mode 100644 index 00000000..b60fa130 --- /dev/null +++ b/owlplug-client/src/main/java/com/owlplug/core/utils/ArchiveUtils.java @@ -0,0 +1,129 @@ +/* OwlPlug + * Copyright (C) 2021 Arthur + * + * This file is part of OwlPlug. + * + * OwlPlug is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 + * as published by the Free Software Foundation. + * + * OwlPlug is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OwlPlug. If not, see . + */ + +package com.owlplug.core.utils; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.ArchiveInputStream; +import org.apache.commons.compress.archivers.ArchiveStreamFactory; +import org.apache.commons.compress.compressors.CompressorException; +import org.apache.commons.compress.compressors.CompressorInputStream; +import org.apache.commons.compress.compressors.CompressorStreamFactory; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArchiveUtils { + + private static final Logger log = LoggerFactory.getLogger(ArchiveUtils.class); + + public static void extract(String source, String dest) { + File sourceFile = new File(source); + File destDirectory = new File(dest); + + extract(sourceFile, destDirectory); + } + + public static void extract(File source, File dest) { + try { + uncompress(source, dest); + } catch (Exception e) { + log.error("Error extracting archive {} at {}", source.getAbsolutePath(), + dest.getAbsolutePath(), e); + throw new RuntimeException(e); + } + + } + + private static boolean isCompressed(File file) throws IOException { + log.debug("Verify file compression: {}", file.getAbsolutePath()); + try (InputStream inputStream = new FileInputStream(file); + InputStream bufferedIn = new BufferedInputStream(inputStream)) { + String comp = CompressorStreamFactory.detect(bufferedIn); + log.debug("Compression signature found: {}", comp); + return true; + } catch (CompressorException e) { + log.debug("Compression signature not found"); + return false; + } + + } + + private static void uncompress(File sourceFile, File destinationDirectory) throws IOException { + + if (isCompressed(sourceFile)) { + try (InputStream fi = new FileInputStream(sourceFile); + InputStream bi = new BufferedInputStream(fi); + CompressorInputStream gzi = new CompressorStreamFactory().createCompressorInputStream(bi); + InputStream bgzi = new BufferedInputStream(gzi); + ArchiveInputStream o = new ArchiveStreamFactory().createArchiveInputStream(bgzi)) { + + uncompress(o, destinationDirectory); + } catch (CompressorException e) { + throw new IOException("Error while uncompressing the archive stream: " + sourceFile.getAbsolutePath(), e); + } catch (ArchiveException e) { + throw new IOException("Error while extracting the archive stream: " + sourceFile.getAbsolutePath(), e); + } + + } else { + try (InputStream fi = new FileInputStream(sourceFile); + InputStream bi = new BufferedInputStream(fi); + ArchiveInputStream o = new ArchiveStreamFactory().createArchiveInputStream(bi)) { + + uncompress(o, destinationDirectory); + } catch (ArchiveException e) { + throw new IOException("Error while extracting the archive stream: " + sourceFile.getAbsolutePath(), e); + } + } + } + + private static void uncompress(ArchiveInputStream o, File destinationDirectory) throws IOException { + + ArchiveEntry entry = null; + while ((entry = o.getNextEntry()) != null) { + if (!o.canReadEntryData(entry)) { + log.debug("Stream entry cannot be read: {}", entry.getName()); + continue; + } + + File f = new File(destinationDirectory, entry.getName()); + if (entry.isDirectory()) { + if (!f.isDirectory() && !f.mkdirs()) { + throw new IOException("failed to create directory " + f); + } + } else { + File parent = f.getParentFile(); + if (!parent.isDirectory() && !parent.mkdirs()) { + throw new IOException("failed to create directory " + parent); + } + try (OutputStream output = Files.newOutputStream(f.toPath())) { + IOUtils.copy(o, output); + } + } + } + } + +} diff --git a/owlplug-client/src/main/java/com/owlplug/core/utils/FileUtils.java b/owlplug-client/src/main/java/com/owlplug/core/utils/FileUtils.java index 91294994..838296be 100644 --- a/owlplug-client/src/main/java/com/owlplug/core/utils/FileUtils.java +++ b/owlplug-client/src/main/java/com/owlplug/core/utils/FileUtils.java @@ -119,54 +119,6 @@ private static void innerListFiles(List files, File directory, boolean inc } } - public static void unzip(String source, String dest) throws IOException { - - // Open the file - try (ZipFile file = new ZipFile(source)) { - FileSystem fileSystem = FileSystems.getDefault(); - // Get file entries - Enumeration entries = file.entries(); - - // We will unzip files in this folder - String uncompressedDirectory = dest; - Files.createDirectory(fileSystem.getPath(uncompressedDirectory)); - - // Iterate over entries - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - // If directory then create a new directory in uncompressed folder - if (entry.isDirectory()) { - log.debug("Creating Directory:" + uncompressedDirectory + File.separator + entry.getName()); - Files.createDirectories(fileSystem.getPath(uncompressedDirectory + File.separator + entry.getName())); - - // Else create the file - } else { - InputStream is = file.getInputStream(entry); - BufferedInputStream bis = new BufferedInputStream(is); - String uncompressedFileName = uncompressedDirectory + File.separator + entry.getName(); - - new File(uncompressedFileName).getParentFile().mkdirs(); - - Path uncompressedFilePath = fileSystem.getPath(uncompressedFileName); - Files.createFile(uncompressedFilePath); - - FileOutputStream fileOutput = new FileOutputStream(uncompressedFileName); - - byte[] buffer = new byte[2048]; - int read = 0; - while ((read = bis.read(buffer)) > 0) { - fileOutput.write(buffer, 0, read); - } - - fileOutput.close(); - log.debug("Written :" + entry.getName()); - } - } - } catch (IOException e) { - throw e; - } - } - public static void copyDirectory(File source, File target) throws IOException { org.apache.commons.io.FileUtils.copyDirectory(source, target); } diff --git a/owlplug-client/src/main/java/com/owlplug/explore/tasks/BundleInstallTask.java b/owlplug-client/src/main/java/com/owlplug/explore/tasks/BundleInstallTask.java index f3cc02e8..8d38c37d 100644 --- a/owlplug-client/src/main/java/com/owlplug/explore/tasks/BundleInstallTask.java +++ b/owlplug-client/src/main/java/com/owlplug/explore/tasks/BundleInstallTask.java @@ -23,6 +23,7 @@ import com.owlplug.core.tasks.AbstractTask; import com.owlplug.core.tasks.TaskException; import com.owlplug.core.tasks.TaskResult; +import com.owlplug.core.utils.ArchiveUtils; import com.owlplug.core.utils.CryptoUtils; import com.owlplug.core.utils.FileUtils; import com.owlplug.core.utils.nio.CallbackByteChannel; @@ -100,7 +101,7 @@ protected TaskResult call() throws Exception { this.updateMessage("Installing plugin " + bundle.getRemotePackage().getName() + " - Extracting files..."); File extractedArchiveFolder = new File(ApplicationDefaults.getTempDownloadDirectory() + "/" + "temp-" + archiveFile.getName().replace(".owlpack", "")); - FileUtils.unzip(archiveFile.getAbsolutePath(), extractedArchiveFolder.getAbsolutePath()); + ArchiveUtils.extract(archiveFile.getAbsolutePath(), extractedArchiveFolder.getAbsolutePath()); this.commitProgress(30); From 21b066134c7fdfdd8cbf89d954d037190476ba9e Mon Sep 17 00:00:00 2001 From: Arthur Poiret Date: Sat, 21 Jan 2023 11:50:43 +0100 Subject: [PATCH 2/2] fix: display file chooser if no installation directory is set for a plugin format --- .../controllers/ExploreController.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/owlplug-client/src/main/java/com/owlplug/explore/controllers/ExploreController.java b/owlplug-client/src/main/java/com/owlplug/explore/controllers/ExploreController.java index e8e236d5..6d3bc101 100644 --- a/owlplug-client/src/main/java/com/owlplug/explore/controllers/ExploreController.java +++ b/owlplug-client/src/main/java/com/owlplug/explore/controllers/ExploreController.java @@ -335,25 +335,26 @@ public boolean installBundle(PackageBundle bundle) { bundle.getRemotePackage().getName(), bundle.getName()); - - String baseDirectoryPath = exploreService.getBundleInstallFolder(bundle); - String relativeDirectoryPath = this.getPreferences().get(ApplicationDefaults.STORE_DIRECTORY_KEY, ""); - - Boolean shouldGroupByCreator = this.getPreferences().getBoolean(ApplicationDefaults.STORE_BY_CREATOR_ENABLED_KEY, false); - - //if the enduser wishes to group plugins by their creator, - //then we need to include the subdirectory as well. - if (shouldGroupByCreator) { - String creator = FileUtils.sanitizeFileName(bundle.getRemotePackage().getCreator()); - relativeDirectoryPath = relativeDirectoryPath + File.separator + creator; - } File selectedDirectory = null; + String baseDirectoryPath = exploreService.getBundleInstallFolder(bundle); - // A custom root directory to store plugin is defined - if (this.getPreferences().getBoolean(ApplicationDefaults.STORE_DIRECTORY_ENABLED_KEY, false)) { + // A custom root directory to store plugin is defined and the base directory for + // the bundle type is defined or not blank. + if (this.getPreferences().getBoolean(ApplicationDefaults.STORE_DIRECTORY_ENABLED_KEY, false) && + baseDirectoryPath != null && !baseDirectoryPath.isBlank()) { // Store install target is already defined + String relativeDirectoryPath = this.getPreferences().get(ApplicationDefaults.STORE_DIRECTORY_KEY, ""); + Boolean shouldGroupByCreator = this.getPreferences().getBoolean(ApplicationDefaults.STORE_BY_CREATOR_ENABLED_KEY, false); + + //if the enduser wishes to group plugins by their creator, + //then we need to include the subdirectory as well. + if (shouldGroupByCreator) { + String creator = FileUtils.sanitizeFileName(bundle.getRemotePackage().getCreator()); + relativeDirectoryPath = relativeDirectoryPath + File.separator + creator; + } + selectedDirectory = new File(baseDirectoryPath, relativeDirectoryPath); // A plugin root directory is not defined @@ -369,7 +370,6 @@ public boolean installBundle(PackageBundle bundle) { Window mainWindow = masonryPane.getScene().getWindow(); selectedDirectory = directoryChooser.showDialog(mainWindow); } - // If any install target directory can be found, abort install