Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: eed3si9n/jarjar-abrams
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.8.3
Choose a base ref
...
head repository: eed3si9n/jarjar-abrams
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: develop
Choose a head ref
Loading
Showing with 958 additions and 162 deletions.
  1. +39 −7 .github/workflows/ci.yml
  2. 0 {jarjar → ant-jarjar}/src/main/java/com/eed3si9n/jarjar/JarJarTask.java
  3. 0 {jarjar → ant-jarjar}/src/main/java/com/eed3si9n/jarjar/util/AntJarProcessor.java
  4. +56 −8 build.sbt
  5. +3 −2 core/src/main/scala/com/eed3si9n/jarjar/JJProcessor.scala
  6. +89 −0 core/src/main/scala/com/eed3si9n/jarjarabrams/Main.scala
  7. +61 −5 core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala
  8. +93 −0 core/src/main/scala/com/eed3si9n/jarjarabrams/Using.scala
  9. +216 −0 core/src/main/scala/com/eed3si9n/jarjarabrams/Zip.scala
  10. +2 −2 core/src/main/scala/com/eed3si9n/jarjarabrams/scalasig/ScalaSigAnnotationVisitor.scala
  11. +71 −0 core/src/test/scala/testpkg/ShaderTest.scala
  12. BIN example/byte-buddy-agent.jar
  13. +2 −0 example/shade.rules
  14. BIN example/shapeless_2.12-2.3.2.jar
  15. +3 −3 jarjar/src/it/java/com/eed3si9n/jarjar/integration/BadPackagesTest.java
  16. +0 −10 jarjar/src/it/java/com/eed3si9n/jarjar/integration/JavaVersionsTest.java
  17. +4 −4 jarjar/src/main/java/com/eed3si9n/jarjar/EmptyClassVisitor.java
  18. +2 −2 jarjar/src/main/java/com/eed3si9n/jarjar/MainProcessor.java
  19. +5 −1 jarjar/src/main/java/com/eed3si9n/jarjar/MainUtil.java
  20. +14 −11 jarjar/src/main/java/com/eed3si9n/jarjar/MethodSignatureProcessor.java
  21. +19 −2 jarjar/src/main/java/com/eed3si9n/jarjar/PackageRemapper.java
  22. +1 −1 jarjar/src/main/java/com/eed3si9n/jarjar/RulesFileParser.java
  23. +4 −4 jarjar/src/main/java/com/eed3si9n/jarjar/StringReader.java
  24. +15 −0 jarjar/src/main/java/com/eed3si9n/jarjar/TracingRemapper.java
  25. +14 −3 jarjar/src/main/java/com/eed3si9n/jarjar/ZapProcessor.java
  26. +9 −0 jarjar/src/main/java/com/eed3si9n/jarjar/util/EntryStruct.java
  27. +1 −1 jarjar/src/main/java/com/eed3si9n/jarjar/util/GetNameClassWriter.java
  28. +31 −63 jarjar/src/main/java/com/eed3si9n/jarjar/util/IoUtil.java
  29. +11 −4 jarjar/src/main/java/com/eed3si9n/jarjar/util/JarTransformer.java
  30. +9 −7 jarjar/src/main/java/com/eed3si9n/jarjar/util/JarTransformerChain.java
  31. +9 −4 jarjar/src/main/java/com/eed3si9n/jarjar/util/RemappingClassTransformer.java
  32. +41 −0 jarjar/src/main/java/com/eed3si9n/jarjar/util/RemappingJarProcessor.java
  33. +3 −2 jarjar/src/test/java/com/eed3si9n/jarjar/GenericsTest.java
  34. +3 −3 jarjar/src/test/java/com/eed3si9n/jarjar/MethodRewriterTest.java
  35. +35 −0 jarjar/src/test/java/com/eed3si9n/jarjar/UnmodifiedTest.java
  36. +9 −6 jarjar/src/test/java/com/eed3si9n/jarjar/VersionedClassTest.java
  37. +6 −0 jarjar/src/test/java/com/eed3si9n/jarjar/ZapProcessorTest.java
  38. +68 −0 jarjar/src/test/java/com/eed3si9n/jarjar/util/IOUtilTest.java
  39. 0 {jarjar → maven-jarjar}/src/main/java/com/eed3si9n/jarjar/JarJarMojo.java
  40. +2 −2 project/Dependencies.scala
  41. +1 −1 project/build.properties
  42. +5 −2 project/plugins.sbt
  43. +1 −1 sbtplugin/src/sbt-test/actions/simple/build.sbt
  44. +1 −1 sbtplugin/src/sbt-test/actions/two/build.sbt
46 changes: 39 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -15,19 +15,51 @@ jobs:
- os: ubuntu-latest
java: 11
jobtype: 1
- os: ubuntu-latest
java: 11
jobtype: 2
runs-on: ${{ matrix.os }}
env:
# define Java options for both official sbt and sbt-extras
JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
uses: olafurpg/setup-scala@v13
uses: actions/checkout@v4
- name: Setup JDK
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: "${{ matrix.java }}"
cache: sbt
- name: Build and test (1)
if: ${{ matrix.jobtype == 1 }}
shell: bash
run: |
sbt -v -Dfile.encoding=UTF8 "jarjar/publishLocal" "jarjar/IntegrationTest/test" "+test" "publishLocal;scripted"
- name: Build and test (2)
if: ${{ matrix.jobtype == 2 }}
shell: bash
run: |
sbt -v -Dfile.encoding=UTF8 scalafmtCheckAll
ea-test:
runs-on: ubuntu-latest
env:
# define Java options for both official sbt and sbt-extras
JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup JDK
uses: actions/setup-java@v3
with:
java-version: "adopt@1.${{ matrix.java }}"
- name: Coursier cache
uses: coursier/cache-action@v6
java-version: 22-ea
distribution: temurin
jdkFile: https://download.java.net/java/early_access/jdk22/20/GPL/openjdk-22-ea+20_linux-x64_bin.tar.gz
cache: sbt
- name: Build and test
run: sbt -v "scalafmtCheckAll" "jarjar/publishLocal" "jarjar/IntegrationTest/test" "+test" "publishLocal;scripted"
shell: bash
run: |
sbt -v -Dfile.encoding=UTF8 "jarjar/publishLocal" "jarjar/IntegrationTest/test" "+test" "publishLocal;scripted"
64 changes: 56 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -4,7 +4,11 @@ ThisBuild / scalaVersion := scala212
ThisBuild / organization := "com.eed3si9n.jarjarabrams"
ThisBuild / organizationName := "eed3si9n"
ThisBuild / organizationHomepage := Some(url("http://eed3si9n.com/"))
ThisBuild / version := "1.8.2-SNAPSHOT"
ThisBuild / version := {
val old = (ThisBuild / version).value
if ((ThisBuild / isSnapshot).value) "1.9.0-SNAPSHOT"
else old
}
ThisBuild / description := "utility to shade Scala libraries"
ThisBuild / licenses := Seq(
"Apache 2" -> new URL("https://www.apache.org/licenses/LICENSE-2.0.txt")
@@ -23,10 +27,8 @@ lazy val jarjar = project
crossPaths := false
autoScalaLibrary := false
libraryDependencies ++= Seq(
"org.ow2.asm" % "asm" % "9.2",
"org.ow2.asm" % "asm-commons" % "9.2",
"org.apache.ant" % "ant" % "1.10.14",
"org.apache.maven" % "maven-plugin-api" % "3.9.4",
"org.ow2.asm" % "asm" % "9.6",
"org.ow2.asm" % "asm-commons" % "9.6",
"org.apache.commons" % "commons-lang3" % "3.8.1",
"junit" % "junit" % "4.12" % "it,test",
"com.github.sbt" % "junit-interface" % "0.13.2" % "it,test"
@@ -52,6 +54,36 @@ lazy val jarjar = project
}
})

lazy val ant_jarjar = project
.in(file("ant-jarjar"))
.disablePlugins(ScalafmtPlugin)
.dependsOn(jarjar)
.settings(nocomma {
organization := "com.eed3si9n.jarjar"
name := "ant-jarjar"
crossScalaVersions := Vector(scala212)
crossPaths := false
autoScalaLibrary := false
libraryDependencies ++= Seq(
"org.apache.ant" % "ant" % "1.10.14",
)
})

lazy val maven_jarjar = project
.in(file("maven-jarjar"))
.disablePlugins(ScalafmtPlugin)
.dependsOn(jarjar)
.settings(nocomma {
organization := "com.eed3si9n.jarjar"
name := "maven-jarjar"
crossScalaVersions := Vector(scala212)
crossPaths := false
autoScalaLibrary := false
libraryDependencies ++= Seq(
"org.apache.maven" % "maven-plugin-api" % "3.9.4",
)
})

lazy val jarjar_assembly = project
.settings(nocomma {
organization := "com.eed3si9n.jarjar"
@@ -62,13 +94,20 @@ lazy val jarjar_assembly = project
Compile / packageBin := (jarjar / assembly).value
})

lazy val jarjar_abrams_assembly = project
.settings(nocomma {
crossScalaVersions := Vector(scala212, scala213)
name := "jarjar-abrams-assembly"
Compile / packageBin := (core / assembly).value
})

lazy val core = project
.enablePlugins(ContrabandPlugin)
.dependsOn(jarjar)
.settings(nocomma {
name := "jarjar-abrams-core"

crossScalaVersions := Vector(scala212, scala213, scala211, scala210)
crossScalaVersions := Vector(scala212, scala213)

libraryDependencies ++= {
if (scalaVersion.value.startsWith("2.10.")) Nil
@@ -86,9 +125,11 @@ lazy val core = project

testFrameworks += new TestFramework("verify.runner.Framework")

Compile / scalacOptions += "-deprecation"
Compile / scalacOptions ++= {
if (scalaVersion.value.startsWith("2.13.")) Vector("-Xlint")
else Vector("-Xlint", "-Xfatal-warnings")
if (scalaVersion.value.startsWith("2.13.")) Vector("-Xlint", "-Xsource:3")
else if (scalaVersion.value.startsWith("2.12.")) Vector("-Xlint", "-Xfatal-warnings")
else Vector("-Xlint")
}
})

@@ -105,6 +146,7 @@ lazy val sbtplugin = project
Vector("-Xmx1024M", "-Dplugin.version=" + version.value)
}
pluginCrossBuild / sbtVersion := "1.2.8"
scriptedSbt := "1.9.7"
scriptedBufferLog := false
})

@@ -131,3 +173,9 @@ ThisBuild / publishTo := {
else Some("releases" at nexus + "service/local/staging/deploy/maven2")
}
ThisBuild / publishMavenStyle := true
ThisBuild / assemblyMergeStrategy := {
case "module-info.class" => MergeStrategy.discard
case x =>
val oldStrategy = (ThisBuild / assemblyMergeStrategy).value
oldStrategy(x)
}
5 changes: 3 additions & 2 deletions core/src/main/scala/com/eed3si9n/jarjar/JJProcessor.scala
Original file line number Diff line number Diff line change
@@ -52,13 +52,14 @@ class JJProcessor(
processors += new ZapProcessor(zapList.asJava)
processors += misplacedClassProcessor
processors += new JarTransformerChain(
Array[RemappingClassTransformer](new RemappingClassTransformer(pr))
Array[RemappingClassTransformer](new RemappingClassTransformer()),
pr
)

val renamer: String => Option[String] = {
val wildcards = PatternElement.createWildcards(ruleList.asJava).asScala

value: String => {
(value: String) => {
val result = wildcards.flatMap { wc =>
val slashed = value.replace('.', '/') // The jarjar wildcards expect slashes instead of dots
// Hack to replace the package object name.
89 changes: 89 additions & 0 deletions core/src/main/scala/com/eed3si9n/jarjarabrams/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.eed3si9n.jarjarabrams

import com.eed3si9n.jarjar.MainUtil
import java.nio.file.Path

class Main {
def help(): Unit = Main.printHelp()

def process(rulesFile: Path, inJar: Path, outJar: Path): Unit = {
if (rulesFile == null || inJar == null || outJar == null) {
throw new IllegalArgumentException("rulesFile, inJar, and outJar are required");
}
val verbose = java.lang.Boolean.getBoolean("verbose")
val skipManifest = java.lang.Boolean.getBoolean("skipManifest")
val resetTimestamp = sys.props.get("resetTimestamp") match {
case Some(_) => java.lang.Boolean.getBoolean("resetTimestamp")
case None => true
}
val warnOnDuplicateClass = java.lang.Boolean.getBoolean("duplicateClassToWarn")
Shader.shadeFile(
Shader.parseRulesFile(rulesFile),
inJar,
outJar,
verbose,
skipManifest,
resetTimestamp,
warnOnDuplicateClass
)
}
}

object Main {
def main(args: Array[String]): Unit = {
MainUtil.runMain(new Main(), args, "help")
}

def printHelp(): Unit = {
val jarName = "jarjar-abrams-assembly.jar"
val str = s"""Jar Jar Abrams - A utility to repackage and embed Java and Scala libraries

Command-line usage:

java -jar $jarName [help]

Prints this help message.

java -jar $jarName process <rulesFile> <inJar> <outJar>

Transform the <inJar> jar file, writing a new jar file to <outJar>.
Any existing file named by <outJar> will be deleted.

The transformation is defined by a set of rules in the file specified
by the rules argument (see below).

Rules file format:

The rules file is a text file, one rule per line. Leading and trailing
whitespace is ignored. There are three types of rules:

rule <pattern> <result>
zap <pattern>
keep <pattern>

The standard rule ("rule") is used to rename classes. All references
to the renamed classes will also be updated. If a class name is
matched by more than one rule, only the first one will apply.

<pattern> is a class name with optional wildcards. "**" will
match against any valid class name substring. To match a single
package component (by excluding "." from the match), a single "*" may
be used instead.

<result> is a class name which can optionally reference the
substrings matched by the wildcards. A numbered reference is available
for every "*" or "**" in the <pattern>, starting from left to
right: "@1", "@2", etc. A special "@0" reference contains the entire
matched class name.

The "zap" rule causes any matched class to be removed from the resulting
jar file. All zap rules are processed before renaming rules.

The "keep" rule marks all matched classes as "roots". If any keep
rules are defined all classes which are not reachable from the roots
via dependency analysis are discarded when writing the output
jar. This is the last step in the process, after renaming and zapping.
"""
str.linesIterator.foreach(Console.err.println)
}
}
66 changes: 61 additions & 5 deletions core/src/main/scala/com/eed3si9n/jarjarabrams/Shader.scala
Original file line number Diff line number Diff line change
@@ -3,31 +3,71 @@ package com.eed3si9n.jarjarabrams
import java.nio.file.{ Files, Path, StandardOpenOption }
import com.eed3si9n.jarjar.{ JJProcessor, _ }
import com.eed3si9n.jarjar.util.EntryStruct
import Zip.createDirectories
import scala.collection.JavaConverters._

object Shader {
def shadeFile(
rules: Seq[ShadeRule],
inputJar: Path,
outputJar: Path,
verbose: Boolean,
skipManifest: Boolean,
resetTimestamp: Boolean,
warnOnDuplicateClass: Boolean
): Unit = {
val shader = bytecodeShader(rules, verbose, skipManifest)
Zip.transformJarFile(inputJar, outputJar, resetTimestamp, warnOnDuplicateClass) { struct0 =>
shader(struct0.data, struct0.name).map {
case (shadedBytes, shadedName) =>
Zip.entryStruct(shadedName, struct0.time, shadedBytes, struct0.skipTransform)
}
}
}

def makeMappings(dir: Path): List[(Path, String)] =
Files.walk(dir).iterator().asScala.toList.flatMap { x =>
if (x == dir) None
else Some(x -> dir.relativize(x).toString)
}

def shadeDirectory(
rules: Seq[ShadeRule],
dir: Path,
mappings: Seq[(Path, String)],
verbose: Boolean
): Unit = shadeDirectory(rules, dir, mappings, verbose, skipManifest = true)

def shadeDirectory(
rules: Seq[ShadeRule],
dir: Path,
mappings: Seq[(Path, String)],
verbose: Boolean,
skipManifest: Boolean
): Unit =
if (rules.isEmpty) {} else {
val shader = bytecodeShader(rules, verbose)
if (rules.isEmpty) ()
else {
val shader = bytecodeShader(rules, verbose, skipManifest)
for {
(path, name) <- mappings
if !Files.isDirectory(path)
bytes = Files.readAllBytes(path)
_ = Files.delete(path)
(shadedBytes, shadedName) <- shader(bytes, name)
out = dir.resolve(shadedName)
_ = Files.createDirectories(out.getParent)
_ = createDirectories(out.getParent)
_ = Files.write(out, shadedBytes, StandardOpenOption.CREATE)
} yield ()
Files.walk(dir).iterator().asScala.toList.foreach { x =>
if (x == dir) ()
else Zip.resetModifiedTime(x)
}
}

def bytecodeShader(
rules: Seq[ShadeRule],
verbose: Boolean
verbose: Boolean,
skipManifest: Boolean
): (Array[Byte], String) => Option[(Array[Byte], String)] =
if (rules.isEmpty)(bytes, mapping) => Some(bytes -> mapping)
else {
@@ -57,7 +97,12 @@ object Shader {
}
}

val proc = new JJProcessor(jjrules, verbose, true, null)
val proc = new JJProcessor(
patterns = jjrules,
verbose = verbose,
skipManifest = skipManifest,
misplacedClassStrategy = null
)
val excludes = proc.getExcludes

(bytes, mapping) =>
@@ -77,6 +122,17 @@ object Shader {
else
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 =>
ShadeRule(ShadeRule.rename((r.getPattern, r.getResult)), Vector(ShadeTarget.inAll))
case r: Keep => ShadeRule(ShadeRule.keep((r.getPattern)), Vector(ShadeTarget.inAll))
case r: Zap => ShadeRule(ShadeRule.zap((r.getPattern)), Vector(ShadeTarget.inAll))
}
}

sealed trait ShadePattern {
Loading