mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 21:16:30 +02:00
Better exception handling, progress system
This commit is contained in:
parent
905630cb2a
commit
3d28f0a674
@ -10,4 +10,23 @@ public class CLIHandler implements IUserInterface {
|
|||||||
@Override
|
@Override
|
||||||
public void show() {}
|
public void show() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submitProgress(InstallProgress progress) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (progress.hasProgress) {
|
||||||
|
sb.append('(');
|
||||||
|
sb.append(progress.progress);
|
||||||
|
sb.append('/');
|
||||||
|
sb.append(progress.progressTotal);
|
||||||
|
sb.append(") ");
|
||||||
|
}
|
||||||
|
sb.append(progress.message);
|
||||||
|
System.out.println(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeManager(Runnable task) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ public interface IUserInterface {
|
|||||||
|
|
||||||
public void handleException(Exception e);
|
public void handleException(Exception e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This might not exit straight away, return after calling this!
|
||||||
|
*/
|
||||||
public default void handleExceptionAndExit(Exception e) {
|
public default void handleExceptionAndExit(Exception e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
@ -13,4 +16,8 @@ public interface IUserInterface {
|
|||||||
|
|
||||||
public default void setTitle(String title) {};
|
public default void setTitle(String title) {};
|
||||||
|
|
||||||
|
public void submitProgress(InstallProgress progress);
|
||||||
|
|
||||||
|
public void executeManager(Runnable task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package link.infra.packwiz.installer;
|
||||||
|
|
||||||
|
public class InstallProgress {
|
||||||
|
public final String message;
|
||||||
|
public final boolean hasProgress;
|
||||||
|
public final int progress;
|
||||||
|
public final int progressTotal;
|
||||||
|
|
||||||
|
InstallProgress(String message) {
|
||||||
|
this.message = message;
|
||||||
|
hasProgress = false;
|
||||||
|
progress = 0;
|
||||||
|
progressTotal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallProgress(String message, int progress, int progressTotal) {
|
||||||
|
this.message = message;
|
||||||
|
hasProgress = true;
|
||||||
|
this.progress = progress;
|
||||||
|
this.progressTotal = progressTotal;
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,10 @@ import java.awt.Component;
|
|||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.GridBagConstraints;
|
import java.awt.GridBagConstraints;
|
||||||
import java.awt.GridBagLayout;
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
@ -14,13 +18,16 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.JProgressBar;
|
import javax.swing.JProgressBar;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
|
|
||||||
public class InstallWindow implements IUserInterface {
|
public class InstallWindow implements IUserInterface {
|
||||||
|
|
||||||
private JFrame frmPackwizlauncher;
|
private JFrame frmPackwizlauncher;
|
||||||
|
private JLabel lblProgresslabel;
|
||||||
|
private JProgressBar progressBar;
|
||||||
|
|
||||||
private String title = "Updating modpack...";
|
private String title = "Updating modpack...";
|
||||||
|
private SwingWorkerButWithPublicPublish<Void, InstallProgress> worker;
|
||||||
|
private AtomicBoolean aboutToCrash = new AtomicBoolean();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void show() {
|
public void show() {
|
||||||
@ -52,11 +59,11 @@ public class InstallWindow implements IUserInterface {
|
|||||||
frmPackwizlauncher.getContentPane().add(panel, BorderLayout.CENTER);
|
frmPackwizlauncher.getContentPane().add(panel, BorderLayout.CENTER);
|
||||||
panel.setLayout(new BorderLayout(0, 0));
|
panel.setLayout(new BorderLayout(0, 0));
|
||||||
|
|
||||||
JProgressBar progressBar = new JProgressBar();
|
progressBar = new JProgressBar();
|
||||||
progressBar.setValue(50);
|
progressBar.setIndeterminate(true);
|
||||||
panel.add(progressBar, BorderLayout.CENTER);
|
panel.add(progressBar, BorderLayout.CENTER);
|
||||||
|
|
||||||
JLabel lblProgresslabel = new JLabel("Loading...");
|
lblProgresslabel = new JLabel("Loading...");
|
||||||
panel.add(lblProgresslabel, BorderLayout.SOUTH);
|
panel.add(lblProgresslabel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
JPanel panel_1 = new JPanel();
|
JPanel panel_1 = new JPanel();
|
||||||
@ -75,8 +82,13 @@ public class InstallWindow implements IUserInterface {
|
|||||||
JButton btnCancel = new JButton("Cancel");
|
JButton btnCancel = new JButton("Cancel");
|
||||||
btnCancel.addActionListener(new ActionListener() {
|
btnCancel.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
//updateManager.cleanup();
|
if (worker != null) {
|
||||||
|
worker.cancel(true);
|
||||||
|
}
|
||||||
frmPackwizlauncher.dispose();
|
frmPackwizlauncher.dispose();
|
||||||
|
// TODO: show window to ask user what to do
|
||||||
|
System.out.println("Update process cancelled by user!");
|
||||||
|
System.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
btnCancel.setAlignmentX(Component.CENTER_ALIGNMENT);
|
btnCancel.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
@ -88,7 +100,23 @@ public class InstallWindow implements IUserInterface {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleException(Exception e) {
|
public void handleException(Exception e) {
|
||||||
JOptionPane.showMessageDialog(null, e.getMessage(), title, JOptionPane.ERROR_MESSAGE);
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
JOptionPane.showMessageDialog(null, e.getMessage(), title, JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleExceptionAndExit(Exception e) {
|
||||||
|
// Used to prevent the done() handler of SwingWorker executing if the invokeLater hasn't happened yet
|
||||||
|
aboutToCrash.set(true);
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
JOptionPane.showMessageDialog(null, e.getMessage(), title, JOptionPane.ERROR_MESSAGE);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -103,4 +131,57 @@ public class InstallWindow implements IUserInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submitProgress(InstallProgress progress) {
|
||||||
|
if (worker != null) {
|
||||||
|
worker.publishPublic(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeManager(Runnable task) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
worker = new SwingWorkerButWithPublicPublish<Void, InstallProgress>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground() throws Exception {
|
||||||
|
task.run();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void process(List<InstallProgress> chunks) {
|
||||||
|
// Only process last chunk
|
||||||
|
if (chunks.size() > 0) {
|
||||||
|
InstallProgress prog = chunks.get(chunks.size() - 1);
|
||||||
|
if (prog.hasProgress) {
|
||||||
|
progressBar.setIndeterminate(false);
|
||||||
|
progressBar.setValue(prog.progress);
|
||||||
|
progressBar.setMaximum(prog.progressTotal);
|
||||||
|
} else {
|
||||||
|
progressBar.setIndeterminate(true);
|
||||||
|
progressBar.setValue(0);
|
||||||
|
}
|
||||||
|
lblProgresslabel.setText(prog.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
if (aboutToCrash.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: a better way to do this?
|
||||||
|
frmPackwizlauncher.dispose();
|
||||||
|
System.out.println("Finished successfully!");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
worker.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package link.infra.packwiz.installer;
|
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.JOptionPane;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
@ -14,6 +19,31 @@ public class Main {
|
|||||||
// Actual main() is in RequiresBootstrap!
|
// Actual main() is in RequiresBootstrap!
|
||||||
|
|
||||||
public Main(String[] args) {
|
public Main(String[] args) {
|
||||||
|
// Big overarching try/catch just in case everything breaks
|
||||||
|
try {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// In case the eventqueue is broken, exit after 1 minute
|
||||||
|
try {
|
||||||
|
Thread.sleep(60 * 1000);
|
||||||
|
} catch (InterruptedException e1) {
|
||||||
|
// Good, it was already called?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startup(String[] args) {
|
||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
addNonBootstrapOptions(options);
|
addNonBootstrapOptions(options);
|
||||||
addBootstrapOptions(options);
|
addBootstrapOptions(options);
|
||||||
@ -34,7 +64,8 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IUserInterface ui;
|
IUserInterface ui;
|
||||||
if (cmd.hasOption("no-gui")) {
|
// if "headless", GUI creation will fail anyway!
|
||||||
|
if (cmd.hasOption("no-gui") || GraphicsEnvironment.isHeadless()) {
|
||||||
ui = new CLIHandler();
|
ui = new CLIHandler();
|
||||||
} else {
|
} else {
|
||||||
ui = new InstallWindow();
|
ui = new InstallWindow();
|
||||||
@ -43,8 +74,10 @@ public class Main {
|
|||||||
String[] unparsedArgs = cmd.getArgs();
|
String[] unparsedArgs = cmd.getArgs();
|
||||||
if (unparsedArgs.length > 1) {
|
if (unparsedArgs.length > 1) {
|
||||||
ui.handleExceptionAndExit(new RuntimeException("Too many arguments specified!"));
|
ui.handleExceptionAndExit(new RuntimeException("Too many arguments specified!"));
|
||||||
|
return;
|
||||||
} else if (unparsedArgs.length < 1) {
|
} else if (unparsedArgs.length < 1) {
|
||||||
ui.handleExceptionAndExit(new RuntimeException("URI to install from must be specified!"));
|
ui.handleExceptionAndExit(new RuntimeException("URI to install from must be specified!"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String title = cmd.getOptionValue("title");
|
String title = cmd.getOptionValue("title");
|
||||||
@ -52,18 +85,42 @@ public class Main {
|
|||||||
ui.setTitle(title);
|
ui.setTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
String side = cmd.getOptionValue("side");
|
|
||||||
if (side == null) {
|
|
||||||
side = "client";
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.show();
|
ui.show();
|
||||||
|
|
||||||
|
UpdateManager.Options uOptions = new UpdateManager.Options();
|
||||||
|
|
||||||
|
String side = cmd.getOptionValue("side");
|
||||||
|
if (side != null) {
|
||||||
|
uOptions.side = UpdateManager.Options.Side.from(side);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uOptions.downloadURI = new URI(unparsedArgs[0]);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
// TODO: better error message?
|
||||||
|
ui.handleExceptionAndExit(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start update process!
|
||||||
|
// TODO: start in SwingWorker?
|
||||||
|
try {
|
||||||
|
ui.executeManager(new Runnable(){
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
new UpdateManager(uOptions, ui);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO: better error message?
|
||||||
|
ui.handleExceptionAndExit(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by packwiz-installer-bootstrap to set up the help command
|
// Called by packwiz-installer-bootstrap to set up the help command
|
||||||
public static void addNonBootstrapOptions(Options options) {
|
public static void addNonBootstrapOptions(Options options) {
|
||||||
options.addOption("s", "side", true, "Side to install mods from (client/server, defaults to client)"); // TODO: implement
|
options.addOption("s", "side", true, "Side to install mods from (client/server, defaults to client)");
|
||||||
options.addOption(null, "title", true, "Title of the installer window");
|
options.addOption(null, "title", true, "Title of the installer window");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +130,7 @@ public class Main {
|
|||||||
options.addOption(null, "bootstrap-update-token", true, "Github API Access Token, for private repositories");
|
options.addOption(null, "bootstrap-update-token", true, "Github API Access Token, for private repositories");
|
||||||
options.addOption(null, "bootstrap-no-update", false, "Don't update packwiz-installer");
|
options.addOption(null, "bootstrap-no-update", false, "Don't update packwiz-installer");
|
||||||
options.addOption(null, "bootstrap-main-jar", true, "Location of the packwiz-installer JAR file");
|
options.addOption(null, "bootstrap-main-jar", true, "Location of the packwiz-installer JAR file");
|
||||||
options.addOption("g", "no-gui", false, "Don't display a GUI to show update progress"); // TODO: implement
|
options.addOption("g", "no-gui", false, "Don't display a GUI to show update progress");
|
||||||
options.addOption("h", "help", false, "Display this message"); // Implemented in packwiz-installer-bootstrap!
|
options.addOption("h", "help", false, "Display this message"); // Implemented in packwiz-installer-bootstrap!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package link.infra.packwiz.installer;
|
||||||
|
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
|
// Q: AAA WHAT HAVE YOU DONE THIS IS DISGUSTING
|
||||||
|
// A: it just makes things easier, so i can easily have one interface for CLI/GUI
|
||||||
|
// if someone has a better way to do this please PR it
|
||||||
|
public abstract class SwingWorkerButWithPublicPublish<T,V> extends SwingWorker<T,V> {
|
||||||
|
@SafeVarargs
|
||||||
|
public final void publishPublic(V... chunks) {
|
||||||
|
publish(chunks);
|
||||||
|
}
|
||||||
|
}
|
@ -10,14 +10,79 @@ public class UpdateManager {
|
|||||||
public static class Options {
|
public static class Options {
|
||||||
public URI downloadURI;
|
public URI downloadURI;
|
||||||
public String manifestFile = "packwiz.json";
|
public String manifestFile = "packwiz.json";
|
||||||
|
public Side side = Side.CLIENT;
|
||||||
|
|
||||||
|
public static enum Side {
|
||||||
|
CLIENT("client"), SERVER("server"), BOTH("both", new Side[] { CLIENT, SERVER });
|
||||||
|
|
||||||
|
private final String sideName;
|
||||||
|
private final Side[] depSides;
|
||||||
|
|
||||||
|
Side(String sideName) {
|
||||||
|
this.sideName = sideName.toLowerCase();
|
||||||
|
this.depSides = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Side(String sideName, Side[] depSides) {
|
||||||
|
this.sideName = sideName.toLowerCase();
|
||||||
|
this.depSides = depSides;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.sideName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasSide(Side tSide) {
|
||||||
|
if (this.equals(tSide)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this.depSides != null) {
|
||||||
|
for (int i = 0; i < this.depSides.length; i++) {
|
||||||
|
if (this.depSides[i].equals(tSide)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Side from(String name) {
|
||||||
|
String lowerName = name.toLowerCase();
|
||||||
|
for (Side side : Side.values()) {
|
||||||
|
if (side.sideName == lowerName) {
|
||||||
|
return side;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateManager(Options opts, IUserInterface ui) {
|
public UpdateManager(Options opts, IUserInterface ui) {
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
this.ui = ui;
|
this.ui = ui;
|
||||||
|
this.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup() {
|
protected void start() {
|
||||||
|
ui.submitProgress(new InstallProgress("Loading pack file..."));
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Big oof
|
||||||
|
}
|
||||||
|
ui.submitProgress(new InstallProgress("Loading metadata", 1, 2));
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Big oof
|
||||||
|
}
|
||||||
|
ui.submitProgress(new InstallProgress("Loading magic", 2, 2));
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Big oof
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user