diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..14ff0eb --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..25d34a4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/link/infra/packwiz/installer/DownloadTask.java b/src/main/java/link/infra/packwiz/installer/DownloadTask.java new file mode 100644 index 0000000..773287c --- /dev/null +++ b/src/main/java/link/infra/packwiz/installer/DownloadTask.java @@ -0,0 +1,5 @@ +package link.infra.packwiz.installer; + +class DownloadTask { + +} \ No newline at end of file diff --git a/src/main/java/link/infra/packwiz/installer/Main.java b/src/main/java/link/infra/packwiz/installer/Main.java index d514c97..2811a73 100644 --- a/src/main/java/link/infra/packwiz/installer/Main.java +++ b/src/main/java/link/infra/packwiz/installer/Main.java @@ -1,22 +1,14 @@ package link.infra.packwiz.installer; -import java.awt.EventQueue; -import java.awt.GraphicsEnvironment; -import java.net.URI; -import java.net.URISyntaxException; - -import javax.swing.JOptionPane; -import javax.swing.UIManager; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; - import link.infra.packwiz.installer.ui.CLIHandler; import link.infra.packwiz.installer.ui.IUserInterface; import link.infra.packwiz.installer.ui.InstallWindow; +import org.apache.commons.cli.*; + +import javax.swing.*; +import java.awt.*; +import java.net.URI; +import java.net.URISyntaxException; public class Main { @@ -28,13 +20,11 @@ public class Main { this.startup(args); } catch (Exception e) { e.printStackTrace(); - EventQueue.invokeLater(new Runnable() { - public void run() { - JOptionPane.showMessageDialog(null, - "A fatal error occurred: \n" + e.getClass().getCanonicalName() + ": " + e.getMessage(), - "packwiz-installer", JOptionPane.ERROR_MESSAGE); - System.exit(1); - } + EventQueue.invokeLater(() -> { + JOptionPane.showMessageDialog(null, + "A fatal error occurred: \n" + e.getClass().getCanonicalName() + ": " + e.getMessage(), + "packwiz-installer", JOptionPane.ERROR_MESSAGE); + System.exit(1); }); // In case the eventqueue is broken, exit after 1 minute try { @@ -127,14 +117,12 @@ public class Main { } catch (Exception e) { // TODO: better error message? ui.handleExceptionAndExit(e); - return; } } }); } catch (Exception e) { // TODO: better error message? ui.handleExceptionAndExit(e); - return; } } diff --git a/src/main/java/link/infra/packwiz/installer/RequiresBootstrap.java b/src/main/java/link/infra/packwiz/installer/RequiresBootstrap.java index ff56ed2..813a37b 100644 --- a/src/main/java/link/infra/packwiz/installer/RequiresBootstrap.java +++ b/src/main/java/link/infra/packwiz/installer/RequiresBootstrap.java @@ -1,10 +1,8 @@ package link.infra.packwiz.installer; +import javax.swing.*; import java.util.Arrays; -import javax.swing.JOptionPane; -import javax.swing.UIManager; - public class RequiresBootstrap { public static void main(String[] args) { @@ -15,10 +13,10 @@ public class RequiresBootstrap { if (Arrays.stream(args).map(str -> { if (str == null) return ""; if (str.startsWith("--")) { - return str.substring(2, str.length()); + return str.substring(2); } if (str.startsWith("-")) { - return str.substring(1, str.length()); + return str.substring(1); } return ""; }).anyMatch(str -> str.equals("g") || str.equals("no-gui"))) { diff --git a/src/main/java/link/infra/packwiz/installer/UpdateManager.java b/src/main/java/link/infra/packwiz/installer/UpdateManager.java index a840d63..c9ceacd 100644 --- a/src/main/java/link/infra/packwiz/installer/UpdateManager.java +++ b/src/main/java/link/infra/packwiz/installer/UpdateManager.java @@ -1,36 +1,11 @@ package link.infra.packwiz.installer; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletionService; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.stream.Collectors; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; import com.google.gson.annotations.SerializedName; import com.moandjiezana.toml.Toml; - import link.infra.packwiz.installer.metadata.IndexFile; import link.infra.packwiz.installer.metadata.ManifestFile; import link.infra.packwiz.installer.metadata.PackFile; @@ -44,6 +19,16 @@ import okio.Buffer; import okio.Okio; import okio.Source; +import java.io.*; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.*; +import java.util.concurrent.*; +import java.util.stream.Collectors; + public class UpdateManager { public final Options opts; @@ -84,8 +69,8 @@ public class UpdateManager { return true; } if (this.depSides != null) { - for (int i = 0; i < this.depSides.length; i++) { - if (this.depSides[i].equals(tSide)) { + for (Side depSide : this.depSides) { + if (depSide.equals(tSide)) { return true; } } @@ -96,7 +81,7 @@ public class UpdateManager { public static Side from(String name) { String lowerName = name.toLowerCase(); for (Side side : Side.values()) { - if (side.sideName == lowerName) { + if (side.sideName.equals(lowerName)) { return side; } } @@ -150,9 +135,7 @@ public class UpdateManager { List invalidatedUris = new ArrayList<>(); if (manifest.cachedFiles != null) { - Iterator> it = manifest.cachedFiles.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); + for (Map.Entry entry : manifest.cachedFiles.entrySet()) { if (entry.getValue().cachedLocation != null) { if (!Files.exists(Paths.get(opts.packFolder, entry.getValue().cachedLocation))) { URI fileUri = entry.getKey(); @@ -225,7 +208,7 @@ public class UpdateManager { } if (manifest.cachedFiles == null) { - manifest.cachedFiles = new HashMap(); + manifest.cachedFiles = new HashMap<>(); } ui.submitProgress(new InstallProgress("Checking local files...")); @@ -233,7 +216,7 @@ public class UpdateManager { while (it.hasNext()) { Map.Entry entry = it.next(); if (entry.getValue().cachedLocation != null) { - if (!indexFile.files.stream().anyMatch(f -> f.file.equals(entry.getKey()))) { + if (indexFile.files.stream().noneMatch(f -> f.file.equals(entry.getKey()))) { // File has been removed from the index try { Files.deleteIfExists(Paths.get(opts.packFolder, entry.getValue().cachedLocation)); @@ -248,12 +231,11 @@ public class UpdateManager { ui.submitProgress(new InstallProgress("Comparing new files...")); // TODO: progress bar - ConcurrentLinkedQueue exceptionQueue = new ConcurrentLinkedQueue(); - List newFiles = indexFile.files.stream().map(f -> { + ConcurrentLinkedQueue exceptionQueue = new ConcurrentLinkedQueue<>(); + List newFiles = indexFile.files.stream().peek(f -> { if (f.hashFormat == null || f.hashFormat.length() == 0) { f.hashFormat = indexFile.hashFormat; } - return f; }).filter(f -> { if (invalidatedUris.contains(f.file)) { return true; @@ -267,13 +249,12 @@ public class UpdateManager { return false; } return cachedFile == null || !newHash.equals(cachedFile.hash); - }).parallel().map(f -> { + }).parallel().peek(f -> { try { f.downloadMeta(indexFile, indexUri); } catch (Exception e) { exceptionQueue.add(e); } - return f; }).collect(Collectors.toList()); for (Exception e : exceptionQueue) { @@ -284,81 +265,78 @@ public class UpdateManager { // TODO: present options // TODO: all options should be presented, not just new files!!!!!!! // and options should be readded to newFiles after option -> true - newFiles.stream().filter(f -> f.linkedFile != null).filter(f -> f.linkedFile.option != null).map(f -> { - return "option: " + (f.linkedFile.option.description == null ? "null" : f.linkedFile.option.description); - }).forEachOrdered(desc -> { + newFiles.stream().filter(f -> f.linkedFile != null).filter(f -> f.linkedFile.option != null).map(f -> + "option: " + (f.linkedFile.option.description == null ? "null" : f.linkedFile.option.description) + ).forEachOrdered(desc -> { System.out.println(desc); }); // TODO: different thread pool type? ExecutorService threadPool = Executors.newFixedThreadPool(10); - CompletionService completionService = new ExecutorCompletionService( - threadPool); + CompletionService completionService = new ExecutorCompletionService<>(threadPool); for (IndexFile.File f : newFiles) { ManifestFile.File cachedFile = manifest.cachedFiles.get(f.file); - completionService.submit(new Callable() { - public DownloadCompletion call() { - DownloadCompletion dc = new DownloadCompletion(); - dc.file = f; + completionService.submit(() -> { + DownloadCompletion dc = new DownloadCompletion(); + dc.file = f; - if (cachedFile != null && cachedFile.linkedFileHash != null && f.linkedFile != null) { - try { - if (cachedFile.linkedFileHash.equals(f.linkedFile.getHash())) { - // Do nothing, the file didn't change - // TODO: but if the hash of the metafile changed, what did change????? - // should this be checked somehow?? - return dc; - } - } catch (Exception e) {} - } - - Path destPath = Paths.get(opts.packFolder, f.getDestURI().toString()); - - // Don't update files marked with preserve if they already exist on disk - if (f.preserve) { - if (Files.exists(destPath)) { + if (cachedFile != null && cachedFile.linkedFileHash != null && f.linkedFile != null) { + try { + if (cachedFile.linkedFileHash.equals(f.linkedFile.getHash())) { + // Do nothing, the file didn't change + // TODO: but if the hash of the metafile changed, what did change????? + // should this be checked somehow?? return dc; } - } + } catch (Exception ignored) {} + } - try { - Hash hash; - String fileHashFormat; - if (f.linkedFile != null) { - hash = f.linkedFile.getHash(); - fileHashFormat = f.linkedFile.download.hashFormat; - } else { - hash = f.getHash(); - fileHashFormat = f.hashFormat; - } + Path destPath = Paths.get(opts.packFolder, f.getDestURI().toString()); - Source src = f.getSource(indexUri); - GeneralHashingSource fileSource = HashUtils.getHasher(fileHashFormat).getHashingSource(src); - Buffer data = new Buffer(); - Okio.buffer(fileSource).readAll(data); - - if (fileSource.hashIsEqual(hash)) { - Files.createDirectories(destPath.getParent()); - Files.copy(data.inputStream(), destPath, StandardCopyOption.REPLACE_EXISTING); - } else { - System.out.println("Invalid hash for " + f.getDestURI().toString()); - System.out.println("Calculated: " + fileSource.getHash()); - System.out.println("Expected: " + hash); - dc.err = new Exception("Hash invalid!"); - } - - if (cachedFile != null && !destPath.equals(Paths.get(opts.packFolder, cachedFile.cachedLocation))) { - // Delete old file if location changes - Files.delete(Paths.get(opts.packFolder, cachedFile.cachedLocation)); - } - - return dc; - } catch (Exception e) { - dc.err = e; + // Don't update files marked with preserve if they already exist on disk + if (f.preserve) { + if (Files.exists(destPath)) { return dc; } } + + try { + Hash hash; + String fileHashFormat; + if (f.linkedFile != null) { + hash = f.linkedFile.getHash(); + fileHashFormat = f.linkedFile.download.hashFormat; + } else { + hash = f.getHash(); + fileHashFormat = f.hashFormat; + } + + Source src = f.getSource(indexUri); + GeneralHashingSource fileSource = HashUtils.getHasher(fileHashFormat).getHashingSource(src); + Buffer data = new Buffer(); + Okio.buffer(fileSource).readAll(data); + + if (fileSource.hashIsEqual(hash)) { + Files.createDirectories(destPath.getParent()); + Files.copy(data.inputStream(), destPath, StandardCopyOption.REPLACE_EXISTING); + } else { + System.out.println("Invalid hash for " + f.getDestURI().toString()); + System.out.println("Calculated: " + fileSource.getHash()); + System.out.println("Expected: " + hash); + dc.err = new Exception("Hash invalid!"); + } + + if (cachedFile != null && !destPath.equals(Paths.get(opts.packFolder, cachedFile.cachedLocation))) { + // Delete old file if location changes + Files.delete(Paths.get(opts.packFolder, cachedFile.cachedLocation)); + } + + return dc; + } catch (Exception e) { + dc.err = e; + return dc; + } }); } diff --git a/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java b/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java index 26d4985..ab0349a 100644 --- a/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java +++ b/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java @@ -1,13 +1,8 @@ package link.infra.packwiz.installer.metadata; -import java.net.URI; -import java.nio.file.Paths; -import java.util.List; - import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; import com.moandjiezana.toml.Toml; - import link.infra.packwiz.installer.metadata.hash.GeneralHashingSource; import link.infra.packwiz.installer.metadata.hash.Hash; import link.infra.packwiz.installer.metadata.hash.HashUtils; @@ -15,6 +10,10 @@ import link.infra.packwiz.installer.request.HandlerManager; import okio.Okio; import okio.Source; +import java.net.URI; +import java.nio.file.Paths; +import java.util.List; + public class IndexFile { @SerializedName("hash-format") public String hashFormat; @@ -69,6 +68,7 @@ public class IndexFile { public Hash getHash() throws Exception { if (hash == null) { + // TODO: should these be more specific exceptions (e.g. IndexFileException?!) throw new Exception("Index file doesn't have a hash"); } if (hashFormat == null) { @@ -90,7 +90,8 @@ public class IndexFile { if (file != null) { return Paths.get(file.getPath()).getFileName().toString(); } - return file.getPath(); + // TODO: throw some kind of exception? + return "Invalid file"; } public URI getDestURI() { diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java index ea8c985..23767bf 100644 --- a/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java +++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java @@ -48,7 +48,7 @@ public class HashingSourceHasher implements IHasher { if (value != null) { return value.equals(objHash.value); } else { - return objHash.value == null ? true : false; + return objHash.value == null; } } diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java index 64139da..0964c0b 100644 --- a/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java +++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java @@ -1,10 +1,10 @@ package link.infra.packwiz.installer.metadata.hash; -import java.io.IOException; - import okio.Buffer; import okio.Source; +import java.io.IOException; + public class Murmur2Hasher implements IHasher { private class Murmur2GeneralHashingSource extends GeneralHashingSource { Murmur2Hash value; @@ -40,8 +40,7 @@ public class Murmur2Hasher implements IHasher { private byte[] computeNormalizedArray(byte[] input) { byte[] output = new byte[input.length]; int num = 0; - for (int i = 0; i < input.length; i++) { - byte b = input[i]; + for (byte b : input) { if (!(b == 9 || b == 10 || b == 13 || b == 32)) { output[num] = b; num++; @@ -54,7 +53,7 @@ public class Murmur2Hasher implements IHasher { } - private class Murmur2Hash extends Hash { + private static class Murmur2Hash extends Hash { int value; private Murmur2Hash(String value) { // Parsing as long then casting to int converts values gt int max value but lt uint max value diff --git a/src/main/java/link/infra/packwiz/installer/request/IRequestHandler.java b/src/main/java/link/infra/packwiz/installer/request/IRequestHandler.java index 30d5cdc..23e0abb 100644 --- a/src/main/java/link/infra/packwiz/installer/request/IRequestHandler.java +++ b/src/main/java/link/infra/packwiz/installer/request/IRequestHandler.java @@ -1,17 +1,17 @@ package link.infra.packwiz.installer.request; -import java.net.URI; - import okio.Source; +import java.net.URI; + /** * IRequestHandler handles requests for locations specified in modpack metadata. */ public interface IRequestHandler { - public boolean matchesHandler(URI loc); + boolean matchesHandler(URI loc); - public default URI getNewLoc(URI loc) { + default URI getNewLoc(URI loc) { return loc; } @@ -22,6 +22,6 @@ public interface IRequestHandler { * @return The Source containing the data of the file * @throws Exception */ - public Source getFileSource(URI loc) throws Exception; + Source getFileSource(URI loc) throws Exception; } diff --git a/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerGithub.java b/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerGithub.java index 15f35dd..33c8948 100644 --- a/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerGithub.java +++ b/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerGithub.java @@ -19,14 +19,17 @@ public class RequestHandlerGithub extends RequestHandlerZip { } // TODO: is caching really needed, if HTTPURLConnection follows redirects correctly? - private Map zipUriMap = new HashMap(); - final ReentrantReadWriteLock zipUriLock = new ReentrantReadWriteLock(); + private Map zipUriMap = new HashMap<>(); + private final ReentrantReadWriteLock zipUriLock = new ReentrantReadWriteLock(); private static Pattern repoMatcherPattern = Pattern.compile("/([\\w.-]+/[\\w.-]+).*"); private String getRepoName(URI loc) { Matcher matcher = repoMatcherPattern.matcher(loc.getPath()); - matcher.matches(); - return matcher.group(1); + if (matcher.matches()) { + return matcher.group(1); + } else { + return null; + } } @Override @@ -57,8 +60,11 @@ public class RequestHandlerGithub extends RequestHandlerZip { private String getBranch(URI loc) { Matcher matcher = branchMatcherPattern.matcher(loc.getPath()); - matcher.matches(); - return matcher.group(1); + if (matcher.matches()) { + return matcher.group(1); + } else { + return null; + } } @Override diff --git a/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerZip.java b/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerZip.java index 0217ce7..7e307d0 100644 --- a/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerZip.java +++ b/src/main/java/link/infra/packwiz/installer/request/handlers/RequestHandlerZip.java @@ -1,5 +1,10 @@ package link.infra.packwiz.installer.request.handlers; +import okio.Buffer; +import okio.BufferedSource; +import okio.Okio; +import okio.Source; + import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -11,14 +16,9 @@ import java.util.function.Predicate; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import okio.Buffer; -import okio.BufferedSource; -import okio.Okio; -import okio.Source; - public abstract class RequestHandlerZip extends RequestHandlerHTTP { - protected final boolean modeHasFolder; + private final boolean modeHasFolder; public RequestHandlerZip(boolean modeHasFolder) { this.modeHasFolder = modeHasFolder; @@ -35,14 +35,14 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP { private class ZipReader { private final ZipInputStream zis; - private final Map readFiles = new HashMap(); + private final Map readFiles = new HashMap<>(); // Write lock implies access to ZipInputStream - only 1 thread must read at a time! final ReentrantLock filesLock = new ReentrantLock(); private ZipEntry entry; private final BufferedSource zipSource; - public ZipReader(Source zip) { + ZipReader(Source zip) { zis = new ZipInputStream(Okio.buffer(zip).inputStream()); zipSource = Okio.buffer(Okio.source(zis)); } @@ -71,7 +71,7 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP { } } - public Source getFileSource(URI loc) throws Exception { + Source getFileSource(URI loc) throws Exception { filesLock.lock(); // Assume files are only read once, allow GC by removing Buffer file = readFiles.remove(loc); @@ -82,13 +82,10 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP { file = findFile(loc); filesLock.unlock(); - if (file != null) { - return file; - } - return null; + return file; } - public URI findInZip(Predicate matches) throws Exception { + URI findInZip(Predicate matches) throws Exception { filesLock.lock(); for (URI file : readFiles.keySet()) { if (matches.test(file)) { @@ -115,8 +112,8 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP { } - private final Map cache = new HashMap(); - final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock(); + private final Map cache = new HashMap<>(); + private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock(); protected abstract URI getZipUri(URI loc) throws Exception;