Modpack updates

This commit is contained in:
huangyuhui 2018-01-27 01:19:13 +08:00
parent 12fa94627d
commit e8316de160
20 changed files with 472 additions and 81 deletions

View File

@ -17,41 +17,58 @@
*/
package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.DependencyManager;
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
import org.jackhuang.hmcl.mod.Modpack;
import org.jackhuang.hmcl.mod.*;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.CompressingUtils;
import org.jackhuang.hmcl.util.Constants;
import org.jackhuang.hmcl.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
public final class HMCLModpackInstallTask extends Task {
private final File zipFile;
private final String id;
private final String name;
private final HMCLGameRepository repository;
private final DefaultDependencyManager dependency;
private final Modpack modpack;
private final File run;
private final List<Task> dependencies = new LinkedList<>();
private final List<Task> dependents = new LinkedList<>();
public HMCLModpackInstallTask(Profile profile, File zipFile, Modpack modpack, String id) {
dependency = profile.getDependency();
public HMCLModpackInstallTask(Profile profile, File zipFile, Modpack modpack, String name) {
DependencyManager dependency = profile.getDependency();
repository = profile.getRepository();
this.zipFile = zipFile;
this.id = id;
this.name = name;
this.modpack = modpack;
this.run = repository.getRunDirectory(name);
if (repository.hasVersion(id))
throw new IllegalArgumentException("Version " + id + " already exists");
File json = new File(run, "modpack.json");
if (repository.hasVersion(name) && !json.exists())
throw new IllegalArgumentException("Version " + name + " already exists");
dependents.add(dependency.gameBuilder().name(id).gameVersion(modpack.getGameVersion()).buildAsync());
dependents.add(dependency.gameBuilder().name(name).gameVersion(modpack.getGameVersion()).buildAsync());
onDone().register(event -> {
if (event.isFailed()) repository.removeVersionFromDisk(id);
if (event.isFailed()) repository.removeVersionFromDisk(name);
});
ModpackConfiguration<Modpack> config = null;
try {
if (json.exists())
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<Modpack>>(){}.getType());
} catch (JsonParseException | IOException ignore) {
}
dependents.add(new ModpackInstallTask<>(zipFile, run, "minecraft/", it -> !Objects.equals(it, "minecraft/pack.json"), config));
}
@Override
@ -69,8 +86,6 @@ public final class HMCLModpackInstallTask extends Task {
String json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json");
Version version = Constants.GSON.fromJson(json, Version.class).setJar(null);
dependencies.add(new VersionJsonSaveTask(repository, version));
CompressingUtils.unzip(zipFile, repository.getRunDirectory(id),
"minecraft/", it -> !Objects.equals(it, "minecraft/pack.json"), false);
dependencies.add(new MinecraftInstanceTask<>(zipFile, "minecraft/", modpack, new File(run, "modpack.json")));
}
}

View File

@ -33,10 +33,26 @@ import java.util.List;
*/
public final class HMCLModpackManager {
public static final List<String> MODPACK_BLACK_LIST = Arrays.asList("usernamecache.json", "asm", "logs", "backups", "versions", "assets", "usercache.json", "libraries", "crash-reports", "launcher_profiles.json", "NVIDIA", "AMD", "TCNodeTracker", "screenshots", "natives", "native", "$native", "pack.json", "launcher.jar", "minetweaker.log", "launcher.pack.lzma", "hmclmc.log");
public static final List<String> MODPACK_SUGGESTED_BLACK_LIST = Arrays.asList("fonts", "saves", "servers.dat", "options.txt", "optionsof.txt", "journeymap", "optionsshaders.txt", "mods/VoxelMods");
public static final List<String> MODPACK_BLACK_LIST = Arrays.asList(
"usernamecache.json", "usercache.json", // Minecraft
"launcher_profiles.json", "launcher.pack.lzma", // Minecraft Launcher
"pack.json", "launcher.jar", "hmclmc.log", // HMCL
"manifest.json", "minecraftinstance.json", ".curseclient", // Curse
"minetweaker.log", // Mods
"logs", "versions", "assets", "libraries", "crash-reports", "NVIDIA", "AMD", "screenshots", "natives", "native", "$native", "server-resource-packs", // Minecraft
"downloads", // Curse
"asm", "backups", "TCNodeTracker", "CustomDISkins", "data" // Mods
);
public static final List<String> MODPACK_SUGGESTED_BLACK_LIST = Arrays.asList(
"fonts", // BetterFonts
"saves", "servers.dat", "options.txt", // Minecraft
"blueprints" /* BuildCraft */,
"optionsof.txt" /* OptiFine */,
"journeymap" /* JourneyMap */,
"optionsshaders.txt",
"mods/VoxelMods");
public static ModAdviser MODPACK_PREDICATE = (String fileName, boolean isDirectory) -> {
public static ModAdviser.ModSuggestion suggestMod(String fileName, boolean isDirectory) {
if (match(MODPACK_BLACK_LIST, fileName, isDirectory))
return ModAdviser.ModSuggestion.HIDDEN;
if (match(MODPACK_SUGGESTED_BLACK_LIST, fileName, isDirectory))

View File

@ -61,7 +61,7 @@ public final class ModpackHelper {
}
if (c.isOverrideMemory()) {
vs.setPermSize(Optional.ofNullable(c.getPermGen()).map(i -> i.toString()).orElse(""));
vs.setPermSize(Optional.ofNullable(c.getPermGen()).map(Object::toString).orElse(""));
if (c.getMaxMemory() != null)
vs.setMaxMemory(c.getMaxMemory());
vs.setMinMemory(c.getMinMemory());

View File

@ -405,6 +405,10 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
private Node nowPage;
public void showPage(Node content) {
contentPlaceHolder.getStyleClass().removeAll("gray-background", "white-background");
if (content != null)
contentPlaceHolder.getStyleClass().add("gray-background");
Node c = content == null ? mainPage : content;
onEnd();
if (nowPage instanceof DecoratorPage)
@ -457,6 +461,8 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
@Override
public void navigateTo(Node page, Navigation.NavigationDirection nav) {
contentPlaceHolder.getStyleClass().removeAll("gray-background", "white-background");
contentPlaceHolder.getStyleClass().add("white-background");
setContent(page, nav.getAnimation().getAnimationProducer());
}

View File

@ -34,6 +34,7 @@ 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.task.FileDownloadTask;
import org.jackhuang.hmcl.task.Task;
@ -87,6 +88,8 @@ public final class TaskListPane extends StackPane {
task.setName(Main.i18n("modpack.install", Main.i18n("modpack.type.curse")));
} else if (task instanceof HMCLModpackExportTask) {
task.setName(Main.i18n("modpack.export"));
} else if (task instanceof MinecraftInstanceTask) {
task.setName(Main.i18n("modpack.scan"));
}
ProgressListNode node = new ProgressListNode(task);

View File

@ -983,6 +983,14 @@
-fx-border-width: 1;
}
.gray-background {
-fx-background-color: rgba(244, 244, 244, 0.5);
}
.white-background {
-fx-background-color: rgba(255, 255, 255);
}
/*******************************************************************************
* *
* Tree Table View *

View File

@ -23,7 +23,7 @@
<StackPane minWidth="200" maxWidth="200" styleClass="jfx-decorator-content-container">
<BorderPane fx:id="leftRootPane">
<center>
<BorderPane style="-fx-background-color: rgba(244, 244, 244, 0.5);">
<BorderPane styleClass="gray-background">
<center>
<AdvancedListBox fx:id="leftPane"/>
</center>

View File

@ -412,3 +412,4 @@ extension.mod=Mod file
extension.png=Image file
message.success=Tasks succeeded
message.doing=Please wait
modpack.scan=Scanning this modpack

View File

@ -412,3 +412,4 @@ extension.mod=模组文件
extension.png=图片文件
message.success=已完成
message.doing=请耐心等待
modpack.scan=解析整合包

View File

@ -17,16 +17,22 @@
*/
package org.jackhuang.hmcl.mod;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.CompressingUtils;
import org.jackhuang.hmcl.util.Constants;
import org.jackhuang.hmcl.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
/**
* Install a downloaded CurseForge modpack.
@ -40,6 +46,8 @@ public final class CurseInstallTask extends Task {
private final File zipFile;
private final CurseManifest manifest;
private final String name;
private final File run;
private final ModpackConfiguration<CurseManifest> config;
private final List<Task> dependents = new LinkedList<>();
private final List<Task> dependencies = new LinkedList<>();
@ -57,10 +65,11 @@ public final class CurseInstallTask extends Task {
this.zipFile = zipFile;
this.manifest = manifest;
this.name = name;
this.repository = dependencyManager.getGameRepository();
this.run = repository.getRunDirectory(name);
repository = dependencyManager.getGameRepository();
if (repository.hasVersion(name))
File json = new File(run, "modpack.json");
if (repository.hasVersion(name) && !json.exists())
throw new IllegalArgumentException("Version " + name + " already exists.");
GameBuilder builder = dependencyManager.gameBuilder().name(name).gameVersion(manifest.getMinecraft().getGameVersion());
@ -68,6 +77,15 @@ public final class CurseInstallTask extends Task {
if (modLoader.getId().startsWith("forge-"))
builder.version("forge", modLoader.getId().substring("forge-".length()));
dependents.add(builder.buildAsync());
ModpackConfiguration<CurseManifest> config = null;
try {
if (json.exists())
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<CurseManifest>>(){}.getType());
} catch (JsonParseException | IOException ignore) {
}
this.config = config;
dependents.add(new ModpackInstallTask<>(zipFile, run, manifest.getOverrides(), Constants.truePredicate(), config));
}
@Override
@ -82,10 +100,17 @@ public final class CurseInstallTask extends Task {
@Override
public void execute() throws Exception {
File run = repository.getRunDirectory(name);
CompressingUtils.unzip(zipFile, run, manifest.getOverrides());
if (config != null)
for (CurseManifestFile oldCurseManifestFile : config.getManifest().getFiles()) {
if (oldCurseManifestFile.getFileName() == null) continue;
File oldFile = new File(run, "mods/" + oldCurseManifestFile.getFileName());
if (!oldFile.exists()) continue;
if (manifest.getFiles().stream().noneMatch(oldCurseManifestFile::equals))
oldFile.delete();
}
dependencies.add(new CurseCompletionTask(dependencyManager, name));
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getOverrides(), false, manifest, new File(run, "modpack.json")));
}
}

View File

@ -24,6 +24,7 @@ import org.jackhuang.hmcl.util.NetworkUtils;
import org.jackhuang.hmcl.util.Validation;
import java.net.URL;
import java.util.Objects;
/**
*
@ -84,4 +85,18 @@ public final class CurseManifestFile implements Validation {
public CurseManifestFile setFileName(String fileName) {
return new CurseManifestFile(projectID, fileID, fileName, required);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CurseManifestFile that = (CurseManifestFile) o;
return projectID == that.projectID &&
fileID == that.fileID;
}
@Override
public int hashCode() {
return Objects.hash(projectID, fileID);
}
}

View File

@ -17,5 +17,57 @@
*/
package org.jackhuang.hmcl.mod;
public class MinecraftInstanceTask {
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Constants;
import org.jackhuang.hmcl.util.DigestUtils;
import org.jackhuang.hmcl.util.FileUtils;
import org.jackhuang.hmcl.util.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
public final class MinecraftInstanceTask<T> extends Task {
private final File zipFile;
private final String subDirectory;
private final File jsonFile;
private final T manifest;
public MinecraftInstanceTask(File zipFile, String subDirectory, T manifest, File jsonFile) {
this.zipFile = zipFile;
this.subDirectory = subDirectory;
this.manifest = manifest;
this.jsonFile = jsonFile;
if (!zipFile.exists())
throw new IllegalArgumentException("File " + zipFile + " does not exist. Cannot parse this modpack.");
}
@Override
public void execute() throws Exception {
Map<String, ModpackConfiguration.FileInformation> overrides = new HashMap<>();
byte[] buf = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
try (ZipArchiveInputStream zip = new ZipArchiveInputStream(new FileInputStream(zipFile), null, true, true)) {
ArchiveEntry entry;
while ((entry = zip.getNextEntry()) != null) {
String path = entry.getName();
if (!path.startsWith(subDirectory) || entry.isDirectory())
continue;
path = path.substring(subDirectory.length());
if (path.startsWith("/") || path.startsWith("\\"))
path = path.substring(1);
overrides.put(path, new ModpackConfiguration.FileInformation(
path, DigestUtils.sha1Hex(zip)
));
}
}
FileUtils.writeText(jsonFile, Constants.GSON.toJson(new ModpackConfiguration<>(manifest, overrides)));
}
}

View File

@ -0,0 +1,105 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.mod;
import com.google.gson.JsonParseException;
import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.Validation;
import java.util.Collections;
import java.util.Map;
@Immutable
public final class ModpackConfiguration<T> implements Validation {
private final T manifest;
private final Map<String, FileInformation> overrides;
public ModpackConfiguration() {
this(null, Collections.emptyMap());
}
public ModpackConfiguration(T manifest, Map<String, FileInformation> overrides) {
this.manifest = manifest;
this.overrides = overrides;
}
public T getManifest() {
return manifest;
}
public ModpackConfiguration<T> setManifest(T manifest) {
return new ModpackConfiguration<>(manifest, overrides);
}
public ModpackConfiguration<T> setOverrides(Map<String, FileInformation> overrides) {
return new ModpackConfiguration<>(manifest, overrides);
}
public Map<String, FileInformation> getOverrides() {
return Collections.unmodifiableMap(overrides);
}
@Override
public void validate() throws JsonParseException {
if (manifest == null)
throw new JsonParseException("MinecraftInstanceConfiguration missing `manifest`");
}
@Immutable
public static class FileInformation implements Validation {
private final String location; // relative
private final String hash;
private final String downloadURL;
public FileInformation() {
this(null, null);
}
public FileInformation(String location, String hash) {
this(location, hash, null);
}
public FileInformation(String location, String hash, String downloadURL) {
this.location = location;
this.hash = hash;
this.downloadURL = downloadURL;
}
public String getLocation() {
return location;
}
public String getDownloadURL() {
return downloadURL;
}
public String getHash() {
return hash;
}
@Override
public void validate() throws JsonParseException {
if (location == null)
throw new JsonParseException("FileInformation missing `location`.");
if (hash == null)
throw new JsonParseException("FileInformation missing file hash code.");
}
}
}

View File

@ -0,0 +1,109 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.mod;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.DigestUtils;
import org.jackhuang.hmcl.util.FileUtils;
import org.jackhuang.hmcl.util.IOUtils;
import java.io.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
public class ModpackInstallTask<T> extends Task {
private final File modpackFile;
private final File dest;
private final String subDirectory;
private final Map<String, ModpackConfiguration.FileInformation> overrides;
private final Predicate<String> callback;
public ModpackInstallTask(File modpackFile, File dest, String subDirectory, Predicate<String> callback, ModpackConfiguration<T> oldConfiguration) {
this.modpackFile = modpackFile;
this.dest = dest;
this.subDirectory = subDirectory;
this.callback = callback;
if (oldConfiguration == null)
overrides = Collections.emptyMap();
else
overrides = oldConfiguration.getOverrides();
}
@Override
public void execute() throws Exception {
Set<String> entries = new HashSet<>();
byte[] buf = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
if (!FileUtils.makeDirectory(dest))
throw new IOException("Unable to make directory " + dest);
try (ZipArchiveInputStream zipStream = new ZipArchiveInputStream(new FileInputStream(modpackFile), null, true, true)) {
ArchiveEntry entry;
while ((entry = zipStream.getNextEntry()) != null) {
String path = entry.getName();
if (!path.startsWith(subDirectory))
continue;
path = path.substring(subDirectory.length());
if (path.startsWith("/") || path.startsWith("\\"))
path = path.substring(1);
File entryFile = new File(dest, path);
if (callback != null)
if (!callback.test(path))
continue;
if (entry.isDirectory()) {
if (!FileUtils.makeDirectory(entryFile))
throw new IOException("Unable to make directory: " + entryFile);
} else {
if (!FileUtils.makeDirectory(entryFile.getAbsoluteFile().getParentFile()))
throw new IOException("Unable to make parent directory for file " + entryFile);
entries.add(path);
ByteArrayOutputStream os = new ByteArrayOutputStream(IOUtils.DEFAULT_BUFFER_SIZE);
IOUtils.copyTo(zipStream, os, buf);
byte[] data = os.toByteArray();
if (!overrides.containsKey(path) || entryFile.exists()) {
String oldHash = DigestUtils.sha1Hex(new FileInputStream(entryFile));
String newHash = DigestUtils.sha1Hex(new ByteArrayInputStream(data));
if (!oldHash.equals(newHash)) {
try (FileOutputStream fos = new FileOutputStream(entryFile)) {
IOUtils.copyTo(new ByteArrayInputStream(data), fos, buf);
}
}
}
}
}
}
for (String path : overrides.keySet()) {
File original = new File(dest, path);
if (original.exists() && !entries.contains(path))
original.delete();
}
}
}

View File

@ -17,6 +17,8 @@
*/
package org.jackhuang.hmcl.mod;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
@ -25,12 +27,10 @@ import org.jackhuang.hmcl.game.Arguments;
import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.CompressingUtils;
import org.jackhuang.hmcl.util.Constants;
import org.jackhuang.hmcl.util.IOUtils;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.*;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@ -57,14 +57,24 @@ public final class MultiMCModpackInstallTask extends Task {
this.name = name;
this.repository = dependencyManager.getGameRepository();
this.run = repository.getRunDirectory(name);
if (repository.hasVersion(name))
File json = new File(run, "modpack.json");
if (repository.hasVersion(name) && !json.exists())
throw new IllegalArgumentException("Version " + name + " already exists.");
dependents.add(dependencyManager.gameBuilder().name(name).gameVersion(manifest.getGameVersion()).buildAsync());
onDone().register(event -> {
if (event.isFailed())
repository.removeVersionFromDisk(name);
});
ModpackConfiguration<MultiMCInstanceConfiguration> config = null;
try {
if (json.exists())
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<MultiMCInstanceConfiguration>>(){}.getType());
} catch (JsonParseException | IOException ignore) {
}
dependents.add(new ModpackInstallTask<>(zipFile, run, manifest.getName() + "/minecraft/", Constants.truePredicate(), config));
}
@Override
@ -80,8 +90,7 @@ public final class MultiMCModpackInstallTask extends Task {
@Override
public void execute() throws Exception {
Version version = Objects.requireNonNull(repository.readVersionJson(name));
CompressingUtils.unzip(zipFile, run, manifest.getName() + "/minecraft/", null, false, true);
try (ZipFile zip = new ZipFile(zipFile)) {
for (ZipArchiveEntry entry : Lang.asIterable(zip.getEntries())) {
// ensure that this entry is in folder 'patches' and is a json file.
@ -99,8 +108,9 @@ public final class MultiMCModpackInstallTask extends Task {
}
}
}
dependencies.add(new VersionJsonSaveTask(repository, version));
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getName() + "/minecraft/", manifest, new File(run, "modpack.json")));
}
}

View File

@ -107,6 +107,10 @@ public class FileDownloadTask extends Task {
return url;
}
public File getFile() {
return file;
}
@Override
public void execute() throws Exception {
URL currentURL = url;
@ -189,12 +193,12 @@ public class FileDownloadTask extends Task {
Thread.currentThread().interrupt();
break;
} else {
if (file.exists())
file.delete();
if (file.exists() || !file.delete())
throw new IOException("Unable to delete existent file " + file);
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
throw new IOException("Cannot make parent directory " + file);
throw new IOException("Unable to make parent directory " + file);
if (!temp.renameTo(file))
throw new IOException("Cannot move temp file to " + file);
throw new IOException("Unable move temp file to " + file);
}
if (downloaded != contentLength)

View File

@ -52,6 +52,16 @@ public abstract class Task {
this.significance = significance;
}
private TaskState state = TaskState.READY;
public TaskState getState() {
return state;
}
void setState(TaskState state) {
this.state = state;
}
/**
* The scheduler that decides how this task runs.
*/
@ -111,14 +121,14 @@ public abstract class Task {
/**
* The collection of sub-tasks that should execute **before** this task running.
*/
public Collection<Task> getDependents() {
public Collection<? extends Task> getDependents() {
return Collections.emptySet();
}
/**
* The collection of sub-tasks that should execute **after** this task running.
*/
public Collection<Task> getDependencies() {
public Collection<? extends Task> getDependencies() {
return Collections.emptySet();
}
@ -298,4 +308,11 @@ public abstract class Task {
return this == MAJOR;
}
}
public enum TaskState {
READY,
RUNNING,
SUCCEEDED,
FAILED
}
}

View File

@ -108,7 +108,7 @@ public final class TaskExecutor {
}
}
private boolean executeTasks(Collection<Task> tasks) throws InterruptedException {
private boolean executeTasks(Collection<? extends Task> tasks) throws InterruptedException {
if (tasks.isEmpty())
return true;
@ -140,8 +140,12 @@ public final class TaskExecutor {
}
private boolean executeTask(Task task) {
if (canceled)
if (canceled) {
task.setState(Task.TaskState.FAILED);
return false;
}
task.setState(Task.TaskState.RUNNING);
if (task.getSignificance().shouldLog())
Logging.LOG.log(Level.FINE, "Executing task: {0}", task.getName());
@ -165,7 +169,7 @@ public final class TaskExecutor {
if (!executeTasks(task.getDependencies()) && task.isRelyingOnDependencies()) {
Logging.LOG.severe("Subtasks failed for " + task.getName());
return false;
throw new SilentException();
}
flag = true;
@ -182,10 +186,8 @@ public final class TaskExecutor {
task.onDone().fireEvent(new TaskEvent(this, task, true));
taskListeners.forEach(it -> it.onFailed(task, e));
}
} catch (SilentException e) {
} catch (SilentException | RejectedExecutionException e) {
// do nothing
} catch (RejectedExecutionException e) {
return false;
} catch (Exception e) {
lastException = e;
Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e);
@ -194,6 +196,7 @@ public final class TaskExecutor {
} finally {
task.setVariables(null);
}
task.setState(flag ? Task.TaskState.SUCCEEDED : Task.TaskState.FAILED);
return flag;
}

View File

@ -43,7 +43,7 @@ public final class CompressingUtils {
* @param sourceDir the source directory or a file.
* @param zipFile the location of dest zip file.
* @param pathNameCallback callback(pathName, isDirectory) returns your modified pathName
* @throws IOException
* @throws IOException if there is filesystem error.
*/
public static void zip(File sourceDir, File zipFile, BiFunction<String, Boolean, String> pathNameCallback) throws IOException {
try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(new FileOutputStream(zipFile))) {
@ -71,6 +71,8 @@ public final class CompressingUtils {
File[] files = src.isDirectory() ? src.listFiles() : new File[] { src };
String pathName;// the relative path (relative to the root directory to be compressed)
byte[] buf = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
if (files == null) return;
for (File file : files)
if (file.isDirectory()) {
pathName = file.getPath().substring(basePath.length() + 1) + "/";
@ -152,48 +154,39 @@ public final class CompressingUtils {
* @param callback will be called for every entry in the zip file, returns false if you dont want this file being uncompressed.
* @param ignoreExistentFile true if skip all existent files.
* @param allowStoredEntriesWithDataDescriptor whether the zip stream will try to read STORED entries that use a data descriptor
* @throws IOException
* @throws IOException if zip file is malformed or filesystem error.
*/
public static void unzip(File src, File dest, String subDirectory, Predicate<String> callback, boolean ignoreExistentFile, boolean allowStoredEntriesWithDataDescriptor) throws IOException {
byte[] buf = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
dest.mkdirs();
try (ZipArchiveInputStream zipFile = new ZipArchiveInputStream(new FileInputStream(src), null, true, allowStoredEntriesWithDataDescriptor)) {
if (src.exists()) {
String strPath, gbkPath, strtemp;
strPath = dest.getAbsolutePath();
ArchiveEntry zipEnt;
while ((zipEnt = zipFile.getNextEntry()) != null) {
gbkPath = zipEnt.getName();
if (!FileUtils.makeDirectory(dest))
throw new IOException("Unable to make directory " + dest);
try (ZipArchiveInputStream zipStream = new ZipArchiveInputStream(new FileInputStream(src), null, true, allowStoredEntriesWithDataDescriptor)) {
ArchiveEntry entry;
while ((entry = zipStream.getNextEntry()) != null) {
String path = entry.getName();
if (!gbkPath.startsWith(subDirectory))
if (!path.startsWith(subDirectory))
continue;
path = path.substring(subDirectory.length());
if (path.startsWith("/") || path.startsWith("\\"))
path = path.substring(1);
File entryFile = new File(dest, path);
if (callback != null)
if (!callback.test(path))
continue;
gbkPath = gbkPath.substring(subDirectory.length());
if (gbkPath.startsWith("/") || gbkPath.startsWith("\\"))
gbkPath = gbkPath.substring(1);
strtemp = strPath + File.separator + gbkPath;
if (callback != null)
if (!callback.test(gbkPath))
continue;
if (entry.isDirectory()) {
if (!FileUtils.makeDirectory(entryFile))
throw new IOException("Unable to make directory: " + entryFile);
} else {
if (!FileUtils.makeDirectory(entryFile.getAbsoluteFile().getParentFile()))
throw new IOException("Unable to make parent directory for file " + entryFile);
if (zipEnt.isDirectory()) {
File dir = new File(strtemp);
dir.mkdirs();
} else {
// create directories
String strsubdir = gbkPath;
for (int i = 0; i < strsubdir.length(); i++)
if (strsubdir.substring(i, i + 1).equalsIgnoreCase("/")) {
String temp = strPath + File.separator + strsubdir.substring(0, i);
File subdir = new File(temp);
if (!subdir.exists())
subdir.mkdir();
}
if (ignoreExistentFile && new File(strtemp).exists())
continue;
try (FileOutputStream fos = new FileOutputStream(new File(strtemp))) {
IOUtils.copyTo(zipFile, fos, buf);
}
if (ignoreExistentFile && entryFile.exists())
continue;
try (FileOutputStream fos = new FileOutputStream(entryFile)) {
IOUtils.copyTo(zipStream, fos, buf);
}
}
}

View File

@ -32,6 +32,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Constants.
@ -86,4 +87,11 @@ public final class Constants {
.registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory.INSTANCE)
.create();
public static <T> Predicate<T> truePredicate() {
return s -> true;
}
public static <T> Predicate<T> falsePredicate() {
return s -> false;
}
}