mirror of https://github.com/sbt/sbt.git
{publish,deliver}{,-local} and package tasks
This commit is contained in:
parent
8df5cbabf5
commit
e68f133c7f
|
|
@ -8,9 +8,9 @@ package sbt
|
|||
import TaskExtra._
|
||||
import ClasspathProject._
|
||||
import java.io.File
|
||||
import Path._
|
||||
import Path._
|
||||
import Types._
|
||||
import scala.xml.NodeSeq
|
||||
import scala.xml.{Node => XNode,NodeSeq}
|
||||
import scala.collection.mutable.{LinkedHashMap, LinkedHashSet}
|
||||
|
||||
trait ClasspathProject
|
||||
|
|
@ -55,7 +55,6 @@ trait BasicClasspathProject extends ClasspathProject
|
|||
val unmanagedBase: Task[File]
|
||||
def cacheDirectory: File
|
||||
|
||||
|
||||
val updateConfig: Task[UpdateConfiguration]
|
||||
|
||||
lazy val ivySbt: Task[IvySbt] =
|
||||
|
|
@ -84,9 +83,26 @@ trait BasicClasspathProject extends ClasspathProject
|
|||
|
||||
lazy val update = (ivyModule, updateConfig) map cachedUpdate(cacheDirectory / "update", configurationMap)
|
||||
}
|
||||
|
||||
trait DefaultClasspathProject extends BasicClasspathProject with Project
|
||||
trait PublishProject extends BasicClasspathProject
|
||||
{
|
||||
val publishConfig: Task[PublishConfiguration]
|
||||
val publishLocalConfig: Task[PublishConfiguration]
|
||||
val makePomConfig: Task[MakePomConfiguration]
|
||||
def packageToPublish: Seq[Task[_]]
|
||||
|
||||
def publishMavenStyle = true
|
||||
def deliverDepends = if(publishMavenStyle) makePom :: Nil else packageToPublish
|
||||
|
||||
lazy val makePom = (ivyModule, makePomConfig) map(IvyActions.makePom) dependsOn( packageToPublish : _*)
|
||||
lazy val deliver = (ivyModule, publishConfig) map cachedPublish(cacheDirectory / "deliver")(IvyActions.deliver) dependsOn(deliverDepends : _*)
|
||||
lazy val deliverLocal = (ivyModule, publishLocalConfig) map cachedPublish(cacheDirectory / "deliver-local")(IvyActions.deliver) dependsOn(deliverDepends : _*)
|
||||
lazy val publish = (ivyModule, publishConfig) map cachedPublish(cacheDirectory / "publish")(IvyActions.publish) dependsOn(deliver)
|
||||
lazy val publishLocal = (ivyModule, publishLocalConfig) map cachedPublish(cacheDirectory / "publish-local")(IvyActions.publish) dependsOn(deliverLocal)
|
||||
}
|
||||
|
||||
trait DefaultClasspathProject extends BasicClasspathProject with PublishProject with Project
|
||||
{
|
||||
def outputDirectory: Path
|
||||
def projectID: ModuleID
|
||||
def baseResolvers: Seq[Resolver]
|
||||
lazy val resolvers: Task[Seq[Resolver]] = task { baseResolvers }
|
||||
|
|
@ -119,6 +135,10 @@ trait DefaultClasspathProject extends BasicClasspathProject with Project
|
|||
def defaultConfiguration: Option[Configuration] = None
|
||||
def ivyScala: Option[IvyScala] = None
|
||||
def ivyValidate: Boolean = false
|
||||
def moduleID = normalizedName
|
||||
|
||||
def pomFile: File
|
||||
def publishTo: Resolver = error("Repository for publishing is not specified.")
|
||||
|
||||
lazy val internalDependencyClasspath: Classpath = internalDependencies(this)
|
||||
|
||||
|
|
@ -127,6 +147,10 @@ trait DefaultClasspathProject extends BasicClasspathProject with Project
|
|||
lazy val moduleSettings: Task[ModuleSettings] = task {
|
||||
new InlineConfiguration(projectID, libraryDependencies, ivyXML, configurations, defaultConfiguration, ivyScala, ivyValidate)
|
||||
}
|
||||
|
||||
lazy val publishConfig = task { publishConfiguration( publishPatterns(outputDirectory), resolverName = publishTo.name ) }
|
||||
lazy val publishLocalConfig = task { publishConfiguration( publishPatterns(outputDirectory, true) ) }
|
||||
lazy val makePomConfig = task { makePomConfiguration(pomFile) }
|
||||
}
|
||||
trait MultiClasspathProject extends DefaultClasspathProject
|
||||
{
|
||||
|
|
@ -134,6 +158,8 @@ trait MultiClasspathProject extends DefaultClasspathProject
|
|||
def name: String
|
||||
def organization: String
|
||||
def version: String
|
||||
def pomFile: File = outputDirectory / (moduleID + "-" + version + ".pom")
|
||||
def artifacts: Seq[Artifact] = Nil
|
||||
|
||||
def projectDependencies: Seq[ModuleID] =
|
||||
resolvedDependencies(this) collect { case (p: DefaultClasspathProject, conf) => p.projectID.copy(configurations = conf) }
|
||||
|
|
@ -143,7 +169,7 @@ trait MultiClasspathProject extends DefaultClasspathProject
|
|||
new RawRepository(new ProjectResolver("inter-project", m))
|
||||
}
|
||||
|
||||
override def projectID = ModuleID(organization, name, version)
|
||||
override def projectID = ModuleID(organization, moduleID, version).cross(true).artifacts(artifacts.toSeq : _*)
|
||||
override def libraryDependencies: Seq[ModuleID] = super.libraryDependencies ++ projectDependencies
|
||||
|
||||
override lazy val resolvers: Task[Seq[Resolver]] = projectResolver map { _ +: baseResolvers }
|
||||
|
|
@ -274,10 +300,29 @@ object ClasspathProject
|
|||
case _ => Configurations.Default
|
||||
}
|
||||
|
||||
def makePomConfiguration(file: File, configurations: Option[Iterable[Configuration]] = None, extra: NodeSeq = NodeSeq.Empty, process: XNode => XNode = n => n, filterRepositories: MavenRepository => Boolean = _ => true) =
|
||||
new MakePomConfiguration(file, configurations, extra, process, filterRepositories)
|
||||
|
||||
def publishConfiguration(patterns: PublishPatterns, resolverName: String = "local", status: String = "release", logging: UpdateLogging.Value = UpdateLogging.DownloadOnly) =
|
||||
new PublishConfiguration(patterns, status, resolverName, None, logging)
|
||||
|
||||
def publishPatterns(outputPath: Path, publishIvy: Boolean = false): PublishPatterns =
|
||||
{
|
||||
val deliverPattern = (outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
|
||||
val srcArtifactPatterns: Seq[String] =
|
||||
{
|
||||
val pathPatterns =
|
||||
(outputPath / "[artifact]-[revision]-[type](-[classifier]).[ext]") ::
|
||||
(outputPath / "[artifact]-[revision](-[classifier]).[ext]") ::
|
||||
Nil
|
||||
pathPatterns.map(_.absolutePath)
|
||||
}
|
||||
new PublishPatterns( if(publishIvy) Some(deliverPattern) else None, srcArtifactPatterns)
|
||||
}
|
||||
|
||||
import Cache._
|
||||
import Types._
|
||||
import CacheIvy.{classpathFormat, updateIC}
|
||||
|
||||
import CacheIvy.{classpathFormat, publishIC, updateIC}
|
||||
|
||||
def cachedUpdate(cacheFile: File, configMap: Map[String, Configuration]): (IvySbt#Module :+: UpdateConfiguration :+: HNil) => Map[Configuration, Seq[File]] =
|
||||
{ case module :+: config :+: HNil =>
|
||||
|
|
@ -293,4 +338,13 @@ object ClasspathProject
|
|||
classpaths map { case (key, value) => (confMap(key), value) } toMap;
|
||||
}
|
||||
|
||||
// can't cache deliver/publish easily since files involved are hidden behind patterns. publish will be difficult to verify target-side anyway
|
||||
def cachedPublish(cacheFile: File)(g: (IvySbt#Module, PublishConfiguration) => Unit): (IvySbt#Module :+: PublishConfiguration :+: HNil) => Unit =
|
||||
{ case module :+: config :+: HNil =>
|
||||
/* implicit val publishCache = publishIC
|
||||
val f = cached(cacheFile) { (conf: IvyConfiguration, settings: ModuleSettings, config: PublishConfiguration) =>*/
|
||||
g(module, config)
|
||||
/*}
|
||||
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)*/
|
||||
}
|
||||
}
|
||||
|
|
@ -22,10 +22,10 @@ class DefaultProject(val info: ProjectInfo) extends BasicProject
|
|||
}
|
||||
trait IntegrationTest extends BasicProject
|
||||
{
|
||||
override def productsTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
||||
override def directoryProductsTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
||||
conf match {
|
||||
case ITestConfig => makeProducts(integrationTestCompile.compile, integrationTestCompile.compileInputs, name, "it-")
|
||||
case _ => super.productsTask(conf)
|
||||
case _ => super.directoryProductsTask(conf)
|
||||
}
|
||||
|
||||
override def configurations: Seq[Configuration] = super.configurations :+ Configurations.IntegrationTest
|
||||
|
|
@ -39,6 +39,9 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with
|
|||
// easier to demo for now
|
||||
override def organization = "org.example"
|
||||
override def version = "1.0"
|
||||
def artifactID = normalizedName
|
||||
override def artifacts: Seq[Artifact] = Artifact(artifactID) :: pomArtifact
|
||||
def pomArtifact = (if(publishMavenStyle) Artifact(artifactID, "pom", "pom") :: Nil else Nil)
|
||||
|
||||
override def watchPaths: PathFinder = (info.projectDirectory: Path) * sourceFilter +++ descendents("src","*")
|
||||
|
||||
|
|
@ -46,6 +49,7 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with
|
|||
def scalacOptions: Seq[String] = Nil
|
||||
def consoleOptions: Seq[String] = scalacOptions
|
||||
def initialCommands: String = ""
|
||||
def maximumErrors: Int = 100
|
||||
|
||||
def outputDirectory = "target": Path
|
||||
def cacheDirectory = outputDirectory / "cache"
|
||||
|
|
@ -53,21 +57,53 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with
|
|||
def testResources = descendents("src" / "test" / "resources" ###, "*")
|
||||
|
||||
def classesDirectory(configuration: Configuration): File =
|
||||
configuration match {
|
||||
case CompileConfig => outputDirectory / "classes"
|
||||
case c => outputDirectory / (c.name + "-classes")
|
||||
}
|
||||
outputDirectory / (configString(configuration, "", "-") + "classes")
|
||||
|
||||
lazy val products: Classpath = TaskMap(productsTask)
|
||||
def packageToPublish: Seq[Task[_]] = configurations map packages.apply
|
||||
|
||||
// TODO: include resources, perhaps handle jars v. directories
|
||||
def productsTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
||||
lazy val products: Classpath = directoryProducts //TaskMap(productsTask)
|
||||
|
||||
lazy val directoryProducts = TaskMap(directoryProductsTask)
|
||||
lazy val packages = TaskMap(packageTask)
|
||||
lazy val pkgMainClass = TaskMap(mainClassTask)
|
||||
lazy val jarPath = TaskMap(jarPathTask)
|
||||
|
||||
lazy val `package` = packages(CompileConfig)
|
||||
lazy val testPackage = packages(TestConfig)
|
||||
|
||||
def directoryProductsTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
||||
conf match {
|
||||
case CompileConfig | DefaultConfig => makeProducts(compile.compile, compile.compileInputs, name, "")
|
||||
case TestConfig => makeProducts(testCompile.compile, testCompile.compileInputs, name, "test-")
|
||||
case x => task { Nil }
|
||||
}
|
||||
|
||||
def mainClassesTask(conf: Configuration): Task[Seq[String]] = conf match {
|
||||
case CompileConfig => discoveredMainClasses
|
||||
case TestConfig => test.testDiscoveredMainClasses
|
||||
case _ => task { Nil }
|
||||
}
|
||||
def mainClassTask(conf: Configuration): Task[Option[String]] = mainClassesTask(conf) map { classes => SelectMainClass(None, classes) }
|
||||
def configString(conf: Configuration, pre: String, post: String): String = conf match {
|
||||
case CompileConfig | DefaultConfig => ""
|
||||
case _ => pre + conf.name + post
|
||||
}
|
||||
|
||||
def jarPathTask(conf: Configuration): Task[File] = task { outputDirectory / jarName(conf) }
|
||||
def jarName(conf: Configuration): String = artifactID + "-" + version + configString(conf, "-", "") + ".jar"
|
||||
|
||||
def packageConfigTask(conf: Configuration): Task[Package.Configuration] =
|
||||
pkgMainClass(conf) :^: directoryProductsTask(conf) :^: jarPath(conf) :^: KNil map { case main :+: in :+: jar :+: HNil =>
|
||||
val srcs = data(in) flatMap { dir => descendents(dir ###, "*").xx }
|
||||
new Package.Configuration(srcs, jar, main.map(Package.MainClass.apply).toList)
|
||||
}
|
||||
|
||||
def packageTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
||||
streams :^: packageConfigTask(conf) :^: KNil map { case s :+: config :+: HNil =>
|
||||
Package(config, cacheDirectory / conf.name / "package", s.log)
|
||||
List(config.jar)
|
||||
}
|
||||
|
||||
lazy val buildScalaVersions: Task[String] = task { info.app.scalaProvider.version }//cross(MultiProject.ScalaVersion)(info.app.scalaProvider.version)
|
||||
lazy val buildScalaInstance: Task[ScalaInstance] =
|
||||
buildScalaVersions map { version => ScalaInstance(version, info.app.scalaProvider) }
|
||||
|
|
@ -78,9 +114,6 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with
|
|||
lazy val discoveredMainClasses: Task[Seq[String]] =
|
||||
discoverMain map { _ collect { case (definition, discovered) if(discovered.hasMain) => definition.name } }
|
||||
|
||||
lazy val pkgMainClass: Task[Option[String]] =
|
||||
discoveredMainClasses map { classes => SelectMainClass(None, classes) }
|
||||
|
||||
lazy val runner: Task[ScalaRun] =
|
||||
buildScalaInstance map { si => new Run(si) }
|
||||
|
||||
|
|
@ -108,7 +141,7 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with
|
|||
|
||||
lazy val clean = task { IO.delete(outputDirectory) }
|
||||
|
||||
// lazy val doc, test-only, test-quick, test-failed, publish(-local), deliver(-local), make-pom, package-*, javap, copy-resources
|
||||
// lazy val test-only, test-quick, test-failed, package-src, package-test, package-doc, javap
|
||||
|
||||
lazy val set = input map { in =>
|
||||
val Seq(name, value) = in.splitArgs.take(2)
|
||||
|
|
@ -138,7 +171,7 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with
|
|||
val classpath = classes +: data(cp)
|
||||
val analysis = analysisMap(cp)
|
||||
val cache = cacheDirectory / "compile" / configuration.toString
|
||||
Compile.inputs(classpath, sources.getFiles.toSeq, classes, scalacOptions, javacOptions, allBases.getFiles.toSeq, analysis, cache, 100)(compilers, log)
|
||||
Compile.inputs(classpath, sources.getFiles.toSeq, classes, scalacOptions, javacOptions, allBases.getFiles.toSeq, analysis, cache, maximumErrors)(compilers, log)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,3 +272,9 @@ class TestTasks(val prefix: Option[String], val project: ClasspathProject with P
|
|||
}
|
||||
lazy val test = (project.streams, executeTests) map { case s :+: results :+: HNil => Test.showResults(s.log, results) }
|
||||
}
|
||||
/*class PackageTasks
|
||||
/* def zipTask(sources: PathFinder, outputDirectory: Path, zipName: => String): Task =
|
||||
zipTask(sources, outputDirectory / zipName)
|
||||
def zipTask(sources: PathFinder, zipPath: => Path): Task =
|
||||
fileTask("zip", zipPath from sources) { FileUtilities.zip(sources.get, zipPath, false, log) }*/
|
||||
}*/
|
||||
|
|
@ -167,6 +167,7 @@ trait Project extends Tasked with HistoryEnabled with Member[Project] with Named
|
|||
|
||||
def settings: Settings = Settings.empty
|
||||
def name: String = info.name getOrElse error("'name' not overridden")
|
||||
def normalizedName: String = StringUtilities.normalize(name)
|
||||
|
||||
def base = info.projectDirectory
|
||||
def outputRootPath = base / "target"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
/* 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, existsInputCache}
|
||||
import FilesInfo.lastModified
|
||||
import lastModified.infosInputCache
|
||||
|
||||
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 m2 into m1 (mutating m1 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)
|
||||
{
|
||||
import conf._
|
||||
val manifest = new Manifest
|
||||
val main = manifest.getMainAttributes
|
||||
for(option <- 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)
|
||||
}
|
||||
}
|
||||
|
||||
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 makeJar(sources: Seq[(File, String)], jar: File, manifest: Manifest)
|
||||
{
|
||||
println("Packaging...")
|
||||
IO.delete(jar)
|
||||
IO.jar(sources, jar, manifest)
|
||||
println("Done packaging.")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Loading…
Reference in New Issue