Skip to content

Commit

Permalink
Generate AssemblyOption as pseudo case class
Browse files Browse the repository at this point in the history
  • Loading branch information
eed3si9n committed Jun 6, 2021
1 parent 226282d commit ede52ca
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 33 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ single JAR file: `target/scala_X.X.X/projectname-assembly-X.X.X.jar`.

> assembly

If you specify a `mainClass in assembly` in build.sbt (or just let it autodetect
If you specify a `assembly / mainClass` in build.sbt (or just let it autodetect
one) then you'll end up with a fully executable JAR, ready to rock.

Here is the list of the keys you can rewire for `assembly` task.
Here is the list of the keys you can rewire scoped to `Compile / assembly` task:

assemblyJarName test mainClass
assemblyOutputPath assemblyMergeStrategy assemblyOption
Expand Down Expand Up @@ -332,7 +332,7 @@ To make a JAR file containing only the external dependencies, type
This is intended to be used with a JAR that only contains your project

```scala
Compile / assembly / assemblyOption := (assembly / assemblyOption).value.copy(includeScala = false, includeDependency = false)
Compile / assembly / assemblyOption := (Compile / assembly / assemblyOption).value.copy(includeScala = false, includeDependency = false)
```

NOTE: If you use [`-jar` option for `java`](http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html#jar), it will ignore `-cp`, so if you have multiple JAR files you have to use `-cp` and pass the main class: `java -cp "jar1.jar:jar2.jar" Main`
Expand All @@ -342,7 +342,7 @@ NOTE: If you use [`-jar` option for `java`](http://docs.oracle.com/javase/7/docs
To exclude Scala library (JARs that start with `scala-` and are included in the binary Scala distribution) to run with `scala` command,

```scala
Compile / assembly / assemblyOption := (assembly / assemblyOption).value.copy(includeScala = false)
Compile / assembly / assemblyOption := (Compile / assembly / assemblyOption).value.copy(includeScala = false)
```

### assemblyExcludedJars
Expand All @@ -364,21 +364,21 @@ Other Things
You can also append SHA-1 fingerprint to the assembly file name, this may help you to determine whether it has changed and, for example, if it's necessary to deploy the dependencies,

```scala
Compile / assembly / assemblyOption := (assembly / assemblyOption).value.copy(appendContentHash = true)
Compile / assembly / assemblyOption := (assembly / assemblyOption).withAppendContentHash(true)
```

### Caching

By default for performance reasons, the result of unzipping any dependency JAR files to disk is cached from run-to-run. This feature can be disabled by setting:

```scala
Compile / assembly / assemblyOption := (assembly / assemblyOption).value.copy(cacheUnzip = false)
Compile / assembly / assemblyOption := (assembly / assemblyOption).withCacheUnzip(false)
```

In addition the fat JAR is cached so its timestamp changes only when the input changes. This feature requires checking the SHA-1 hash of all *.class files, and the hash of all dependency *.jar files. If there are a large number of class files, this could take a long time, although with hashing of jar files, rather than their contents, the speed has recently been [improved](https://github.com/sbt/sbt-assembly/issues/68). This feature can be disabled by setting:

```scala
Compile / assembly / assemblyOption := (assembly / assemblyOption).value.copy(cacheOutput = false)
Compile / assembly / assemblyOption := (assembly / assemblyOption).withCacheOutput(false)
```

### Prepending a launch script
Expand Down
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ThisBuild / crossScalaVersions := Seq(scala212, scala210)
ThisBuild / scalaVersion := scala212

lazy val root = (project in file("."))
.enablePlugins(SbtPlugin)
.enablePlugins(SbtPlugin) // ContrabandPlugin
.settings(pomConsistency2021DraftSettings)
.settings(nocomma {
name := "sbt-assembly"
Expand All @@ -23,6 +23,7 @@ lazy val root = (project in file("."))
case "2.12" => "1.2.8"
}
}
Compile / generateContrabands / sourceManaged := baseDirectory.value / "src" / "main" / "contraband-scala"
})

ThisBuild / scmInfo := Some(
Expand Down
1 change: 1 addition & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("com.eed3si9n" % "sbt-nocomma" % "0.1.0")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.5.1")
36 changes: 36 additions & 0 deletions src/main/contraband/AssemblyOption.contra
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package sbtassembly
@target(Scala)

type AssemblyOption {
assemblyDirectory: java.io.File @since("0.15.0")

## include compiled class files from itself or subprojects
includeBin: Boolean! = true @since("0.15.0")

includeScala: Boolean! = true @since("0.15.0")

## include class files from external dependencies
includeDependency: Boolean! = true @since("0.15.0")

excludedJars: sbt.Keys.Classpath! = raw"Nil" @since("0.15.0")

excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile! = raw"sbtassembly.Assembly.defaultExcludedFiles" @since("0.15.0")

mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy! = raw"sbtassembly.MergeStrategy.defaultMergeStrategy" @since("0.15.0")

cacheOutput: Boolean! = true @since("0.15.0")

cacheUnzip: Boolean! = true @since("0.15.0")

appendContentHash: Boolean! = false @since("0.15.0")

prependShellScript: sbtassembly.Assembly.SeqString @since("0.15.0")

maxHashLength: Int @since("0.15.0")

shadeRules: [com.eed3si9n.jarjarabrams.ShadeRule] @since("0.15.0")

scalaVersion: String! = "" @since("0.15.0")

level: sbt.Level.Value! = raw"sbt.Level.Info" @since("0.15.0")
}
8 changes: 6 additions & 2 deletions src/main/scala/sbtassembly/Assembly.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import com.eed3si9n.jarjarabrams._
object Assembly {
import AssemblyPlugin.autoImport.{ Assembly => _, _ }

// used for contraband
type SeqFileToSeqFile = Seq[File] => Seq[File]
type SeqString = Seq[String]

private val scalaPre213Libraries = Vector(
"scala-actors",
"scala-compiler",
Expand Down Expand Up @@ -40,7 +44,7 @@ object Assembly {

lazy val (ms: Vector[(File, String)], stratMapping: List[(String, MergeStrategy)]) = {
log.debug("Merging files...")
applyStrategies(mappings, ao.mergeStrategy, ao.assemblyDirectory, log)
applyStrategies(mappings, ao.mergeStrategy, ao.assemblyDirectory.get, log)
}
def makeJar(outPath: File): Unit = {
import Package._
Expand Down Expand Up @@ -215,7 +219,7 @@ object Assembly {
// which jars exactly belong to the deps for packageDependency option.
def assembleMappings(classpath: Classpath, dependencies: Classpath,
ao: AssemblyOption, log: Logger): Vector[MappingSet] = {
val tempDir = ao.assemblyDirectory
val tempDir = ao.assemblyDirectory.get
if (!ao.cacheUnzip) IO.delete(tempDir)
if (!tempDir.exists) tempDir.mkdir()

Expand Down
126 changes: 126 additions & 0 deletions src/main/scala/sbtassembly/AssemblyOption.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/

package sbtassembly

/**
* @param includeBin include compiled class files from itself or subprojects
* @param includeDependency include class files from external dependencies
*/
final class AssemblyOption private (
val assemblyDirectory: Option[java.io.File],
val includeBin: Boolean,
val includeScala: Boolean,
val includeDependency: Boolean,
val excludedJars: sbt.Keys.Classpath,
val excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile,
val mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy,
val cacheOutput: Boolean,
val cacheUnzip: Boolean,
val appendContentHash: Boolean,
val prependShellScript: Option[sbtassembly.Assembly.SeqString],
val maxHashLength: Option[Int],
val shadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule],
val scalaVersion: String,
val level: sbt.Level.Value) extends Serializable {

private def this() = this(None, true, true, true, Nil, sbtassembly.Assembly.defaultExcludedFiles, sbtassembly.MergeStrategy.defaultMergeStrategy, true, true, false, None, None, Vector(), "", sbt.Level.Info)

override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: AssemblyOption => (this.assemblyDirectory == x.assemblyDirectory) && (this.includeBin == x.includeBin) && (this.includeScala == x.includeScala) && (this.includeDependency == x.includeDependency) && (this.excludedJars == x.excludedJars) && (this.excludedFiles == x.excludedFiles) && (this.mergeStrategy == x.mergeStrategy) && (this.cacheOutput == x.cacheOutput) && (this.cacheUnzip == x.cacheUnzip) && (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 _ => false
})

override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbtassembly.AssemblyOption".##) + assemblyDirectory.##) + includeBin.##) + includeScala.##) + includeDependency.##) + excludedJars.##) + excludedFiles.##) + mergeStrategy.##) + cacheOutput.##) + cacheUnzip.##) + appendContentHash.##) + prependShellScript.##) + maxHashLength.##) + shadeRules.##) + scalaVersion.##) + level.##)
}

override def toString: String = {
"AssemblyOption(" + assemblyDirectory + ", " + includeBin + ", " + includeScala + ", " + includeDependency + ", " + excludedJars + ", " + excludedFiles + ", " + mergeStrategy + ", " + cacheOutput + ", " + cacheUnzip + ", " + appendContentHash + ", " + prependShellScript + ", " + maxHashLength + ", " + shadeRules + ", " + scalaVersion + ", " + level + ")"
}

@deprecated("copy method is deprecated; use withIncludeBin(...) etc", "1.0.0")
def copy(assemblyDirectory: Option[java.io.File] = assemblyDirectory, includeBin: Boolean = includeBin, includeScala: Boolean = includeScala, includeDependency: Boolean = includeDependency, excludedJars: sbt.Keys.Classpath = excludedJars, excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile = excludedFiles, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy = mergeStrategy, cacheOutput: Boolean = cacheOutput, cacheUnzip: Boolean = cacheUnzip, appendContentHash: Boolean = appendContentHash, prependShellScript: Option[sbtassembly.Assembly.SeqString] = prependShellScript, maxHashLength: Option[Int] = maxHashLength, shadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule] = shadeRules, scalaVersion: String = scalaVersion, level: sbt.Level.Value = level): AssemblyOption = {
cp(assemblyDirectory = assemblyDirectory,
includeBin = includeBin,
includeScala = includeScala,
includeDependency = includeDependency,
excludedJars = excludedJars,
excludedFiles = excludedFiles,
mergeStrategy = mergeStrategy,
cacheOutput = cacheOutput,
cacheUnzip = cacheUnzip,
appendContentHash = appendContentHash,
prependShellScript = prependShellScript,
maxHashLength = maxHashLength,
shadeRules = shadeRules,
scalaVersion = scalaVersion,
level = level)
}

private def cp(assemblyDirectory: Option[java.io.File] = assemblyDirectory, includeBin: Boolean = includeBin, includeScala: Boolean = includeScala, includeDependency: Boolean = includeDependency, excludedJars: sbt.Keys.Classpath = excludedJars, excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile = excludedFiles, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy = mergeStrategy, cacheOutput: Boolean = cacheOutput, cacheUnzip: Boolean = cacheUnzip, appendContentHash: Boolean = appendContentHash, prependShellScript: Option[sbtassembly.Assembly.SeqString] = prependShellScript, maxHashLength: Option[Int] = maxHashLength, shadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule] = shadeRules, scalaVersion: String = scalaVersion, level: sbt.Level.Value = level): AssemblyOption = {
new AssemblyOption(assemblyDirectory, includeBin, includeScala, includeDependency, excludedJars, excludedFiles, mergeStrategy, cacheOutput, cacheUnzip, appendContentHash, prependShellScript, maxHashLength, shadeRules, scalaVersion, level)
}

def withAssemblyDirectory(assemblyDirectory: Option[java.io.File]): AssemblyOption = {
cp(assemblyDirectory = assemblyDirectory)
}
def withAssemblyDirectory(assemblyDirectory: java.io.File): AssemblyOption = {
cp(assemblyDirectory = Option(assemblyDirectory))
}
def withIncludeBin(includeBin: Boolean): AssemblyOption = {
cp(includeBin = includeBin)
}
def withIncludeScala(includeScala: Boolean): AssemblyOption = {
cp(includeScala = includeScala)
}
def withIncludeDependency(includeDependency: Boolean): AssemblyOption = {
cp(includeDependency = includeDependency)
}
def withExcludedJars(excludedJars: sbt.Keys.Classpath): AssemblyOption = {
cp(excludedJars = excludedJars)
}
def withExcludedFiles(excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile): AssemblyOption = {
cp(excludedFiles = excludedFiles)
}
def withMergeStrategy(mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy): AssemblyOption = {
cp(mergeStrategy = mergeStrategy)
}
def withCacheOutput(cacheOutput: Boolean): AssemblyOption = {
cp(cacheOutput = cacheOutput)
}
def withCacheUnzip(cacheUnzip: Boolean): AssemblyOption = {
cp(cacheUnzip = cacheUnzip)
}
def withAppendContentHash(appendContentHash: Boolean): AssemblyOption = {
cp(appendContentHash = appendContentHash)
}
def withPrependShellScript(prependShellScript: Option[sbtassembly.Assembly.SeqString]): AssemblyOption = {
cp(prependShellScript = prependShellScript)
}
def withPrependShellScript(prependShellScript: sbtassembly.Assembly.SeqString): AssemblyOption = {
cp(prependShellScript = Option(prependShellScript))
}
def withMaxHashLength(maxHashLength: Option[Int]): AssemblyOption = {
cp(maxHashLength = maxHashLength)
}
def withMaxHashLength(maxHashLength: Int): AssemblyOption = {
cp(maxHashLength = Option(maxHashLength))
}
def withShadeRules(shadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule]): AssemblyOption = {
cp(shadeRules = shadeRules)
}
def withScalaVersion(scalaVersion: String): AssemblyOption = {
cp(scalaVersion = scalaVersion)
}
def withLevel(level: sbt.Level.Value): AssemblyOption = {
cp(level = level)
}
}

object AssemblyOption {
def apply(): AssemblyOption = new AssemblyOption()
def apply(assemblyDirectory: Option[java.io.File], includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, cacheUnzip: Boolean, appendContentHash: Boolean, prependShellScript: Option[sbtassembly.Assembly.SeqString], maxHashLength: Option[Int], shadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule], scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(assemblyDirectory, includeBin, includeScala, includeDependency, excludedJars, excludedFiles, mergeStrategy, cacheOutput, cacheUnzip, appendContentHash, prependShellScript, maxHashLength, shadeRules, scalaVersion, level)
def apply(assemblyDirectory: java.io.File, includeBin: Boolean, includeScala: Boolean, includeDependency: Boolean, excludedJars: sbt.Keys.Classpath, excludedFiles: sbtassembly.Assembly.SeqFileToSeqFile, mergeStrategy: sbtassembly.MergeStrategy.StringToMergeStrategy, cacheOutput: Boolean, cacheUnzip: Boolean, appendContentHash: Boolean, prependShellScript: sbtassembly.Assembly.SeqString, maxHashLength: Int, shadeRules: Seq[com.eed3si9n.jarjarabrams.ShadeRule], scalaVersion: String, level: sbt.Level.Value): AssemblyOption = new AssemblyOption(Option(assemblyDirectory), includeBin, includeScala, includeDependency, excludedJars, excludedFiles, mergeStrategy, cacheOutput, cacheUnzip, appendContentHash, Option(prependShellScript), Option(maxHashLength), shadeRules, scalaVersion, level)
}
32 changes: 10 additions & 22 deletions src/main/scala/sbtassembly/AssemblyPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ object AssemblyPlugin extends sbt.AutoPlugin {
assemblyOption in assembly := {
val s = streams.value
AssemblyOption(
assemblyDirectory = s.cacheDirectory / "assembly",
assemblyDirectory = Some(s.cacheDirectory / "assembly"),
includeBin = (assembleArtifact in packageBin).value,
includeScala = (assembleArtifact in assemblyPackageScala).value,
includeDependency = (assembleArtifact in assemblyPackageDependency).value,
Expand All @@ -95,18 +95,23 @@ object AssemblyPlugin extends sbt.AutoPlugin {
appendContentHash = false,
prependShellScript = None,
maxHashLength = None,
shadeRules = (assemblyShadeRules in assembly).value,
shadeRules = (assemblyShadeRules in assembly).value.toVector,
scalaVersion = scalaVersion.value,
level = (logLevel in assembly).value)
},

assemblyOption in assemblyPackageScala := {
val ao = (assemblyOption in assembly).value
ao.copy(includeBin = false, includeScala = true, includeDependency = false)
ao.withIncludeBin(false)
.withIncludeScala(true)
.withIncludeDependency(false)
},

assemblyOption in assemblyPackageDependency := {
val ao = (assemblyOption in assembly).value
ao.copy(includeBin = false, includeScala = true, includeDependency = true)
ao.withIncludeBin(false)
.withIncludeScala(true)
.withIncludeDependency(true)
},

// packageOptions
Expand All @@ -116,6 +121,7 @@ object AssemblyPlugin extends sbt.AutoPlugin {
Package.MainClass(s) +: (os filterNot {_.isInstanceOf[Package.MainClass]})
} getOrElse {os}
},

packageOptions in assemblyPackageScala := (packageOptions in (Compile, packageBin)).value,
packageOptions in assemblyPackageDependency := (packageOptions in (Compile, packageBin)).value,

Expand All @@ -142,21 +148,3 @@ object AssemblyPlugin extends sbt.AutoPlugin {

lazy val assemblySettings: Seq[sbt.Def.Setting[_]] = baseAssemblySettings
}

case class AssemblyOption(assemblyDirectory: File,
// include compiled class files from itself or subprojects
includeBin: Boolean = true,
includeScala: Boolean = true,
// include class files from external dependencies
includeDependency: Boolean = true,
excludedJars: Classpath = Nil,
excludedFiles: Seq[File] => Seq[File] = Assembly.defaultExcludedFiles, // use mergeStrategy instead
mergeStrategy: String => MergeStrategy = MergeStrategy.defaultMergeStrategy,
cacheOutput: Boolean = true,
cacheUnzip: Boolean = true,
appendContentHash: Boolean = false,
prependShellScript: Option[Seq[String]] = None,
maxHashLength: Option[Int] = None,
shadeRules: Seq[jarjarabrams.ShadeRule] = Seq(),
scalaVersion: String = "",
level: Level.Value)
2 changes: 1 addition & 1 deletion src/main/scala/sbtassembly/AssemblyUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ErrorHandling.translate
import PluginCompat._
import Using._

object AssemblyUtils {
private[sbtassembly] object AssemblyUtils {
private val PathRE = "([^/]+)/(.*)".r

/** Find the source file (and possibly the entry within a jar) whence a conflicting file came.
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/sbtassembly/MergeStrategy.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ abstract class MergeStrategy extends Function1[(File, String, Seq[File]), Either
}

object MergeStrategy {
type StringToMergeStrategy = String => MergeStrategy

private val FileExtension = """([.]\w+)$""".r
private def filenames(tempDir: File, fs: Seq[File]): Seq[String] =
for(f <- fs) yield {
Expand Down

0 comments on commit ede52ca

Please sign in to comment.