package me.tvhee.tvheeapi.repositoryinstaller; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.lang.reflect.Array; import java.net.HttpURLConnection; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.file.Files; import java.util.Arrays; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.function.Predicate; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class Builder { public static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows"); public static final File CWD = new File("."); private static File msysDir; private static File maven; public static void start() throws Exception { System.out.println("Java Version: " + JavaVersion.getCurrentVersion()); System.out.println("Current Path: " + CWD.getAbsolutePath()); if(CWD.getAbsolutePath().contains("'") || CWD.getAbsolutePath().contains("#") || CWD.getAbsolutePath().contains("~") || CWD.getAbsolutePath().contains("(") || CWD.getAbsolutePath().contains(")")) { System.err.println("Please do not run in a path with special characters!"); return; } if(CWD.getAbsolutePath().contains("Dropbox") || CWD.getAbsolutePath().contains("OneDrive")) { System.err.println("Please do not run in a Dropbox, OneDrive, or similar. You can always copy the completed jars there later."); return; } try { runProcess(CWD, "sh", "-c", "exit"); } catch(Exception ex) { if(Builder.IS_WINDOWS) { final String gitVersion = "PortableGit-2.30.0-" + (System.getProperty("os.arch").endsWith("64") ? "64" : "32") + "-bit"; msysDir = new File(gitVersion, "PortableGit"); if(!msysDir.isDirectory()) { System.out.println("*** Could not find PortableGit installation, downloading. ***"); final String gitName = gitVersion + ".7z.exe"; final File gitInstall = new File(gitVersion, gitName); gitInstall.deleteOnExit(); gitInstall.getParentFile().mkdirs(); if(!gitInstall.exists()) { download("https://github.com/git-for-windows/git/releases/download/v2.30.0.windows.1/" + gitName, gitInstall); } System.out.println("Extracting downloaded git install"); runProcess(gitInstall.getParentFile(), gitInstall.getAbsolutePath(), "-y", "-gm2", "-nr"); gitInstall.delete(); } System.out.println("*** Using downloaded git " + msysDir + " ***"); System.out.println("*** Please note that this is a beta feature, so if it does not work please also try a manual install of git from https://git-for-windows.github.io/ ***"); } else { System.out.println("You must run this jar through bash (msysgit)"); System.exit(1); } } try { runProcess(CWD, "git", "--version"); } catch(Exception ex) { System.out.println("Could not successfully run git. Please ensure it is installed and functioning. " + ex.getMessage()); System.exit(1); } try { runProcess(CWD, "git", "config", "--global", "--includes", "user.name"); } catch(Exception ex) { System.out.println("Git name not set, setting it to default value."); runProcess(CWD, "git", "config", "--global", "user.name", "BuildTools"); } try { runProcess(CWD, "git", "config", "--global", "--includes", "user.email"); } catch(Exception ex) { System.out.println("Git email not set, setting it to default value."); runProcess(CWD, "git", "config", "--global", "user.email", "example@mail.com"); } final String mavenVersion = "apache-maven-3.6.0"; final String m2Home = System.getenv("M2_HOME"); if(m2Home == null || !(maven = new File(m2Home)).exists()) { maven = new File(mavenVersion); if(!maven.exists()) { System.out.println("Maven does not exist, downloading. Please wait."); final File mvnTemp = new File(mavenVersion + "-bin.zip"); mvnTemp.deleteOnExit(); download("https://static.spigotmc.org/maven/" + mvnTemp.getName(), mvnTemp); unzip(mvnTemp, new File(".")); mvnTemp.delete(); } } String version = getNewestVersion(); final File download = new File("TvheeAPI-" + version + ".jar"); int resourceId = 85346; download("https://api.spigotmc.org/legacy/update.php?resource=" + resourceId, download); //runProcess(new File("C:\\Users\\<>\\IdeaProjects\\TvheeAPIRepositoryInstaller\\test\\apache-maven-3.6.0\\bin\\mvn.cmd"), "install:install-file", "-Dfile=\"" + download.getAbsolutePath() + "\"", "-DgroupId=me.tvhee", "-DartifactId=TvheeAPI", "-Dversion=" + version, "-Dpackaging=jar"); runMaven(CWD, "install:install-file", "-Dfile=\"" + download.getAbsolutePath() + "\"", "-DgroupId=me.tvhee", "-DartifactId=TvheeAPI", "-Dversion=" + version, "-Dpackaging=jar"); } private static String getNewestVersion() { try { int resourceId = 85346; HttpURLConnection connection = (HttpURLConnection) new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceId).openConnection(); connection.setRequestMethod("GET"); final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); return reader.readLine(); } catch(final Exception ex) { System.out.println("Could not check for update from SpigotMC.org" + ex.getMessage()); return ""; } } public static int runMaven(final File workDir, final String... command) throws Exception { final List args = new LinkedList<>(); if(Builder.IS_WINDOWS) { args.add("\"" + Builder.maven.getAbsolutePath() + "\\bin\\mvn.cmd\""); } else { args.add("sh"); args.add("\"" + Builder.maven.getAbsolutePath() + "\\bin\\mvn\""); } args.add("-Dbt.name=dev"); args.addAll(Arrays.asList(command)); return runProcess(workDir, args.toArray(new String[args.size()])); } public static int runProcess(final File workDir, String... command) throws Exception { if(command[0].equals("java")) { command[0] = System.getProperty("java.home") + "/bin/" + command[0]; } if(msysDir != null) { if("bash".equals(command[0])) { command[0] = "git-bash"; } String cmd = System.getenv("ComSpec"); if(cmd == null) { cmd = "cmd.exe"; } final String[] shim = { cmd, "/D", "/C" }; command = concat(shim, command, String.class); } return runProcess0(workDir, command); } public static T[] concat(final T[] first, final T[] second, final Class type) { final T[] result = newArray(type, first.length + second.length); System.arraycopy(first, 0, result, 0, first.length); System.arraycopy(second, 0, result, first.length, second.length); return result; } public static T[] newArray(final Class type, final int length) { return (T[]) Array.newInstance(type, length); } private static int runProcess0(final File workDir, final String... command) throws Exception { if(workDir == null) throw new NullPointerException(); if(command == null || command.length < 1) throw new NullPointerException("Invalid command"); final ProcessBuilder pb = new ProcessBuilder(command); pb.directory(workDir); pb.environment().put("JAVA_HOME", System.getProperty("java.home")); pb.environment().remove("M2_HOME"); if(!pb.environment().containsKey("MAVEN_OPTS")) { pb.environment().put("MAVEN_OPTS", "-Xmx1024M"); } if(!pb.environment().containsKey("_JAVA_OPTIONS")) { StringBuilder javaOptions = new StringBuilder("-Djdk.net.URLClassPath.disableClassPathURLCheck=true"); for(final String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) { if(arg.startsWith("-Xmx")) { javaOptions.append(" ").append(arg); } } pb.environment().put("_JAVA_OPTIONS", javaOptions.toString()); } if(Builder.IS_WINDOWS) { String pathEnv = null; for(final String key : pb.environment().keySet()) { if(key.equalsIgnoreCase("path")) { pathEnv = key; } } if(pathEnv == null) { throw new IllegalStateException("Could not find path variable!"); } if(msysDir != null) { final String path = msysDir.getAbsolutePath() + ";" + new File(msysDir, "bin").getAbsolutePath() + ";" + pb.environment().get(pathEnv); pb.environment().put(pathEnv, path); } String path = pb.environment().get(pathEnv); if(!path.contains("C:\\WINDOWS\\system32;")) { path = System.getenv("SystemRoot") + "\\system32;" + path; pb.environment().put(pathEnv, path); } } final Process ps = pb.start(); new Thread(new StreamRedirector(ps.getInputStream(), System.out), "System.out redirector").start(); new Thread(new StreamRedirector(ps.getErrorStream(), System.err), "System.err redirector").start(); final int status = ps.waitFor(); if(status != 0) { throw new RuntimeException("Error running command, return status !=0: " + Arrays.toString(command)); } return status; } public static void unzip(final File zipFile, final File targetFolder) throws IOException { unzip(zipFile, targetFolder, null); } public static void unzip(final File zipFile, final File targetFolder, final Predicate filter) throws IOException { targetFolder.mkdir(); final ZipFile zip = new ZipFile(zipFile); try { final Enumeration entries = zip.entries(); while(entries.hasMoreElements()) { final ZipEntry entry = entries.nextElement(); if(filter != null && !filter.test(entry.getName())) { continue; } final File outFile = new File(targetFolder, entry.getName()); if(entry.isDirectory()) { outFile.mkdirs(); } else { if(outFile.getParentFile() != null) { outFile.getParentFile().mkdirs(); } try(InputStream is = zip.getInputStream(entry)) { Files.copy(is, outFile.toPath()); } System.out.println("Extracted: " + outFile); } } } finally { zip.close(); } } public static void download(final String url, final File target) { try { final ReadableByteChannel channel; HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestProperty("User-Agent", "TvheeAPIRepositoryDownloader"); channel = Channels.newChannel(connection.getInputStream()); final FileOutputStream output = new FileOutputStream(target); output.getChannel().transferFrom(channel, 0, Long.MAX_VALUE); output.flush(); output.close(); } catch(final Exception ex) { System.out.println("Could not download file " + target.getName() + ": " + ex.getMessage()); } } }