diff --git a/src/main/java/se/lantz/gui/MenuManager.java b/src/main/java/se/lantz/gui/MenuManager.java index c08264e..76feac4 100644 --- a/src/main/java/se/lantz/gui/MenuManager.java +++ b/src/main/java/se/lantz/gui/MenuManager.java @@ -46,9 +46,9 @@ import se.lantz.gui.install.VersionDownloadDialog; import se.lantz.manager.BackupManager; import se.lantz.manager.ExportManager; import se.lantz.manager.ImportManager; -import se.lantz.manager.PCUAEInstallManager; import se.lantz.manager.RestoreManager; import se.lantz.manager.SavedStatesManager; +import se.lantz.manager.pcuae.PCUAEInstallManager; import se.lantz.model.MainViewModel; import se.lantz.model.data.GameListData; import se.lantz.model.data.GameView; diff --git a/src/main/java/se/lantz/gui/install/PCUAEVersionDownloadDialog.java b/src/main/java/se/lantz/gui/install/PCUAEVersionDownloadDialog.java index bb48aab..61d1e7e 100644 --- a/src/main/java/se/lantz/gui/install/PCUAEVersionDownloadDialog.java +++ b/src/main/java/se/lantz/gui/install/PCUAEVersionDownloadDialog.java @@ -4,7 +4,7 @@ import java.awt.Dimension; import java.awt.Frame; import se.lantz.gui.BaseDialog; -import se.lantz.manager.PCUAEInstallManager; +import se.lantz.manager.pcuae.PCUAEInstallManager; public class PCUAEVersionDownloadDialog extends BaseDialog { diff --git a/src/main/java/se/lantz/manager/PCUAEInstallManager.java b/src/main/java/se/lantz/manager/pcuae/BaseInstallManger.java similarity index 55% rename from src/main/java/se/lantz/manager/PCUAEInstallManager.java rename to src/main/java/se/lantz/manager/pcuae/BaseInstallManger.java index 3e13aff..eb5c2b8 100644 --- a/src/main/java/se/lantz/manager/PCUAEInstallManager.java +++ b/src/main/java/se/lantz/manager/pcuae/BaseInstallManger.java @@ -1,4 +1,4 @@ -package se.lantz.manager; +package se.lantz.manager.pcuae; import java.awt.AWTEvent; import java.awt.Toolkit; @@ -19,8 +19,6 @@ import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; @@ -33,89 +31,75 @@ import dyorgio.runtime.out.process.CallableSerializable; import dyorgio.runtime.run.as.root.RootExecutor; import se.lantz.gui.MainWindow; import se.lantz.gui.download.DownloadDialog; -import se.lantz.gui.install.PCUAEVersionDownloadDialog; import se.lantz.util.ExceptionHandler; -public class PCUAEInstallManager implements AWTEventListener +public abstract class BaseInstallManger implements AWTEventListener { public static final String INSTALL_FOLDER = "./pcuae-install/"; + private boolean blockEvents = false; - private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); + protected ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); - private static String latestVersion = ""; - private static String tagloadUrl = ""; - private String downloadUrl = ""; - private String pcuaeMainInstallFile = ""; - private static String pcuaeLatestInInstallFolder = ""; - private static String latestReleaseDescription = ""; + protected volatile boolean downloadIterrupted = false; - private JMenuItem exportMenuItem; - private volatile boolean downloadIterrupted = false; - - public PCUAEInstallManager(JMenuItem exportMenuItem) + public BaseInstallManger() { - this.exportMenuItem = exportMenuItem; Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); } - public void installPCUAE() + @Override + public void eventDispatched(AWTEvent event) { - readVersionFromInstallFolder(); - if (isNewVersionAvailable()) + if (blockEvents) { - askAndStartDownload(pcuaeLatestInInstallFolder.isEmpty()); - } - else - { - askToInstallExistingVersion(); + if (event instanceof InputEvent) + { + ((InputEvent) event).consume(); + } + else if (event instanceof MouseEvent) + { + ((MouseEvent) event).consume(); + } } } - private void askAndStartDownload(boolean firstDownload) + public void switchToBusyCursor(final javax.swing.JFrame frame) { - PCUAEVersionDownloadDialog dialog = new PCUAEVersionDownloadDialog(MainWindow.getInstance(), firstDownload); - dialog.pack(); - dialog.setLocationRelativeTo(MainWindow.getInstance()); - if (dialog.showDialog()) - { - downloadLatestPCUAE(); - } - else if (!firstDownload) - { - askToInstallExistingVersion(); - } + startEventTrap(frame); + frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); } - private void askToInstallExistingVersion() + public void switchToNormalCursor(final javax.swing.JFrame frame) { - int value = JOptionPane.showConfirmDialog(MainWindow.getInstance(), - "Do you want to install PCUAE (" + pcuaeMainInstallFile + ") now?", - "Install PCUAE", - JOptionPane.YES_NO_OPTION); - if (value == JOptionPane.YES_OPTION) - { - singleThreadExecutor.execute(() -> runAndWaitForInstallation()); - } + frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); + stopEventTrap(frame); } - private boolean isNewVersionAvailable() + protected void startEventTrap(javax.swing.JFrame frame) { - fetchLatestPCUAEVersionFromGithub(); - return !pcuaeLatestInInstallFolder.equals(pcuaeMainInstallFile); + blockEvents = true; + frame.getGlassPane().setVisible(true); } - private void readVersionFromInstallFolder() + protected void stopEventTrap(javax.swing.JFrame frame) { - pcuaeLatestInInstallFolder = ""; + blockEvents = false; + java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue(); + frame.getGlassPane().setVisible(false); + } + + protected String readVersionFromInstallFolder(String installFileName) + { + String latestInInstallFolder = ""; FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File f, String name) { - return name.endsWith(".exe"); + return name.contains(installFileName) && name.endsWith(".exe"); } }; File installFolder = new File(INSTALL_FOLDER); @@ -134,94 +118,21 @@ public class PCUAEInstallManager implements AWTEventListener if (latestFile != null) { - pcuaeLatestInInstallFolder = latestFile.getName(); + latestInInstallFolder = latestFile.getName(); } + return latestInInstallFolder; } - private void runAndWaitForInstallation() - { - switchToBusyCursor(MainWindow.getInstance()); - RootExecutor rootExecutor; - try - { - rootExecutor = new RootExecutor("-Xmx64m"); - // Execute privileged action without return - CallableSerializable installCallable = new InstallCallable(pcuaeMainInstallFile); - int value = rootExecutor.call(installCallable); - - //0 -> installed - //255 -> aborted - if (value == 0) - { - launchExportDialog(); - } - } - catch (Exception e1) - { - ExceptionHandler.logException(e1, "Could not execute RootExecutor"); - } - finally - { - SwingUtilities.invokeLater(() -> switchToNormalCursor(MainWindow.getInstance())); - } - } - - private void launchExportDialog() - { - SwingUtilities.invokeLater(() -> exportMenuItem.doClick()); - } - - public void switchToBusyCursor(final javax.swing.JFrame frame) - { - startEventTrap(frame); - frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); - } - - public void switchToNormalCursor(final javax.swing.JFrame frame) - { - frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); - stopEventTrap(frame); - } - - private void startEventTrap(javax.swing.JFrame frame) - { - blockEvents = true; - frame.getGlassPane().setVisible(true); - } - - private void stopEventTrap(javax.swing.JFrame frame) - { - blockEvents = false; - java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue(); - frame.getGlassPane().setVisible(false); - } - - @Override - public void eventDispatched(AWTEvent event) - { - if (blockEvents) - { - if (event instanceof InputEvent) - { - ((InputEvent) event).consume(); - } - else if (event instanceof MouseEvent) - { - ((MouseEvent) event).consume(); - } - } - - } - - public void fetchLatestPCUAEVersionFromGithub() + public GithubAssetInformation fetchLatestVersionFromGithub(String assetsName) { + GithubAssetInformation githubInfo = new GithubAssetInformation(); try { //TODO: To get all releases, use "https://CommodoreOS@api.github.com/repos/CommodoreOS/PCUAE/releases"- - //How to handle mode packs? - + //Get all releases, check which one contains the latest file with assetName (part of the name) + URL url = new URL("https://CommodoreOS@api.github.com/repos/CommodoreOS/PCUAE/releases/latest"); - + HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("accept", "application/vnd.github.v3+json"); con.setRequestMethod("GET"); @@ -238,57 +149,50 @@ public class PCUAEInstallManager implements AWTEventListener reader.setLenient(true); JsonElement root = new JsonParser().parse(reader); JsonObject jsonObject = root.getAsJsonObject(); - latestVersion = jsonObject.get("tag_name").getAsString(); - tagloadUrl = jsonObject.get("html_url").getAsString(); - downloadUrl = jsonObject.get("assets").getAsJsonArray().get(0).getAsJsonObject() - .get("browser_download_url").getAsString(); - latestReleaseDescription = jsonObject.get("body").getAsString(); - - pcuaeMainInstallFile = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1); + githubInfo.setLatestVersion(jsonObject.get("tag_name").getAsString()); + githubInfo.setReleaseTagUrl(jsonObject.get("html_url").getAsString()); + //TODO: fix + String downloadUrl = + jsonObject.get("assets").getAsJsonArray().get(0).getAsJsonObject().get("browser_download_url").getAsString(); + githubInfo.setDownloadUrl(downloadUrl); + githubInfo.setInstallFile(downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1)); } catch (IOException ex) { ExceptionHandler.handleException(ex, "Could not check version"); } + return githubInfo; } - private void downloadLatestPCUAE() + protected void runAndWaitForInstallation(String fileToInstall) { - DownloadDialog progressDialog = new DownloadDialog("Downloading PCUAE version " + latestVersion); - singleThreadExecutor.execute(() -> startDownload(progressDialog)); - progressDialog.pack(); - progressDialog.setLocationRelativeTo(MainWindow.getInstance()); - if (progressDialog.showDialog()) + switchToBusyCursor(MainWindow.getInstance()); + RootExecutor rootExecutor; + try { - pcuaeLatestInInstallFolder = pcuaeMainInstallFile; - int value = - JOptionPane.showConfirmDialog(MainWindow.getInstance(), - "Download completed, do you want to install PCUAE " + latestVersion + " now?", - "Download Complete", - JOptionPane.YES_NO_OPTION); - if (value == JOptionPane.YES_OPTION) + rootExecutor = new RootExecutor("-Xmx64m"); + // Execute privileged action without return + CallableSerializable installCallable = new InstallCallable(fileToInstall); + int value = rootExecutor.call(installCallable); + + //0 -> installed + //255 -> aborted + if (value == 0) { - singleThreadExecutor.execute(() -> runAndWaitForInstallation()); + executeAfterInstallation(); } } - else + catch (Exception e1) { - downloadIterrupted = true; - //Make sure this executes after the downloading has been interrupted - singleThreadExecutor.execute(() -> { - try - { - Files.deleteIfExists(new File(INSTALL_FOLDER + pcuaeMainInstallFile).toPath()); - } - catch (IOException e) - { - ExceptionHandler.handleException(e, "Could not delete partially downloaded file"); - } - }); + ExceptionHandler.logException(e1, "Could not execute RootExecutor"); + } + finally + { + SwingUtilities.invokeLater(() -> switchToNormalCursor(MainWindow.getInstance())); } } - public void startDownload(final DownloadDialog downloadDialog) + public void startDownload(final DownloadDialog downloadDialog, GithubAssetInformation assetInfo) { downloadIterrupted = false; JProgressBar progressBar = downloadDialog.getProgressBar(); @@ -296,13 +200,13 @@ public class PCUAEInstallManager implements AWTEventListener URL url; try { - url = new URL(downloadUrl); + url = new URL(assetInfo.getDownloadUrl()); Files.createDirectories(new File(INSTALL_FOLDER).toPath()); HttpURLConnection httpConnection = (HttpURLConnection) (url.openConnection()); long completeFileSize = httpConnection.getContentLength(); BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream()); - FileOutputStream fos = new FileOutputStream(INSTALL_FOLDER + pcuaeMainInstallFile); + FileOutputStream fos = new FileOutputStream(INSTALL_FOLDER + assetInfo.getInstallFile()); BufferedOutputStream bout = new BufferedOutputStream(fos, 1024); byte[] data = new byte[1024]; long downloadedFileSize = 0; @@ -337,23 +241,21 @@ public class PCUAEInstallManager implements AWTEventListener } } - public static String getLatestInInstallFolder() + protected void cleanupInterruptedDownload(String fileName) { - return pcuaeLatestInInstallFolder; + downloadIterrupted = true; + //Make sure this executes after the downloading has been interrupted + singleThreadExecutor.execute(() -> { + try + { + Files.deleteIfExists(new File(INSTALL_FOLDER + fileName).toPath()); + } + catch (IOException e) + { + ExceptionHandler.handleException(e, "Could not delete partially downloaded file"); + } + }); } - public static String getLatestVersion() - { - return latestVersion; - } - - public static String getDownloadUrl() - { - return tagloadUrl; - } - - public static String getLatestReleaseDescription() - { - return latestReleaseDescription; - } + protected abstract void executeAfterInstallation(); } diff --git a/src/main/java/se/lantz/manager/pcuae/GithubAssetInformation.java b/src/main/java/se/lantz/manager/pcuae/GithubAssetInformation.java new file mode 100644 index 0000000..a16dddf --- /dev/null +++ b/src/main/java/se/lantz/manager/pcuae/GithubAssetInformation.java @@ -0,0 +1,54 @@ +package se.lantz.manager.pcuae; + +public class GithubAssetInformation +{ + String latestVersion = ""; + String releaseTagUrl = ""; + String downloadUrl = ""; + String installFile = ""; + + public GithubAssetInformation() + { + } + + public String getLatestVersion() + { + return latestVersion; + } + + public void setLatestVersion(String latestVersion) + { + this.latestVersion = latestVersion; + } + + public String getReleaseTagUrl() + { + return releaseTagUrl; + } + + public void setReleaseTagUrl(String releaseTagUrl) + { + this.releaseTagUrl = releaseTagUrl; + } + + public String getDownloadUrl() + { + return downloadUrl; + } + + public void setDownloadUrl(String downloadUrl) + { + this.downloadUrl = downloadUrl; + } + + public String getInstallFile() + { + return installFile; + } + + public void setInstallFile(String installFile) + { + this.installFile = installFile; + } + +} diff --git a/src/main/java/se/lantz/manager/InstallCallable.java b/src/main/java/se/lantz/manager/pcuae/InstallCallable.java similarity index 97% rename from src/main/java/se/lantz/manager/InstallCallable.java rename to src/main/java/se/lantz/manager/pcuae/InstallCallable.java index bcd44e5..d12495a 100644 --- a/src/main/java/se/lantz/manager/InstallCallable.java +++ b/src/main/java/se/lantz/manager/pcuae/InstallCallable.java @@ -1,4 +1,4 @@ -package se.lantz.manager; +package se.lantz.manager.pcuae; import java.io.File; import java.io.IOException; diff --git a/src/main/java/se/lantz/manager/pcuae/PCUAEInstallManager.java b/src/main/java/se/lantz/manager/pcuae/PCUAEInstallManager.java new file mode 100644 index 0000000..2f105a9 --- /dev/null +++ b/src/main/java/se/lantz/manager/pcuae/PCUAEInstallManager.java @@ -0,0 +1,128 @@ +package se.lantz.manager.pcuae; + +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import se.lantz.gui.MainWindow; +import se.lantz.gui.download.DownloadDialog; +import se.lantz.gui.install.PCUAEVersionDownloadDialog; +import se.lantz.util.ManagerVersionChecker; + +public class PCUAEInstallManager extends BaseInstallManger +{ + public static final String INSTALL_FOLDER = "./pcuae-install/"; + + private static final String PCUAE_INSTALL_NAME = "pcuae"; + +// private static final String AMIGA_MODE_INSTALL_NAME = "amiga"; +// private static final String ATARI_MODE_INSTALL_NAME = "atari"; +// private static final String LINUX_MODE_INSTALL_NAME = "linux"; +// private static final String RETROARCH_MODE_INSTALL_NAME = "retroarch"; +// private static final String VICE_MODE_INSTALL_NAME = "vice"; + + private static String pcuaeLatestInInstallFolder = ""; + + private static GithubAssetInformation gitHubReleaseInformation = new GithubAssetInformation(); + + private JMenuItem exportMenuItem; + + public PCUAEInstallManager(JMenuItem exportMenuItem) + { + this.exportMenuItem = exportMenuItem; + } + + public void installPCUAE() + { + pcuaeLatestInInstallFolder = readVersionFromInstallFolder(PCUAE_INSTALL_NAME); + if (isNewVersionAvailable()) + { + askAndStartDownload(pcuaeLatestInInstallFolder.isEmpty()); + } + else + { + askToInstallExistingVersion(); + } + } + + private void askAndStartDownload(boolean firstDownload) + { + PCUAEVersionDownloadDialog dialog = new PCUAEVersionDownloadDialog(MainWindow.getInstance(), firstDownload); + dialog.pack(); + dialog.setLocationRelativeTo(MainWindow.getInstance()); + if (dialog.showDialog()) + { + downloadLatestPCUAE(); + } + else if (!firstDownload) + { + askToInstallExistingVersion(); + } + } + + private void askToInstallExistingVersion() + { + int value = JOptionPane.showConfirmDialog(MainWindow.getInstance(), + "Do you want to install PCUAE (" + pcuaeLatestInInstallFolder + ") now?", + "Install PCUAE", + JOptionPane.YES_NO_OPTION); + if (value == JOptionPane.YES_OPTION) + { + singleThreadExecutor.execute(() -> runAndWaitForInstallation(pcuaeLatestInInstallFolder)); + } + } + + private boolean isNewVersionAvailable() + { + gitHubReleaseInformation = fetchLatestVersionFromGithub(PCUAE_INSTALL_NAME); + return ManagerVersionChecker.getIntVersion(pcuaeLatestInInstallFolder) < ManagerVersionChecker + .getIntVersion(gitHubReleaseInformation.getInstallFile()); + } + + @Override + protected void executeAfterInstallation() + { + SwingUtilities.invokeLater(() -> exportMenuItem.doClick()); + } + + private void downloadLatestPCUAE() + { + DownloadDialog progressDialog = + new DownloadDialog("Downloading PCUAE version " + gitHubReleaseInformation.getLatestVersion()); + singleThreadExecutor.execute(() -> startDownload(progressDialog, gitHubReleaseInformation)); + progressDialog.pack(); + progressDialog.setLocationRelativeTo(MainWindow.getInstance()); + if (progressDialog.showDialog()) + { + pcuaeLatestInInstallFolder = gitHubReleaseInformation.getInstallFile(); + int value = JOptionPane.showConfirmDialog(MainWindow.getInstance(), + "Download completed, do you want to install PCUAE " + + gitHubReleaseInformation.getLatestVersion() + " now?", + "Download Complete", + JOptionPane.YES_NO_OPTION); + if (value == JOptionPane.YES_OPTION) + { + singleThreadExecutor.execute(() -> runAndWaitForInstallation(pcuaeLatestInInstallFolder)); + } + } + else + { + cleanupInterruptedDownload(gitHubReleaseInformation.getInstallFile()); + } + } + + public static String getLatestInInstallFolder() + { + return pcuaeLatestInInstallFolder; + } + + public static String getLatestVersion() + { + return gitHubReleaseInformation.getLatestVersion(); + } + + public static String getDownloadUrl() + { + return gitHubReleaseInformation.getDownloadUrl(); + } +} diff --git a/src/main/java/se/lantz/util/ManagerVersionChecker.java b/src/main/java/se/lantz/util/ManagerVersionChecker.java index f6ef02a..6ce28fa 100644 --- a/src/main/java/se/lantz/util/ManagerVersionChecker.java +++ b/src/main/java/se/lantz/util/ManagerVersionChecker.java @@ -15,10 +15,15 @@ import java.nio.file.StandardCopyOption; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -29,6 +34,7 @@ import se.lantz.gui.download.DownloadDialog; public class ManagerVersionChecker { + private static final Logger logger = LoggerFactory.getLogger(FileManager.class); public static final String TEMP_FOLDER = "./temp/"; private static String latestVersion = ""; private static String tagloadUrl = ""; @@ -178,8 +184,31 @@ public class ManagerVersionChecker public static boolean isNewVersionAvailable() { - //Ignore all versions that starts with 1 - return !latestVersion.startsWith("1") && !FileManager.getPcuVersionFromManifest().equals(latestVersion); + logger.debug("Manifest version=" + FileManager.getPcuVersionFromManifest()); + //Ignore versions starting with 1, the comparison does not work well with that. + //Once 2.x is available it will be calculated correctly + if (latestVersion.startsWith("1")) + { + return false; + } + return getIntVersion(FileManager.getPcuVersionFromManifest()) < getIntVersion(latestVersion); + } + + public static int getIntVersion(String versionString) + { + //Regular expression to match digits in a string + String regex = "\\d+"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(versionString); + String numbers = ""; + while(matcher.find()) { + numbers = numbers + matcher.group(); + } + if (numbers.isEmpty()) + { + return 0; + } + return Integer.parseInt(numbers); } public static String getLatestVersion()