From e023516629c825f8de96482da8e9e5fe7277aa85 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sat, 13 Jul 2024 13:07:03 -0400 Subject: [PATCH] Initial commit --- .gitattributes | 9 + .github/workflows/build.yml | 62 ++++ .github/workflows/release.yml | 123 +++++++ .gitignore | 26 ++ CaDoodleUpdater/.gitignore | 1 + CaDoodleUpdater/build.gradle | 66 ++++ .../com/commonwealthrobotics/JvmManager.java | 258 ++++++++++++++ .../LatestFromGithubLaunchUI.java | 332 ++++++++++++++++++ .../com/commonwealthrobotics/Listener.java | 5 + .../java/com/commonwealthrobotics/Main.java | 42 +++ .../ProcessInputStream.java | 69 ++++ .../com/commonwealthrobotics/ui.fxml | 105 ++++++ README.md | 50 +++ SourceIcon.png | Bin 0 -> 6090906 bytes gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 245 +++++++++++++ gradlew.bat | 92 +++++ package-linux_x64.sh | 118 +++++++ package-macos.sh | 80 +++++ package-windows_x86_64.sh | 91 +++++ settings.gradle | 16 + 22 files changed, 1796 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 CaDoodleUpdater/.gitignore create mode 100644 CaDoodleUpdater/build.gradle create mode 100644 CaDoodleUpdater/src/main/java/com/commonwealthrobotics/JvmManager.java create mode 100644 CaDoodleUpdater/src/main/java/com/commonwealthrobotics/LatestFromGithubLaunchUI.java create mode 100644 CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Listener.java create mode 100644 CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Main.java create mode 100644 CaDoodleUpdater/src/main/java/com/commonwealthrobotics/ProcessInputStream.java create mode 100644 CaDoodleUpdater/src/main/resources/com/commonwealthrobotics/ui.fxml create mode 100644 README.md create mode 100644 SourceIcon.png create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 package-linux_x64.sh create mode 100644 package-macos.sh create mode 100644 package-windows_x86_64.sh create mode 100644 settings.gradle diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..097f9f9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..57adb2d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,62 @@ +# test +name: Test package +on: + push: + +jobs: + linux: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Build + run: bash package-linux_x64.sh + - name: Upload math result for job Linux + uses: actions/upload-artifact@v3 + with: + name: linux-lib + path: release/* + + windows: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + - uses: ilammy/msvc-dev-cmd@v1 + - uses: microsoft/setup-msbuild@v1.1 + - uses: milliewalky/setup-7-zip@v1 + - name: Install ImageMagick + run: choco install imagemagick -y + shell: powershell + - name: Build + run: bash package-windows_x86_64.sh + - name: Upload math result for job Windows + uses: actions/upload-artifact@v3 + with: + name: win-lib + path: release/* + macos-arm: + runs-on: macos-14 + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Build + run: bash package-macos.sh + - name: Upload math result for job Mac + uses: actions/upload-artifact@v3 + with: + name: mac-lib-arm + path: release/* + macos: + runs-on: macos-13 + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Build + run: bash package-macos.sh + - name: Upload math result for job Mac + uses: actions/upload-artifact@v3 + with: + name: mac-lib-x86 + path: release/* + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..62972e0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,123 @@ +# test +name: Publish package to GitHub Packages +on: + push: + tags: + - '*' + +jobs: + linux: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Build + env: + VERSION_SEMVER: ${{ steps.vars.outputs.tag }} + run: bash package-linux_x64.sh + - name: Upload math result for job Linux + uses: actions/upload-artifact@v3 + with: + name: linux-lib + path: release/* + + windows: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + - uses: ilammy/msvc-dev-cmd@v1 + - uses: microsoft/setup-msbuild@v1.1 + - uses: milliewalky/setup-7-zip@v1 + - name: Build + env: + VERSION_SEMVER: ${{ steps.vars.outputs.tag }} + run: bash package-windows_x86_64.sh + - name: Upload math result for job Windows + uses: actions/upload-artifact@v3 + with: + name: win-lib + path: release/* + macos-arm: + runs-on: macos-14 + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Build + env: + VERSION_SEMVER: ${{ steps.vars.outputs.tag }} + run: bash package-macos.sh + - name: Upload math result for job Mac + uses: actions/upload-artifact@v3 + with: + name: mac-lib-arm + path: release/* + macos: + runs-on: macos-13 + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Build + env: + VERSION_SEMVER: ${{ steps.vars.outputs.tag }} + run: bash package-macos.sh + - name: Upload math result for job Mac + uses: actions/upload-artifact@v3 + with: + name: mac-lib-x86 + path: release/* + publish: + runs-on: ubuntu-latest + needs: [macos,windows,linux,macos-arm] + permissions: + contents: write + packages: write + steps: + - uses: actions/checkout@v3 + - name: Set output + id: vars + run: echo ::set-output name=tag::${GITHUB_REF#refs/*/} + - name: Check output + env: + VERSION_SEMVER: ${{ steps.vars.outputs.tag }} + run: | + echo $VERSION_SEMVER + echo ${{ steps.vars.outputs.tag }} + - name: Download math result for job Windows + uses: actions/download-artifact@v3 + with: + name: win-lib + path: . + - name: Download math result for job Linux + uses: actions/download-artifact@v3 + with: + name: linux-lib + path: . + - name: Download math result for job Mac-arm + uses: actions/download-artifact@v3 + with: + name: mac-lib-arm + path: . + - name: Download math result for job Mac-x86 + uses: actions/download-artifact@v3 + with: + name: mac-lib-x86 + path: . + - name: Check downloads + run: | + echo "Downloads:" + ls -als + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + CaDoodle-Linux-x86_64.AppImage + CaDoodle-Linux-x86_64.deb + CaDoodle-Windows-x86_64.exe + CaDoodle-Windows-x86_64.zip + CaDoodle-MacOS-x86_64.dmg + CaDoodle-MacOS-arm64.dmg + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7511b35 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build + +.settings +.project +**.class** +/BowlerStudioUpdater/ +/BowlerStudioUpdater.AppDir/ +**.AppImage** +**.classpath** +/input/ +/temp*/ +/BowlerLauncher*.* +/BowlerLauncher/ +HatRack* +/zulu*.zip* +/zulu*.tar* +**.deb +release +**.DS_Store** +**AppDir** +CaDoodle +/CaDoodle.png diff --git a/CaDoodleUpdater/.gitignore b/CaDoodleUpdater/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/CaDoodleUpdater/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/CaDoodleUpdater/build.gradle b/CaDoodleUpdater/build.gradle new file mode 100644 index 0000000..9e969ad --- /dev/null +++ b/CaDoodleUpdater/build.gradle @@ -0,0 +1,66 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java library project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/8.1.1/userguide/building_java_projects.html + */ +buildscript { + repositories { + gradlePluginPortal() + } + dependencies { + classpath 'com.github.johnrengelman:shadow:8.1.1' + } +} + +apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: 'java' +apply plugin: 'application' +apply plugin: 'eclipse' + + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use JUnit Jupiter for testing. + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1' + + // This dependency is used internally, and not exposed to consumers on their own compile classpath. + implementation 'com.google.guava:guava:31.1-jre' + implementation 'com.google.code.gson:gson:2.8.6' + implementation 'org.apache.commons:commons-compress:1.26.2' +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +tasks.named('test') { + // Use JUnit Platform for unit tests. + useJUnitPlatform() +} +application { + // Define the main class for the application. + mainClass = 'com.commonwealthrobotics.Main' +} + +shadowJar { + archiveBaseName.set('CaDoodleUpdater') + archiveClassifier.set('') + archiveVersion.set('') + } +jar { + manifest { + attributes 'Implementation-Title': 'BowlerStudioUpdater', + 'Implementation-Version': '0.0.1', + 'Main-Class': 'com.commonwealthrobotics.Main' + + } +} diff --git a/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/JvmManager.java b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/JvmManager.java new file mode 100644 index 0000000..dc2f9b1 --- /dev/null +++ b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/JvmManager.java @@ -0,0 +1,258 @@ +package com.commonwealthrobotics; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.lang.reflect.Type; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +//import java.util.zip.ZipEntry; +//import java.util.zip.ZipFile; + +import org.apache.commons.compress.archivers.examples.Archiver; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarUtils; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.commons.io.FilenameUtils; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import javafx.application.Platform; +import javafx.scene.control.ProgressBar; + +public class JvmManager { + + public static String getCommandString(String project, String repo, String version, String downloadJsonURL, + long sizeOfJson, ProgressBar progress, String bindir) throws Exception { + if(version==null) + version="0.0.1"; + File exe; + + exe= download(version, downloadJsonURL, sizeOfJson, progress, bindir, "jvm.json"); + Type TT_mapStringString = new TypeToken>() { + }.getType(); + // chreat the gson object, this is the parsing factory + Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); + String jsonText = Files.readString(exe.toPath()); + + HashMap database = gson.fromJson(jsonText, TT_mapStringString); + String key = "UNKNOWN"; + key = discoverKey(key); + Map vm = (Map) database.get(key); + String baseURL = vm.get("url").toString(); + String type = vm.get("type").toString(); + String name = vm.get("name").toString(); + List jvmargs = null; + Object o = vm.get("jvmargs"); + if (o != null) + jvmargs = (List) o; + else + jvmargs = new ArrayList(); + String jvmURL = baseURL + name + "." + type; + File jvmArchive = download("", jvmURL, 185000000, progress, bindir, name + "." + type); + File dest = new File(bindir + name); + if (!dest.exists()) { + if (type.toLowerCase().contains("zip")) { + try { + unzip(jvmArchive, bindir); + }catch(java.util.zip.ZipException ex) { + System.out.println("Failed the extract, erasing and re-downloading"); + jvmArchive.delete(); + ex.printStackTrace(); + return getCommandString(project, repo, version, downloadJsonURL, + sizeOfJson, progress, bindir); + } + } + if (type.toLowerCase().contains("tar.gz")) { + untar(jvmArchive, bindir); + } + } else { + System.out.println("Not extraction, VM exists " + dest.getAbsolutePath()); + } + String cmd = bindir + name + "/bin/java" + (LatestFromGithubLaunchUI.isWin() ? ".exe" : "") + " "; + for (String s : jvmargs) { + cmd += s + " "; + } + return cmd + " -jar "; + } + + private static String discoverKey(String key) { + if (LatestFromGithubLaunchUI.isLin()) { + if (LatestFromGithubLaunchUI.isArm()) { + key = "Linux-aarch64"; + } else { + key = "Linux-x64"; + } + } + + if (LatestFromGithubLaunchUI.isMac()) { + if (LatestFromGithubLaunchUI.isArm()) { + key = "Mac-aarch64"; + } else { + key = "Mac-x64"; + } + } + if (LatestFromGithubLaunchUI.isWin()) { + if (LatestFromGithubLaunchUI.isArm()) { + key = "UNKNOWN"; + } else { + key = "Windows-x64"; + } + } + return key; + } + + public static boolean isExecutable(ZipArchiveEntry entry) { + int unixMode = entry.getUnixMode(); + // Check if any of the executable bits are set for user, group, or others. + // User executable: 0100 (0x40), Group executable: 0010 (0x10), Others + // executable: 0001 (0x01) + return (unixMode & 0x49) != 0; + } + + private static void unzip(File path, String dir) throws Exception { + String fileBaseName = FilenameUtils.getBaseName(path.getName().toString()); + Path destFolderPath = new File(dir).toPath(); + + try (ZipFile zipFile = ZipFile.builder().setFile(path).get()) { + Enumeration entries = zipFile.getEntries(); + while (entries.hasMoreElements()) { + ZipArchiveEntry entry = entries.nextElement(); + Path entryPath = destFolderPath.resolve(entry.getName()); + if (entryPath.normalize().startsWith(destFolderPath.normalize())) { + if (entry.isDirectory()) { + Files.createDirectories(entryPath); + } else { + Files.createDirectories(entryPath.getParent()); + try (InputStream in = zipFile.getInputStream(entry)) { + try { + // ar.setExternalAttributes(entry.extraAttributes); + if (entry.isUnixSymlink()) { + String text = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) + .lines().collect(Collectors.joining("\n")); + Path target = Paths.get(".", text); + System.out.println("Creating symlink " + entryPath + " with " + target); + + Files.createSymbolicLink(entryPath, target); + continue; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + try (OutputStream out = new FileOutputStream(entryPath.toFile())) { + IOUtils.copy(in, out); + } + if (isExecutable(entry)) { + entryPath.toFile().setExecutable(true); + } + } + } + } + } + } + } + + private static void untar(File tarFile, String dir) throws Exception { + File dest = new File(dir); + dest.mkdir(); + TarArchiveInputStream tarIn = null; + + tarIn = new TarArchiveInputStream( + new GzipCompressorInputStream(new BufferedInputStream(new FileInputStream(tarFile)))); + TarArchiveEntry tarEntry = tarIn.getNextTarEntry(); + // tarIn is a TarArchiveInputStream + while (tarEntry != null) {// create a file with the same name as the tarEntry + File destPath = new File(dest.toString() + System.getProperty("file.separator") + tarEntry.getName()); + // System.out.println("working: " + destPath.getCanonicalPath()); + if (tarEntry.isDirectory()) { + destPath.mkdirs(); + } else { + destPath.createNewFile(); + FileOutputStream fout = new FileOutputStream(destPath); + byte[] b = new byte[(int) tarEntry.getSize()]; + tarIn.read(b); + fout.write(b); + fout.close(); + int mode = tarEntry.getMode(); + b = new byte[5]; + TarUtils.formatUnsignedOctalString(mode, b, 0, 4); + if (bits(b[1]).endsWith("1")) { + destPath.setExecutable(true); + } + } + tarEntry = tarIn.getNextTarEntry(); + } + tarIn.close(); + } + + private static String bits(byte b) { + return String.format("%6s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'); + } + + private static File download(String version, String downloadJsonURL, long sizeOfJson, ProgressBar progress, + String bindir, String filename) throws MalformedURLException, IOException, FileNotFoundException { + File folder = new File(bindir + version + "/"); + File exe = new File(bindir + version + "/" + filename); + try { + URL url = new URL(downloadJsonURL); + URLConnection connection = url.openConnection(); + InputStream is = connection.getInputStream(); + ProcessInputStream pis = new ProcessInputStream(is, (int) sizeOfJson); + pis.addListener(new Listener() { + @Override + public void process(double percent) { + //System.out.println("Download percent " + percent); + Platform.runLater(() -> { + progress.setProgress(percent); + }); + } + }); + + if (!folder.exists() || !exe.exists()) { + System.out.println("Start Downloading " + filename); + folder.mkdirs(); + exe.createNewFile(); + byte dataBuffer[] = new byte[1024]; + int bytesRead; + FileOutputStream fileOutputStream = new FileOutputStream(exe.getAbsoluteFile()); + while ((bytesRead = pis.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + fileOutputStream.close(); + pis.close(); + System.out.println("Finished downloading " + filename); + } else { + System.out.println("Not downloadeing, it existst " + filename); + } + } catch (Throwable t) { + t.printStackTrace(); + } + System.out.println("Using JVM "+exe.getAbsolutePath()); + return exe; + } +} diff --git a/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/LatestFromGithubLaunchUI.java b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/LatestFromGithubLaunchUI.java new file mode 100644 index 0000000..cd0f836 --- /dev/null +++ b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/LatestFromGithubLaunchUI.java @@ -0,0 +1,332 @@ +package com.commonwealthrobotics; +/** + * Sample Skeleton for 'ui.fxml' Controller Class + */ + +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.net.URLConnection; +import java.util.ResourceBundle; + +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.stage.Stage; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +public class LatestFromGithubLaunchUI { + public static String[] argsFromSystem; + //public static String[] args; + public static String project; + public static Stage stage; + + public static String latestVersionString = ""; + public static String myVersionString = null; + public static long sizeOfJar = 0; + public static long sizeOfJson = 0; + @FXML // ResourceBundle that was given to the FXMLLoader + private ResourceBundle resources; + + @FXML // URL location of the FXML file that was given to the FXMLLoader + private URL location; + + @FXML // fx:id="progress" + private ProgressBar progress; // Value injected by FXMLLoader + + @FXML // fx:id="previousVersion" + private Label previousVersion; // Value injected by FXMLLoader + @FXML // fx:id="previousVersion" + private Label binary; // Value injected by FXMLLoader + @FXML // fx:id="currentVersion" + private Label currentVersion; // Value injected by FXMLLoader + + @FXML // fx:id="yesButton" + private Button yesButton; // Value injected by FXMLLoader + + @FXML // fx:id="noButton" + private Button noButton; // Value injected by FXMLLoader + + private static HashMap database; + + private String bindir; + + private File bindirFile; + + private File myVersionFile; + + private String myVersionFileString; + + private static String downloadJarURL; + private static String downloadJsonURL; + + public static String repoName; + public static String jarName; + + @FXML + void onNo(ActionEvent event) { + System.out.println("No path"); + launchApplication(); + } + + @FXML + void onYes(ActionEvent event) { + System.out.println("Yes path"); + yesButton.setDisable(true); + noButton.setDisable(true); + new Thread(() -> { + + try { + String downloadURL2 = downloadJarURL; + URL url = new URL(downloadURL2); + URLConnection connection = url.openConnection(); + InputStream is = connection.getInputStream(); + ProcessInputStream pis = new ProcessInputStream(is, (int) sizeOfJar); + pis.addListener(new Listener() { + @Override + public void process(double percent) { + Platform.runLater(() -> { + progress.setProgress(percent); + }); + } + }); + File folder = new File(bindir + latestVersionString + "/"); + File exe = new File(bindir + latestVersionString + "/" + jarName); + + if (!folder.exists() || !exe.exists() || sizeOfJar != exe.length()) { + folder.mkdirs(); + exe.createNewFile(); + byte dataBuffer[] = new byte[1024]; + int bytesRead; + FileOutputStream fileOutputStream = new FileOutputStream(exe.getAbsoluteFile()); + while ((bytesRead = pis.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + fileOutputStream.close(); + pis.close(); + + } + if (folder.exists() && exe.exists() && sizeOfJar == exe.length()) + myVersionString = latestVersionString; + } catch (Exception e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + launchApplication(); + }).start(); + } + private boolean launched=false; + public void launchApplication() { + if(launched) + throw new RuntimeException("Applicaion is already launched!"); + launched=true; + Platform.runLater(() -> { + yesButton.setDisable(true); + noButton.setDisable(true); + + }); + new Thread(() -> { + String command; + try { + command = JvmManager.getCommandString(project, repoName, myVersionString,downloadJsonURL,sizeOfJson,progress,bindir); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.exit(1); + return; + } + // Run this later to show downloading the JVM + Platform.runLater(() ->stage.close()); + + try { + Thread.sleep(100); + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + // + // for (int i = 4; i < args.length; i++) { + // command += " " + args[i]; + // } + try { + myVersionFile.createNewFile(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + BufferedWriter writer; + try { + writer = new BufferedWriter(new FileWriter(myVersionFileString)); + writer.write(myVersionString); + writer.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + String fc =!isWin()? + command + " " + bindir + myVersionString + "/" + jarName+"": + command + " \"" + bindir + myVersionString + "/" + jarName+"\""; + for(String s:argsFromSystem) { + fc+=(" "+s); + } + + String finalCommand=fc; + System.out.println("Running:\n\n"+finalCommand+"\n\n"); + new Thread(() -> { + try { + Process process = Runtime.getRuntime().exec(finalCommand); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); + String line; + while ((line = reader.readLine()) != null && process.isAlive()) { + System.out.println(line); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + reader.close(); + System.out.println("LatestFromGithubLaunch clean exit"); + System.exit(0); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }).start(); + }).start(); + } + + public static boolean isWin() { + return System.getProperty("os.name").toLowerCase().contains("windows"); + } + public static boolean isLin() { + return System.getProperty("os.name").toLowerCase().contains("linux"); + } + public static boolean isMac() { + return System.getProperty("os.name").toLowerCase().contains("mac"); + } + public static boolean isArm() { + return System.getProperty("os.arch").toLowerCase().contains("aarch64"); + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } + + public static void readCurrentVersion(String url) throws IOException { + InputStream is = new URL(url).openStream(); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + // Create the type, this tells GSON what datatypes to instantiate when parsing + // and saving the json + Type TT_mapStringString = new TypeToken>() { + }.getType(); + // chreat the gson object, this is the parsing factory + Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); + database = gson.fromJson(jsonText, TT_mapStringString); + latestVersionString = (String) database.get("tag_name"); + @SuppressWarnings("unchecked") + List> assets = (List>) database.get("assets"); + for (Map key : assets) { + if (((String) key.get("name")).contentEquals(jarName)) { + downloadJarURL = (String) key.get("browser_download_url"); + sizeOfJar = ((Double) key.get("size")).longValue(); + System.out.println(downloadJarURL + " Size " + sizeOfJar + " bytes"); + } + if (((String) key.get("name")).contentEquals("jvm.json")) { + downloadJsonURL = (String) key.get("browser_download_url"); + sizeOfJson = ((Double) key.get("size")).longValue(); + System.out.println(downloadJsonURL + " Size " + sizeOfJson + " bytes"); + } + + } + } finally { + is.close(); + } + } + + @FXML // This method is called by the FXMLLoader when initialization is complete + void initialize() { + assert progress != null : "fx:id=\"progress\" was not injected: check your FXML file 'ui.fxml'."; + assert previousVersion != null : "fx:id=\"previousVersion\" was not injected: check your FXML file 'ui.fxml'."; + assert currentVersion != null : "fx:id=\"currentVersion\" was not injected: check your FXML file 'ui.fxml'."; + boolean noInternet = false; + try { + readCurrentVersion("https://api.github.com/repos/" + project + "/" + repoName + "/releases/latest"); + binary.setText(project + "\n" + repoName + "\n" + jarName + "\n" + (sizeOfJar / 1000000) + " Mb"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + noInternet=true; + } + stage.setTitle("Auto-Updater for " + repoName); + currentVersion.setText(latestVersionString); + bindir = System.getProperty("user.home") + "/bin/" + repoName + "Install/"; + myVersionFileString = bindir + "currentversion.txt"; + myVersionFile = new File(myVersionFileString); + bindirFile = new File(bindir); + if (!bindirFile.exists()) + bindirFile.mkdirs(); + if (!myVersionFile.exists()) { + + onYes(null); + return; + } else { + try { + myVersionString = new String(Files.readAllBytes(Paths.get(myVersionFileString))).trim(); + previousVersion.setText(myVersionString); + if (myVersionString.length() < 3) { + onYes(null); + return; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + if(!noInternet) { + if(myVersionString==null) { + launchApplication(); + return; + } + else + if (myVersionString.contentEquals(latestVersionString)) { + launchApplication(); + return; + } + }else { + onNo(null); + return; + } + + } +} diff --git a/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Listener.java b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Listener.java new file mode 100644 index 0000000..2d44b15 --- /dev/null +++ b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Listener.java @@ -0,0 +1,5 @@ +package com.commonwealthrobotics; + +public interface Listener{ + void process(double percent); +} \ No newline at end of file diff --git a/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Main.java b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Main.java new file mode 100644 index 0000000..deefc1c --- /dev/null +++ b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/Main.java @@ -0,0 +1,42 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.commonwealthrobotics; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class Main extends Application { + + @Override + public void start(Stage stage) throws Exception { + LatestFromGithubLaunchUI.stage=stage; + Parent root = FXMLLoader.load(Main.class.getResource("ui.fxml")); + + Scene scene = new Scene(root, 600, 523); + + + stage.setScene(scene); + stage.show(); + } + public static void main(String [] args) { + //LatestFromGithubLaunchUI.argsFromSystem=args; + LatestFromGithubLaunchUI.argsFromSystem=new String[] { + "-g", + "https://github.com/CommonWealthRobotics/CaDoodle-script.git", + "Main.groovy" + }; + LatestFromGithubLaunchUI.project="CommonWealthRobotics"; + LatestFromGithubLaunchUI.repoName= "BowlerStudio"; + LatestFromGithubLaunchUI.jarName= "BowlerStudio.jar"; + + launch(args); + } + +} + + + diff --git a/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/ProcessInputStream.java b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/ProcessInputStream.java new file mode 100644 index 0000000..7c31c07 --- /dev/null +++ b/CaDoodleUpdater/src/main/java/com/commonwealthrobotics/ProcessInputStream.java @@ -0,0 +1,69 @@ +package com.commonwealthrobotics; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +public class ProcessInputStream extends InputStream { + + private InputStream in; + private int length, sumRead; + private java.util.List listeners; + private double percent; + + public ProcessInputStream(InputStream inputStream, int length) throws IOException { + this.in = inputStream; + listeners = new ArrayList<>(); + sumRead = 0; + this.length = length; + } + + @Override + public int read(byte[] b) throws IOException { + int readCount = in.read(b); + evaluatePercent(readCount); + return readCount; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int readCount = in.read(b, off, len); + evaluatePercent(readCount); + return readCount; + } + + @Override + public long skip(long n) throws IOException { + long skip = in.skip(n); + evaluatePercent(skip); + return skip; + } + + @Override + public int read() throws IOException { + int read = in.read(); + if (read != -1) { + evaluatePercent(1); + } + return read; + } + + public ProcessInputStream addListener(Listener listener) { + this.listeners.add(listener); + return this; + } + + private void evaluatePercent(long readCount) { + if (readCount != -1) { + sumRead += readCount; + percent = sumRead * 1.0 / length; + } + notifyListener(); + } + + private void notifyListener() { + for (Listener listener : listeners) { + listener.process(percent); + } + } +} \ No newline at end of file diff --git a/CaDoodleUpdater/src/main/resources/com/commonwealthrobotics/ui.fxml b/CaDoodleUpdater/src/main/resources/com/commonwealthrobotics/ui.fxml new file mode 100644 index 0000000..d2cf8b6 --- /dev/null +++ b/CaDoodleUpdater/src/main/resources/com/commonwealthrobotics/ui.fxml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +