mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-10-16 16:04:32 +02:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
580408b92a | ||
|
dbdd1fb9f3 | ||
|
79a983bc2f | ||
|
0cba5ba17b | ||
|
ce60cdc385 | ||
|
b314fc8e0b | ||
|
ca4a13589d |
24
build.gradle
24
build.gradle
@@ -3,6 +3,7 @@ plugins {
|
|||||||
id 'application'
|
id 'application'
|
||||||
id 'com.github.johnrengelman.shadow' version '5.0.0'
|
id 'com.github.johnrengelman.shadow' version '5.0.0'
|
||||||
id 'com.palantir.git-version' version '0.11.0'
|
id 'com.palantir.git-version' version '0.11.0'
|
||||||
|
id 'com.github.breadmoirai.github-release' version '2.2.9'
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
@@ -47,4 +48,25 @@ task copyJar(type: Copy) {
|
|||||||
into "build/libs/"
|
into "build/libs/"
|
||||||
}
|
}
|
||||||
|
|
||||||
build.dependsOn copyJar
|
build.dependsOn copyJar
|
||||||
|
|
||||||
|
if (project.hasProperty("github.token")) {
|
||||||
|
githubRelease {
|
||||||
|
// IntelliJ u ok?
|
||||||
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
owner "comp500"
|
||||||
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
repo "packwiz-installer"
|
||||||
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
tagName "${project.version}"
|
||||||
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
releaseName "Release ${project.version}"
|
||||||
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
draft true
|
||||||
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
token findProperty("github.token") ?: ""
|
||||||
|
releaseAssets = [jar.destinationDirectory.file("packwiz-installer.jar").get()]
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.githubRelease.dependsOn(build)
|
||||||
|
}
|
@@ -97,6 +97,7 @@ class DownloadTask implements IOptionDetails, IExceptionDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cachedFile.isOptional = isOptional();
|
cachedFile.isOptional = isOptional();
|
||||||
|
cachedFile.onlyOtherSide = !correctSide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,7 @@ public class UpdateManager {
|
|||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
private boolean cancelledStartGame = false;
|
private boolean cancelledStartGame = false;
|
||||||
private InputStateHandler stateHandler;
|
private InputStateHandler stateHandler;
|
||||||
|
private boolean errorsOccurred = false;
|
||||||
|
|
||||||
public static class Options {
|
public static class Options {
|
||||||
SpaceSafeURI downloadURI = null;
|
SpaceSafeURI downloadURI = null;
|
||||||
@@ -152,6 +153,10 @@ public class UpdateManager {
|
|||||||
List<SpaceSafeURI> invalidatedUris = new ArrayList<>();
|
List<SpaceSafeURI> invalidatedUris = new ArrayList<>();
|
||||||
if (manifest.cachedFiles != null) {
|
if (manifest.cachedFiles != null) {
|
||||||
for (Map.Entry<SpaceSafeURI, ManifestFile.File> entry : manifest.cachedFiles.entrySet()) {
|
for (Map.Entry<SpaceSafeURI, ManifestFile.File> entry : manifest.cachedFiles.entrySet()) {
|
||||||
|
// ignore onlyOtherSide files
|
||||||
|
if (entry.getValue().onlyOtherSide) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
boolean invalid = false;
|
boolean invalid = false;
|
||||||
// if isn't optional, or is optional but optionValue == true
|
// if isn't optional, or is optional but optionValue == true
|
||||||
if (!entry.getValue().isOptional || entry.getValue().optionValue) {
|
if (!entry.getValue().isOptional || entry.getValue().optionValue) {
|
||||||
@@ -199,7 +204,14 @@ public class UpdateManager {
|
|||||||
|
|
||||||
// TODO: update MMC params, java args etc
|
// TODO: update MMC params, java args etc
|
||||||
|
|
||||||
manifest.packFileHash = packFileSource.getHash();
|
// If there were errors, don't write the manifest/index hashes, to ensure they are rechecked later
|
||||||
|
if (errorsOccurred) {
|
||||||
|
manifest.indexFileHash = null;
|
||||||
|
manifest.packFileHash = null;
|
||||||
|
} else {
|
||||||
|
manifest.packFileHash = packFileSource.getHash();
|
||||||
|
}
|
||||||
|
|
||||||
manifest.cachedSide = opts.side;
|
manifest.cachedSide = opts.side;
|
||||||
try (Writer writer = new FileWriter(Paths.get(opts.packFolder, opts.manifestFile).toString())) {
|
try (Writer writer = new FileWriter(Paths.get(opts.packFolder, opts.manifestFile).toString())) {
|
||||||
gson.toJson(manifest, writer);
|
gson.toJson(manifest, writer);
|
||||||
@@ -296,6 +308,10 @@ public class UpdateManager {
|
|||||||
ui.submitProgress(new InstallProgress("Comparing new files..."));
|
ui.submitProgress(new InstallProgress("Comparing new files..."));
|
||||||
|
|
||||||
// TODO: progress bar?
|
// TODO: progress bar?
|
||||||
|
if (indexFile.files == null || indexFile.files.size() == 0) {
|
||||||
|
System.out.println("Warning: Index is empty!");
|
||||||
|
indexFile.files = new ArrayList<>();
|
||||||
|
}
|
||||||
List<DownloadTask> tasks = DownloadTask.createTasksFromIndex(indexFile, indexFile.hashFormat, opts.side);
|
List<DownloadTask> tasks = DownloadTask.createTasksFromIndex(indexFile, indexFile.hashFormat, opts.side);
|
||||||
// If the side changes, invalidate EVERYTHING just in case
|
// If the side changes, invalidate EVERYTHING just in case
|
||||||
// Might not be needed, but done just to be safe
|
// Might not be needed, but done just to be safe
|
||||||
@@ -328,7 +344,8 @@ public class UpdateManager {
|
|||||||
tasks.parallelStream().forEach(f -> f.downloadMetadata(indexFile, indexUri));
|
tasks.parallelStream().forEach(f -> f.downloadMetadata(indexFile, indexUri));
|
||||||
|
|
||||||
List<IExceptionDetails> failedTasks = tasks.stream().filter(t -> t.getException() != null).collect(Collectors.toList());
|
List<IExceptionDetails> failedTasks = tasks.stream().filter(t -> t.getException() != null).collect(Collectors.toList());
|
||||||
if (failedTasks.size() > 0) {
|
if (!failedTasks.isEmpty()) {
|
||||||
|
errorsOccurred = true;
|
||||||
IExceptionDetails.ExceptionListResult exceptionListResult;
|
IExceptionDetails.ExceptionListResult exceptionListResult;
|
||||||
try {
|
try {
|
||||||
exceptionListResult = ui.showExceptions(failedTasks, tasks.size(), true).get();
|
exceptionListResult = ui.showExceptions(failedTasks, tasks.size(), true).get();
|
||||||
@@ -425,8 +442,12 @@ public class UpdateManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shut down the thread pool when the update is done
|
||||||
|
threadPool.shutdown();
|
||||||
|
|
||||||
List<IExceptionDetails> failedTasks2ElectricBoogaloo = nonFailedFirstTasks.stream().filter(t -> t.getException() != null).collect(Collectors.toList());
|
List<IExceptionDetails> failedTasks2ElectricBoogaloo = nonFailedFirstTasks.stream().filter(t -> t.getException() != null).collect(Collectors.toList());
|
||||||
if (failedTasks2ElectricBoogaloo.size() > 0) {
|
if (!failedTasks2ElectricBoogaloo.isEmpty()) {
|
||||||
|
errorsOccurred = true;
|
||||||
IExceptionDetails.ExceptionListResult exceptionListResult;
|
IExceptionDetails.ExceptionListResult exceptionListResult;
|
||||||
try {
|
try {
|
||||||
exceptionListResult = ui.showExceptions(failedTasks2ElectricBoogaloo, tasks.size(), false).get();
|
exceptionListResult = ui.showExceptions(failedTasks2ElectricBoogaloo, tasks.size(), false).get();
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
package link.infra.packwiz.installer.metadata;
|
||||||
|
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EfficientBooleanAdapter extends TypeAdapter<Boolean> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, Boolean value) throws IOException {
|
||||||
|
if (value == null || !value) {
|
||||||
|
out.nullValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.value(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean read(JsonReader in) throws IOException {
|
||||||
|
if (in.peek() == JsonToken.NULL) {
|
||||||
|
in.nextNull();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return in.nextBoolean();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
package link.infra.packwiz.installer.metadata;
|
package link.infra.packwiz.installer.metadata;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
import link.infra.packwiz.installer.UpdateManager;
|
import link.infra.packwiz.installer.UpdateManager;
|
||||||
import link.infra.packwiz.installer.metadata.hash.Hash;
|
import link.infra.packwiz.installer.metadata.hash.Hash;
|
||||||
|
|
||||||
@@ -19,9 +20,13 @@ public class ManifestFile {
|
|||||||
public Hash linkedFileHash = null;
|
public Hash linkedFileHash = null;
|
||||||
public String cachedLocation = null;
|
public String cachedLocation = null;
|
||||||
|
|
||||||
|
@JsonAdapter(EfficientBooleanAdapter.class)
|
||||||
public boolean isOptional = false;
|
public boolean isOptional = false;
|
||||||
public boolean optionValue = true;
|
public boolean optionValue = true;
|
||||||
|
|
||||||
|
@JsonAdapter(EfficientBooleanAdapter.class)
|
||||||
|
public boolean onlyOtherSide = false;
|
||||||
|
|
||||||
// When an error occurs, the state needs to be reverted. To do this, I have a crude revert system.
|
// When an error occurs, the state needs to be reverted. To do this, I have a crude revert system.
|
||||||
public void backup() {
|
public void backup() {
|
||||||
revert = new File();
|
revert = new File();
|
||||||
@@ -30,6 +35,7 @@ public class ManifestFile {
|
|||||||
revert.cachedLocation = cachedLocation;
|
revert.cachedLocation = cachedLocation;
|
||||||
revert.isOptional = isOptional;
|
revert.isOptional = isOptional;
|
||||||
revert.optionValue = optionValue;
|
revert.optionValue = optionValue;
|
||||||
|
revert.onlyOtherSide = onlyOtherSide;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getRevert() {
|
public File getRevert() {
|
||||||
|
@@ -4,9 +4,9 @@ import okio.HashingSource;
|
|||||||
import okio.Source;
|
import okio.Source;
|
||||||
|
|
||||||
public class HashingSourceHasher implements IHasher {
|
public class HashingSourceHasher implements IHasher {
|
||||||
String type;
|
private String type;
|
||||||
|
|
||||||
public HashingSourceHasher(String type) {
|
HashingSourceHasher(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ public class HashingSourceHasher implements IHasher {
|
|||||||
HashingSource delegateHashing;
|
HashingSource delegateHashing;
|
||||||
HashingSourceHash value;
|
HashingSourceHash value;
|
||||||
|
|
||||||
public HashingSourceGeneralHashingSource(HashingSource delegate) {
|
HashingSourceGeneralHashingSource(HashingSource delegate) {
|
||||||
super(delegate);
|
super(delegate);
|
||||||
delegateHashing = delegate;
|
delegateHashing = delegate;
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ public class HashingSourceHasher implements IHasher {
|
|||||||
}
|
}
|
||||||
HashingSourceHash objHash = (HashingSourceHash) obj;
|
HashingSourceHash objHash = (HashingSourceHash) obj;
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
return value.equals(objHash.value);
|
return value.equalsIgnoreCase(objHash.value);
|
||||||
} else {
|
} else {
|
||||||
return objHash.value == null;
|
return objHash.value == null;
|
||||||
}
|
}
|
||||||
@@ -71,9 +71,12 @@ public class HashingSourceHasher implements IHasher {
|
|||||||
@Override
|
@Override
|
||||||
public GeneralHashingSource getHashingSource(Source delegate) {
|
public GeneralHashingSource getHashingSource(Source delegate) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case "md5":
|
||||||
|
return new HashingSourceGeneralHashingSource(HashingSource.md5(delegate));
|
||||||
case "sha256":
|
case "sha256":
|
||||||
return new HashingSourceGeneralHashingSource(HashingSource.sha256(delegate));
|
return new HashingSourceGeneralHashingSource(HashingSource.sha256(delegate));
|
||||||
// TODO: support other hash types
|
case "sha512":
|
||||||
|
return new HashingSourceGeneralHashingSource(HashingSource.sha512(delegate));
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Invalid hash type provided");
|
throw new RuntimeException("Invalid hash type provided");
|
||||||
}
|
}
|
||||||
|
@@ -35,8 +35,14 @@ public class CLIHandler implements IUserInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<Boolean> showOptions(List<IOptionDetails> option) {
|
public Future<Boolean> showOptions(List<IOptionDetails> options) {
|
||||||
throw new RuntimeException("Optional mods not implemented for CLI! Make sure your optional mods are only on the client side!");
|
for (IOptionDetails opt : options) {
|
||||||
|
opt.setOptionValue(true);
|
||||||
|
System.out.println("Warning: accepting option " + opt.getName() + " as option choosing is not implemented in the CLI");
|
||||||
|
}
|
||||||
|
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||||
|
future.complete(false); // Can't be cancelled!
|
||||||
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user