Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use 'publish-all' from the root to publish all projects to local use 'proguard' to package the launcher
- Loading branch information
Showing
18 changed files
with
477 additions
and
694 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,137 @@ | |||
import sbt._ | |||
import Keys._ | |||
import Scope.{GlobalScope, ThisScope} | |||
|
|||
object LaunchProguard | |||
{ | |||
lazy val Proguard = config("proguard") hide ; | |||
|
|||
lazy val configurationFile = SettingKey[File]("configuration-file") | |||
lazy val proguard = TaskKey[File]("proguard", "Produces the final compacted jar that contains only the classes needed using proguard.") | |||
lazy val proguardConfiguration = TaskKey[File]("proguard-configuration", "Creates the configuration file to use with proguard.") | |||
lazy val options = TaskKey[Seq[String]]("options") | |||
lazy val optimizePasses = SettingKey[Int]("optimize-passes") | |||
lazy val keepFullClasses = SettingKey[Seq[String]]("keep-full-classes") | |||
lazy val keepClasses = SettingKey[Seq[String]]("keep-classes") | |||
lazy val inputJars = TaskKey[Seq[File]]("input-jars") | |||
|
|||
lazy val settings: Seq[Setting[_]] = | |||
inScope(GlobalScope)(inConfig(Proguard)(globalSettings)) ++ | |||
inConfig(Proguard)( baseSettings ) :+ | |||
(libraryDependencies += "net.sf.proguard" % "proguard" % "4.4" % Proguard.name) | |||
|
|||
def globalSettings = Seq( | |||
optimizePasses := 2, | |||
keepFullClasses := Nil, | |||
keepClasses := Nil, | |||
options := basicOptions | |||
) | |||
def baseSettings = Seq( | |||
options <++= optimizePasses map { passes => if(passes <= 0) Seq("-dontoptimize") else Seq( "-optimizationpasses " + passes.toString, "-optimizations !code/allocation/variable") }, | |||
options <++= keepFullClasses map { _ map ("-keep public class " + _ + " {\n\tpublic protected * ;\n}") }, | |||
options <++= keepClasses map { _ map ("-keep class " + _ + " {}") }, | |||
configurationFile <<= target / "proguard.pro", | |||
proguardConfiguration <<= writeProguardConfiguration, | |||
proguard <<= proguardTask | |||
) | |||
|
|||
def specific(launchSub: Reference): Seq[Setting[_]] = inConfig(Proguard)(Seq( | |||
keepFullClasses ++= "xsbti.**" :: "jline.**" :: Nil, | |||
keepClasses ++= "org.apache.ivy.plugins.resolver.URLResolver" :: "org.apache.ivy.plugins.resolver.IBiblioResolver" :: Nil, | |||
artifactPath <<= (target, version) { (out,v) => out / ("sbt-launch-" + v + ".jar") }, | |||
options <++= (dependencyClasspath in (launchSub, Compile), compile in (launchSub,Compile), streams) map { (cp, analysis, s) => mapJars(cp.files, analysis.relations.allBinaryDeps.toSeq, s.log) }, | |||
options <+= packageBin map { f => "-injars " + mkpath(f) }, | |||
packageBin <<= (packageBin in (launchSub, Compile)).identity, | |||
options <++= mainClass in (launchSub, Compile) map { _.toList map(s => keepMain.format(s)) }, | |||
options <+= artifactPath map { p => "-outjars " + mkpath(p) }, | |||
fullClasspath <<= (configuration, classpathTypes, update) map Classpaths.managedJars | |||
)) | |||
|
|||
def mapJars(in: Seq[File], all: Seq[File], log: Logger): Seq[String] = | |||
mapInJars(in, log) ++ mapLibraryJars(all filterNot in.toSet) | |||
def writeProguardConfiguration = (options, configurationFile, streams) map { (opts, conf, s) => | |||
val content = opts.mkString("\n") | |||
if(!conf.exists || IO.read(conf) != content) { | |||
s.log.info("Proguard configuration written to " + conf) | |||
IO.write(conf, content) | |||
} | |||
conf | |||
} | |||
|
|||
def basicOptions = | |||
Seq( | |||
"-keep,allowoptimization,allowshrinking class * { *; }", | |||
"-keepattributes SourceFile,LineNumberTable", | |||
"-dontnote", | |||
"-dontwarn", | |||
"-ignorewarnings") | |||
|
|||
private val keepMain = | |||
"""-keep public class %s { | |||
| public static void main(java.lang.String[]); | |||
|}""".stripMargin | |||
|
|||
def mapLibraryJars(libraryJars: Seq[File]): Seq[String] = libraryJars.map(f => "-libraryjars " + mkpath(f)) | |||
def mapOutJar(outJar: File) = "-outjars " + mkpath(outJar) | |||
|
|||
def mkpath(f: File) : String = mkpath(f.getAbsolutePath, '\"') | |||
def mkpath(path: String, delimiter : Char) : String = delimiter + path + delimiter | |||
|
|||
def proguardTask = (cacheDirectory, artifactPath, proguardConfiguration, fullClasspath, packageBin, streams) map { (cache, outputJar, configFile, cp, inJar, s) => | |||
val f = FileFunction.cached(cache / "proguard", FilesInfo.hash) { _ => | |||
runProguard(outputJar, configFile, cp.files, s.log) | |||
Set(outputJar) | |||
} | |||
f(Set(inJar, configFile)) // make the assumption that if the classpath changed, the outputJar would change | |||
outputJar | |||
} | |||
def runProguard(outputJar: File, configFile: File, cp: Seq[File], log: Logger) | |||
{ | |||
IO.delete(outputJar) | |||
val fileString = mkpath(configFile.getAbsolutePath, '\'') | |||
val exitValue = Process("java", List("-Xmx256M", "-cp", Path.makeString(cp), "proguard.ProGuard", "-include " + fileString)) ! log | |||
if(exitValue != 0) error("Proguard failed with nonzero exit code (" + exitValue + ")") | |||
} | |||
|
|||
def mapInJars(inJars: Seq[File], log: Logger): Seq[String] = | |||
{ | |||
val (jlineJars, notJLine) = inJars partition isJarX("jline") | |||
val (ivyJars, notIvy) = notJLine partition isJarX("ivy") | |||
val (libraryJar, remaining) = notIvy partition isJarX("scala-library") | |||
val (compilerJar, otherJars) = remaining partition isJarX("scala-compiler") | |||
|
|||
log.debug("proguard configuration:") | |||
log.debug("\tJLline jar location: " + jlineJars.mkString(", ")) | |||
log.debug("\tIvy jar location: " + ivyJars.mkString(", ")) | |||
log.debug("\tOther jars:\n\t" + otherJars.mkString("\n\t")) | |||
|
|||
((withJar(ivyJars.toSeq, "Ivy") + excludeString(excludeIvyResources)) :: | |||
(withJar(jlineJars, "JLine") + jlineFilter ) :: | |||
(withJar(libraryJar, "Scala library") + libraryFilter) :: | |||
otherJars.map(jar => mkpath(jar) + generalFilter).toList) map { "-injars " + _ } | |||
} | |||
|
|||
private def excludeString(s: List[String]) = s.map("!" + _).mkString("(",",",")") | |||
private def excludeIvyResources = | |||
"META-INF/**" :: | |||
"fr/**" :: | |||
"**/antlib.xml" :: | |||
"**/*.png" :: | |||
"org/apache/ivy/core/settings/ivyconf*.xml" :: | |||
"org/apache/ivy/core/settings/ivysettings-*.xml" :: | |||
"org/apache/ivy/plugins/resolver/packager/*" :: | |||
"**/ivy_vfs.xml" :: | |||
"org/apache/ivy/plugins/report/ivy-report-*" :: | |||
Nil | |||
|
|||
private def libraryFilter = "(!META-INF/**,!*.properties,!scala/actors/**.!scala/util/parsing/*.class,!scala/xml/**.class,!scala/package$.class,**.class)" | |||
private def jlineFilter = "(!META-INF/**)" | |||
private def generalFilter = "(!META-INF/**,!*.properties)" | |||
|
|||
private def withJar[T](files: Seq[File], name: String) = mkpath(files.firstOption getOrElse error(name + " not present") ) | |||
private def isJarX(x: String)(file: File) = | |||
{ | |||
val name = file.getName | |||
name.startsWith(x) && name.endsWith(".jar") | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,211 @@ | |||
// TODO(high): proper incremental xsbt.version.properties generation | |||
// TODO(low): proper generated API sources caching: doesn't detect output directory change | |||
// TODO: fix discovery/test | |||
|
|||
import sbt._ | |||
import Keys._ | |||
import Project.Initialize | |||
import Util._ | |||
import Common._ | |||
import Licensed._ | |||
import Scope.ThisScope | |||
import LaunchProguard.{proguard, Proguard} | |||
|
|||
object Sbt extends Build | |||
{ | |||
override lazy val settings = super.settings ++ Seq( | |||
organization := "org.scala-tools.sbt", | |||
version := "0.10.1-SNAPSHOT", | |||
publishArtifact in packageDoc := false, | |||
scalaVersion := "2.8.1", | |||
publishMavenStyle := false, | |||
componentID := None, | |||
publishTo := Some( Resolver.url("typesafe-ivy-releases", url("http://repo.typesafe.com/typesafe/ivy-releases/"))(Resolver.ivyStylePatterns) ), | |||
credentials += Credentials(Path.userHome / ".ivy2" / ".typesafe-credentials") | |||
) | |||
|
|||
lazy val myProvided = config("provided") intransitive; | |||
override def projects = super.projects.map(p => p.copy(configurations = (p.configurations.filter(_ != Provided)) :+ myProvided)) | |||
lazy val root: Project = Project("xsbt", file("."), aggregate = nonRoots ) settings( rootSettings : _*) configs( Sxr.sxrConf, Proguard ) | |||
lazy val nonRoots = projects.filter(_ != root).map(p => LocalProject(p.id)) | |||
|
|||
/*** Subproject declarations ***/ | |||
|
|||
// defines the Java interfaces through which the launcher and the launched application communicate | |||
lazy val launchInterfaceSub = project(launchPath / "interface", "Launcher Interface") settings(javaOnly : _*) | |||
// the launcher. Retrieves, loads, and runs applications based on a configuration file. | |||
lazy val launchSub = testedBaseProject(launchPath, "Launcher") dependsOn(ioSub % "test->test", interfaceSub % "test", launchInterfaceSub) settings(launchSettings : _*) | |||
def launchSettings = Seq(jline, ivy, crossPaths := false, | |||
compile in Test <<= compile in Test dependsOn(publishLocal in interfaceSub, publishLocal in testSamples, publishLocal in launchInterfaceSub) | |||
// mappings in (Compile, packageBin) <++= (mappings in (launchInterfaceSub, Compile, packageBin) ).identity | |||
) | |||
|
|||
// used to test the retrieving and loading of an application: sample app is packaged and published to the local repository | |||
lazy val testSamples = noPublish( baseProject(launchPath / "test-sample", "Launch Test") ) dependsOn(interfaceSub, launchInterfaceSub) settings(scalaCompiler, crossPaths := false) | |||
|
|||
// defines Java structures used across Scala versions, such as the API structures and relationships extracted by | |||
// the analysis compiler phases and passed back to sbt. The API structures are defined in a simple | |||
// format from which Java sources are generated by the datatype generator subproject | |||
lazy val interfaceSub = project(file("interface"), "Interface") settings(interfaceSettings : _*) | |||
|
|||
// defines operations on the API of a source, including determining whether it has changed and converting it to a string | |||
lazy val apiSub = baseProject(compilePath / "api", "API") dependsOn(interfaceSub) | |||
|
|||
/***** Utilities *****/ | |||
|
|||
lazy val controlSub = baseProject(utilPath / "control", "Control") | |||
lazy val collectionSub = testedBaseProject(utilPath / "collection", "Collections") | |||
// The API for forking, combining, and doing I/O with system processes | |||
lazy val processSub = baseProject(utilPath / "process", "Process") dependsOn(ioSub % "test->test") | |||
// Path, IO (formerly FileUtilities), NameFilter and other I/O utility classes | |||
lazy val ioSub = testedBaseProject(utilPath / "io", "IO") dependsOn(controlSub) | |||
// Utilities related to reflection, managing Scala versions, and custom class loaders | |||
lazy val classpathSub = baseProject(utilPath / "classpath", "Classpath") dependsOn(launchInterfaceSub, ioSub) settings(scalaCompiler) | |||
// Command line-related utilities. | |||
lazy val completeSub = testedBaseProject(utilPath / "complete", "Completion") dependsOn(collectionSub, controlSub, ioSub) settings(jline) | |||
// logging | |||
lazy val logSub = testedBaseProject(utilPath / "log", "Logging") dependsOn(interfaceSub, processSub) settings(libraryDependencies += jlineDep % "optional") | |||
// class file reader and analyzer | |||
lazy val classfileSub = testedBaseProject(utilPath / "classfile", "Classfile") dependsOn(ioSub, interfaceSub, logSub) | |||
// generates immutable or mutable Java data types according to a simple input format | |||
lazy val datatypeSub = baseProject(utilPath /"datatype", "Datatype Generator") dependsOn(ioSub) | |||
|
|||
/***** Intermediate-level Modules *****/ | |||
|
|||
// Apache Ivy integration | |||
lazy val ivySub = baseProject(file("ivy"), "Ivy") dependsOn(interfaceSub, launchInterfaceSub, logSub % "compile;test->test", ioSub % "compile;test->test", launchSub % "test->test") settings(ivy, jsch) | |||
// Runner for uniform test interface | |||
lazy val testingSub = baseProject(file("testing"), "Testing") dependsOn(ioSub, classpathSub, logSub) settings(libraryDependencies += "org.scala-tools.testing" % "test-interface" % "0.5") | |||
|
|||
// Basic task engine | |||
lazy val taskSub = testedBaseProject(tasksPath, "Tasks") dependsOn(controlSub, collectionSub) | |||
// Standard task system. This provides map, flatMap, join, and more on top of the basic task model. | |||
lazy val stdTaskSub = testedBaseProject(tasksPath / "standard", "Task System") dependsOn(taskSub % "compile;test->test", collectionSub, logSub, ioSub, processSub) | |||
// Persisted caching based on SBinary | |||
lazy val cacheSub = baseProject(cachePath, "Cache") dependsOn(ioSub, collectionSub) settings(sbinary) | |||
// Builds on cache to provide caching for filesystem-related operations | |||
lazy val trackingSub = baseProject(cachePath / "tracking", "Tracking") dependsOn(cacheSub, ioSub) | |||
// Embedded Scala code runner | |||
lazy val runSub = baseProject(file("run"), "Run") dependsOn(ioSub, logSub, classpathSub, processSub) | |||
|
|||
// Compiler-side interface to compiler that is compiled against the compiler being used either in advance or on the fly. | |||
// Includes API and Analyzer phases that extract source API and relationships. | |||
lazy val compileInterfaceSub = baseProject(compilePath / "interface", "Compiler Interface") dependsOn(interfaceSub, ioSub % "test->test", logSub % "test->test", launchSub % "test->test") settings( compileInterfaceSettings : _*) | |||
lazy val precompiled29 = precompiled("2.9.0-1") | |||
// lazy val precompiled27 = precompiled("2.7.7") | |||
|
|||
// Implements the core functionality of detecting and propagating changes incrementally. | |||
// Defines the data structures for representing file fingerprints and relationships and the overall source analysis | |||
lazy val compileIncrementalSub = testedBaseProject(compilePath / "inc", "Incremental Compiler") dependsOn(collectionSub, apiSub, ioSub, logSub) | |||
// Persists the incremental data structures using SBinary | |||
lazy val compilePersistSub = baseProject(compilePath / "persist", "Persist") dependsOn(compileIncrementalSub, apiSub) settings(sbinary) | |||
// sbt-side interface to compiler. Calls compiler-side interface reflectively | |||
lazy val compilerSub = testedBaseProject(compilePath, "Compile") dependsOn(launchInterfaceSub, interfaceSub % "compile;test->test", ivySub, ioSub, classpathSub, | |||
logSub % "test->test", launchSub % "test->test", apiSub % "test->test") settings( compilerSettings : _*) | |||
|
|||
// Searches the source API data structures, currently looks for subclasses and annotations | |||
lazy val discoverySub = testedBaseProject(compilePath / "discover", "Discovery") dependsOn(compileIncrementalSub, apiSub, compilerSub % "test->test") | |||
|
|||
lazy val scriptedBaseSub = baseProject(scriptedPath / "base", "Scripted Framework") dependsOn(ioSub, processSub) | |||
lazy val scriptedSbtSub = baseProject(scriptedPath / "sbt", "Scripted sbt") dependsOn(ioSub, logSub, processSub, scriptedBaseSub, launchInterfaceSub % "provided") | |||
lazy val scriptedPluginSub = baseProject(scriptedPath / "plugin", "Scripted Plugin") dependsOn(sbtSub, classpathSub) | |||
|
|||
|
|||
// Implementation and support code for defining actions. | |||
lazy val actionsSub = baseProject(mainPath / "actions", "Actions") dependsOn( | |||
classfileSub, classpathSub, compileIncrementalSub, compilePersistSub, compilerSub, completeSub, discoverySub, | |||
interfaceSub, ioSub, ivySub, logSub, processSub, runSub, stdTaskSub, taskSub, trackingSub, testingSub) | |||
|
|||
// The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions. | |||
lazy val mainSub = testedBaseProject(mainPath, "Main") dependsOn(actionsSub, interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, runSub) | |||
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object | |||
// technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project | |||
// with the sole purpose of providing certain identifiers without qualification (with a package object) | |||
lazy val sbtSub = baseProject(sbtPath, "Simple Build Tool") dependsOn(mainSub, scriptedSbtSub % "test->test") settings(sbtSettings : _*) | |||
|
|||
/* Nested subproject paths */ | |||
def sbtPath = file("sbt") | |||
def cachePath = file("cache") | |||
def tasksPath = file("tasks") | |||
def launchPath = file("launch") | |||
def utilPath = file("util") | |||
def compilePath = file("compile") | |||
def mainPath = file("main") | |||
def scriptedPath = file("scripted") | |||
|
|||
def sbtSettings = Seq( | |||
normalizedName := "sbt" | |||
) | |||
|
|||
def scriptedTask: Initialize[InputTask[Unit]] = inputTask { result => | |||
(proguard in Proguard, fullClasspath in scriptedSbtSub in Test, scalaInstance in scriptedSbtSub, publishAll, version, scalaVersion, scriptedScalaVersion, scriptedSource, result) map { | |||
(launcher, scriptedSbtClasspath, scriptedSbtInstance, _, v, sv, ssv, sourcePath, args) => | |||
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, scriptedSbtInstance.loader) | |||
val m = ModuleUtilities.getObject("sbt.test.ScriptedTests", loader) | |||
val r = m.getClass.getMethod("run", classOf[File], classOf[Boolean], classOf[String], classOf[String], classOf[String], classOf[Array[String]], classOf[File]) | |||
r.invoke(m, sourcePath, true: java.lang.Boolean, v, sv, ssv, args.toArray[String], launcher) | |||
} | |||
} | |||
|
|||
lazy val scriptedScalaVersion = SettingKey[String]("scripted-scala-version") | |||
lazy val scripted = InputKey[Unit]("scripted") | |||
lazy val scriptedSource = SettingKey[File]("scripted-source") | |||
lazy val publishAll = TaskKey[Unit]("publish-all") | |||
|
|||
def deepTasks[T](scoped: ScopedTask[Seq[T]]): Initialize[Task[Seq[T]]] = deep(scoped.task).map { _.flatMap(_.join.map(_.flatten)) } | |||
def deep[T](scoped: ScopedSetting[T]): Initialize[Task[Seq[T]]] = | |||
state map { s => | |||
val sxrProjects = projects filterNot Set(root, sbtSub, scriptedBaseSub, scriptedSbtSub, scriptedPluginSub) map { p => LocalProject(p.id) } | |||
Defaults.inAllProjects(sxrProjects, scoped, Project.extract(s).structure.data) | |||
} | |||
|
|||
import Sxr.sxr | |||
def rootSettings = LaunchProguard.settings ++ LaunchProguard.specific(launchSub) ++ Sxr.settings ++ docSetting ++ Seq( | |||
scriptedScalaVersion := "2.8.1", | |||
scripted <<= scriptedTask, | |||
scriptedSource <<= (sourceDirectory in sbtSub) / "sbt-test", | |||
sources in sxr <<= deepTasks(sources in Compile), | |||
Sxr.sourceDirectories <<= deep(sourceDirectories in Compile).map(_.map(_.flatten)), | |||
fullClasspath in sxr <<= (externalDependencyClasspath in Compile in sbtSub).identity, | |||
compileInputs in (Compile,sxr) <<= (sources in sxr, compileInputs in sbtSub in Compile, fullClasspath in sxr) map { (srcs, in, cp) => | |||
in.copy(config = in.config.copy(sources = srcs, classpath = cp.files)) | |||
}, | |||
publishAll <<= state flatMap { s => nop dependsOn( Defaults.inAllProjects(nonRoots, publishLocal.task, Project.extract(s).structure.data) : _*) }, | |||
TaskKey[Unit]("build-all") <<= (publishAll, sxr, doc) map { (_,_,_) => () } | |||
) | |||
def docSetting = inConfig(Compile)(inTask(sxr)(doc in ThisScope.copy(task = Global, config = Global) <<= Defaults.docTask)) | |||
|
|||
def interfaceSettings = javaOnly ++ Seq( | |||
crossPaths := false, | |||
projectComponent, | |||
exportJars := true, | |||
componentID := Some("xsbti"), | |||
watchSources <++= apiDefinitions.identity, | |||
resourceGenerators in Compile <+= (version, resourceManaged, streams) map generateVersionFile, | |||
apiDefinitions <<= baseDirectory map { base => (base / "definition") :: (base / "other") :: (base / "type") :: Nil }, | |||
sourceGenerators in Compile <+= (cacheDirectory, apiDefinitions, fullClasspath in Compile in datatypeSub, sourceManaged in Compile, mainClass in datatypeSub in Compile, runner, streams) map generateAPICached | |||
) | |||
|
|||
def precompiledSettings = Seq( | |||
artifact in packageBin <<= scalaInstance in Compile apply { si => | |||
val bincID = binID + "_" + si.actualVersion | |||
Artifact(binID) extra("e:component" -> bincID) | |||
}, | |||
target <<= (target, scalaVersion) { (base, sv) => base / ("precompiled_" + sv) }, | |||
scalacOptions := Nil, | |||
crossPaths := false, | |||
exportedProducts in Compile := Nil, | |||
exportedProducts in Test := Nil, | |||
libraryDependencies <+= scalaVersion( "org.scala-lang" % "scala-compiler" % _ % "provided"), | |||
libraryDependencies += jlineDep artifacts(Artifact("jline", Map("e:component" -> srcID))) | |||
) | |||
def compileInterfaceSettings: Seq[Setting[_]] = precompiledSettings ++ Seq( | |||
exportJars := true, | |||
artifact in packageSrc := Artifact(srcID) extra("e:component" -> srcID) | |||
) | |||
def compilerSettings = Seq( | |||
libraryDependencies <+= scalaVersion( "org.scala-lang" % "scala-compiler" % _ % "test"), | |||
unmanagedJars in Test <<= (packageSrc in compileInterfaceSub in Compile).map(x => Seq(x).classpath) | |||
) | |||
def precompiled(scalav: String): Project = baseProject(compilePath / "interface", "Precompiled " + scalav.replace('.', '_')) dependsOn(interfaceSub) settings(scalaVersion := scalav) settings(precompiledSettings : _*) | |||
} |
Oops, something went wrong.