mirror of https://github.com/sbt/sbt.git
Updates to Ivy component and getting launcher component working.
This commit is contained in:
parent
72ce84933d
commit
76e81409df
|
|
@ -80,21 +80,24 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
def withModule[T](f: (Ivy,DefaultModuleDescriptor,String) => T): T =
|
||||
withIvy[T] { ivy => f(ivy, moduleDescriptor, defaultConfig) }
|
||||
|
||||
import moduleConfiguration._
|
||||
private lazy val (moduleDescriptor: DefaultModuleDescriptor, defaultConfig: String) =
|
||||
{
|
||||
val (baseModule, baseConfiguration) =
|
||||
if(isUnconfigured)
|
||||
autodetectDependencies(IvySbt.toID(module))
|
||||
else
|
||||
configureModule
|
||||
ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration))
|
||||
baseModule.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("m", "m")
|
||||
moduleConfiguration match
|
||||
{
|
||||
case ic: InlineConfiguration => configureInline(ic)
|
||||
case ec: EmptyConfiguration => configureEmpty(ec.module)
|
||||
case pc: PomConfiguration => readPom(pc.file, pc.validate)
|
||||
case ifc: IvyFileConfiguration => readIvyFile(ifc.file, ifc.validate)
|
||||
}
|
||||
moduleConfiguration.ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration))
|
||||
baseModule.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("e", "http://ant.apache.org/ivy/extra")
|
||||
(baseModule, baseConfiguration)
|
||||
}
|
||||
private def configureModule =
|
||||
private def configureInline(ic: InlineConfiguration) =
|
||||
{
|
||||
val moduleID = newConfiguredModuleID
|
||||
import ic._
|
||||
val moduleID = newConfiguredModuleID(module, configurations)
|
||||
val defaultConf = defaultConfiguration getOrElse Configurations.config(ModuleDescriptor.DEFAULT_CONFIGURATION)
|
||||
log.debug("Using inline dependencies specified in Scala" + (if(ivyXML.isEmpty) "." else " and XML."))
|
||||
|
||||
|
|
@ -105,7 +108,7 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
IvySbt.addMainArtifact(moduleID)
|
||||
(moduleID, parser.getDefaultConf)
|
||||
}
|
||||
private def newConfiguredModuleID =
|
||||
private def newConfiguredModuleID(module: ModuleID, configurations: Iterable[Configuration]) =
|
||||
{
|
||||
val mod = new DefaultModuleDescriptor(IvySbt.toID(module), "release", null, false)
|
||||
mod.setLastModified(System.currentTimeMillis)
|
||||
|
|
@ -114,13 +117,13 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
}
|
||||
|
||||
/** Parses the given Maven pom 'pomFile'.*/
|
||||
private def readPom(pomFile: File) =
|
||||
private def readPom(pomFile: File, validate: Boolean) =
|
||||
{
|
||||
val md = PomModuleDescriptorParser.getInstance.parseDescriptor(settings, toURL(pomFile), validate)
|
||||
(IvySbt.toDefaultModuleDescriptor(md), "compile")
|
||||
}
|
||||
/** Parses the given Ivy file 'ivyFile'.*/
|
||||
private def readIvyFile(ivyFile: File) =
|
||||
private def readIvyFile(ivyFile: File, validate: Boolean) =
|
||||
{
|
||||
val url = toURL(ivyFile)
|
||||
val parser = new CustomXmlParser.CustomParser(settings)
|
||||
|
|
@ -131,30 +134,14 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
(IvySbt.toDefaultModuleDescriptor(md), parser.getDefaultConf)
|
||||
}
|
||||
private def toURL(file: File) = file.toURI.toURL
|
||||
/** Called to determine dependencies when the dependency manager is SbtManager and no inline dependencies (Scala or XML)
|
||||
* are defined. It will try to read from pom.xml first and then ivy.xml if pom.xml is not found. If neither is found,
|
||||
* Ivy is configured with defaults.*/
|
||||
private def autodetectDependencies(module: ModuleRevisionId) =
|
||||
private def configureEmpty(module: ModuleID) =
|
||||
{
|
||||
log.debug("Autodetecting dependencies.")
|
||||
val defaultPOMFile = IvySbt.defaultPOM(paths.baseDirectory)
|
||||
if(defaultPOMFile.canRead)
|
||||
readPom(defaultPOMFile)
|
||||
else
|
||||
{
|
||||
val defaultIvy = IvySbt.defaultIvyFile(paths.baseDirectory)
|
||||
if(defaultIvy.canRead)
|
||||
readIvyFile(defaultIvy)
|
||||
else
|
||||
{
|
||||
val defaultConf = ModuleDescriptor.DEFAULT_CONFIGURATION
|
||||
log.warn("No dependency configuration found, using defaults.")
|
||||
val moduleID = DefaultModuleDescriptor.newDefaultInstance(module)
|
||||
IvySbt.addMainArtifact(moduleID)
|
||||
IvySbt.addDefaultArtifact(defaultConf, moduleID)
|
||||
(moduleID, defaultConf)
|
||||
}
|
||||
}
|
||||
val defaultConf = ModuleDescriptor.DEFAULT_CONFIGURATION
|
||||
val moduleID = new DefaultModuleDescriptor(IvySbt.toID(module), "release", null, false)
|
||||
moduleID.setLastModified(System.currentTimeMillis)
|
||||
moduleID.addConfiguration(IvySbt.toIvyConfiguration(Configurations.Default))
|
||||
IvySbt.addMainArtifact(moduleID)
|
||||
(moduleID, defaultConf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -165,9 +152,9 @@ private object IvySbt
|
|||
val DefaultIvyFilename = "ivy.xml"
|
||||
val DefaultMavenFilename = "pom.xml"
|
||||
|
||||
private def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename)
|
||||
private def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename)
|
||||
private def defaultPOM(project: File) = new File(project, DefaultMavenFilename)
|
||||
def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename)
|
||||
def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename)
|
||||
def defaultPOM(project: File) = new File(project, DefaultMavenFilename)
|
||||
|
||||
/** Sets the resolvers for 'settings' to 'resolvers'. This is done by creating a new chain and making it the default. */
|
||||
private def setResolvers(settings: IvySettings, resolvers: Seq[Resolver], log: IvyLogger)
|
||||
|
|
@ -190,7 +177,7 @@ private object IvySbt
|
|||
manager.setChangingPattern(".*-SNAPSHOT");
|
||||
settings.setDefaultRepositoryCacheManager(manager)
|
||||
}
|
||||
private def toIvyConfiguration(configuration: Configuration) =
|
||||
def toIvyConfiguration(configuration: Configuration) =
|
||||
{
|
||||
import org.apache.ivy.core.module.descriptor.{Configuration => IvyConfig}
|
||||
import IvyConfig.Visibility._
|
||||
|
|
@ -207,10 +194,10 @@ private object IvySbt
|
|||
moduleID.check()
|
||||
}
|
||||
/** Converts the given sbt module id into an Ivy ModuleRevisionId.*/
|
||||
private[xsbt] def toID(m: ModuleID) =
|
||||
def toID(m: ModuleID) =
|
||||
{
|
||||
import m._
|
||||
ModuleRevisionId.newInstance(organization, name, revision)
|
||||
ModuleRevisionId.newInstance(organization, name, revision, javaMap(extraAttributes))
|
||||
}
|
||||
private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact =
|
||||
{
|
||||
|
|
@ -218,7 +205,19 @@ private object IvySbt
|
|||
configurations.foreach(artifact.addConfiguration)
|
||||
artifact
|
||||
}
|
||||
private def extra(artifact: Artifact) = artifact.classifier.map(c => javaMap("m:classifier" -> c)).getOrElse(null)
|
||||
private def extra(artifact: Artifact) =
|
||||
{
|
||||
val ea = artifact.classifier match { case Some(c) => artifact.extra("e:classifier" -> c); case None => artifact }
|
||||
javaMap(artifact.extraAttributes)
|
||||
}
|
||||
private def javaMap(map: Map[String,String]) =
|
||||
if(map.isEmpty) null
|
||||
else
|
||||
{
|
||||
val wrap = scala.collection.jcl.Map(new java.util.HashMap[String,String])
|
||||
wrap ++= map
|
||||
wrap.underlying
|
||||
}
|
||||
|
||||
private object javaMap
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,17 +9,21 @@ import scala.xml.NodeSeq
|
|||
final class IvyPaths(val baseDirectory: File, val cacheDirectory: Option[File]) extends NotNull
|
||||
final class IvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val log: IvyLogger) extends NotNull
|
||||
|
||||
final class ModuleConfiguration(val module: ModuleID, val dependencies: Iterable[ModuleID], val ivyXML: NodeSeq,
|
||||
val configurations: Iterable[Configuration], val defaultConfiguration: Option[Configuration], val ivyScala: Option[IvyScala],
|
||||
val artifacts: Iterable[Artifact], val validate: Boolean) extends NotNull
|
||||
sealed trait ModuleConfiguration extends NotNull
|
||||
{
|
||||
def isUnconfigured = dependencies.isEmpty && ivyXML.isEmpty && configurations.isEmpty &&
|
||||
defaultConfiguration.isEmpty && artifacts.isEmpty
|
||||
def validate: Boolean
|
||||
def ivyScala: Option[IvyScala]
|
||||
}
|
||||
object ModuleConfiguration
|
||||
final class IvyFileConfiguration(val file: File, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleConfiguration
|
||||
final class PomConfiguration(val file: File, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleConfiguration
|
||||
final class InlineConfiguration(val module: ModuleID, val dependencies: Iterable[ModuleID], val ivyXML: NodeSeq,
|
||||
val configurations: Iterable[Configuration], val defaultConfiguration: Option[Configuration], val ivyScala: Option[IvyScala],
|
||||
val artifacts: Iterable[Artifact], val validate: Boolean) extends ModuleConfiguration
|
||||
final class EmptyConfiguration(val module: ModuleID, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleConfiguration
|
||||
object InlineConfiguration
|
||||
{
|
||||
def apply(module: ModuleID, dependencies: Iterable[ModuleID], artifacts: Iterable[Artifact]) =
|
||||
new ModuleConfiguration(module, dependencies, NodeSeq.Empty, Nil, None, None, artifacts, false)
|
||||
new InlineConfiguration(module, dependencies, NodeSeq.Empty, Nil, None, None, artifacts, false)
|
||||
def configurations(explicitConfigurations: Iterable[Configuration], defaultConfiguration: Option[Configuration]) =
|
||||
if(explicitConfigurations.isEmpty)
|
||||
{
|
||||
|
|
@ -32,4 +36,25 @@ object ModuleConfiguration
|
|||
}
|
||||
else
|
||||
explicitConfigurations
|
||||
}
|
||||
object ModuleConfiguration
|
||||
{
|
||||
def apply(ivyScala: Option[IvyScala], validate: Boolean, module: => ModuleID)(baseDirectory: File, log: IvyLogger) =
|
||||
{
|
||||
log.debug("Autodetecting dependencies.")
|
||||
val defaultPOMFile = IvySbt.defaultPOM(baseDirectory)
|
||||
if(defaultPOMFile.canRead)
|
||||
new PomConfiguration(defaultPOMFile, ivyScala, validate)
|
||||
else
|
||||
{
|
||||
val defaultIvy = IvySbt.defaultIvyFile(baseDirectory)
|
||||
if(defaultIvy.canRead)
|
||||
new IvyFileConfiguration(defaultIvy, ivyScala, validate)
|
||||
else
|
||||
{
|
||||
log.warn("No dependency configuration found, using defaults.")
|
||||
new EmptyConfiguration(module, ivyScala, validate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,16 +9,17 @@ import scala.xml.NodeSeq
|
|||
import org.apache.ivy.plugins.resolver.IBiblioResolver
|
||||
import org.apache.ivy.util.url.CredentialsStore
|
||||
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]) extends NotNull
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact], extraAttributes: Map[String,String]) extends NotNull
|
||||
{
|
||||
override def toString = organization + ":" + name + ":" + revision
|
||||
// () required for chaining
|
||||
def notTransitive() = intransitive()
|
||||
def intransitive() = ModuleID(organization, name, revision, configurations, isChanging, false, explicitArtifacts)
|
||||
def changing() = ModuleID(organization, name, revision, configurations, true, isTransitive, explicitArtifacts)
|
||||
def intransitive() = ModuleID(organization, name, revision, configurations, isChanging, false, explicitArtifacts, extraAttributes)
|
||||
def changing() = ModuleID(organization, name, revision, configurations, true, isTransitive, explicitArtifacts, extraAttributes)
|
||||
def from(url: String) = artifacts(Artifact(name, new URL(url)))
|
||||
def classifier(c: String) = artifacts(Artifact(name, c))
|
||||
def artifacts(newArtifacts: Artifact*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, newArtifacts ++ explicitArtifacts)
|
||||
def artifacts(newArtifacts: Artifact*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, newArtifacts ++ explicitArtifacts, extraAttributes)
|
||||
def extra(attributes: (String,String)*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, extraAttributes ++ attributes)
|
||||
}
|
||||
object ModuleID
|
||||
{
|
||||
|
|
@ -27,6 +28,8 @@ object ModuleID
|
|||
ModuleID(organization, name, revision, configurations, false, true)
|
||||
def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean): ModuleID =
|
||||
ModuleID(organization, name, revision, configurations, isChanging, isTransitive, Nil)
|
||||
def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]): ModuleID =
|
||||
ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, Map.empty)
|
||||
}
|
||||
sealed trait Resolver extends NotNull
|
||||
{
|
||||
|
|
@ -302,13 +305,19 @@ final case class Configuration(name: String, description: String, isPublic: Bool
|
|||
override def toString = name
|
||||
}
|
||||
|
||||
final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]) extends NotNull
|
||||
final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String,String]) extends NotNull
|
||||
{
|
||||
def extra(attributes: (String,String)*) = Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes ++ attributes)
|
||||
}
|
||||
object Artifact
|
||||
{
|
||||
def apply(name: String): Artifact = Artifact(name, defaultType, defaultExtension, None, Nil, None)
|
||||
def apply(name: String, extra: Map[String,String]): Artifact = Artifact(name, defaultType, defaultExtension, None, Nil, None, extra)
|
||||
def apply(name: String, classifier: String): Artifact = Artifact(name, defaultType, defaultExtension, Some(classifier), Nil, None)
|
||||
def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Nil, None)
|
||||
def apply(name: String, url: URL): Artifact =Artifact(name, extract(url, defaultType), extract(url, defaultExtension), None, Nil, Some(url))
|
||||
def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]): Artifact =
|
||||
Artifact(name, `type`, extension, classifier, configurations, url, Map.empty)
|
||||
val defaultExtension = "jar"
|
||||
val defaultType = "jar"
|
||||
def extract(url: URL, default: String): String = extract(url.toString, default)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ object Boot
|
|||
{
|
||||
def main(args: Array[String])
|
||||
{
|
||||
System.setProperty("scala.home", "") // avoid errors from mixing Scala versions in the same JVM
|
||||
CheckProxy()
|
||||
try { Launch(args) }
|
||||
catch
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ private object BootConfiguration
|
|||
/** The class name prefix used to hide the sbt launcher classes from sbt and the project definition.
|
||||
* Note that access to xsbti classes are allowed.*/
|
||||
val SbtBootPackage = "xsbt.boot."
|
||||
/** The prefix for JLine resources.*/
|
||||
val JLinePackagePath = "jline/"
|
||||
/** The loader will check that these classes can be loaded and will assume that their presence indicates
|
||||
* sbt and its dependencies have been downloaded.*/
|
||||
val TestLoadSbtClasses = "xsbt.Main" :: "org.apache.ivy.Ivy" :: Nil
|
||||
|
|
@ -66,7 +68,7 @@ private object BootConfiguration
|
|||
|
||||
/** The Ivy pattern to use for retrieving sbt and its dependencies. It is relative to the directory
|
||||
* containing all jars for the requested version of scala. */
|
||||
def sbtRetrievePattern(sbtVersion: String) = sbtDirectoryName(sbtVersion) + "/[conf]/[artifact]-[revision].[ext]"
|
||||
def sbtRetrievePattern(sbtVersion: String) = sbtDirectoryName(sbtVersion) + "(/[component])/[artifact]-[revision].[ext]"
|
||||
/** The Ivy pattern to use for resolving sbt and its dependencies from the Google code project.*/
|
||||
def sbtResolverPattern(scalaVersion: String) = sbtRootBase + "[revision]/[type]s/[artifact].[ext]"
|
||||
/** The name of the directory to retrieve sbt and its dependencies to.*/
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
package xsbt.boot
|
||||
|
||||
import BootConfiguration.{IvyPackage, SbtBootPackage, ScalaPackage}
|
||||
import BootConfiguration.{IvyPackage, JLinePackagePath, SbtBootPackage, ScalaPackage}
|
||||
|
||||
/** A custom class loader to ensure the main part of sbt doesn't load any Scala or
|
||||
* Ivy classes from the jar containing the loader. */
|
||||
|
|
@ -12,11 +12,13 @@ private[boot] final class BootFilteredLoader(parent: ClassLoader) extends ClassL
|
|||
@throws(classOf[ClassNotFoundException])
|
||||
override final def loadClass(className: String, resolve: Boolean): Class[_] =
|
||||
{
|
||||
// note that we allow xsbti.* and jline.*
|
||||
if(className.startsWith(ScalaPackage) || className.startsWith(IvyPackage) || className.startsWith(SbtBootPackage))
|
||||
throw new ClassNotFoundException(className)
|
||||
else
|
||||
super.loadClass(className, resolve)
|
||||
}
|
||||
override def getResources(name: String) = null
|
||||
override def getResource(name: String) = null
|
||||
override def getResources(name: String) = if(includeResource(name)) super.getResources(name) else null
|
||||
override def getResource(name: String) = if(includeResource(name)) super.getResource(name) else null
|
||||
def includeResource(name: String) = name.startsWith(JLinePackagePath)
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
// satisfies requests from the main sbt for different versions of Scala for use in the build.
|
||||
|
||||
import java.io.{File, FileFilter}
|
||||
import java.net.URLClassLoader
|
||||
import java.net.{URL, URLClassLoader}
|
||||
|
||||
import xsbti.{Exit => IExit, Launcher, MainResult, Reboot, SbtConfiguration, SbtMain}
|
||||
|
||||
|
|
@ -18,19 +18,19 @@ import BootConfiguration._
|
|||
import UpdateTarget.{UpdateScala, UpdateSbt}
|
||||
|
||||
|
||||
class Launch(projectRootDirectory: File, mainClassName: String) extends Launcher with NotNull
|
||||
class Launch(val BaseDirectory: File, mainClassName: String) extends Launcher with NotNull
|
||||
{
|
||||
def this(projectRootDirectory: File) = this(projectRootDirectory, SbtMainClass)
|
||||
def this(baseDirectory: File) = this(baseDirectory, SbtMainClass)
|
||||
def this() = this(new File("."))
|
||||
|
||||
import Launch._
|
||||
final def boot(args: Array[String])
|
||||
{
|
||||
System.setProperty("scala.home", "") // avoid errors from mixing Scala versions in the same JVM
|
||||
checkAndLoad(args) match
|
||||
{
|
||||
case e: Exit => System.exit(e.code)
|
||||
case e: IExit => System.exit(e.code)
|
||||
case r: Reboot => boot(r.arguments())
|
||||
case x => println("Unknown result (" + x.getClass + "): " + x); System.exit(1)
|
||||
}
|
||||
}
|
||||
def checkAndLoad(args: Array[String]): MainResult =
|
||||
|
|
@ -67,6 +67,7 @@ class Launch(projectRootDirectory: File, mainClassName: String) extends Launcher
|
|||
def scalaVersion = definitionScalaVersion
|
||||
def sbtVersion = useSbtVersion
|
||||
def launcher: Launcher = Launch.this
|
||||
def baseDirectory = BaseDirectory
|
||||
}
|
||||
run(sbtLoader, mainClassName, configuration)
|
||||
}
|
||||
|
|
@ -83,7 +84,7 @@ class Launch(projectRootDirectory: File, mainClassName: String) extends Launcher
|
|||
main.run(configuration)
|
||||
}
|
||||
|
||||
final val ProjectDirectory = new File(projectRootDirectory, ProjectDirectoryName)
|
||||
final val ProjectDirectory = new File(BaseDirectory, ProjectDirectoryName)
|
||||
final val BootDirectory = new File(ProjectDirectory, BootDirectoryName)
|
||||
final val PropertiesFile = new File(ProjectDirectory, BuildPropertiesName)
|
||||
|
||||
|
|
@ -134,19 +135,21 @@ class Launch(projectRootDirectory: File, mainClassName: String) extends Launcher
|
|||
{
|
||||
val baseDirectory = new File(BootDirectory, baseDirectoryName(scalaVersion))
|
||||
val mainComponentLocation = componentLocation(sbtVersion, MainSbtComponentID, scalaVersion)
|
||||
val sbtLoader = newSbtLoader(mainComponentLocation, parentLoader)
|
||||
val nonComponentLocation = getSbtHome(sbtVersion, scalaVersion)
|
||||
val directories = Seq(mainComponentLocation, nonComponentLocation)
|
||||
val sbtLoader = newSbtLoader(directories, parentLoader)
|
||||
if(needsUpdate(sbtLoader, TestLoadSbtClasses))
|
||||
{
|
||||
(new Update(baseDirectory, sbtVersion, scalaVersion))(UpdateSbt)
|
||||
val sbtLoader = newSbtLoader(mainComponentLocation, parentLoader)
|
||||
val sbtLoader = newSbtLoader(directories, parentLoader)
|
||||
failIfMissing(sbtLoader, TestLoadSbtClasses, "sbt " + sbtVersion)
|
||||
sbtLoader
|
||||
}
|
||||
else
|
||||
sbtLoader
|
||||
}
|
||||
private def newScalaLoader(dir: File) = newLoader(dir, new BootFilteredLoader(getClass.getClassLoader))
|
||||
private def newSbtLoader(dir: File, parentLoader: ClassLoader) = newLoader(dir, parentLoader)
|
||||
private def newScalaLoader(dir: File) = newLoader(Seq(dir), new BootFilteredLoader(getClass.getClassLoader))
|
||||
private def newSbtLoader(directories: Seq[File], parentLoader: ClassLoader) = newLoader(directories, parentLoader)
|
||||
}
|
||||
private object Launch
|
||||
{
|
||||
|
|
@ -171,8 +174,8 @@ private object Launch
|
|||
}
|
||||
catch { case e: ClassNotFoundException => ifFailure }
|
||||
}
|
||||
private def newLoader(directory: File, parent: ClassLoader) = new URLClassLoader(getJars(directory), parent)
|
||||
private def getJars(directory: File) = wrapNull(directory.listFiles(JarFilter)).map(_.toURI.toURL)
|
||||
private def newLoader(directories: Seq[File], parent: ClassLoader) = new URLClassLoader(getJars(directories), parent)
|
||||
private def getJars(directories: Seq[File]): Array[URL] = directories.flatMap(directory => wrapNull(directory.listFiles(JarFilter))).map(_.toURI.toURL).toArray
|
||||
private def wrapNull(a: Array[File]): Array[File] = if(a == null) Array() else a
|
||||
}
|
||||
private object JarFilter extends FileFilter
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ public interface Launcher extends ScalaProvider, SbtProvider
|
|||
public ClassLoader update(String scalaVersion, String sbtVersion);
|
||||
public MainResult run(ClassLoader sbtLoader, String mainClassName, SbtConfiguration configuration);
|
||||
|
||||
public File BaseDirectory();
|
||||
public File ProjectDirectory();
|
||||
public File BootDirectory();
|
||||
public File PropertiesFile();
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@ public interface SbtConfiguration
|
|||
public String[] arguments();
|
||||
public String scalaVersion();
|
||||
public String sbtVersion();
|
||||
public java.io.File baseDirectory();
|
||||
public Launcher launcher();
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package xsbt
|
||||
|
||||
import xsbti.{Exit => IExit, MainResult, SbtConfiguration, SbtMain}
|
||||
|
||||
class Main extends xsbti.SbtMain
|
||||
{
|
||||
def run(configuration: SbtConfiguration): MainResult =
|
||||
{
|
||||
println(configuration.arguments.mkString("\n"))
|
||||
Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
final case class Exit(code: Int) extends IExit
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#Project properties
|
||||
#Fri Aug 28 10:19:53 EDT 2009
|
||||
#Tue Sep 08 15:55:04 EDT 2009
|
||||
project.organization=org.scala-tools.sbt
|
||||
project.name=xsbt
|
||||
sbt.version=0.5.3-p1
|
||||
project.version=0.7
|
||||
sbt.version=0.5.3-p4
|
||||
project.version=0.7.0_13
|
||||
scala.version=2.7.5
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import sbt._
|
||||
import java.io.File
|
||||
|
||||
trait ProguardLaunch extends ProguardProject
|
||||
{
|
||||
override def basicOptions = super.basicOptions ++ Seq(keepJLine)
|
||||
def outputJar = rootProject.outputPath / ("xsbt-launch-" + version + ".jar")
|
||||
override def keepClasses =
|
||||
"org.apache.ivy.plugins.resolver.URLResolver" ::
|
||||
"org.apache.ivy.plugins.resolver.IBiblioResolver" ::
|
||||
"xsbti.**" ::
|
||||
Nil
|
||||
override def mapInJars(inJars: Seq[File]) =
|
||||
{
|
||||
val inputJar = jarPath.asFile.getAbsolutePath
|
||||
val runtimeClasspath = runClasspath.get.map(_.asFile).toList
|
||||
val jlineJars = runtimeClasspath.filter(isJLineJar)
|
||||
// pull out Ivy in order to exclude resources inside
|
||||
val (ivyJars, notIvy) = inJars.partition(_.getName.startsWith("ivy"))
|
||||
val otherJars = notIvy.filter(jar => !isJarX(jar, "scala-compiler"))
|
||||
|
||||
log.debug("proguard configuration ivy jar location: " + ivyJars.mkString(", "))
|
||||
|
||||
(withJar(ivyJars.toSeq, "Ivy") + "(!META-INF/**,!fr/**,!**/antlib.xml,!**/*.png)") ::
|
||||
(withJar(jlineJars, "JLine") + "(!META-INF/**)" ) ::
|
||||
otherJars.map( _.getAbsolutePath + "(!META-INF/**,!*.properties)").toList
|
||||
}
|
||||
|
||||
private def withJar[T](files: Seq[File], name: String) = files.firstOption.getOrElse(error(name + " not present (try running update)")).getAbsolutePath
|
||||
private def isJLineJar(file: File) = isJarX(file, "jline")
|
||||
private def isJarX(file: File, x: String) =
|
||||
{
|
||||
val name = file.getName
|
||||
name.startsWith(x) && name.endsWith(".jar")
|
||||
}
|
||||
// class body declaration for proguard that keeps all public members
|
||||
private val allPublic = " {\n public * ;\n}"
|
||||
|
||||
private val keepJLine =
|
||||
"""
|
||||
|-keep public class jline.** {
|
||||
| public protected *;
|
||||
|}
|
||||
|""".stripMargin
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
|
||||
object ProguardProject
|
||||
{
|
||||
val ProguardDescription = "Produces the final compacted jar that contains only the minimum classes needed using proguard."
|
||||
val WriteProguardDescription = "Creates the configuration file to use with proguard."
|
||||
}
|
||||
import ProguardProject._
|
||||
trait ProguardProject extends BasicScalaProject
|
||||
{
|
||||
def rawJarPath: Path
|
||||
def rawPackage: Task
|
||||
|
||||
def proguardConfigurationPath: Path = outputPath / "proguard.pro"
|
||||
def outputJar: Path
|
||||
def rootProjectDirectory = rootProject.info.projectPath
|
||||
|
||||
val toolsConfig = config("tools")
|
||||
val proguardJar = "net.sf.proguard" % "proguard" % "4.3" % "tools->default"
|
||||
|
||||
lazy val proguard = proguardAction
|
||||
def proguardAction = proguardTask dependsOn(writeProguardConfiguration) describedAs(ProguardDescription)
|
||||
lazy val writeProguardConfiguration = writeProguardConfigurationAction
|
||||
def writeProguardConfigurationAction = writeProguardConfigurationTask dependsOn rawPackage describedAs WriteProguardDescription
|
||||
|
||||
def basicOptions: Seq[String] =
|
||||
Seq(
|
||||
"-dontoptimize",
|
||||
"-dontobfuscate",
|
||||
"-dontnote",
|
||||
"-dontwarn",
|
||||
"-ignorewarnings")
|
||||
def keepClasses: Seq[String] = Nil
|
||||
def mapInJars(inJars: Seq[File]): Seq[String] = inJars.map(_.getAbsolutePath)
|
||||
def mapLibraryJars(libJars: Seq[File]): Seq[String] = libJars.map(_.getAbsolutePath)
|
||||
|
||||
def template(inJars: Seq[String], libraryJars: Seq[String], outJars: String, options: Seq[String], mainClass: Option[String], keepClasses: Seq[String]) =
|
||||
{
|
||||
val keepMain =
|
||||
"""-keep public class %s {
|
||||
| public static void main(java.lang.String[]);
|
||||
|}"""
|
||||
|
||||
val lines =
|
||||
options ++
|
||||
keepClasses.map("-keep public class " + _ + " {\n public * ;\n}") ++
|
||||
inJars.map("-injars " + _) ++
|
||||
Seq("-injars " + rawJarPath.absolutePath,
|
||||
"-outjars " + outJars) ++
|
||||
libraryJars.map("-libraryjars " + _) ++
|
||||
mainClass.map(main => keepMain.stripMargin.format(main)).toList
|
||||
lines.mkString("\n")
|
||||
}
|
||||
|
||||
private def proguardTask =
|
||||
task
|
||||
{
|
||||
FileUtilities.clean(outputJar :: Nil, log)
|
||||
val proguardClasspathString = Path.makeString(managedClasspath(toolsConfig).get)
|
||||
val configFile = proguardConfigurationPath.asFile.getAbsolutePath
|
||||
val exitValue = Process("java", List("-Xmx128M", "-cp", proguardClasspathString, "proguard.ProGuard", "@" + configFile)) ! log
|
||||
if(exitValue == 0) None else Some("Proguard failed with nonzero exit code (" + exitValue + ")")
|
||||
}
|
||||
private def writeProguardConfigurationTask =
|
||||
task
|
||||
{
|
||||
val externalDependencies = (mainCompileConditional.analysis.allExternals).map(_.getAbsoluteFile).filter(_.getName.endsWith(".jar"))
|
||||
log.debug("proguard configuration external dependencies: \n\t" + externalDependencies.mkString("\n\t"))
|
||||
// partition jars from the external jar dependencies of this project by whether they are located in the project directory
|
||||
// if they are, they are specified with -injars, otherwise they are specified with -libraryjars
|
||||
val (externalJars, libraryJars) = externalDependencies.toList.partition(jar => Path.relativize(rootProjectDirectory, jar).isDefined)
|
||||
log.debug("proguard configuration library jars locations: " + libraryJars.mkString(", "))
|
||||
|
||||
val proguardConfiguration = template(mapInJars(externalJars), mapLibraryJars(libraryJars), outputJar.absolutePath, basicOptions, getMainClass(false), keepClasses)
|
||||
log.debug("Proguard configuration written to " + proguardConfigurationPath)
|
||||
FileUtilities.write(proguardConfigurationPath.asFile, proguardConfiguration, log)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
{
|
||||
/* Subproject declarations*/
|
||||
|
||||
val launchInterfaceSub = project(launchPath / "interface", "Launcher Interface", new InterfaceProject(_))
|
||||
val launchInterfaceSub = project(launchPath / "interface", "Launcher Interface", new LaunchInterfaceProject(_))
|
||||
val launchSub = project(launchPath, "Launcher", new LaunchProject(_), launchInterfaceSub)
|
||||
|
||||
val interfaceSub = project("interface", "Interface", new InterfaceProject(_))
|
||||
|
|
@ -17,7 +17,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
val ivySub = project("ivy", "Ivy", new IvyProject(_), interfaceSub)
|
||||
val logSub = project(utilPath / "log", "Logging", new Base(_), interfaceSub)
|
||||
|
||||
val compileInterfaceSub = project(compilePath / "interface", "Compiler Interface Src", new CompilerInterfaceProject(_), interfaceSub)
|
||||
val compileInterfaceSub = project(compilePath / "interface", "Compiler Interface", new CompilerInterfaceProject(_), interfaceSub)
|
||||
|
||||
val taskSub = project(tasksPath, "Tasks", new TaskProject(_), controlSub, collectionSub)
|
||||
val cacheSub = project(cachePath, "Cache", new CacheProject(_), taskSub, ioSub)
|
||||
|
|
@ -26,21 +26,45 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
launchInterfaceSub, interfaceSub, ivySub, ioSub, classpathSub, compileInterfaceSub)
|
||||
val stdTaskSub = project(tasksPath / "standard", "Standard Tasks", new StandardTaskProject(_), trackingSub, compilerSub)
|
||||
|
||||
/* Multi-subproject paths */
|
||||
val mainSub = project("main", "Main", new Base(_), stdTaskSub)
|
||||
val distSub = project("dist", "Distribution", new DistProject(_))
|
||||
|
||||
/* Multi-subproject paths */
|
||||
def cachePath = path("cache")
|
||||
def tasksPath = path("tasks")
|
||||
def launchPath = path("launch")
|
||||
def utilPath = path("util")
|
||||
def compilePath = path("compile")
|
||||
|
||||
class DistProject(info: ProjectInfo) extends Base(info) with ManagedBase
|
||||
{
|
||||
lazy val interDependencies = (XSbt.this.dependencies.toList -- List(distSub, launchSub, launchInterfaceSub, interfaceSub, compileInterfaceSub)) flatMap {
|
||||
case b: Base => b :: Nil; case _ => Nil
|
||||
}
|
||||
override def dependencies = interfaceSub :: compileInterfaceSub :: interDependencies
|
||||
lazy val dist = increment dependsOn(publishLocal)
|
||||
override def artifactID = "xsbt"
|
||||
}
|
||||
|
||||
def increment = task {
|
||||
val Array(keep, inc) = projectVersion.value.toString.split("_")
|
||||
projectVersion() = Version.fromString(keep + "_" + (inc.toInt + 1)).right.get
|
||||
log.info("Version is now " + projectVersion.value)
|
||||
None
|
||||
}
|
||||
|
||||
def compilerInterfaceClasspath = compileInterfaceSub.projectClasspath(Configurations.Test)
|
||||
|
||||
//run in parallel
|
||||
override def parallelExecution = true
|
||||
|
||||
/* Subproject configurations*/
|
||||
class LaunchProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestDependencies
|
||||
class LaunchProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestDependencies with ProguardLaunch
|
||||
{
|
||||
val jline = "jline" % "jline" % "0.9.94"
|
||||
val ivy = "org.apache.ivy" % "ivy" % "2.0.0"
|
||||
def rawJarPath = jarPath
|
||||
lazy val rawPackage = packageTask(packagePaths +++ launchInterfaceSub.packagePaths, rawJarPath, packageOptions).dependsOn(compile)
|
||||
// to test the retrieving and loading of the main sbt, we package and publish the test classes to the local repository
|
||||
override def defaultMainArtifact = Artifact(idWithVersion)
|
||||
override def projectID = ModuleID(organization, idWithVersion, "test-" + version)
|
||||
|
|
@ -68,7 +92,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
// these compilation options are useful for debugging caches and task composition
|
||||
//override def compileOptions = super.compileOptions ++ List(Unchecked,ExplainTypes, CompileOption("-Xlog-implicits"))
|
||||
}
|
||||
class Base(info: ProjectInfo) extends DefaultProject(info) with ManagedBase
|
||||
class Base(info: ProjectInfo) extends DefaultProject(info) with ManagedBase with Component
|
||||
{
|
||||
override def scratch = true
|
||||
override def consoleClasspath = testClasspath
|
||||
|
|
@ -85,15 +109,21 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
{
|
||||
val ivy = "org.apache.ivy" % "ivy" % "2.0.0"
|
||||
}
|
||||
class InterfaceProject(info: ProjectInfo) extends DefaultProject(info) with ManagedBase with TestWithLog
|
||||
class InterfaceProject(info: ProjectInfo) extends DefaultProject(info) with ManagedBase with TestWithLog with Component
|
||||
{
|
||||
// ensure that interfaces are only Java sources and that they cannot reference Scala classes
|
||||
override def mainSources = descendents(mainSourceRoots, "*.java")
|
||||
override def compileOrder = CompileOrder.JavaThenScala
|
||||
override def componentID: Option[String] = Some("xsbti")
|
||||
}
|
||||
class LaunchInterfaceProject(info: ProjectInfo) extends InterfaceProject(info)
|
||||
{
|
||||
override def componentID = None
|
||||
}
|
||||
class CompilerInterfaceProject(info: ProjectInfo) extends Base(info) with SourceProject with TestWithIO with TestWithLog
|
||||
{
|
||||
def xTestClasspath = projectClasspath(Configurations.Test)
|
||||
override def componentID = Some("compiler-interface-src")
|
||||
}
|
||||
trait TestWithIO extends BasicScalaProject
|
||||
{
|
||||
|
|
@ -106,7 +136,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
override def testCompileAction = super.testCompileAction dependsOn(logSub.compile)
|
||||
override def testClasspath = super.testClasspath +++ logSub.compileClasspath
|
||||
}
|
||||
def compilerInterfaceClasspath = compileInterfaceSub.projectClasspath(Configurations.Test)
|
||||
}
|
||||
|
||||
trait SourceProject extends BasicScalaProject
|
||||
|
|
@ -122,4 +151,9 @@ trait ManagedBase extends BasicScalaProject
|
|||
override def useDefaultConfigurations = false
|
||||
val defaultConf = Configurations.Default
|
||||
val testConf = Configurations.Test
|
||||
}
|
||||
trait Component extends DefaultProject
|
||||
{
|
||||
override def projectID = componentID match { case Some(id) => super.projectID extra("e:component" -> id); case None => super.projectID }
|
||||
def componentID: Option[String] = None
|
||||
}
|
||||
Loading…
Reference in New Issue