Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3067d323de | ||
|
|
1404a080ad | ||
|
|
cbb2a1b575 | ||
|
|
30b276ec1a | ||
|
|
13a24d5b00 |
No files matched your search
@@ -62,7 +62,7 @@ public final class LauncherHelper {
|
||||
if (account == null)
|
||||
throw new IllegalStateException("No account");
|
||||
|
||||
Version version = repository.getVersion(selectedVersion);
|
||||
Version version = repository.getResolvedVersion(selectedVersion);
|
||||
VersionSetting setting = profile.getVersionSetting(selectedVersion);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
|
||||
@@ -530,8 +530,8 @@ public class Settings {
|
||||
}
|
||||
|
||||
private void onProfileChanged() {
|
||||
getSelectedProfile().getRepository().refreshVersionsAsync().start();
|
||||
EventBus.EVENT_BUS.fireEvent(new ProfileChangedEvent(SETTINGS, getSelectedProfile()));
|
||||
getSelectedProfile().getRepository().refreshVersionsAsync().subscribe(() ->
|
||||
EventBus.EVENT_BUS.fireEvent(new ProfileChangedEvent(SETTINGS, getSelectedProfile())));
|
||||
}
|
||||
|
||||
private void profileNameChanged(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
|
||||
|
||||
@@ -80,8 +80,6 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
FXUtils.loadFXML(this, "/assets/fxml/main.fxml");
|
||||
|
||||
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(() -> Platform.runLater(this::loadVersions));
|
||||
EventBus.EVENT_BUS.channel(ProfileLoadingEvent.class).register(this::onProfilesLoading);
|
||||
EventBus.EVENT_BUS.channel(ProfileChangedEvent.class).register(this::onProfileChanged);
|
||||
|
||||
versionPopup = new JFXPopup(versionList);
|
||||
getChildren().remove(versionList);
|
||||
@@ -178,14 +176,6 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
return item;
|
||||
}
|
||||
|
||||
public void onProfilesLoading() {
|
||||
// TODO: Profiles
|
||||
}
|
||||
|
||||
public void onProfileChanged(ProfileChangedEvent event) {
|
||||
Platform.runLater(() -> loadVersions(event.getProfile()));
|
||||
}
|
||||
|
||||
private void loadVersions() {
|
||||
loadVersions(Settings.INSTANCE.getSelectedProfile());
|
||||
}
|
||||
|
||||
@@ -31,10 +31,7 @@ import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
|
||||
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
|
||||
import org.jackhuang.hmcl.game.HMCLModpackExportTask;
|
||||
import org.jackhuang.hmcl.game.HMCLModpackInstallTask;
|
||||
import org.jackhuang.hmcl.mod.CurseCompletionTask;
|
||||
import org.jackhuang.hmcl.mod.CurseInstallTask;
|
||||
import org.jackhuang.hmcl.mod.MinecraftInstanceTask;
|
||||
import org.jackhuang.hmcl.mod.MultiMCModpackInstallTask;
|
||||
import org.jackhuang.hmcl.mod.*;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||
import org.jackhuang.hmcl.task.TaskListener;
|
||||
@@ -60,7 +57,7 @@ public final class TaskListPane extends StackPane {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady(Task task) {
|
||||
public void onRunning(Task task) {
|
||||
if (!task.getSignificance().shouldShow())
|
||||
return;
|
||||
|
||||
@@ -76,6 +73,8 @@ public final class TaskListPane extends StackPane {
|
||||
task.setName(Main.i18n("install.installer.install", Main.i18n("install.installer.optifine")));
|
||||
} else if (task instanceof CurseCompletionTask) {
|
||||
task.setName(Main.i18n("modpack.type.curse.completion"));
|
||||
} else if (task instanceof ModpackInstallTask) {
|
||||
task.setName(Main.i18n("modpack.installing"));
|
||||
} else if (task instanceof CurseInstallTask) {
|
||||
task.setName(Main.i18n("modpack.install", Main.i18n("modpack.type.curse")));
|
||||
} else if (task instanceof MultiMCModpackInstallTask) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
public Task buildAsync() {
|
||||
return new VersionJsonDownloadTask(gameVersion, dependencyManager).then(variables -> {
|
||||
Version version = Constants.GSON.fromJson(variables.<String>get(VersionJsonDownloadTask.ID), Version.class);
|
||||
version = version.setId(name).setJar(null).resolve(new SimpleVersionProvider());
|
||||
version = version.setId(name).setJar(null);
|
||||
variables.set("version", version);
|
||||
Task result = new ParallelTask(
|
||||
new GameAssetDownloadTask(dependencyManager, version),
|
||||
|
||||
@@ -55,7 +55,7 @@ public final class GameAssetDownloadTask extends Task {
|
||||
*/
|
||||
public GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version.requireResolved();
|
||||
this.version = version;
|
||||
this.refreshTask = new GameAssetRefreshTask(dependencyManager, version);
|
||||
this.dependents.add(refreshTask);
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public final class GameAssetIndexDownloadTask extends Task {
|
||||
*/
|
||||
public GameAssetIndexDownloadTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version.requireResolved();
|
||||
this.version = version;
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public final class GameAssetRefreshTask extends TaskResult<Collection<Pair<File,
|
||||
*/
|
||||
public GameAssetRefreshTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version.requireResolved();
|
||||
this.version = version;
|
||||
this.assetIndexInfo = version.getAssetIndex();
|
||||
this.assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class GameLibrariesTask extends Task {
|
||||
*/
|
||||
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version.requireResolved();
|
||||
this.version = version;
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@@ -62,9 +62,7 @@ public final class GameLibrariesTask extends Task {
|
||||
version.getLibraries().stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> {
|
||||
File file = dependencyManager.getGameRepository().getLibraryFile(version, library);
|
||||
if (!file.exists())
|
||||
dependencies.add(new FileDownloadTask(
|
||||
NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(library.getDownload().getUrl())),
|
||||
file, dependencyManager.getProxy(), library.getDownload().getSha1()));
|
||||
dependencies.add(new LibraryDownloadTask(dependencyManager, file, library));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public final class GameLoggingDownloadTask extends Task {
|
||||
*/
|
||||
public GameLoggingDownloadTask(DependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version.requireResolved();
|
||||
this.version = version;
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.download.game;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.SimpleMultimap;
|
||||
import org.jackhuang.hmcl.util.VersionNumber;
|
||||
|
||||
@@ -49,6 +50,7 @@ public class LibrariesUniqueTask extends TaskResult<Version> {
|
||||
for (Library library : libraries) {
|
||||
String id = library.getGroupId() + ":" + library.getArtifactId();
|
||||
VersionNumber number = VersionNumber.asVersion(library.getVersion());
|
||||
String serialized = Constants.GSON.toJson(library);
|
||||
|
||||
if (versionMap.containsKey(id)) {
|
||||
VersionNumber otherNumber = versionMap.get(id);
|
||||
@@ -56,8 +58,23 @@ public class LibrariesUniqueTask extends TaskResult<Version> {
|
||||
multimap.removeKey(id);
|
||||
versionMap.put(id, number);
|
||||
multimap.put(id, library);
|
||||
} else if (number.compareTo(otherNumber) == 0) {
|
||||
multimap.put(id, library);
|
||||
} else if (number.compareTo(otherNumber) == 0) { // same library id.
|
||||
boolean flag = false;
|
||||
// prevent from duplicated libraries
|
||||
for (Library otherLibrary : multimap.get(id))
|
||||
if (library.equals(otherLibrary)) {
|
||||
String otherSerialized = Constants.GSON.toJson(otherLibrary);
|
||||
// A trick, the library that has more information is better, which can be
|
||||
// considered whose serialized JSON text will be longer.
|
||||
if (serialized.length() <= otherSerialized.length()) {
|
||||
flag = true;
|
||||
break;
|
||||
} else {
|
||||
multimap.removeValue(id, otherLibrary);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
multimap.put(id, library);
|
||||
}
|
||||
} else {
|
||||
versionMap.put(id, number);
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
|
||||
import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Scheduler;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Pack200;
|
||||
|
||||
public final class LibraryDownloadTask extends Task {
|
||||
private final FileDownloadTask xzTask;
|
||||
private final FileDownloadTask task;
|
||||
private final File jar;
|
||||
private final File xzFile;
|
||||
private final Library library;
|
||||
|
||||
private boolean downloaded = false;
|
||||
|
||||
public LibraryDownloadTask(AbstractDependencyManager dependencyManager, File file, Library library) {
|
||||
if (library.is("net.minecraftforge", "forge"))
|
||||
library = library.setClassifier("universal");
|
||||
|
||||
this.library = library;
|
||||
|
||||
String url = dependencyManager.getDownloadProvider().injectURL(library.getDownload().getUrl());
|
||||
jar = file;
|
||||
|
||||
xzFile = new File(file.getAbsoluteFile().getParentFile(), file.getName() + ".pack.xz");
|
||||
|
||||
xzTask = new FileDownloadTask(NetworkUtils.toURL(url + ".pack.xz"),
|
||||
xzFile, dependencyManager.getProxy(), null, 1);
|
||||
xzTask.setSignificance(TaskSignificance.MINOR);
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
|
||||
task = new FileDownloadTask(NetworkUtils.toURL(url),
|
||||
file, dependencyManager.getProxy(), library.getDownload().getSha1());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends Task> getDependents() {
|
||||
return library.getChecksums() != null ? Collections.singleton(xzTask) : Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelyingOnDependents() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
if (isDependentsSucceeded() && library.getChecksums() != null) {
|
||||
unpackLibrary(jar, FileUtils.readBytes(xzFile));
|
||||
if (!checksumValid(jar, library.getChecksums()))
|
||||
throw new IOException("Checksum failed for " + library);
|
||||
|
||||
downloaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends Task> getDependencies() {
|
||||
return downloaded ? Collections.emptySet() : Collections.singleton(task);
|
||||
}
|
||||
|
||||
private static boolean checksumValid(File libPath, List<String> checksums) {
|
||||
try {
|
||||
if ((checksums == null) || (checksums.isEmpty())) {
|
||||
return true;
|
||||
}
|
||||
byte[] fileData = FileUtils.readBytes(libPath);
|
||||
boolean valid = checksums.contains(DigestUtils.sha1Hex(fileData));
|
||||
if ((!valid) && (libPath.getName().endsWith(".jar"))) {
|
||||
}
|
||||
return validateJar(fileData, checksums);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean validateJar(byte[] data, List<String> checksums) throws IOException {
|
||||
HashMap<String, String> files = new HashMap<>();
|
||||
String[] hashes = null;
|
||||
JarInputStream jar = new JarInputStream(new ByteArrayInputStream(data));
|
||||
JarEntry entry = jar.getNextJarEntry();
|
||||
while (entry != null) {
|
||||
byte[] eData = IOUtils.readFullyAsByteArray(jar);
|
||||
if (entry.getName().equals("checksums.sha1")) {
|
||||
hashes = new String(eData, Charset.forName("UTF-8")).split("\n");
|
||||
}
|
||||
if (!entry.isDirectory()) {
|
||||
files.put(entry.getName(), DigestUtils.sha1Hex(eData));
|
||||
}
|
||||
entry = jar.getNextJarEntry();
|
||||
}
|
||||
jar.close();
|
||||
if (hashes != null) {
|
||||
boolean passed = !checksums.contains(files.get("checksums.sha1"));
|
||||
if (passed) {
|
||||
for (String hash : hashes) {
|
||||
if ((!hash.trim().equals("")) && (hash.contains(" "))) {
|
||||
String[] e = hash.split(" ");
|
||||
String validChecksum = e[0];
|
||||
String target = hash.substring(validChecksum.length() + 1);
|
||||
String checksum = files.get(target);
|
||||
if ((!files.containsKey(target)) || (checksum == null)) {
|
||||
Logging.LOG.warning(" " + target + " : missing");
|
||||
passed = false;
|
||||
break;
|
||||
} else if (!checksum.equals(validChecksum)) {
|
||||
Logging.LOG.warning(" " + target + " : failed (" + checksum + ", " + validChecksum + ")");
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return passed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void unpackLibrary(File dest, byte[] src) throws IOException {
|
||||
if (dest.exists())
|
||||
if (!dest.delete())
|
||||
throw new IOException("Unable to delete file " + dest);
|
||||
|
||||
byte[] decompressed = IOUtils.readFullyAsByteArray(new XZCompressorInputStream(new ByteArrayInputStream(src)));
|
||||
|
||||
String end = new String(decompressed, decompressed.length - 4, 4);
|
||||
if (!end.equals("SIGN"))
|
||||
throw new IOException("Unpacking failed, signature missing " + end);
|
||||
|
||||
int x = decompressed.length;
|
||||
int len = decompressed[(x - 8)] & 0xFF | (decompressed[(x - 7)] & 0xFF) << 8 | (decompressed[(x - 6)] & 0xFF) << 16 | (decompressed[(x - 5)] & 0xFF) << 24;
|
||||
|
||||
File temp = FileUtils.createTempFile("minecraft", ".pack");
|
||||
|
||||
byte[] checksums = Arrays.copyOfRange(decompressed, decompressed.length - len - 8, decompressed.length - 8);
|
||||
|
||||
OutputStream out = new FileOutputStream(temp);
|
||||
out.write(decompressed, 0, decompressed.length - len - 8);
|
||||
out.close();
|
||||
|
||||
try (FileOutputStream jarBytes = new FileOutputStream(dest); JarOutputStream jos = new JarOutputStream(jarBytes)) {
|
||||
Pack200.newUnpacker().unpack(temp, jos);
|
||||
|
||||
JarEntry checksumsFile = new JarEntry("checksums.sha1");
|
||||
checksumsFile.setTime(0L);
|
||||
jos.putNextEntry(checksumsFile);
|
||||
jos.write(checksums);
|
||||
jos.closeEntry();
|
||||
}
|
||||
|
||||
temp.delete();
|
||||
}
|
||||
}
|
||||
@@ -40,11 +40,11 @@ public final class VersionJsonSaveTask extends Task {
|
||||
* Constructor.
|
||||
*
|
||||
* @param repository the game repository
|
||||
* @param version the **resolved** version
|
||||
* @param version the game version
|
||||
*/
|
||||
public VersionJsonSaveTask(DefaultGameRepository repository, Version version) {
|
||||
this.repository = repository;
|
||||
this.version = version.requireResolved();
|
||||
this.version = version;
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ClassicVersion extends Version {
|
||||
public ClassicLibrary(String name) {
|
||||
super("", "", "", null, null,
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo("bin/" + name + ".jar"), null),
|
||||
false, null, null, null);
|
||||
false, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ public class Library implements Comparable<Library> {
|
||||
private final boolean lateload;
|
||||
private final Map<OperatingSystem, String> natives;
|
||||
private final List<CompatibilityRule> rules;
|
||||
private final List<String> checksums;
|
||||
|
||||
private final String path;
|
||||
|
||||
@@ -60,10 +61,10 @@ public class Library implements Comparable<Library> {
|
||||
}
|
||||
|
||||
public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads, boolean lateload) {
|
||||
this(groupId, artifactId, version, classifier, url, downloads, lateload, null, null, null);
|
||||
this(groupId, artifactId, version, classifier, url, downloads, lateload, null, null, null, null);
|
||||
}
|
||||
|
||||
public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads, boolean lateload, ExtractRules extract, Map<OperatingSystem, String> natives, List<CompatibilityRule> rules) {
|
||||
public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads, boolean lateload, List<String> checksums, ExtractRules extract, Map<OperatingSystem, String> natives, List<CompatibilityRule> rules) {
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
@@ -80,6 +81,7 @@ public class Library implements Comparable<Library> {
|
||||
this.lateload = lateload;
|
||||
this.natives = natives;
|
||||
this.rules = rules;
|
||||
this.checksums = checksums;
|
||||
|
||||
LibraryDownloadInfo temp = null;
|
||||
if (downloads != null)
|
||||
@@ -141,6 +143,14 @@ public class Library implements Comparable<Library> {
|
||||
return lateload;
|
||||
}
|
||||
|
||||
public List<String> getChecksums() {
|
||||
return checksums;
|
||||
}
|
||||
|
||||
public boolean is(String groupId, String artifactId) {
|
||||
return this.groupId.equals(groupId) && this.artifactId.equals(artifactId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("name", getName()).toString();
|
||||
@@ -168,16 +178,20 @@ public class Library implements Comparable<Library> {
|
||||
return Objects.hash(getName(), isNative());
|
||||
}
|
||||
|
||||
public static Library fromName(String name) {
|
||||
return fromName(name, null, null, null, null, null);
|
||||
public Library setClassifier(String classifier) {
|
||||
return new Library(groupId, artifactId, version, classifier, url, downloads, lateload, checksums, extract, natives, rules);
|
||||
}
|
||||
|
||||
public static Library fromName(String name, String url, LibrariesDownloadInfo downloads, ExtractRules extract, Map<OperatingSystem, String> natives, List<CompatibilityRule> rules) {
|
||||
public static Library fromName(String name) {
|
||||
return fromName(name, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public static Library fromName(String name, String url, LibrariesDownloadInfo downloads, List<String> checksums, ExtractRules extract, Map<OperatingSystem, String> natives, List<CompatibilityRule> rules) {
|
||||
String[] arr = name.split(":", 4);
|
||||
if (arr.length != 3 && arr.length != 4)
|
||||
throw new IllegalArgumentException("Library name is malformed. Correct example: group:artifact:version(:classifier).");
|
||||
|
||||
return new Library(arr[0].replace("\\", "/"), arr[1], arr[2], arr.length >= 4 ? arr[3] : null, url, downloads, false, extract, natives, rules);
|
||||
return new Library(arr[0].replace("\\", "/"), arr[1], arr[2], arr.length >= 4 ? arr[3] : null, url, downloads, false, checksums, extract, natives, rules);
|
||||
}
|
||||
|
||||
public static class Serializer implements JsonDeserializer<Library>, JsonSerializer<Library> {
|
||||
@@ -198,6 +212,8 @@ public class Library implements Comparable<Library> {
|
||||
jsonObject.get("name").getAsString(),
|
||||
jsonObject.has("url") ? jsonObject.get("url").getAsString() : null,
|
||||
context.deserialize(jsonObject.get("downloads"), LibrariesDownloadInfo.class),
|
||||
context.deserialize(jsonObject.get("checksums"), new TypeToken<List<String>>() {
|
||||
}.getType()),
|
||||
context.deserialize(jsonObject.get("extract"), ExtractRules.class),
|
||||
context.deserialize(jsonObject.get("natives"), new TypeToken<Map<OperatingSystem, String>>() {
|
||||
}.getType()),
|
||||
|
||||
@@ -143,13 +143,6 @@ public class Version implements Comparable<Version>, Validation {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Version requireResolved() {
|
||||
if (!resolved)
|
||||
throw new RuntimeException("Version not resolved");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve given version
|
||||
*/
|
||||
|
||||
@@ -220,7 +220,6 @@ public class FileDownloadTask extends Task {
|
||||
} catch (IOException | IllegalStateException e) {
|
||||
if (temp != null)
|
||||
temp.delete();
|
||||
Logging.LOG.log(Level.WARNING, "Unable to download file " + currentURL, e);
|
||||
exception = e;
|
||||
} finally {
|
||||
closeFiles();
|
||||
@@ -228,7 +227,7 @@ public class FileDownloadTask extends Task {
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
throw exception;
|
||||
throw new IOException("Unable to download file " + currentURL, exception);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,10 @@ class SchedulerExecutorService extends Scheduler {
|
||||
|
||||
@Override
|
||||
public Future<?> schedule(ExceptionalRunnable<?> block) {
|
||||
return executorService.submit(block.toCallable());
|
||||
if (executorService.isShutdown() || executorService.isTerminated())
|
||||
return Schedulers.NONE.schedule(block);
|
||||
else
|
||||
return executorService.submit(block.toCallable());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
@@ -112,6 +114,8 @@ public final class Schedulers {
|
||||
return newThread();
|
||||
}
|
||||
|
||||
static final Scheduler NONE = new SchedulerImpl(Constants.emptyConsumer());
|
||||
|
||||
public static synchronized void shutdown() {
|
||||
if (CACHED_EXECUTOR != null)
|
||||
CACHED_EXECUTOR.shutdown();
|
||||
|
||||
@@ -133,6 +133,7 @@ public abstract class Task {
|
||||
|
||||
/**
|
||||
* The collection of sub-tasks that should execute **after** this task running.
|
||||
* Will not be executed if execution fails.
|
||||
*/
|
||||
public Collection<? extends Task> getDependencies() {
|
||||
return Collections.emptySet();
|
||||
@@ -350,6 +351,7 @@ public abstract class Task {
|
||||
public enum TaskState {
|
||||
READY,
|
||||
RUNNING,
|
||||
EXECUTED,
|
||||
SUCCEEDED,
|
||||
FAILED
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public final class TaskExecutor {
|
||||
return false;
|
||||
}
|
||||
|
||||
task.setState(Task.TaskState.RUNNING);
|
||||
task.setState(Task.TaskState.READY);
|
||||
|
||||
if (task.getSignificance().shouldLog())
|
||||
Logging.LOG.log(Level.FINE, "Executing task: {0}", task.getName());
|
||||
@@ -150,10 +150,18 @@ public final class TaskExecutor {
|
||||
|
||||
task.setVariables(variables);
|
||||
|
||||
task.setState(Task.TaskState.RUNNING);
|
||||
|
||||
taskListeners.forEach(it -> it.onRunning(task));
|
||||
try {
|
||||
task.getScheduler().schedule(task::execute).get();
|
||||
} catch (ExecutionException e) {
|
||||
throw (Exception) e.getCause();
|
||||
if (e.getCause() instanceof Exception)
|
||||
throw (Exception) e.getCause();
|
||||
else
|
||||
throw e;
|
||||
} finally {
|
||||
task.setState(Task.TaskState.EXECUTED);
|
||||
}
|
||||
|
||||
if (task instanceof TaskResult<?>) {
|
||||
@@ -169,22 +177,24 @@ public final class TaskExecutor {
|
||||
flag = true;
|
||||
if (task.getSignificance().shouldLog()) {
|
||||
Logging.LOG.log(Level.FINER, "Task finished: {0}", task.getName());
|
||||
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
||||
taskListeners.forEach(it -> it.onFinished(task));
|
||||
}
|
||||
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
||||
taskListeners.forEach(it -> it.onFinished(task));
|
||||
} catch (InterruptedException e) {
|
||||
if (task.getSignificance().shouldLog()) {
|
||||
Logging.LOG.log(Level.FINE, "Task aborted: " + task.getName());
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, true));
|
||||
taskListeners.forEach(it -> it.onFailed(task, e));
|
||||
}
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, true));
|
||||
taskListeners.forEach(it -> it.onFailed(task, e));
|
||||
} catch (SilentException | RejectedExecutionException e) {
|
||||
// do nothing
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
variables.set(LAST_EXCEPTION_ID, e);
|
||||
Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e);
|
||||
if (task.getSignificance().shouldLog()) {
|
||||
Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e);
|
||||
}
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, true));
|
||||
taskListeners.forEach(it -> it.onFailed(task, e));
|
||||
} finally {
|
||||
|
||||
@@ -31,6 +31,9 @@ public abstract class TaskListener implements EventListener {
|
||||
public void onReady(Task task) {
|
||||
}
|
||||
|
||||
public void onRunning(Task task) {
|
||||
}
|
||||
|
||||
public void onFinished(Task task) {
|
||||
}
|
||||
|
||||
|
||||
@@ -74,9 +74,15 @@ public final class SimpleMultimap<K, V> {
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public void removeValue(V value) {
|
||||
public boolean removeValue(V value) {
|
||||
boolean flag = false;
|
||||
for (Collection<V> c : map.values())
|
||||
c.remove(value);
|
||||
flag |= c.remove(value);
|
||||
return flag;
|
||||
}
|
||||
|
||||
public boolean removeValue(K key, V value) {
|
||||
return get(key).remove(value);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
||||
@@ -13,7 +13,7 @@ public class ToStringBuilder {
|
||||
if (!first)
|
||||
stringBuilder.append(", ");
|
||||
first = false;
|
||||
stringBuilder.append(name).append('=').append(content.toString());
|
||||
stringBuilder.append(name).append('=').append(content);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ allprojects {
|
||||
dependencies {
|
||||
compile "com.google.code.gson:gson:2.8.2"
|
||||
compile "org.apache.commons:commons-compress:1.15"
|
||||
compile "org.tukaani:xz:1.2"
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user