diff --git a/.gitignore b/.gitignore index 74dc7ea2..de408ec0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ run/ autotest/ +dist/ # Gradle build/ diff --git a/.travis.yml b/.travis.yml index c54706cf..a8344ba0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ install: - travis_retry docker build -t cabaletta/baritone . script: -- docker run --name baritone cabaletta/baritone /bin/sh -c "set -e; /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 128x128x24 -ac +extension GLX +render; sh scripts/build.sh; DISPLAY=:99 BARITONE_AUTO_TEST=true ./gradlew runClient" +- docker run --name baritone cabaletta/baritone /bin/sh -c "set -e; /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 128x128x24 -ac +extension GLX +render; DISPLAY=:99 BARITONE_AUTO_TEST=true ./gradlew runClient" - docker cp baritone:/code/dist dist - ls dist - cat dist/checksums.txt diff --git a/build.gradle b/build.gradle index aa8f5763..34020ece 100755 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,9 @@ buildscript { } } -import baritone.gradle.ProguardTask + +import baritone.gradle.task.CreateDistTask +import baritone.gradle.task.ProguardTask apply plugin: 'java' apply plugin: 'net.minecraftforge.gradle.tweaker-client' @@ -108,4 +110,6 @@ task proguard(type: ProguardTask) { versionManifest 'https://launchermeta.mojang.com/mc/game/version_manifest.json' } -build.finalizedBy(proguard) +task createDist(type: CreateDistTask, dependsOn: proguard) + +build.finalizedBy(createDist) diff --git a/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java new file mode 100644 index 00000000..22dac86e --- /dev/null +++ b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java @@ -0,0 +1,102 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.gradle.task; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.gradle.api.DefaultTask; + +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * @author Brady + * @since 10/12/2018 + */ +class BaritoneGradleTask extends DefaultTask { + + static final JsonParser PARSER = new JsonParser(); + + static final String + PROGUARD_ZIP = "proguard.zip", + PROGUARD_JAR = "proguard.jar", + PROGUARD_CONFIG_TEMPLATE = "scripts/proguard.pro", + PROGUARD_CONFIG_DEST = "template.pro", + PROGUARD_API_CONFIG = "api.pro", + PROGUARD_STANDALONE_CONFIG = "standalone.pro", + PROGUARD_EXPORT_PATH = "proguard_out.jar", + + VERSION_MANIFEST = "version_manifest.json", + + TEMP_LIBRARY_DIR = "tempLibraries/", + + ARTIFACT_STANDARD = "%s-%s.jar", + ARTIFACT_UNOPTIMIZED = "%s-unoptimized-%s.jar", + ARTIFACT_API = "%s-api-%s.jar", + ARTIFACT_STANDALONE = "%s-standalone-%s.jar"; + + String artifactName, artifactVersion; + Path artifactPath, artifactUnoptimizedPath, artifactApiPath, artifactStandalonePath, proguardOut; + + void verifyArtifacts() throws Exception { + this.artifactName = getProject().getName(); + this.artifactVersion = getProject().getVersion().toString(); + + this.artifactPath = this.getBuildFile(formatVersion(ARTIFACT_STANDARD)); + this.artifactUnoptimizedPath = this.getBuildFile(formatVersion(ARTIFACT_UNOPTIMIZED)); + this.artifactApiPath = this.getBuildFile(formatVersion(ARTIFACT_API)); + this.artifactStandalonePath = this.getBuildFile(formatVersion(ARTIFACT_STANDALONE)); + + this.proguardOut = this.getTemporaryFile(PROGUARD_EXPORT_PATH); + + if (!Files.exists(this.artifactPath)) { + throw new Exception("Artifact not found! Run build first!"); + } + } + + void write(InputStream stream, Path file) throws Exception { + if (Files.exists(file)) { + Files.delete(file); + } + Files.copy(stream, file); + } + + String formatVersion(String string) { + return String.format(string, this.artifactName, this.artifactVersion); + } + + Path getRelativeFile(String file) { + return Paths.get(new File(file).getAbsolutePath()); + } + + Path getTemporaryFile(String file) { + return Paths.get(new File(getTemporaryDir(), file).getAbsolutePath()); + } + + Path getBuildFile(String file) { + return getRelativeFile("build/libs/" + file); + } + + JsonElement readJson(List lines) { + return PARSER.parse(String.join("\n", lines)); + } +} diff --git a/buildSrc/src/main/java/baritone/gradle/task/CreateDistTask.java b/buildSrc/src/main/java/baritone/gradle/task/CreateDistTask.java new file mode 100644 index 00000000..34c9df57 --- /dev/null +++ b/buildSrc/src/main/java/baritone/gradle/task/CreateDistTask.java @@ -0,0 +1,81 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.gradle.task; + +import org.gradle.api.tasks.TaskAction; + +import javax.xml.bind.DatatypeConverter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +/** + * @author Brady + * @since 10/12/2018 + */ +public class CreateDistTask extends BaritoneGradleTask { + + private static MessageDigest SHA1_DIGEST; + + @TaskAction + private void exec() throws Exception { + super.verifyArtifacts(); + + // Define the distribution file paths + Path unoptimized = getRelativeFile("dist/" + formatVersion(ARTIFACT_UNOPTIMIZED)); + Path api = getRelativeFile("dist/" + formatVersion(ARTIFACT_API)); + Path standalone = getRelativeFile("dist/" + formatVersion(ARTIFACT_STANDALONE)); + + // NIO will not automatically create directories + Path dir = getRelativeFile("dist/"); + if (!Files.exists(dir)) { + Files.createDirectory(dir); + } + + // Copy build jars to dist/ + Files.copy(this.artifactUnoptimizedPath, unoptimized, REPLACE_EXISTING); + Files.copy(this.artifactApiPath, api, REPLACE_EXISTING); + Files.copy(this.artifactStandalonePath, standalone, REPLACE_EXISTING); + + // Calculate all checksums and format them like "shasum" + List shasum = Stream.of(unoptimized, api, standalone) + .map(path -> sha1(path) + " " + path.getFileName().toString()) + .collect(Collectors.toList()); + + // Write the checksums to a file + Files.write(getRelativeFile("dist/checksums.txt"), shasum); + } + + private static String sha1(Path path) { + try { + if (SHA1_DIGEST == null) { + SHA1_DIGEST = MessageDigest.getInstance("SHA-1"); + } + return DatatypeConverter.printHexBinary(SHA1_DIGEST.digest(Files.readAllBytes(path))).toLowerCase(); + } catch (Exception e) { + // haha no thanks + throw new RuntimeException(e); + } + } +} diff --git a/buildSrc/src/main/java/baritone/gradle/ProguardTask.java b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java similarity index 75% rename from buildSrc/src/main/java/baritone/gradle/ProguardTask.java rename to buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java index 86e138ab..ad0db8cc 100644 --- a/buildSrc/src/main/java/baritone/gradle/ProguardTask.java +++ b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java @@ -15,12 +15,11 @@ * along with Baritone. If not, see . */ -package baritone.gradle; +package baritone.gradle.task; import baritone.gradle.util.Determinizer; import com.google.gson.*; import org.apache.commons.io.IOUtils; -import org.gradle.api.DefaultTask; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.tasks.Input; @@ -31,7 +30,6 @@ import java.io.*; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -44,29 +42,10 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; * @author Brady * @since 10/11/2018 */ -public class ProguardTask extends DefaultTask { - - private static final JsonParser PARSER = new JsonParser(); +public class ProguardTask extends BaritoneGradleTask { private static final Pattern TEMP_LIBRARY_PATTERN = Pattern.compile("-libraryjars 'tempLibraries\\/([a-zA-Z0-9/_\\-\\.]+)\\.jar'"); - private static final String - PROGUARD_ZIP = "proguard.zip", - PROGUARD_JAR = "proguard.jar", - PROGUARD_CONFIG_TEMPLATE = "scripts/proguard.pro", - PROGUARD_CONFIG_DEST = "template.pro", - PROGUARD_API_CONFIG = "api.pro", - PROGUARD_STANDALONE_CONFIG = "standalone.pro", - PROGUARD_EXPORT_PATH = "proguard_out.jar", - - VERSION_MANIFEST = "version_manifest.json", - - TEMP_LIBRARY_DIR = "tempLibraries/", - - ARTIFACT_UNOPTIMIZED = "%s-unoptimized-%s.jar", - ARTIFACT_API = "%s-api-%s.jar", - ARTIFACT_STANDALONE = "%s-standalone-%s.jar"; - @Input private String url; @@ -76,15 +55,14 @@ public class ProguardTask extends DefaultTask { @Input private String versionManifest; - private String artifactName, artifactVersion; - private Path artifactPath, artifactUnoptimizedPath, artifactApiPath, artifactStandalonePath, proguardOut; private Map versionDownloadMap; private List requiredLibraries; @TaskAction private void exec() throws Exception { + super.verifyArtifacts(); + // "Haha brady why don't you make separate tasks" - verifyArtifacts(); processArtifact(); downloadProguard(); extractProguard(); @@ -96,25 +74,6 @@ public class ProguardTask extends DefaultTask { cleanup(); } - private void verifyArtifacts() throws Exception { - this.artifactName = getProject().getName(); - this.artifactVersion = getProject().getVersion().toString(); - - // The compiled baritone artifact that is exported when the build task is ran - String artifactName = String.format("%s-%s.jar", this.artifactName, this.artifactVersion); - - this.artifactPath = this.getBuildFile(artifactName); - this.artifactUnoptimizedPath = this.getBuildFile(String.format(ARTIFACT_UNOPTIMIZED, this.artifactName, this.artifactVersion)); - this.artifactApiPath = this.getBuildFile(String.format(ARTIFACT_API, this.artifactName, this.artifactVersion)); - this.artifactStandalonePath = this.getBuildFile(String.format(ARTIFACT_STANDALONE, this.artifactName, this.artifactVersion)); - - this.proguardOut = this.getTemporaryFile(PROGUARD_EXPORT_PATH); - - if (!Files.exists(this.artifactPath)) { - throw new Exception("Artifact not found! Run build first!"); - } - } - private void processArtifact() throws Exception { if (Files.exists(this.artifactUnoptimizedPath)) { Files.delete(this.artifactUnoptimizedPath); @@ -264,12 +223,6 @@ public class ProguardTask extends DefaultTask { this.versionManifest = versionManifest; } - /* - * A LOT OF SHITTY UTIL METHODS ARE BELOW. - * - * PROCEED WITH CAUTION - */ - private void runProguard(Path config) throws Exception { // Delete the existing proguard output file. Proguard probably handles this already, but why not do it ourselves if (Files.exists(this.proguardOut)) { @@ -278,11 +231,13 @@ public class ProguardTask extends DefaultTask { Path proguardJar = getTemporaryFile(PROGUARD_JAR); Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString()) - .directory(getTemporaryFile("").toFile()) // Set the working directory to the temporary folder - .redirectOutput(ProcessBuilder.Redirect.INHERIT) - .redirectError(ProcessBuilder.Redirect.INHERIT) + .directory(getTemporaryFile("").toFile()) // Set the working directory to the temporary folder] .start(); + // We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this + this.printOutputLog(p.getInputStream()); + this.printOutputLog(p.getErrorStream()); + // Halt the current thread until the process is complete, if the exit code isn't 0, throw an exception int exitCode; if ((exitCode = p.waitFor()) != 0) { @@ -290,26 +245,16 @@ public class ProguardTask extends DefaultTask { } } - private void write(InputStream stream, Path file) throws Exception { - if (Files.exists(file)) { - Files.delete(file); - } - Files.copy(stream, file); - } - - private Path getRelativeFile(String file) { - return Paths.get(new File(file).getAbsolutePath()); - } - - private Path getTemporaryFile(String file) { - return Paths.get(new File(getTemporaryDir(), file).getAbsolutePath()); - } - - private Path getBuildFile(String file) { - return getRelativeFile("build/libs/" + file); - } - - private JsonElement readJson(List lines) { - return PARSER.parse(String.join("\n", lines)); + private void printOutputLog(InputStream stream) { + new Thread(() -> { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + } catch (final Exception e) { + e.printStackTrace(); + } + }).start(); } } diff --git a/scripts/Determinizer.java b/scripts/Determinizer.java deleted file mode 100644 index e15f0b2c..00000000 --- a/scripts/Determinizer.java +++ /dev/null @@ -1,49 +0,0 @@ -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.JarOutputStream; -import java.util.stream.Collectors; - -/** - * Make a .jar file deterministic by sorting all entries by name, and setting all the last modified times to 0. - * This makes the build 100% reproducible since the timestamp when you built it no longer affects the final file. - * @author leijurv - */ -public class Determinizer { - - public static void main(String[] args) throws IOException { - System.out.println("Input path: " + args[0] + " Output path: " + args[1]); - JarFile jarFile = new JarFile(new File(args[0])); - JarOutputStream jos = new JarOutputStream(new FileOutputStream(new File(args[1]))); - ArrayList entries = jarFile.stream().collect(Collectors.toCollection(ArrayList::new)); - entries.sort(Comparator.comparing(JarEntry::getName)); - for (JarEntry entry : entries) { - if (entry.getName().equals("META-INF/fml_cache_annotation.json")) { - continue; - } - if (entry.getName().equals("META-INF/fml_cache_class_versions.json")) { - continue; - } - JarEntry clone = new JarEntry(entry.getName()); - clone.setTime(0); - jos.putNextEntry(clone); - copy(jarFile.getInputStream(entry), jos); - } - jos.finish(); - jarFile.close(); - } - - public static void copy(InputStream is, OutputStream os) throws IOException { - byte[] buffer = new byte[1024]; - int len; - while ((len = is.read(buffer)) != -1) { - os.write(buffer, 0, len); - } - } -} diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100644 index 4f0bc608..00000000 --- a/scripts/build.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -set -e # this makes the whole script fail immediately if any one of these commands fails -./gradlew build -export VERSION=$(cat build.gradle | grep "version '" | cut -d "'" -f 2-2) - -unzip -p build/libs/baritone-$VERSION.jar "mixins.baritone.refmap.json" | jq --sort-keys -c -M '.' > mixins.baritone.refmap.json -zip -u build/libs/baritone-$VERSION.jar mixins.baritone.refmap.json -rm mixins.baritone.refmap.json - -cd scripts -javac Determinizer.java -java Determinizer ../build/libs/baritone-$VERSION.jar temp.jar -mv temp.jar ../build/libs/baritone-$VERSION.jar -cd .. - - -wget -nv https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip -unzip proguard6.0.3.zip 2>&1 > /dev/null -cd build/libs -rm -rf api.pro -echo "-injars 'baritone-$VERSION.jar'" >> api.pro # insert current version -cat ../../scripts/proguard.pro | grep -v "this is the rt jar" | grep -v "\-injars" >> api.pro # remove default rt jar and injar lines -echo "-libraryjars '$(java -verbose 2>/dev/null | sed -ne '1 s/\[Opened \(.*\)\]/\1/p')'" >> api.pro # insert correct rt.jar location -tail api.pro # debug, print out what the previous two commands generated -cat api.pro | grep -v "this is the keep api" > standalone.pro # standalone doesn't keep baritone api - -#instead of downloading these jars from my dropbox in a zip, just assume gradle's already got them for us -mkdir -p tempLibraries -cat ../../scripts/proguard.pro | grep tempLibraries | grep .jar | cut -d "/" -f 2- | cut -d "'" -f -1 | xargs -n1 -I{} bash -c "find ~/.gradle -name {}" | tee /dev/stderr | xargs -n1 -I{} cp {} tempLibraries - -rm -rf ../../dist -mkdir ../../dist -java -jar ../../proguard6.0.3/lib/proguard.jar @api.pro -cd ../../scripts -java Determinizer ../build/libs/Obfuscated/baritone-$VERSION.jar ../dist/baritone-api-$VERSION.jar -cd ../build/libs -rm -rf Obfuscated/* -java -jar ../../proguard6.0.3/lib/proguard.jar @standalone.pro -cd ../../scripts -java Determinizer ../build/libs/Obfuscated/baritone-$VERSION.jar ../dist/baritone-standalone-$VERSION.jar -cd ../build/libs -mv baritone-$VERSION.jar ../../dist/baritone-unoptimized-$VERSION.jar -cd ../../dist -shasum * | tee checksums.txt -cd .. \ No newline at end of file