{"id":13441228,"url":"https://github.com/sbt/sbt-assembly","last_synced_at":"2025-09-29T01:30:41.100Z","repository":{"id":40580512,"uuid":"1874483","full_name":"sbt/sbt-assembly","owner":"sbt","description":"Deploy über-JARs. Restart processes. (port of codahale/assembly-sbt)","archived":false,"fork":true,"pushed_at":"2025-01-03T18:38:16.000Z","size":732,"stargazers_count":1951,"open_issues_count":113,"forks_count":223,"subscribers_count":50,"default_branch":"develop","last_synced_at":"2025-01-03T19:32:54.419Z","etag":null,"topics":["jarjar","sbt","sbt-plugin"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"softprops/assembly-sbt","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sbt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-06-10T05:30:27.000Z","updated_at":"2025-01-03T18:38:20.000Z","dependencies_parsed_at":"2023-01-29T18:45:28.266Z","dependency_job_id":null,"html_url":"https://github.com/sbt/sbt-assembly","commit_stats":null,"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbt%2Fsbt-assembly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbt%2Fsbt-assembly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbt%2Fsbt-assembly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbt%2Fsbt-assembly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sbt","download_url":"https://codeload.github.com/sbt/sbt-assembly/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234579583,"owners_count":18855636,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jarjar","sbt","sbt-plugin"],"created_at":"2024-07-31T03:01:31.368Z","updated_at":"2025-09-29T01:30:35.797Z","avatar_url":"https://github.com/sbt.png","language":"Scala","readme":"sbt-assembly\n============\n\n*Deploy über JARs. Restart processes.*\n\nsbt-assembly is a sbt plugin originally ported from codahale's assembly-sbt, which I'm guessing was inspired by Maven's assembly plugin. The goal is simple: Create a über JAR of your project with all of its dependencies.\n\nRequirements\n------------\n\n* sbt\n* The burning desire to have a simple deploy procedure.\n\nReporting Issues \u0026 Contributing\n-------------------------------\n\nBefore you email me, please read [Issue Reporting Guideline](CONTRIBUTING.md) carefully. Twice. (Don't email me)\n\nSetup\n-----\n\n### Using Published Plugin\n\n[![sbt-assembly Scala version support](https://index.scala-lang.org/sbt/sbt-assembly/sbt-assembly/latest-by-scala-version.svg?targetType=Sbt)](https://index.scala-lang.org/sbt/sbt-assembly/sbt-assembly)\n\nAdd sbt-assembly as a dependency in `project/plugins.sbt`:\n\n```scala\naddSbtPlugin(\"com.eed3si9n\" % \"sbt-assembly\" % \"x.y.z\")\n```\nStarting in `sbt-assembly` `1.2.0`, sbt `0.13.x` has been deprecated.  Please use `1.1.0` if this is required.\n\nUsage\n-----\n\nSince sbt-assembly is now an auto plugin that's triggered for all projects with `JvmPlugin`, it shouldn't require extra setup to include `assembly` task into your project.\nSee [migration guide](Migration.md) for details on how to upgrade from older sbt-assembly.\n\n### Applying the plugin to multi-project build.sbt\n\nFor example, here's a multi-project `build.sbt`:\n\n```scala\nThisBuild / version := \"0.1.0-SNAPSHOT\"\nThisBuild / organization := \"com.example\"\nThisBuild / scalaVersion := \"2.13.11\"\n\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / mainClass := Some(\"com.example.Main\"),\n    // more settings here ...\n  )\n\nlazy val utils = (project in file(\"utils\"))\n  .settings(\n    assembly / assemblyJarName := \"utils.jar\",\n    // more settings here ...\n  )\n```\n\nIn the above example, both the `app` project and the `utils` project do not run tests during assembly. The `app` project sets a main class whereas the `utils` project sets the name of its jar file.\n\n### assembly task\n\nNow you'll have an awesome new `assembly` task which will compile your project,\nrun your tests, and then pack your class files and all your dependencies into a\nsingle JAR file: `target/scala_X.X.X/projectname-assembly-X.X.X.jar`.\n\n    \u003e assembly\n\nIf you specify a `assembly / mainClass` in build.sbt (or just let it autodetect\none) then you'll end up with a fully executable JAR, ready to rock.\n\nHere is the list of the keys you can rewire that are scoped to current subproject's `assembly` task:\n\n    assemblyJarName               test                          mainClass\n    assemblyOutputPath            assemblyOption\n\nAnd here is the list of the keys you can rewite that are scoped globally:\n\n    assemblyAppendContentHash     assemblyCacheOutput           assemblyShadeRules\n    assemblyExcludedJars          assemblyMergeStrategy         assemblyRepeatableBuild\n\nKeys scoped to the subproject should be placed in `.settings(...)` whereas the globally scoped keys can either be placed inside of `.settings(...)` or scoped using `ThisBuild / ` to be shared across multiple subprojects.\n\nFor example the name of the jar can be set as follows in build.sbt:\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / assemblyJarName := \"something.jar\",\n    // more settings here ...\n  )\n```\n\nTo set an explicit main class,\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / mainClass := Some(\"com.example.Main\"),\n    // more settings here ...\n  )\n```\n\nTo run the test during assembly,\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / test := (Test / test).value,\n    // more settings here ...\n  )\n```\n\nExcluding an explicit main class from your assembly requires something a little bit different though\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / packageOptions ~= { pos =\u003e\n      pos.filterNot { po =\u003e\n        po.isInstanceOf[Package.MainClass]\n      }\n    },\n    // more settings here ...\n  )\n```\n\n### Merge Strategy\n\nIf multiple files share the same relative path (e.g. a resource named\n`application.conf` in multiple dependency JARs), the default strategy is to\nverify that all candidates have the same contents and error out otherwise.\nThis behavior can be configured on a per-path basis using either one\nof the following built-in strategies or writing a custom one:\n\n* `MergeStrategy.deduplicate` is the default described above\n* `MergeStrategy.first` picks the first of the matching files in classpath order\n* `MergeStrategy.last` picks the last one\n* `MergeStrategy.singleOrError` bails out with an error message on conflict\n* `MergeStrategy.concat` simply concatenates all matching files and includes the result. There is also an overload that accepts a line separator for formatting the result\n* `MergeStrategy.filterDistinctLines` also concatenates, but leaves out duplicates along the way. There is also an overload that accepts a `Charset` for reading the lines\n* `MergeStrategy.rename` renames the files originating from jar files\n* `MergeStrategy.discard` simply discards matching files\n* `MergeStrategy.preferProject` will choose the first project file over library files if present. Otherwise, it works like `MergeStrategy.first`\n\nThe mapping of path names to merge strategies is done via the setting\n`assemblyMergeStrategy` which can be augmented as follows:\n\n```scala\nThisBuild / assemblyMergeStrategy := {\n  case PathList(\"javax\", \"servlet\", xs @ _*)         =\u003e MergeStrategy.first\n  case PathList(ps @ _*) if ps.last endsWith \".html\" =\u003e MergeStrategy.first\n  case \"application.conf\"                            =\u003e MergeStrategy.concat\n  case \"unwanted.txt\"                                =\u003e MergeStrategy.discard\n  case x =\u003e\n    val oldStrategy = (ThisBuild / assemblyMergeStrategy).value\n    oldStrategy(x)\n}\n```\n\n**NOTE**:\n- Actually, a merge strategy serves two purposes:\n  * To merge conflicting files\n  * To transform a single file (despite the naming), such as in the case of a `MergeStrategy.rename`. Sometimes, the transformation is a pass-through, as in the case of a `MergeStrategy.deduplicate` if there are no conflicts on a `target` path.\n- `ThisBuild / assemblyMergeStrategy` expects a function. You can't do `ThisBuild / assemblyMergeStrategy := MergeStrategy.first`!\n- Some files must be discarded or renamed otherwise to avoid breaking the zip (due to duplicate file name) or the legal license. Delegate default handling to `(ThisBuild / assemblyMergeStrategy)` as the above pattern matching example.\n- Renames are processed first, since renamed file targets might match more merge patterns afterwards. By default, LICENSEs and READMEs are renamed before applying every other merge strategy. If you need a custom logic for renaming, create a new rename merge strategy so it is processsed first, along with the custom logic. See how to create custom `MergeStrategy`s in a later section of this README.\n- There is an edge case that may occasionally fail. If a project has a file that has the same relative path as a directory to be written, an error notification will be written to the console as shown below. To resolve this, create a shade rule or a new merge strategy.\n\n  ```bash\n    [error] Files to be written at 'shadeio' have the same name as directories to be written:\n    [error]   Jar name = commons-io-2.4.jar, jar org = commons-io, entry target = shadeio/input/Tailer.class (from original source = org/apache/commons/io/input/Tailer.class)\n    [error]   Project name = foo, target = shadeio\n  ```\n\nBy the way, the first case pattern in the above using `PathList(...)` is how you can pick `javax/servlet/*` from the first jar. If the default `MergeStrategy.deduplicate` is not working for you, that likely means you have multiple versions of some library pulled by your dependency graph. The real solution is to fix that dependency graph. You can work around it by `MergeStrategy.first` but don't be surprised when you see `ClassNotFoundException`.\n\nHere is the default:\n\n```scala\n  val defaultMergeStrategy: String =\u003e MergeStrategy = {\n    case x if Assembly.isConfigFile(x) =\u003e\n      MergeStrategy.concat\n    case PathList(ps @ _*) if Assembly.isReadme(ps.last) || Assembly.isLicenseFile(ps.last) =\u003e\n      MergeStrategy.rename\n    case PathList(\"META-INF\", xs @ _*) =\u003e\n      (xs map {_.toLowerCase}) match {\n        case (\"manifest.mf\" :: Nil) | (\"index.list\" :: Nil) | (\"dependencies\" :: Nil) =\u003e\n          MergeStrategy.discard\n        case ps @ (x :: xs) if ps.last.endsWith(\".sf\") || ps.last.endsWith(\".dsa\") =\u003e\n          MergeStrategy.discard\n        case \"plexus\" :: xs =\u003e\n          MergeStrategy.discard\n        case \"services\" :: xs =\u003e\n          MergeStrategy.filterDistinctLines\n        case (\"spring.schemas\" :: Nil) | (\"spring.handlers\" :: Nil) =\u003e\n          MergeStrategy.filterDistinctLines\n        case _ =\u003e MergeStrategy.deduplicate\n      }\n    case _ =\u003e MergeStrategy.deduplicate\n  }\n```\n\n#### Creating a custom Merge Strategy (since 2.0.0)\nCustom merge strategies can be plugged-in to the `assemblyMergeStrategy` function, for example:\n\n```scala \n...\nThisBuild / assemblyMergeStrategy := {\n  case \"matching-file\" =\u003e CustomMergeStrategy(\"my-custom-merge-strat\") { conflicts =\u003e\n    // NB! same as MergeStrategy.discard\n    Right(Vector.empty)\n  }\n  case x   =\u003e\n    val oldStrategy = (ThisBuild / assemblyMergeStrategy).value\n    oldStrategy(x)\n}\n...\n```\n\nThe `CustomMergeStrategy` accepts a `name` and a `notifyIfGTE` that affects how the result is reported in the logs.\nPlease see the scaladoc for more details.\n\nFinally, to perform the actual merge/transformation logic, a function has to be provided. The function accepts a `Vector` of `Dependency`, where you can access the `target` of type `String` and the byte payload of type `LazyInputStream`, which is just a type alias for `() =\u003e InputStream`.\n\nThe input `Dependency` also has two subtypes that you can pattern match on:\n  - `Project` represents an internal/project dependency\n  - `Library` represents an external/library dependency that also contains the `ModuleCoordinate` (jar org, name and version) it originated from\n\nTo create a merge result, a `Vector` of `JarEntry` must be returned wrapped in an `Either.Right`, or empty to discard these conflicts from the final jar.\n`JarEntry` only has two fields, a `target` of type `String` and the byte payload of type lazy `InputStream`.\n\nTo fail the assembly, return an `Either.Left` with an error message.\n\nThere is also a factory specifically for renames, so it gets processed first along with the built-in rename merge strategy, before other merge strategies, as mentioned in a previous section. It accepts a function `Dependency -\u003e String`, so the `Dependency` can be inspected and a new `target` path returned.\n\nHere is an example that appends a `String` to the original `target` path of the matched file.\n\n```scala\n...\ncase \"matching-file\" =\u003e\n  import sbtassembly.Assembly.{Project, Library}\n  CustomMergeStrategy.rename {\n    case dependency@(_: Project) =\u003e dependency.target + \"_from_project\"\n    case dependency@(_: Library) =\u003e dependency.target + \"_from_library\"\n  }\n...\n```\n\nFor more information/examples, see the scaladoc/source code in `sbtassembly.Assembly` and `sbtassembly.MergeStrategy`.\n\n**NOTE**:\n- The `name` parameter will be distinguished from a built-in strategy. For example, the `name`=`First` will execute its custom logic along with the built-in `MergeStrategy.first`. They cannot cancel/override one another. In fact, the custom merge strategy will be logged as `First (Custom)` for clarity.\n- However, you should still choose a unique `name` for a custom merge strategy within the build. Even if all built-in and custom merge strategies are guaranteed to execute if they match a pattern regardless of their `name`s, similarly-named custom merge strategies will have their log reports joined. YMMV, but you are encouraged to **avoid duplicate names**.\n\n#### Third Party Merge Strategy Plugins\n\nSupport for special-case merge strategies beyond the generic scope can be\nprovided by companion plugins, below is a non-exhaustive list:\n\n* [Log4j2 Plugin Caches](https://github.com/mpollmeier/sbt-assembly-log4j2): merge `Log4j2Plugins.dat` binaries\n\n### Shading\n\nsbt-assembly can shade classes from your projects or from the library dependencies.\nBacked by [Jar Jar Links](https://code.google.com/archive/p/jarjar/wikis/CommandLineDocs.wiki), bytecode transformation (via ASM) is used to change references to the renamed classes.\n\n```scala\nThisBuild / assemblyShadeRules := Seq(\n  ShadeRule.rename(\"org.apache.commons.io.**\" -\u003e \"shadeio.@1\").inAll\n)\n```\n\nHere are the shade rules:\n\n* `ShadeRule.rename(\"x.**\" -\u003e \"y.@1\", ...).inAll` This is the main rule.\n* `ShadeRule.zap(\"a.b.c\").inAll`\n* `ShadeRule.keep(\"x.**\").inAll`\n\nThe main `ShadeRule.rename` 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.\nThe `rename` rules takes a vararg of String pairs in `\u003cpattern\u003e -\u003e \u003cresult\u003e` format:\n\n- `\u003cpattern\u003e` 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.\n- `\u003cresult\u003e` is a class name which can optionally reference the substrings matched by the wildcards. A numbered reference is available for every `*` or `**` in the `\u003cpattern\u003e`, starting from left to right: `@1`, `@2`, etc. A special `@0` reference contains the entire matched class name.\n\nInstead of `.inAll`, call `.inProject` to match your project source, or call `.inLibrary(\"commons-io\" % \"commons-io\" % \"2.4\", ...)` to match specific library dependencies. `inProject` and `inLibrary(...)` can be chained.\n\n```scala\nThisBuild / assemblyShadeRules := Seq(\n  ShadeRule.rename(\"org.apache.commons.io.**\" -\u003e \"shadeio.@1\").inLibrary(\"commons-io\" % \"commons-io\" % \"2.4\", ...).inProject\n)\n```\n\nThe `ShadeRule.zap` rule causes any matched class to be removed from the resulting jar file. All zap rules are processed before renaming rules.\n\nThe `ShadeRule.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.\n\nTo see the verbose output for shading:\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / logLevel := Level.Debug\n    // more settings here ...\n  )\n```\n\n#### Scala libraries\n\nScala classes contain an annotation which, among other things, contain all symbols referenced in that class. As of sbt-assembly XXX the rename rules\nwill be applied to these annotations as well which makes it possible to compile or reflect against a shaded library.\n\nThis is currently limited to renaming packages. Renaming class names will not work and cause compiler errors when compiling against the shaded library.\n\nExcluding JARs and files\n------------------------\n\nIf you need to tell sbt-assembly to ignore JARs, you're probably doing it wrong.\nassembly task grabs deps JARs from your project's classpath. Try fixing the classpath first.\n\n### % \"provided\" configuration\n\nIf you're trying to exclude JAR files that are already part of the container (like Spark), consider scoping the dependent library to `\"provided\"` configuration:\n\n```scala\nlibraryDependencies ++= Seq(\n  \"org.apache.spark\" %% \"spark-core\" % \"0.8.0-incubating\" % \"provided\",\n  \"org.apache.hadoop\" % \"hadoop-client\" % \"2.0.0-cdh4.4.0\" % \"provided\"\n)\n```\n\nMaven defines [\"provided\"](http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope) as:\n\n\u003e This is much like `compile`, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope `provided` because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.\n\nThe dependency will be part of compilation and test, but excluded from the runtime. If you're using Spark and want to include \"provided\" dependencies back to `run`, [@douglaz](https://github.com/douglaz) has come up with a one-liner solution on StackOverflow [sbt: how can I add \"provided\" dependencies back to run/test tasks' classpath?](http://stackoverflow.com/a/21803413/3827):\n\n```scala\nCompile / run := Defaults.runTask(Compile / fullClasspath, Compile / run / mainClass, Compile / run / runner).evaluated\n```\n\n### Exclude specific transitive deps\n\nYou might be thinking about excluding JAR files because of the merge conflicts. Merge conflict of `*.class` files indicate pathological classpath, often due to non-modular bundle JAR files or [SLF4J](http://www.slf4j.org/legacy.html), not the problem with assembly. Here's what happens when you try to create a über JAR with Spark included:\n\n```\n[error] (*:assembly) deduplicate: different file contents found in the following:\n[error] /Users/foo/.ivy2/cache/org.eclipse.jetty.orbit/javax.servlet/orbits/javax.servlet-2.5.0.v201103041518.jar:javax/servlet/SingleThreadModel.class\n[error] /Users/foo/.ivy2/cache/org.mortbay.jetty/servlet-api/jars/servlet-api-2.5-20081211.jar:javax/servlet/SingleThreadModel.class\n```\n\nIn the above case two separate JAR files `javax.servlet-2.5.0.v201103041518.jar` and `servlet-api-2.5-20081211.jar` are defining `javax/servlet/SingleThreadModel.class`! Similarly also conflicts on [common-beanutils](http://commons.apache.org/proper/commons-beanutils/) and [EsotericSoftware/minlog](https://github.com/EsotericSoftware/minlog). Here's how to evict specific transitive deps:\n\n```scala\nlibraryDependencies ++= Seq(\n  (\"org.apache.spark\" %% \"spark-core\" % \"0.8.0-incubating\").\n    exclude(\"org.mortbay.jetty\", \"servlet-api\").\n    exclude(\"commons-beanutils\", \"commons-beanutils-core\").\n    exclude(\"commons-collections\", \"commons-collections\").\n    exclude(\"commons-logging\", \"commons-logging\").\n    exclude(\"com.esotericsoftware.minlog\", \"minlog\")\n)\n```\n\nSee sbt's [Exclude Transitive Dependencies](https://www.scala-sbt.org/release/docs/Library-Management.html#Exclude+Transitive+Dependencies) for more details.\n\nSometimes it takes a bit of detective work to figure out which transitive deps to exclude. Play! comes with `dist` task, so `assembly` is not needed, but suppose we wanted to run `assembly`. It brings in signpost-commonshttp4, which leads to commons-logging. This conflicts with jcl-over-slf4j, which re-implements the logging API. Since the deps are added via build.sbt and `playScalaSettings`, here's one way to work around it:\n\n```scala\nlibraryDependencies ~= { _ map {\n  case m if m.organization == \"com.typesafe.play\" =\u003e\n    m.exclude(\"commons-logging\", \"commons-logging\").\n      exclude(\"com.typesafe.play\", \"sbt-link\")\n  case m =\u003e m\n}}\n```\n\n### Excluding specific files\n\nTo exclude specific files, customize merge strategy:\n\n```scala\nThisBuild / assemblyMergeStrategy := {\n  case PathList(\"about.html\") =\u003e MergeStrategy.rename\n  case x =\u003e\n    val oldStrategy = (ThisBuild / assemblyMergeStrategy).value\n    oldStrategy(x)\n}\n```\n\n### Splitting your project and deps JARs\n\nTo make a JAR file containing only the external dependencies, type\n\n    \u003e assemblyPackageDependency\n\nThis is intended to be used with a JAR that only contains your project\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assemblyPackageScala / assembleArtifact := false,\n    assemblyPackageDependency / assembleArtifact := false,\n\n    // or as follows\n    assembly / assemblyOption ~= {\n      _.withIncludeScala(false)\n       .withIncludeDependency(false)\n    },\n\n    // more settings here ...\n  )\n```\n\nNOTE: 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`\n\n### Excluding Scala library JARs\n\nTo exclude Scala library (JARs that start with `scala-` and are included in the binary Scala distribution) to run with `scala` command,\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assemblyPackageScala / assembleArtifact := false,\n\n    // or as follows\n    assembly / assemblyOption ~= {\n      _.withIncludeScala(false)\n    },\n\n    // more settings here ...\n  )\n```\n\n### assemblyExcludedJars\n\nIf all efforts fail, here's a way to exclude JAR files:\n\n```scala\nlazy val app = (project in file(\"app\"))\n  .settings(\n    assembly / assemblyExcludedJars := {\n      val cp = (assembly / fullClasspath).value\n      cp filter {_.data.getName == \"compile-0.1.0.jar\"}\n    },\n\n    // more settings here ...\n  )\n```\n\nOther Things\n------------\n\n### Content hash\n\nYou 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,\n\n```scala\nThisBuild / assemblyAppendContentHash := true\n\n// or\nlazy val app = (project in file(\"app\"))\n  .settings(\n     assembly / assemblyOption ~= { _.withAppendContentHash(true) }\n  )\n```\n\n### Caching\n\nCaching is implemented by checking all the input dependencies (class and jar files)' latest timestamp and some configuration changes from the build file.\n\nIn addition the über JAR is cached so its timestamp changes only when the input changes.\n\nTo disable caching:\n\n```scala\nThisBuild / assemblyCacheOutput := false\n\n// or\nlazy val app = (project in file(\"app\"))\n  .settings(\n     assembly / assemblyOption ~= { _.withCacheOutput(false) }\n  )\n```\n\n**NOTE**:\n- Unfortunately, using a custom `MergeStrategy` other than `rename` will create a function in which the plugin cannot predict\n   the outcome. This custom function must always be executed if it matches a `PathList` pattern, and thus, **will disable caching**.\n\n#### Jar assembly performance\n\nBy default, the setting key `assemblyRepeatableBuild` is set to `true`. This ensures that the jar entries are assembled in a specific order, resulting in a consistent hash for the jar.\n\nThere is actually a performance improvement to be gained if this setting is set to `false`, since jar entries will now be assembled in parallel. The trade-off is, the jar will not have a consistent hash, and thus, caching will not work.\n\nTo set the repeatable build to false:\n\n```scala \nThisBuild / assemblyRepeatableBuild := false\n```\n\nIf a repeatable build/consistent jar is not of much importance, one may avail of this feature for improved performance, especially for large projects.\n\n### Prepending a launch script\n\nYour can prepend a launch script to the über jar. This script will be a valid shell and batch script and will make the jar executable on Unix and Windows. If you enable the shebang the file will be detected as an executable under Linux but this will cause an error message to appear on Windows. On Windows just append a \".bat\" to the files name to make it executable.\n\n```scala\nimport sbtassembly.AssemblyPlugin.defaultUniversalScript\n\nThisBuild / assemblyPrependShellScript := Some(defaultUniversalScript(shebang = false))\n\nlazy val app = (project in file(\"app\"))\n  .settings(\n     assembly / assemblyJarName := s\"${name.value}-${version.value}\"\n  )\n```\n\nThis will prepend the following shell script to the jar.\n\n```\n(#!/usr/bin/env sh)\n@ 2\u003e/dev/null # 2\u003enul \u0026 echo off \u0026 goto BOF\n:\nexec java -jar $JAVA_OPTS \"$0\" \"$@\"\nexit\n\n:BOF\n@echo off\njava -jar %JAVA_OPTS% \"%~dpnx0\" %*\nexit /B %errorlevel%\n```\n\nYou can also choose to prepend just the shell script to the über jar as follows:\n\n```scala\nimport sbtassembly.AssemblyPlugin.defaultShellScript\n\nThisBuild / assemblyPrependShellScript := Some(defaultShellScript)\n\nlazy val app = (project in file(\"app\"))\n  .settings(\n     assembly / assemblyJarName := s\"${name.value}-${version.value}\"\n  )\n```\n\n### Publishing (Not Recommended)\n\nWe discourage you from publishing non-shaded über JARs beyond deployment. The moment your über JAR is used as a library, it becomes a **parasitized über JAR**, bringing in parasite libraries that can not be excluded or resolved. One might think non-modularity is convenience, but it turns into others' headache down the road.\n\nHere are some example of parasitized über JARs:\n\n- hive-exec 2.3.9 and 3.1.3 contain com.google.common, com.google.protobuf, io.airlift, org.apache.parquet, org.codehaus.jackson, org.joda.time, etc.\n\n### Q: Despite the concerned friends, I still want publish über JARs. What advice do you have?\n\nShade everything. Next, you would likely need to set up a front business to lie about what dependencies you have in `pom.xml` and `ivy.xml`.\nTo do so, make a subproject for über JAR purpose only where you depend on the dependencies, and make a second cosmetic subproject that you use only for publishing purpose:\n\n```scala\nlazy val uberJar = project\n  .enablePlugins(AssemblyPlugin)\n  .settings(\n    depend on the good stuff\n    publish / skip := true\n  )\n\nlazy val cosmetic = project\n  .settings(\n    name := \"shaded-something\",\n    Compile / packageBin := (uberJar / assembly).value\n  )\n```\n\nLicense\n-------\n\nPublished under The MIT License, see LICENSE\n\nCopyright e.e d3si9n, LLC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","funding_links":[],"categories":["HarmonyOS","BUILD \u0026 RELEASE","Release","Table of Contents","Sbt plugins","Tooling"],"sub_categories":["Windows Manager","Sbt plugins","Angular"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbt%2Fsbt-assembly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbt%2Fsbt-assembly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbt%2Fsbt-assembly/lists"}