Merge pull request #221 from cabaletta/gradle-proguard
Proguard Gradle Build Magic
This commit is contained in:
commit
917f393f7a
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
run/
|
run/
|
||||||
autotest/
|
autotest/
|
||||||
|
dist/
|
||||||
|
|
||||||
# Gradle
|
# Gradle
|
||||||
build/
|
build/
|
||||||
|
@ -9,7 +9,7 @@ install:
|
|||||||
- travis_retry docker build -t cabaletta/baritone .
|
- travis_retry docker build -t cabaletta/baritone .
|
||||||
|
|
||||||
script:
|
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
|
- docker cp baritone:/code/dist dist
|
||||||
- ls dist
|
- ls dist
|
||||||
- cat dist/checksums.txt
|
- cat dist/checksums.txt
|
||||||
|
14
build.gradle
14
build.gradle
@ -37,6 +37,10 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
import baritone.gradle.task.CreateDistTask
|
||||||
|
import baritone.gradle.task.ProguardTask
|
||||||
|
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'net.minecraftforge.gradle.tweaker-client'
|
apply plugin: 'net.minecraftforge.gradle.tweaker-client'
|
||||||
apply plugin: 'org.spongepowered.mixin'
|
apply plugin: 'org.spongepowered.mixin'
|
||||||
@ -99,3 +103,13 @@ jar {
|
|||||||
preserveFileTimestamps = false
|
preserveFileTimestamps = false
|
||||||
reproducibleFileOrder = true
|
reproducibleFileOrder = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task proguard(type: ProguardTask) {
|
||||||
|
url 'https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip'
|
||||||
|
extract 'proguard6.0.3/lib/proguard.jar'
|
||||||
|
versionManifest 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
task createDist(type: CreateDistTask, dependsOn: proguard)
|
||||||
|
|
||||||
|
build.finalizedBy(createDist)
|
||||||
|
3
buildSrc/.gitignore
vendored
Normal file
3
buildSrc/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
build/
|
||||||
|
.gradle/
|
||||||
|
out/
|
25
buildSrc/build.gradle
Normal file
25
buildSrc/build.gradle
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
|
||||||
|
compile group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<String> lines) {
|
||||||
|
return PARSER.parse(String.join("\n", lines));
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 api = getRelativeFile("dist/" + formatVersion(ARTIFACT_API));
|
||||||
|
Path standalone = getRelativeFile("dist/" + formatVersion(ARTIFACT_STANDALONE));
|
||||||
|
Path unoptimized = getRelativeFile("dist/" + formatVersion(ARTIFACT_UNOPTIMIZED));
|
||||||
|
|
||||||
|
// 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.artifactApiPath, api, REPLACE_EXISTING);
|
||||||
|
Files.copy(this.artifactStandalonePath, standalone, REPLACE_EXISTING);
|
||||||
|
Files.copy(this.artifactUnoptimizedPath, unoptimized, REPLACE_EXISTING);
|
||||||
|
|
||||||
|
// Calculate all checksums and format them like "shasum"
|
||||||
|
List<String> shasum = Stream.of(api, standalone, unoptimized)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
260
buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java
Normal file
260
buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.gradle.task;
|
||||||
|
|
||||||
|
import baritone.gradle.util.Determinizer;
|
||||||
|
import com.google.gson.*;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.artifacts.Dependency;
|
||||||
|
import org.gradle.api.tasks.Input;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
import org.gradle.internal.Pair;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Brady
|
||||||
|
* @since 10/11/2018
|
||||||
|
*/
|
||||||
|
public class ProguardTask extends BaritoneGradleTask {
|
||||||
|
|
||||||
|
private static final Pattern TEMP_LIBRARY_PATTERN = Pattern.compile("-libraryjars 'tempLibraries\\/([a-zA-Z0-9/_\\-\\.]+)\\.jar'");
|
||||||
|
|
||||||
|
@Input
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Input
|
||||||
|
private String extract;
|
||||||
|
|
||||||
|
@Input
|
||||||
|
private String versionManifest;
|
||||||
|
|
||||||
|
private Map<String, String> versionDownloadMap;
|
||||||
|
private List<String> requiredLibraries;
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
private void exec() throws Exception {
|
||||||
|
super.verifyArtifacts();
|
||||||
|
|
||||||
|
// "Haha brady why don't you make separate tasks"
|
||||||
|
processArtifact();
|
||||||
|
downloadProguard();
|
||||||
|
extractProguard();
|
||||||
|
generateConfigs();
|
||||||
|
downloadVersionManifest();
|
||||||
|
acquireDependencies();
|
||||||
|
proguardApi();
|
||||||
|
proguardStandalone();
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processArtifact() throws Exception {
|
||||||
|
if (Files.exists(this.artifactUnoptimizedPath)) {
|
||||||
|
Files.delete(this.artifactUnoptimizedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Determinizer.main(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadProguard() throws Exception {
|
||||||
|
Path proguardZip = getTemporaryFile(PROGUARD_ZIP);
|
||||||
|
if (!Files.exists(proguardZip)) {
|
||||||
|
write(new URL(this.url).openStream(), proguardZip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractProguard() throws Exception {
|
||||||
|
Path proguardJar = getTemporaryFile(PROGUARD_JAR);
|
||||||
|
if (!Files.exists(proguardJar)) {
|
||||||
|
ZipFile zipFile = new ZipFile(getTemporaryFile(PROGUARD_ZIP).toFile());
|
||||||
|
ZipEntry zipJarEntry = zipFile.getEntry(this.extract);
|
||||||
|
write(zipFile.getInputStream(zipJarEntry), proguardJar);
|
||||||
|
zipFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateConfigs() throws Exception {
|
||||||
|
Files.copy(getRelativeFile(PROGUARD_CONFIG_TEMPLATE), getTemporaryFile(PROGUARD_CONFIG_DEST), REPLACE_EXISTING);
|
||||||
|
|
||||||
|
// Setup the template that will be used to derive the API and Standalone configs
|
||||||
|
List<String> template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST));
|
||||||
|
template.add(0, "-injars " + this.artifactPath.toString());
|
||||||
|
template.add(1, "-outjars " + this.getTemporaryFile(PROGUARD_EXPORT_PATH));
|
||||||
|
|
||||||
|
// Acquire the RT jar using "java -verbose". This doesn't work on Java 9+
|
||||||
|
Process p = new ProcessBuilder("java", "-verbose").start();
|
||||||
|
String out = IOUtils.toString(p.getInputStream(), "UTF-8").split("\n")[0].split("Opened ")[1].replace("]", "");
|
||||||
|
template.add(2, "-libraryjars '" + out + "'");
|
||||||
|
|
||||||
|
// API config doesn't require any changes from the changes that we made to the template
|
||||||
|
Files.write(getTemporaryFile(PROGUARD_API_CONFIG), template);
|
||||||
|
|
||||||
|
// For the Standalone config, don't keep the API package
|
||||||
|
List<String> standalone = new ArrayList<>(template);
|
||||||
|
standalone.removeIf(s -> s.contains("# this is the keep api"));
|
||||||
|
Files.write(getTemporaryFile(PROGUARD_STANDALONE_CONFIG), standalone);
|
||||||
|
|
||||||
|
// Discover all of the libraries that we will need to acquire from gradle
|
||||||
|
this.requiredLibraries = new ArrayList<>();
|
||||||
|
template.forEach(line -> {
|
||||||
|
if (!line.startsWith("#")) {
|
||||||
|
Matcher m = TEMP_LIBRARY_PATTERN.matcher(line);
|
||||||
|
if (m.find()) {
|
||||||
|
this.requiredLibraries.add(m.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadVersionManifest() throws Exception {
|
||||||
|
Path manifestJson = getTemporaryFile(VERSION_MANIFEST);
|
||||||
|
write(new URL(this.versionManifest).openStream(), manifestJson);
|
||||||
|
|
||||||
|
// Place all the versions in the map with their download URL
|
||||||
|
this.versionDownloadMap = new HashMap<>();
|
||||||
|
JsonObject json = readJson(Files.readAllLines(manifestJson)).getAsJsonObject();
|
||||||
|
JsonArray versions = json.getAsJsonArray("versions");
|
||||||
|
versions.forEach(element -> {
|
||||||
|
JsonObject object = element.getAsJsonObject();
|
||||||
|
this.versionDownloadMap.put(object.get("id").getAsString(), object.get("url").getAsString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acquireDependencies() throws Exception {
|
||||||
|
|
||||||
|
// Create a map of all of the dependencies that we are able to access in this project
|
||||||
|
// Likely a better way to do this, I just pair the dependency with the first valid configuration
|
||||||
|
Map<String, Pair<Configuration, Dependency>> dependencyLookupMap = new HashMap<>();
|
||||||
|
getProject().getConfigurations().stream().filter(Configuration::isCanBeResolved).forEach(config ->
|
||||||
|
config.getAllDependencies().forEach(dependency ->
|
||||||
|
dependencyLookupMap.putIfAbsent(dependency.getName() + "-" + dependency.getVersion(), Pair.of(config, dependency))));
|
||||||
|
|
||||||
|
// Create the directory if it doesn't already exist
|
||||||
|
Path tempLibraries = getTemporaryFile(TEMP_LIBRARY_DIR);
|
||||||
|
if (!Files.exists(tempLibraries)) {
|
||||||
|
Files.createDirectory(tempLibraries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate the required libraries to copy them to tempLibraries
|
||||||
|
for (String lib : this.requiredLibraries) {
|
||||||
|
// Download the version jar from the URL acquired from the version manifest
|
||||||
|
if (lib.startsWith("minecraft")) {
|
||||||
|
String version = lib.split("-")[1];
|
||||||
|
Path versionJar = getTemporaryFile("tempLibraries/" + lib + ".jar");
|
||||||
|
if (!Files.exists(versionJar)) {
|
||||||
|
JsonObject versionJson = PARSER.parse(new InputStreamReader(new URL(this.versionDownloadMap.get(version)).openStream())).getAsJsonObject();
|
||||||
|
String url = versionJson.getAsJsonObject("downloads").getAsJsonObject("client").getAsJsonPrimitive("url").getAsString();
|
||||||
|
write(new URL(url).openStream(), versionJar);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a configuration/dependency pair that matches the desired library
|
||||||
|
Pair<Configuration, Dependency> pair = null;
|
||||||
|
for (Map.Entry<String, Pair<Configuration, Dependency>> entry : dependencyLookupMap.entrySet()) {
|
||||||
|
if (entry.getKey().startsWith(lib)) {
|
||||||
|
pair = entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pair must be non-null
|
||||||
|
Objects.requireNonNull(pair);
|
||||||
|
|
||||||
|
// Find the library jar file, and copy it to tempLibraries
|
||||||
|
for (File file : pair.getLeft().files(pair.getRight())) {
|
||||||
|
if (file.getName().startsWith(lib)) {
|
||||||
|
Files.copy(file.toPath(), getTemporaryFile("tempLibraries/" + lib + ".jar"), REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void proguardApi() throws Exception {
|
||||||
|
runProguard(getTemporaryFile(PROGUARD_API_CONFIG));
|
||||||
|
Determinizer.main(this.proguardOut.toString(), this.artifactApiPath.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void proguardStandalone() throws Exception {
|
||||||
|
runProguard(getTemporaryFile(PROGUARD_STANDALONE_CONFIG));
|
||||||
|
Determinizer.main(this.proguardOut.toString(), this.artifactStandalonePath.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanup() {
|
||||||
|
try {
|
||||||
|
Files.delete(this.proguardOut);
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtract(String extract) {
|
||||||
|
this.extract = extract;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersionManifest(String versionManifest) {
|
||||||
|
this.versionManifest = versionManifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
Files.delete(this.proguardOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
||||||
|
.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) {
|
||||||
|
throw new Exception("Proguard exited with code " + exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
181
buildSrc/src/main/java/baritone/gradle/util/Determinizer.java
Normal file
181
buildSrc/src/main/java/baritone/gradle/util/Determinizer.java
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.gradle.util;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import com.google.gson.internal.LazilyParsedNumber;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
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("Running Determinizer");
|
||||||
|
System.out.println(" Input path: " + args[0]);
|
||||||
|
System.out.println(" Output path: " + args[1]);
|
||||||
|
|
||||||
|
JarFile jarFile = new JarFile(new File(args[0]));
|
||||||
|
JarOutputStream jos = new JarOutputStream(new FileOutputStream(new File(args[1])));
|
||||||
|
|
||||||
|
List<JarEntry> entries = jarFile.stream()
|
||||||
|
.sorted(Comparator.comparing(JarEntry::getName))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (entry.getName().endsWith(".refmap.json")) {
|
||||||
|
JsonObject object = new JsonParser().parse(new InputStreamReader(jarFile.getInputStream(entry))).getAsJsonObject();
|
||||||
|
copy(writeSorted(object), jos);
|
||||||
|
} else {
|
||||||
|
copy(jarFile.getInputStream(entry), jos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jos.finish();
|
||||||
|
jos.close();
|
||||||
|
jarFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copy(String s, OutputStream os) throws IOException {
|
||||||
|
os.write(s.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String writeSorted(JsonObject in) throws IOException {
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
JsonWriter jw = new JsonWriter(writer);
|
||||||
|
JSON_ELEMENT.write(jw, in);
|
||||||
|
return writer.toString() + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All credits go to GSON and its contributors. GSON is licensed under the Apache 2.0 License.
|
||||||
|
* This implementation has been modified to write {@link JsonObject} keys in order.
|
||||||
|
*
|
||||||
|
* @see <a href="https://github.com/google/gson/blob/master/LICENSE">GSON License</a>
|
||||||
|
* @see <a href="https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L698">Original Source</a>
|
||||||
|
*/
|
||||||
|
private static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement read(JsonReader in) throws IOException {
|
||||||
|
switch (in.peek()) {
|
||||||
|
case STRING:
|
||||||
|
return new JsonPrimitive(in.nextString());
|
||||||
|
case NUMBER:
|
||||||
|
String number = in.nextString();
|
||||||
|
return new JsonPrimitive(new LazilyParsedNumber(number));
|
||||||
|
case BOOLEAN:
|
||||||
|
return new JsonPrimitive(in.nextBoolean());
|
||||||
|
case NULL:
|
||||||
|
in.nextNull();
|
||||||
|
return JsonNull.INSTANCE;
|
||||||
|
case BEGIN_ARRAY:
|
||||||
|
JsonArray array = new JsonArray();
|
||||||
|
in.beginArray();
|
||||||
|
while (in.hasNext()) {
|
||||||
|
array.add(read(in));
|
||||||
|
}
|
||||||
|
in.endArray();
|
||||||
|
return array;
|
||||||
|
case BEGIN_OBJECT:
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
in.beginObject();
|
||||||
|
while (in.hasNext()) {
|
||||||
|
object.add(in.nextName(), read(in));
|
||||||
|
}
|
||||||
|
in.endObject();
|
||||||
|
return object;
|
||||||
|
case END_DOCUMENT:
|
||||||
|
case NAME:
|
||||||
|
case END_OBJECT:
|
||||||
|
case END_ARRAY:
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, JsonElement value) throws IOException {
|
||||||
|
if (value == null || value.isJsonNull()) {
|
||||||
|
out.nullValue();
|
||||||
|
} else if (value.isJsonPrimitive()) {
|
||||||
|
JsonPrimitive primitive = value.getAsJsonPrimitive();
|
||||||
|
if (primitive.isNumber()) {
|
||||||
|
out.value(primitive.getAsNumber());
|
||||||
|
} else if (primitive.isBoolean()) {
|
||||||
|
out.value(primitive.getAsBoolean());
|
||||||
|
} else {
|
||||||
|
out.value(primitive.getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (value.isJsonArray()) {
|
||||||
|
out.beginArray();
|
||||||
|
for (JsonElement e : value.getAsJsonArray()) {
|
||||||
|
write(out, e);
|
||||||
|
}
|
||||||
|
out.endArray();
|
||||||
|
|
||||||
|
} else if (value.isJsonObject()) {
|
||||||
|
out.beginObject();
|
||||||
|
|
||||||
|
List<Map.Entry<String, JsonElement>> entries = new ArrayList<>(value.getAsJsonObject().entrySet());
|
||||||
|
entries.sort(Comparator.comparing(Map.Entry::getKey));
|
||||||
|
for (Map.Entry<String, JsonElement> e : entries) {
|
||||||
|
out.name(e.getKey());
|
||||||
|
write(out, e.getValue());
|
||||||
|
}
|
||||||
|
out.endObject();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Couldn't write " + value.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -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<JarEntry> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 ..
|
|
17
scripts/proguard.pro
vendored
17
scripts/proguard.pro
vendored
@ -1,7 +1,3 @@
|
|||||||
-injars baritone-0.0.8.jar
|
|
||||||
-outjars Obfuscated
|
|
||||||
|
|
||||||
|
|
||||||
-keepattributes Signature
|
-keepattributes Signature
|
||||||
-keepattributes *Annotation*
|
-keepattributes *Annotation*
|
||||||
|
|
||||||
@ -29,7 +25,6 @@
|
|||||||
-keep class baritone.launch.** { *; }
|
-keep class baritone.launch.** { *; }
|
||||||
|
|
||||||
# copy all necessary libraries into tempLibraries to build
|
# copy all necessary libraries into tempLibraries to build
|
||||||
-libraryjars '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/rt.jar' # this is the rt jar
|
|
||||||
|
|
||||||
-libraryjars 'tempLibraries/minecraft-1.12.2.jar'
|
-libraryjars 'tempLibraries/minecraft-1.12.2.jar'
|
||||||
|
|
||||||
@ -49,7 +44,6 @@
|
|||||||
-libraryjars 'tempLibraries/httpclient-4.3.3.jar'
|
-libraryjars 'tempLibraries/httpclient-4.3.3.jar'
|
||||||
-libraryjars 'tempLibraries/httpcore-4.3.2.jar'
|
-libraryjars 'tempLibraries/httpcore-4.3.2.jar'
|
||||||
-libraryjars 'tempLibraries/icu4j-core-mojang-51.2.jar'
|
-libraryjars 'tempLibraries/icu4j-core-mojang-51.2.jar'
|
||||||
-libraryjars 'tempLibraries/java-objc-bridge-1.0.0.jar'
|
|
||||||
-libraryjars 'tempLibraries/jinput-2.0.5.jar'
|
-libraryjars 'tempLibraries/jinput-2.0.5.jar'
|
||||||
-libraryjars 'tempLibraries/jna-4.4.0.jar'
|
-libraryjars 'tempLibraries/jna-4.4.0.jar'
|
||||||
-libraryjars 'tempLibraries/jopt-simple-5.0.3.jar'
|
-libraryjars 'tempLibraries/jopt-simple-5.0.3.jar'
|
||||||
@ -60,13 +54,10 @@
|
|||||||
-libraryjars 'tempLibraries/log4j-api-2.8.1.jar'
|
-libraryjars 'tempLibraries/log4j-api-2.8.1.jar'
|
||||||
-libraryjars 'tempLibraries/log4j-core-2.8.1.jar'
|
-libraryjars 'tempLibraries/log4j-core-2.8.1.jar'
|
||||||
|
|
||||||
# linux / travis
|
# startsWith is used to check the library, and mac/linux differ in which version they use
|
||||||
-libraryjars 'tempLibraries/lwjgl-2.9.4-nightly-20150209.jar'
|
# this is FINE
|
||||||
-libraryjars 'tempLibraries/lwjgl_util-2.9.4-nightly-20150209.jar'
|
-libraryjars 'tempLibraries/lwjgl-.jar'
|
||||||
|
-libraryjars 'tempLibraries/lwjgl_util-.jar'
|
||||||
# mac
|
|
||||||
#-libraryjars 'tempLibraries/lwjgl_util-2.9.2-nightly-20140822.jar'
|
|
||||||
#-libraryjars 'tempLibraries/lwjgl-2.9.2-nightly-20140822.jar'
|
|
||||||
|
|
||||||
-libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar'
|
-libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar'
|
||||||
-libraryjars 'tempLibraries/oshi-core-1.1.jar'
|
-libraryjars 'tempLibraries/oshi-core-1.1.jar'
|
||||||
|
Loading…
Reference in New Issue
Block a user