From 6692a5e121f54e46172f528ff537fba497b3a499 Mon Sep 17 00:00:00 2001 From: Shani Elharrar Date: Sun, 11 Dec 2022 08:29:13 +0200 Subject: [PATCH] Assembly: Added keepRules which runs on the final jar This allows users of this lib/plugin to keep only files from libraries they use in their project without specifying them in zap --- src/main/contraband/AssemblyOption.contra | 2 + src/main/scala/sbtassembly/Assembly.scala | 62 +++++++-- src/main/scala/sbtassembly/AssemblyKeys.scala | 1 + .../scala/sbtassembly/AssemblyOption.scala | 21 ++- .../scala/sbtassembly/AssemblyPlugin.scala | 2 + src/sbt-test/shading/keeprules/build.sbt | 126 ++++++++++++++++++ .../shading/keeprules/project/plugins.sbt | 7 + .../src/main/scala/keep/Keeped.scala | 10 ++ .../src/main/scala/removed/ShadeClass.scala | 3 + .../src/main/scala/removed/ShadePackage.scala | 3 + src/sbt-test/shading/keeprules/test | 7 + 11 files changed, 225 insertions(+), 19 deletions(-) create mode 100644 src/sbt-test/shading/keeprules/build.sbt create mode 100644 src/sbt-test/shading/keeprules/project/plugins.sbt create mode 100644 src/sbt-test/shading/keeprules/src/main/scala/keep/Keeped.scala create mode 100644 src/sbt-test/shading/keeprules/src/main/scala/removed/ShadeClass.scala create mode 100644 src/sbt-test/shading/keeprules/src/main/scala/removed/ShadePackage.scala create mode 100644 src/sbt-test/shading/keeprules/test diff --git a/src/main/contraband/AssemblyOption.contra b/src/main/contraband/AssemblyOption.contra index 32fb69d1..2c90a1bf 100644 --- a/src/main/contraband/AssemblyOption.contra +++ b/src/main/contraband/AssemblyOption.contra @@ -26,6 +26,8 @@ type AssemblyOption { shadeRules: sbtassembly.Assembly.SeqShadeRules! = raw"sbtassembly.Assembly.defaultShadeRules" @since("0.15.0") + keepRules: sbtassembly.Assembly.SeqString! = raw"sbtassembly.Assembly.defaultKeepRules" @since("2.0.1") + scalaVersion: String! = "" @since("0.15.0") level: sbt.Level.Value! = raw"sbt.Level.Info" @since("0.15.0") diff --git a/src/main/scala/sbtassembly/Assembly.scala b/src/main/scala/sbtassembly/Assembly.scala index b0f9e18a..babffc87 100644 --- a/src/main/scala/sbtassembly/Assembly.scala +++ b/src/main/scala/sbtassembly/Assembly.scala @@ -3,27 +3,29 @@ package sbtassembly import com.eed3si9n.jarjarabrams._ import sbt.Def.Initialize import sbt.Keys._ -import sbt.Package.{ manifestFormat, JarManifest, MainClass, ManifestAttributes } +import sbt.Package.{JarManifest, MainClass, ManifestAttributes, manifestFormat} import sbt.internal.util.HListFormats._ import sbt.internal.util.HNil import sbt.internal.util.Types.:+: -import sbt.io.{ DirectoryFilter => _, IO => _, Path => _, Using } +import sbt.io.{Using, DirectoryFilter => _, IO => _, Path => _} import sbt.util.FileInfo.lastModified -import sbt.util.Tracked.{ inputChanged, lastOutput } -import sbt.util.{ FilesInfo, Level, ModifiedFileInfo } -import sbt.{ File, Logger, _ } +import sbt.util.Tracked.{inputChanged, lastOutput} +import sbt.util.{FilesInfo, Level, ModifiedFileInfo} +import sbt.{File, Logger, _} import sbt.Tags.Tag import CacheImplicits._ -import sbtassembly.AssemblyPlugin.autoImport.{ Assembly => _, _ } +import com.eed3si9n.jarjar.util.EntryStruct +import com.eed3si9n.jarjar.{JJProcessor, Keep} +import sbtassembly.AssemblyPlugin.autoImport.{Assembly => _, _} import sbtassembly.PluginCompat.ClasspathUtilities import java.io._ import java.net.URI -import java.nio.file.attribute.{ BasicFileAttributeView, FileTime, PosixFilePermission } -import java.nio.file.{ Path, _ } +import java.nio.file.attribute.{BasicFileAttributeView, FileTime, PosixFilePermission} +import java.nio.file.{Path, _} import java.security.MessageDigest import java.time.Instant -import java.util.jar.{ Attributes => JAttributes, JarFile, Manifest => JManifest } +import java.util.jar.{JarFile, Attributes => JAttributes, Manifest => JManifest} import scala.annotation.tailrec import scala.collection.GenSeq import scala.collection.JavaConverters._ @@ -36,7 +38,8 @@ object Assembly { type SeqShadeRules = Seq[com.eed3si9n.jarjarabrams.ShadeRule] type LazyInputStream = () => InputStream - val defaultShadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule] = Nil + val defaultShadeRules: SeqShadeRules = Nil + val defaultKeepRules: SeqString = Nil val newLine: String = "\n" val indent: String = " " * 2 val newLineIndented: String = newLine + indent @@ -336,11 +339,15 @@ object Assembly { timed(Level.Debug, "Finding remaining conflicts that were not merged") { reportConflictsMissedByTheMerge(mergedEntries, log) } + val finalEntries = timed(Level.Debug, "Applying keep rules") { + val entries = mergedEntries.flatMap(_.entries) + if (ao.keepRules.isEmpty) entries else keepShader(ao.keepRules, log, entries) + } val jarEntriesToWrite = timed(Level.Debug, "Sort/Parallelize merged entries") { if (ao.repeatableBuild) // we need the jars in a specific order to have a consistent hash - mergedEntries.flatMap(_.entries).seq.sortBy(_.target) + finalEntries.seq.sortBy(_.target) else // we actually gain performance when creating the jar in parallel, but we won't have a consistent hash - mergedEntries.flatMap(_.entries).par + finalEntries.par } val localTime = timestamp .map(t => t - java.util.TimeZone.getDefault.getOffset(t)) @@ -565,6 +572,37 @@ object Assembly { } } + private[sbtassembly] def keepShader(keepRules: SeqString, log: Logger, entries: Seq[JarEntry]): Seq[JarEntry] = { + val jjRules = keepRules.map(pattern => { + val jRule = new Keep() + jRule.setPattern(pattern) + jRule + }) + + val proc = new JJProcessor(jjRules, true, true, null) + + val entryStructs = entries.map({ entry => + val stream = entry.stream() + val entryStruct = new EntryStruct() + val mapping = entry.target + entryStruct.name = if (mapping.contains('\\')) mapping.replace('\\', '/') else mapping + entryStruct.data = Streamable.bytes(stream) + entryStruct.time = -1 + entryStruct.skipTransform = false + stream.close() + entryStruct + }) + + val itemsToExclude = proc.getExcludes + log.info(s"items to exclude: ${itemsToExclude.size}") + entryStructs.filterNot(entry => itemsToExclude.contains(entry.name)) + .map(entryStruct => { + val mapping = entryStruct.name + val name = if (mapping.contains('/')) mapping.replace('/', '\\') else mapping + JarEntry(name, () => new ByteArrayInputStream(entryStruct.data)) + }) + } + private[sbtassembly] def createManifest(po: Seq[PackageOption], log: Logger): (JManifest, Option[Long]) = { import scala.language.reflectiveCalls val manifest = new JManifest diff --git a/src/main/scala/sbtassembly/AssemblyKeys.scala b/src/main/scala/sbtassembly/AssemblyKeys.scala index ca8f49d3..8cad1d56 100644 --- a/src/main/scala/sbtassembly/AssemblyKeys.scala +++ b/src/main/scala/sbtassembly/AssemblyKeys.scala @@ -16,6 +16,7 @@ trait AssemblyKeys { lazy val assemblyExcludedJars = taskKey[Classpath]("list of excluded jars") lazy val assemblyMergeStrategy = settingKey[String => MergeStrategy]("mapping from archive member path to merge strategy") lazy val assemblyShadeRules = settingKey[Seq[jarjarabrams.ShadeRule]]("shading rules backed by jarjar") + lazy val assemblyKeepRules = settingKey[Seq[String]]("Keep rules backed by jarjar to run on the final assembled JAR") lazy val assemblyAppendContentHash = settingKey[Boolean]("Appends SHA-1 fingerprint to the assembly file name") lazy val assemblyMaxHashLength = settingKey[Int]("Length of SHA-1 fingerprint used for the assembly file name") lazy val assemblyCacheOutput = settingKey[Boolean]("Enables (true) or disables (false) cacheing the output if the content has not changed") diff --git a/src/main/scala/sbtassembly/AssemblyOption.scala b/src/main/scala/sbtassembly/AssemblyOption.scala index f342088d..78457677 100644 --- a/src/main/scala/sbtassembly/AssemblyOption.scala +++ b/src/main/scala/sbtassembly/AssemblyOption.scala @@ -20,24 +20,26 @@ final class AssemblyOption private ( val prependShellScript: Option[sbtassembly.Assembly.SeqString], val maxHashLength: Option[Int], val shadeRules: sbtassembly.Assembly.SeqShadeRules, + val keepRules: sbtassembly.Assembly.SeqString, val scalaVersion: String, val level: sbt.Level.Value) extends Serializable { - private def this() = this(true, true, true, Nil, true, sbtassembly.MergeStrategy.defaultMergeStrategy, true, false, None, None, sbtassembly.Assembly.defaultShadeRules, "", sbt.Level.Info) - private def this(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: Option[sbtassembly.Assembly.SeqString], maxHashLength: Option[Int], shadeRules: sbtassembly.Assembly.SeqShadeRules, scalaVersion: String, level: sbt.Level.Value) = this(includeBin, includeScala, includeDependency, excludedJars, true, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, scalaVersion, level) + private def this() = this(true, true, true, Nil, true, sbtassembly.MergeStrategy.defaultMergeStrategy, true, false, None, None, sbtassembly.Assembly.defaultShadeRules, sbtassembly.Assembly.defaultKeepRules, "", sbt.Level.Info) + private def this(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: Option[sbtassembly.Assembly.SeqString], maxHashLength: Option[Int], shadeRules: sbtassembly.Assembly.SeqShadeRules, scalaVersion: String, level: sbt.Level.Value) = this(includeBin, includeScala, includeDependency, excludedJars, true, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, sbtassembly.Assembly.defaultKeepRules, scalaVersion, level) + private def this(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, repeatableBuild: Boolean, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: Option[sbtassembly.Assembly.SeqString], maxHashLength: Option[Int], shadeRules: sbtassembly.Assembly.SeqShadeRules, scalaVersion: String, level: sbt.Level.Value) = this(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, sbtassembly.Assembly.defaultKeepRules, scalaVersion, level) override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { - case x: AssemblyOption => (this.includeBin == x.includeBin) && (this.includeScala == x.includeScala) && (this.includeDependency == x.includeDependency) && (this.excludedJars == x.excludedJars) && (this.repeatableBuild == x.repeatableBuild) && (this.mergeStrategy == x.mergeStrategy) && (this.cacheOutput == x.cacheOutput) && (this.appendContentHash == x.appendContentHash) && (this.prependShellScript == x.prependShellScript) && (this.maxHashLength == x.maxHashLength) && (this.shadeRules == x.shadeRules) && (this.scalaVersion == x.scalaVersion) && (this.level == x.level) + case x: AssemblyOption => (this.includeBin == x.includeBin) && (this.includeScala == x.includeScala) && (this.includeDependency == x.includeDependency) && (this.excludedJars == x.excludedJars) && (this.repeatableBuild == x.repeatableBuild) && (this.mergeStrategy == x.mergeStrategy) && (this.cacheOutput == x.cacheOutput) && (this.appendContentHash == x.appendContentHash) && (this.prependShellScript == x.prependShellScript) && (this.maxHashLength == x.maxHashLength) && (this.shadeRules == x.shadeRules) && (this.keepRules == x.keepRules) && (this.scalaVersion == x.scalaVersion) && (this.level == x.level) case _ => false }) override def hashCode: Int = { - 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbtassembly.AssemblyOption".##) + includeBin.##) + includeScala.##) + includeDependency.##) + excludedJars.##) + repeatableBuild.##) + mergeStrategy.##) + cacheOutput.##) + appendContentHash.##) + prependShellScript.##) + maxHashLength.##) + shadeRules.##) + scalaVersion.##) + level.##) + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbtassembly.AssemblyOption".##) + includeBin.##) + includeScala.##) + includeDependency.##) + excludedJars.##) + repeatableBuild.##) + mergeStrategy.##) + cacheOutput.##) + appendContentHash.##) + prependShellScript.##) + maxHashLength.##) + shadeRules.##) + keepRules.##) + scalaVersion.##) + level.##) } override def toString: String = { - "AssemblyOption(" + includeBin + ", " + includeScala + ", " + includeDependency + ", " + excludedJars + ", " + repeatableBuild + ", " + mergeStrategy + ", " + cacheOutput + ", " + appendContentHash + ", " + prependShellScript + ", " + maxHashLength + ", " + shadeRules + ", " + scalaVersion + ", " + level + ")" + "AssemblyOption(" + includeBin + ", " + includeScala + ", " + includeDependency + ", " + excludedJars + ", " + repeatableBuild + ", " + mergeStrategy + ", " + cacheOutput + ", " + appendContentHash + ", " + prependShellScript + ", " + maxHashLength + ", " + shadeRules + ", " + keepRules + ", " + scalaVersion + ", " + level + ")" } - private[this] def copy(includeBin: Boolean = includeBin, includeScala: Boolean = includeScala, includeDependency: Boolean = includeDependency, excludedJars: sbt.Keys.Classpath = excludedJars, repeatableBuild: Boolean = repeatableBuild, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy = mergeStrategy, cacheOutput: Boolean = cacheOutput, appendContentHash: Boolean = appendContentHash, prependShellScript: Option[sbtassembly.Assembly.SeqString] = prependShellScript, maxHashLength: Option[Int] = maxHashLength, shadeRules: sbtassembly.Assembly.SeqShadeRules = shadeRules, scalaVersion: String = scalaVersion, level: sbt.Level.Value = level): AssemblyOption = { - new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, scalaVersion, level) + private[this] def copy(includeBin: Boolean = includeBin, includeScala: Boolean = includeScala, includeDependency: Boolean = includeDependency, excludedJars: sbt.Keys.Classpath = excludedJars, repeatableBuild: Boolean = repeatableBuild, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy = mergeStrategy, cacheOutput: Boolean = cacheOutput, appendContentHash: Boolean = appendContentHash, prependShellScript: Option[sbtassembly.Assembly.SeqString] = prependShellScript, maxHashLength: Option[Int] = maxHashLength, shadeRules: sbtassembly.Assembly.SeqShadeRules = shadeRules, keepRules: sbtassembly.Assembly.SeqString = keepRules, scalaVersion: String = scalaVersion, level: sbt.Level.Value = level): AssemblyOption = { + new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, keepRules, scalaVersion, level) } def withIncludeBin(includeBin: Boolean): AssemblyOption = { copy(includeBin = includeBin) @@ -78,6 +80,9 @@ final class AssemblyOption private ( def withShadeRules(shadeRules: sbtassembly.Assembly.SeqShadeRules): AssemblyOption = { copy(shadeRules = shadeRules) } + def withKeepRules(keepRules: sbtassembly.Assembly.SeqString): AssemblyOption = { + copy(keepRules = keepRules) + } def withScalaVersion(scalaVersion: String): AssemblyOption = { copy(scalaVersion = scalaVersion) } @@ -92,4 +97,6 @@ object AssemblyOption { def apply(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: sbtassembly.Assembly.SeqString, maxHashLength: Int, shadeRules: sbtassembly.Assembly.SeqShadeRules, scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, mergeStrategy, cacheOutput, appendContentHash, Option(prependShellScript), Option(maxHashLength), shadeRules, scalaVersion, level) def apply(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, repeatableBuild: Boolean, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: Option[sbtassembly.Assembly.SeqString], maxHashLength: Option[Int], shadeRules: sbtassembly.Assembly.SeqShadeRules, scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, scalaVersion, level) def apply(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, repeatableBuild: Boolean, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: sbtassembly.Assembly.SeqString, maxHashLength: Int, shadeRules: sbtassembly.Assembly.SeqShadeRules, scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, Option(prependShellScript), Option(maxHashLength), shadeRules, scalaVersion, level) + def apply(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, repeatableBuild: Boolean, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: Option[sbtassembly.Assembly.SeqString], maxHashLength: Option[Int], shadeRules: sbtassembly.Assembly.SeqShadeRules, keepRules: sbtassembly.Assembly.SeqString, scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, prependShellScript, maxHashLength, shadeRules, keepRules, scalaVersion, level) + def apply(includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, repeatableBuild: Boolean, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, appendContentHash: Boolean, prependShellScript: sbtassembly.Assembly.SeqString, maxHashLength: Int, shadeRules: sbtassembly.Assembly.SeqShadeRules, keepRules: sbtassembly.Assembly.SeqString, scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(includeBin, includeScala, includeDependency, excludedJars, repeatableBuild, mergeStrategy, cacheOutput, appendContentHash, Option(prependShellScript), Option(maxHashLength), shadeRules, keepRules, scalaVersion, level) } diff --git a/src/main/scala/sbtassembly/AssemblyPlugin.scala b/src/main/scala/sbtassembly/AssemblyPlugin.scala index 5265f8c7..9303bce7 100644 --- a/src/main/scala/sbtassembly/AssemblyPlugin.scala +++ b/src/main/scala/sbtassembly/AssemblyPlugin.scala @@ -29,6 +29,7 @@ object AssemblyPlugin extends sbt.AutoPlugin { override lazy val globalSettings: Seq[Def.Setting[_]] = Seq( assemblyMergeStrategy := MergeStrategy.defaultMergeStrategy, assemblyShadeRules := Nil, + assemblyKeepRules := Nil, assemblyExcludedJars := Nil, assembleArtifact in packageBin := true, assembleArtifact in assemblyPackageScala := true, @@ -118,6 +119,7 @@ object AssemblyPlugin extends sbt.AutoPlugin { .withPrependShellScript(assemblyPrependShellScript.value) .withMaxHashLength(assemblyMaxHashLength.?.value) .withShadeRules(assemblyShadeRules.value) + .withKeepRules(assemblyKeepRules.value) .withScalaVersion(scalaVersion.value) .withLevel(logLevel.?.value.getOrElse(Level.Info)) .withRepeatableBuild(assemblyRepeatableBuild.value) diff --git a/src/sbt-test/shading/keeprules/build.sbt b/src/sbt-test/shading/keeprules/build.sbt new file mode 100644 index 00000000..b28b2de5 --- /dev/null +++ b/src/sbt-test/shading/keeprules/build.sbt @@ -0,0 +1,126 @@ +lazy val scala212 = "2.12.15" +lazy val scala213 = "2.13.7" + +scalaVersion := scala212 +crossScalaVersions := List(scala212, scala213) + +lazy val keeprules = (project in file(".")). + settings( + version := "0.1", + assembly / assemblyJarName := "foo.jar", + libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.8.1", + assembly / assemblyKeepRules := Seq("keep.**"), + TaskKey[Unit]("check") := { + IO.withTemporaryDirectory { dir ⇒ + IO.unzip(crossTarget.value / "foo.jar", dir) + mustNotExist(dir / "removed" / "ShadeClass.class") + mustNotExist(dir / "removed" / "ShadePackage.class") + mustExist(dir / "keep" / "Keeped.class") + + val lang3 = dir / "org" / "apache" / "commons" / "lang3" + val lang3Builder = lang3 / "builder" + val lang3Text = lang3 / "text" + val lang3Mutable = lang3 / "mutable" + mustOnlyExistIn(lang3, + lang3 / "ArrayUtils$1.class", + lang3 / "ArrayUtils.class", + lang3 / "BooleanUtils.class", + lang3 / "CharSequenceUtils.class", + lang3 / "CharUtils.class", + lang3 / "ClassUtils$1$1.class", + lang3 / "ClassUtils$1.class", + lang3 / "ClassUtils$2$1.class", + lang3 / "ClassUtils$2.class", + lang3 / "ClassUtils$Interfaces.class", + lang3 / "ClassUtils.class", + lang3 / "ObjectUtils$Null.class", + lang3 / "ObjectUtils.class", + lang3 / "RegExUtils.class", + lang3 / "StringEscapeUtils$CsvEscaper.class", + lang3 / "StringEscapeUtils$CsvUnescaper.class", + lang3 / "StringEscapeUtils.class", + lang3 / "StringUtils.class", + lang3 / "Validate.class", + lang3Builder / "Builder.class", + lang3Builder / "CompareToBuilder.class", + lang3Builder / "EqualsBuilder.class", + lang3Builder / "EqualsExclude.class", + lang3Builder / "HashCodeBuilder.class", + lang3Builder / "HashCodeExclude.class", + lang3Builder / "IDKey.class", + lang3Builder / "ReflectionToStringBuilder.class", + lang3Builder / "ToStringBuilder.class", + lang3Builder / "ToStringExclude.class", + lang3Builder / "ToStringStyle$DefaultToStringStyle.class", + lang3Builder / "ToStringStyle$JsonToStringStyle.class", + lang3Builder / "ToStringStyle$MultiLineToStringStyle.class", + lang3Builder / "ToStringStyle$NoClassNameToStringStyle.class", + lang3Builder / "ToStringStyle$NoFieldNameToStringStyle.class", + lang3Builder / "ToStringStyle$ShortPrefixToStringStyle.class", + lang3Builder / "ToStringStyle$SimpleToStringStyle.class", + lang3Builder / "ToStringStyle.class", + lang3Builder / "ToStringSummary.class", + lang3 / "exception" / "CloneFailedException.class", + lang3 / "math" / "NumberUtils.class", + lang3Mutable / "Mutable.class", + lang3Mutable / "MutableInt.class", + lang3Mutable / "MutableObject.class", + lang3Text / "StrBuilder$StrBuilderReader.class", + lang3Text / "StrBuilder$StrBuilderTokenizer.class", + lang3Text / "StrBuilder$StrBuilderWriter.class", + lang3Text / "StrBuilder.class", + lang3Text / "StrMatcher$CharMatcher.class", + lang3Text / "StrMatcher$CharSetMatcher.class", + lang3Text / "StrMatcher$NoMatcher.class", + lang3Text / "StrMatcher$StringMatcher.class", + lang3Text / "StrMatcher$TrimMatcher.class", + lang3Text / "StrMatcher.class", + lang3Text / "StrTokenizer.class", + lang3Text / "translate" / "AggregateTranslator.class", + lang3Text / "translate" / "CharSequenceTranslator.class", + lang3Text / "translate" / "CodePointTranslator.class", + lang3Text / "translate" / "EntityArrays.class", + lang3Text / "translate" / "JavaUnicodeEscaper.class", + lang3Text / "translate" / "LookupTranslator.class", + lang3Text / "translate" / "NumericEntityEscaper.class", + lang3Text / "translate" / "NumericEntityUnescaper$OPTION.class", + lang3Text / "translate" / "NumericEntityUnescaper.class", + lang3Text / "translate" / "OctalUnescaper.class", + lang3Text / "translate" / "UnicodeEscaper.class", + lang3Text / "translate" / "UnicodeUnescaper.class", + lang3Text / "translate" / "UnicodeUnpairedSurrogateRemover.class", + lang3 / "tuple" / "ImmutablePair.class", + lang3 / "tuple" / "Pair.class" + ) + } + }) + +def mustOnlyExistIn(directory: File, files: File*): Unit = { + if (!directory.exists()) { + sys.error("directory" + directory + " does not exist!") + } + + if (!directory.isDirectory) { + sys.error(directory + " is not a directory!") + } + + def getAllFilesRecursively(f: File): Set[File] = { + val allFiles = f.listFiles() + val (directories, files) = allFiles.partition(_.isDirectory) + directories.toSet.flatMap(getAllFilesRecursively) ++ files + } + + val expectedFilesSet = files.toSet + val actualFileSet = getAllFilesRecursively(directory) + + if (expectedFilesSet != actualFileSet) { + sys.error("files expected in " + directory + " are not matching the actual files") + } +} + +def mustNotExist(f: File): Unit = { + if (f.exists) sys.error("file" + f + " exists!") +} +def mustExist(f: File): Unit = { + if (!f.exists) sys.error("file" + f + " does not exist!") +} diff --git a/src/sbt-test/shading/keeprules/project/plugins.sbt b/src/sbt-test/shading/keeprules/project/plugins.sbt new file mode 100644 index 00000000..b7bb6c0d --- /dev/null +++ b/src/sbt-test/shading/keeprules/project/plugins.sbt @@ -0,0 +1,7 @@ +{ + val pluginVersion = System.getProperty("plugin.version") + if(pluginVersion == null) + throw new RuntimeException("""|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) + else addSbtPlugin("com.eed3si9n" % "sbt-assembly" % pluginVersion) +} diff --git a/src/sbt-test/shading/keeprules/src/main/scala/keep/Keeped.scala b/src/sbt-test/shading/keeprules/src/main/scala/keep/Keeped.scala new file mode 100644 index 00000000..443b3297 --- /dev/null +++ b/src/sbt-test/shading/keeprules/src/main/scala/keep/Keeped.scala @@ -0,0 +1,10 @@ +package keep + +import org.apache.commons.lang3.tuple.ImmutablePair + +class Keeped { + def main(args: Array[String]): Unit = { + val myUsedObject = new ImmutablePair[String, String]("Foo", "Bar") + println(myUsedObject) + } +} diff --git a/src/sbt-test/shading/keeprules/src/main/scala/removed/ShadeClass.scala b/src/sbt-test/shading/keeprules/src/main/scala/removed/ShadeClass.scala new file mode 100644 index 00000000..bfacff85 --- /dev/null +++ b/src/sbt-test/shading/keeprules/src/main/scala/removed/ShadeClass.scala @@ -0,0 +1,3 @@ +package removed + +class ShadeClass diff --git a/src/sbt-test/shading/keeprules/src/main/scala/removed/ShadePackage.scala b/src/sbt-test/shading/keeprules/src/main/scala/removed/ShadePackage.scala new file mode 100644 index 00000000..0171cf08 --- /dev/null +++ b/src/sbt-test/shading/keeprules/src/main/scala/removed/ShadePackage.scala @@ -0,0 +1,3 @@ +package removed + +class ShadePackage diff --git a/src/sbt-test/shading/keeprules/test b/src/sbt-test/shading/keeprules/test new file mode 100644 index 00000000..29d5e420 --- /dev/null +++ b/src/sbt-test/shading/keeprules/test @@ -0,0 +1,7 @@ +# check if the file gets created +> +assembly +$ exists target/scala-2.12/foo.jar +$ exists target/scala-2.13/foo.jar + +# check if it says hello +> +check