-
Notifications
You must be signed in to change notification settings - Fork 26
/
Package.scala
117 lines (108 loc) · 4.33 KB
/
Package.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Predef.{conforms => _, _}
import java.io.File
import java.util.jar.{Attributes, Manifest}
import collection.JavaConversions._
import Types.:+:
import Path._
import sbinary.{DefaultProtocol,Format}
import DefaultProtocol.{FileFormat, immutableMapFormat, StringFormat, UnitFormat}
import Cache.{defaultEquiv, hConsCache, hNilCache, streamFormat, wrapIn}
import Tracked.{inputChanged, outputChanged}
import FileInfo.exists
import FilesInfo.lastModified
sealed trait PackageOption
object Package
{
final case class JarManifest(m: Manifest) extends PackageOption
{
assert(m != null)
}
final case class MainClass(mainClassName: String) extends PackageOption
final case class ManifestAttributes(attributes: (Attributes.Name, String)*) extends PackageOption
def ManifestAttributes(attributes: (String, String)*): ManifestAttributes =
{
val converted = for( (name,value) <- attributes ) yield (new Attributes.Name(name), value)
new ManifestAttributes(converted : _*)
}
def mergeAttributes(a1: Attributes, a2: Attributes) = a1 ++= a2
// merges `mergeManifest` into `manifest` (mutating `manifest` in the process)
def mergeManifests(manifest: Manifest, mergeManifest: Manifest)
{
mergeAttributes(manifest.getMainAttributes, mergeManifest.getMainAttributes)
val entryMap = asScalaMap(manifest.getEntries)
for((key, value) <- mergeManifest.getEntries)
{
entryMap.get(key) match
{
case Some(attributes) => mergeAttributes(attributes, value)
case None => entryMap put (key, value)
}
}
}
final class Configuration(val sources: Seq[(File, String)], val jar: File, val options: Seq[PackageOption])
def apply(conf: Configuration, cacheFile: File, log: Logger)
{
val manifest = new Manifest
val main = manifest.getMainAttributes
for(option <- conf.options)
{
option match
{
case JarManifest(mergeManifest) => mergeManifests(manifest, mergeManifest)
case MainClass(mainClassName) => main.put(Attributes.Name.MAIN_CLASS, mainClassName)
case ManifestAttributes(attributes @ _*) => main ++= attributes
case _ => log.warn("Ignored unknown package option " + option)
}
}
setVersion(main)
val cachedMakeJar = inputChanged(cacheFile / "inputs") { (inChanged, inputs: Map[File, String] :+: FilesInfo[ModifiedFileInfo] :+: Manifest :+: HNil) =>
val sources :+: _ :+: manifest :+: HNil = inputs
outputChanged(cacheFile / "output") { (outChanged, jar: PlainFileInfo) =>
if(inChanged || outChanged)
makeJar(sources.toSeq, jar.file, manifest, log)
else
log.debug("Jar uptodate: " + jar.file)
}
}
val map = conf.sources.toMap
val inputs = map :+: lastModified(map.keySet.toSet) :+: manifest :+: HNil
cachedMakeJar(inputs)(() => exists(conf.jar))
}
def setVersion(main: Attributes)
{
val version = Attributes.Name.MANIFEST_VERSION
if(main.getValue(version) eq null)
main.put(version, "1.0")
}
def addSpecManifestAttributes(name: String, version: String, orgName: String): PackageOption =
{
import Attributes.Name._
val attribKeys = Seq(SPECIFICATION_TITLE, SPECIFICATION_VERSION, SPECIFICATION_VENDOR)
val attribVals = Seq(name, version, orgName)
ManifestAttributes(attribKeys zip attribVals : _*)
}
def addImplManifestAttributes(name: String, version: String, homepage: Option[java.net.URL], org: String, orgName: String): PackageOption =
{
import Attributes.Name._
val attribKeys = Seq(IMPLEMENTATION_TITLE, IMPLEMENTATION_VERSION, IMPLEMENTATION_VENDOR, IMPLEMENTATION_VENDOR_ID)
val attribVals = Seq(name, version, orgName, org)
ManifestAttributes((attribKeys zip attribVals) ++ { homepage map(h => (IMPLEMENTATION_URL, h.toString)) } : _*)
}
def makeJar(sources: Seq[(File, String)], jar: File, manifest: Manifest, log: Logger)
{
log.info("Packaging " + jar.getAbsolutePath + " ...")
IO.delete(jar)
log.debug(sourcesDebugString(sources))
IO.jar(sources, jar, manifest)
log.info("Done packaging.")
}
def sourcesDebugString(sources: Seq[(File, String)]): String =
"Input file mappings:\n\t" + (sources map { case (f,s) => s + "\n\t " + f} mkString("\n\t") )
implicit def manifestEquiv: Equiv[Manifest] = defaultEquiv
implicit def manifestFormat: Format[Manifest] = streamFormat( _ write _, in => new Manifest(in))
implicit def stringMapEquiv: Equiv[Map[File, String]] = defaultEquiv
}