summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Richards <richards.aj@gmail.com>2019-07-29 13:56:01 +0100
committerTobias Roeser <le.petit.fou@web.de>2019-07-29 14:56:01 +0200
commitca1def4d6f5c829701e04f86dacb720bb57f036f (patch)
treeafbf8c216e8c310d7297455e2f44d8f7234c7504
parent1a05b8d392e5d2eef36fc0ea4fd1e43b10cebd36 (diff)
downloadmill-ca1def4d6f5c829701e04f86dacb720bb57f036f.tar.gz
mill-ca1def4d6f5c829701e04f86dacb720bb57f036f.tar.bz2
mill-ca1def4d6f5c829701e04f86dacb720bb57f036f.zip
add ability to define jar manifest (#634)
* add capability to define jar manifest * Don't use the custom manifest for doc-only jars This is to pass test mill.scalalib.HelloWorldTests.scalaDocOptions * Add JarManifest.Default and fix the build rebase fix
-rwxr-xr-xbuild.sc1
-rw-r--r--main/src/modules/Jvm.scala60
-rw-r--r--main/test/src/eval/JavaCompileJarTests.scala4
-rw-r--r--scalalib/src/JavaModule.scala20
4 files changed, 64 insertions, 21 deletions
diff --git a/build.sc b/build.sc
index cba26933..2515abda 100755
--- a/build.sc
+++ b/build.sc
@@ -8,6 +8,7 @@ import mill._
import mill.scalalib._
import publish._
import mill.modules.Jvm.createAssembly
+
trait MillPublishModule extends PublishModule{
def artifactName = "mill-" + super.artifactName()
diff --git a/main/src/modules/Jvm.scala b/main/src/modules/Jvm.scala
index 39813217..fb93b839 100644
--- a/main/src/modules/Jvm.scala
+++ b/main/src/modules/Jvm.scala
@@ -6,7 +6,7 @@ import java.net.URI
import java.nio.file.{FileSystems, Files, StandardOpenOption}
import java.nio.file.attribute.PosixFilePermission
import java.util.Collections
-import java.util.jar.{JarEntry, JarFile, JarOutputStream}
+import java.util.jar.{Attributes, JarEntry, JarFile, JarOutputStream, Manifest}
import coursier.{Dependency, Fetch, Repository, Resolution}
import coursier.util.{Gather, Task}
@@ -19,6 +19,7 @@ import mill.api.Loose.Agg
import scala.collection.mutable
import scala.collection.JavaConverters._
+import upickle.default.{macroRW, ReadWriter => RW}
object Jvm {
/**
@@ -189,15 +190,16 @@ object Jvm {
}
}
-
- private def createManifest(mainClass: Option[String]) = {
- val m = new java.util.jar.Manifest()
- m.getMainAttributes.put(java.util.jar.Attributes.Name.MANIFEST_VERSION, "1.0")
- m.getMainAttributes.putValue( "Created-By", "Scala mill" )
- mainClass.foreach(
- m.getMainAttributes.put(java.util.jar.Attributes.Name.MAIN_CLASS, _)
- )
- m
+ def createManifest(mainClass: Option[String]): JarManifest = {
+ val main =
+ Map[String,String](
+ java.util.jar.Attributes.Name.MANIFEST_VERSION.toString -> "1.0",
+ "Created-By" -> "Scala mill"
+ ) ++
+ mainClass.map(mc =>
+ Map(java.util.jar.Attributes.Name.MAIN_CLASS.toString -> mc)
+ ).getOrElse(Map.empty)
+ JarManifest(main)
}
/**
@@ -214,7 +216,7 @@ object Jvm {
* @return - a `PathRef` for the created jar.
*/
def createJar(inputPaths: Agg[os.Path],
- mainClass: Option[String] = None,
+ manifest: JarManifest = JarManifest.Default,
fileFilter: (os.Path, os.RelPath) => Boolean = (p: os.Path, r: os.RelPath) => true)
(implicit ctx: Ctx.Dest): PathRef = {
val outputPath = ctx.dest / "out.jar"
@@ -224,7 +226,7 @@ object Jvm {
seen.add(os.rel / "META-INF" / "MANIFEST.MF")
val jar = new JarOutputStream(
new FileOutputStream(outputPath.toIO),
- createManifest(mainClass)
+ manifest.build
)
try{
@@ -251,7 +253,7 @@ object Jvm {
}
def createAssembly(inputPaths: Agg[os.Path],
- mainClass: Option[String] = None,
+ manifest: JarManifest = JarManifest.Default,
prependShellScript: String = "",
base: Option[os.Path] = None,
assemblyRules: Seq[Assembly.Rule] = Assembly.defaultRules)
@@ -269,7 +271,6 @@ object Jvm {
val zipFs = FileSystems.newFileSystem(URI.create(baseUri), hm)
- val manifest = createManifest(mainClass)
val manifestPath = zipFs.getPath(JarFile.MANIFEST_NAME)
Files.createDirectories(manifestPath.getParent)
val manifestOut = Files.newOutputStream(
@@ -277,7 +278,7 @@ object Jvm {
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE
)
- manifest.write(manifestOut)
+ manifest.build.write(manifestOut)
manifestOut.close()
Assembly.groupAssemblyEntries(inputPaths, assemblyRules).view
@@ -332,6 +333,7 @@ object Jvm {
outputStream.close()
is.close()
}
+
def universalScript(shellCommands: String,
cmdCommands: String,
shebang: Boolean = false): String = {
@@ -561,4 +563,32 @@ object Jvm {
}
}
+ object JarManifest {
+ implicit val jarManifestRW: RW[JarManifest] = upickle.default.macroRW
+ final val Default = createManifest(None)
+ }
+
+ /** Represents a JAR manifest.
+ * @param main the main manifest attributes
+ * @param groups additional attributes for named entries
+ */
+ final case class JarManifest(main: Map[String,String] = Map.empty, groups: Map[String, Map[String,String]] = Map.empty) {
+ def add(entries: (String,String)*): JarManifest = copy(main = main ++ entries)
+ def addGroup(group: String, entries: (String,String)*): JarManifest =
+ copy(groups = groups + (group -> (groups.getOrElse(group, Map.empty) ++ entries)))
+
+ /** Constructs a [[java.util.jar.Manifest]] from this JarManifest. */
+ def build: Manifest = {
+ val manifest = new Manifest
+ val mainAttributes = manifest.getMainAttributes
+ main.foreach{case(key,value) => mainAttributes.putValue(key, value)}
+ val entries = manifest.getEntries
+ for((group, attribs) <- groups) {
+ val attrib = new Attributes
+ attribs.foreach{case(key,value) => attrib.putValue(key, value)}
+ entries.put(group, attrib)
+ }
+ manifest
+ }
+ }
}
diff --git a/main/test/src/eval/JavaCompileJarTests.scala b/main/test/src/eval/JavaCompileJarTests.scala
index 0f9002df..e243b915 100644
--- a/main/test/src/eval/JavaCompileJarTests.scala
+++ b/main/test/src/eval/JavaCompileJarTests.scala
@@ -2,6 +2,7 @@ package mill.eval
import mill.define.{Discover, Input, Target, Task}
import mill.modules.Jvm
+import mill.modules.Jvm.JarManifest
import mill.api.Ctx.Dest
import mill.{Module, T}
import mill.util.{DummyLogger, TestEvaluator, TestUtil}
@@ -9,6 +10,7 @@ import mill.api.Strict.Agg
import mill.api.Loose
import utest._
import mill._
+
object JavaCompileJarTests extends TestSuite{
def compileAll(sources: mill.api.Loose.Agg[PathRef])(implicit ctx: Dest) = {
os.makeDir.all(ctx.dest)
@@ -39,7 +41,7 @@ object JavaCompileJarTests extends TestSuite{
def classFiles = T{ compileAll(allSources()) }
def jar = T{ Jvm.createJar(Loose.Agg(classFiles().path) ++ resourceRoot().map(_.path)) }
// Test createJar() with optional file filter.
- def filterJar(fileFilter: (os.Path, os.RelPath) => Boolean) = T{ Jvm.createJar(Loose.Agg(classFiles().path) ++ resourceRoot().map(_.path), None, fileFilter) }
+ def filterJar(fileFilter: (os.Path, os.RelPath) => Boolean) = T{ Jvm.createJar(Loose.Agg(classFiles().path) ++ resourceRoot().map(_.path), JarManifest.Default, fileFilter) }
def run(mainClsName: String) = T.command{
os.proc('java, "-Duser.language=en", "-cp", classFiles().path, mainClsName).call()
diff --git a/scalalib/src/JavaModule.scala b/scalalib/src/JavaModule.scala
index 7b373650..c7066d15 100644
--- a/scalalib/src/JavaModule.scala
+++ b/scalalib/src/JavaModule.scala
@@ -1,6 +1,9 @@
package mill
package scalalib
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+
import coursier.Repository
import mill.define.Task
import mill.define.TaskModule
@@ -257,6 +260,14 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
}
/**
+ * Creates a manifest representation which can be modifed or replaced
+ * The default implementation just adds the `Manifest-Version`, `Main-Class` and `Created-By` attributes
+ */
+ def manifest = T{
+ Jvm.createManifest(finalMainClassOpt().toOption)
+ }
+
+ /**
* Build the assembly for upstream dependencies separate from the current
* classpath
*
@@ -266,7 +277,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
def upstreamAssembly = T{
createAssembly(
upstreamAssemblyClasspath().map(_.path),
- mainClass(),
+ manifest(),
assemblyRules = assemblyRules
)
}
@@ -278,7 +289,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
def assembly = T{
createAssembly(
Agg.from(localClasspath().map(_.path)),
- finalMainClassOpt().toOption,
+ manifest(),
prependShellScript(),
Some(upstreamAssembly().path),
assemblyRules
@@ -292,7 +303,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
def jar = T{
createJar(
localClasspath().map(_.path).filter(os.exists),
- mainClass()
+ manifest()
)
}
@@ -345,7 +356,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
* The source jar, containing only source code for publishing to Maven Central
*/
def sourceJar = T {
- createJar((allSources() ++ resources()).map(_.path).filter(os.exists))
+ createJar((allSources() ++ resources()).map(_.path).filter(os.exists), manifest())
}
/**
@@ -626,4 +637,3 @@ object TestModule{
}
}
}
-