diff --git a/core/src/main/scala/com/eed3si9n/jarjarabrams/Main.scala b/core/src/main/scala/com/eed3si9n/jarjarabrams/Main.scala index 33d0b40..2070bda 100644 --- a/core/src/main/scala/com/eed3si9n/jarjarabrams/Main.scala +++ b/core/src/main/scala/com/eed3si9n/jarjarabrams/Main.scala @@ -1,8 +1,7 @@ package com.eed3si9n.jarjarabrams -import com.eed3si9n.jarjar.{ MainUtil, RulesFileParser } -import java.nio.file.Path; -import scala.collection.JavaConverters._ +import com.eed3si9n.jarjar.MainUtil +import java.nio.file.Path class Main { def help(): Unit = Main.printHelp() @@ -11,11 +10,6 @@ class Main { if (rulesFile == null || inJar == null || outJar == null) { throw new IllegalArgumentException("rulesFile, inJar, and outJar are required"); } - val rules = RulesFileParser - .parse(rulesFile.toFile) - .asScala - .toList - .map(Shader.toShadeRule) val verbose = java.lang.Boolean.getBoolean("verbose") val skipManifest = java.lang.Boolean.getBoolean("skipManifest") val resetTimestamp = sys.props.get("resetTimestamp") match { @@ -23,7 +17,7 @@ class Main { case None => true } Shader.shadeFile( - rules, + Shader.parseRulesFile(rulesFile), inJar, outJar, verbose, diff --git a/core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala b/core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala index bde85bd..981cd87 100644 --- a/core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala +++ b/core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala @@ -122,6 +122,9 @@ object Shader { None } + def parseRulesFile(rulesFile: Path): List[ShadeRule] = + RulesFileParser.parse(rulesFile.toFile()).asScala.map(toShadeRule).toList + def toShadeRule(rule: PatternElement): ShadeRule = rule match { case r: Rule => diff --git a/core/src/main/scala/com/eed3si9n/jarjarabrams/Zip.scala b/core/src/main/scala/com/eed3si9n/jarjarabrams/Zip.scala index 00ad467..782ba26 100644 --- a/core/src/main/scala/com/eed3si9n/jarjarabrams/Zip.scala +++ b/core/src/main/scala/com/eed3si9n/jarjarabrams/Zip.scala @@ -4,6 +4,7 @@ import com.eed3si9n.jarjar.util.EntryStruct import java.nio.file.{ Files, NoSuchFileException, Path } import java.nio.file.attribute.FileTime import java.io.{ ByteArrayOutputStream, FileNotFoundException, InputStream, OutputStream } +import java.security.MessageDigest import java.util.jar.JarEntry import scala.annotation.tailrec import scala.collection.JavaConverters._ @@ -51,7 +52,7 @@ object Zip { val tempJar = Files.createTempFile("jarjar", ".jar") Using.jarOutputStream(tempJar) { out => val names = new mutable.HashSet[String] - in.entries.asScala.toList.foreach { entry0 => + in.entries.asScala.foreach { entry0 => val struct0 = entryStruct( entry0.getName, entry0.getTime, @@ -189,4 +190,23 @@ object Zip { def createDirectories(p: Path): Unit = if (Files.exists(p)) () else Files.createDirectories(p) + + def sha256(p: Path): String = + Using.fileInputStream(p) { in => + val digest = MessageDigest.getInstance("SHA-256") + val hash = digest.digest(toByteArray(in)) + toHex(hash) + } + + private def toHex(bytes: Array[Byte]): String = { + val buffer = new StringBuilder(bytes.length * 2) + for { i <- bytes.indices } { + val hex = Integer.toHexString(bytes(i) & 0xff) + if (hex.length() == 1) { + buffer.append('0') + } + buffer.append(hex) + } + buffer.toString + } } diff --git a/core/src/test/scala/testpkg/ShaderTest.scala b/core/src/test/scala/testpkg/ShaderTest.scala index badb7bf..0519340 100644 --- a/core/src/test/scala/testpkg/ShaderTest.scala +++ b/core/src/test/scala/testpkg/ShaderTest.scala @@ -2,23 +2,70 @@ package testpkg import verify._ import java.nio.file.{ Files, Path, Paths } -import com.eed3si9n.jarjarabrams.{ Main, Zip } +import com.eed3si9n.jarjarabrams.{ Shader, Zip } object ShaderTest extends BasicTestSuite { + final val byteBuddyJar = "example/byte-buddy-agent.jar" + final val shapelessJar = "example/shapeless_2.12-2.3.2.jar" + final val expectedByteBuddyClass = "foo/Attacher.class" + final val expectedShapelessClass = "bar/shapeless/Poly8.class" + test("shade bytebuddy") { - testShading(Paths.get("example/byte-buddy-agent.jar"), "foo/Attacher.class") + testShading( + Paths.get(byteBuddyJar), + resetTimestamp = false, + expectedClass = expectedByteBuddyClass, + expectedSha = "6e7372e52e3b2e981ffa42fc29d5cec1cc84431972d45fb51d605210e11c3ebd" + ) + } + + test("shade bytebuddy (resetTimestamp)") { + testShading( + Paths.get(byteBuddyJar), + resetTimestamp = true, + expectedClass = expectedByteBuddyClass, + expectedSha = "33ceee11fb2b5e4d46ebe552025bc17bc4d9391974c55e07d63f9e85d2ec381a" + ) } test("shade shapeless") { - testShading(Paths.get("example/shapeless_2.12-2.3.2.jar"), "bar/shapeless/Poly8.class") + testShading( + Paths.get(shapelessJar), + resetTimestamp = false, + expectedClass = expectedShapelessClass, + expectedSha = "b0675ab6b2171faad08de45ccbc4674df569e03b434745ebd9e7442cd7846796" + ) + } + + test("shade shapeless (resetTimestamp)") { + testShading( + Paths.get(shapelessJar), + resetTimestamp = true, + expectedClass = expectedShapelessClass, + expectedSha = "68ac892591bb30eb2ba5c0c2c3195e7529e15bacd221b8bb3d75b154f5a4ce76" + ) } - def testShading(inJar: Path, expectedClass: String): Unit = { + def testShading( + inJar: Path, + resetTimestamp: Boolean, + expectedClass: String, + expectedSha: String + ): Unit = { val tempJar = Files.createTempFile("test", ".jar") Files.delete(tempJar) - val rules = Paths.get("example/shade.rules") - new Main().process(rules, inJar, tempJar) + val rules = Shader.parseRulesFile(Paths.get("example/shade.rules")) + Shader.shadeFile( + rules, + inJar, + tempJar, + verbose = false, + skipManifest = false, + resetTimestamp + ) val entries = Zip.list(tempJar).map(_._1) assert(entries.contains(expectedClass)) + val actualSha = Zip.sha256(tempJar) + assert(actualSha == expectedSha) } }