diff --git a/compile/CompilerArguments.scala b/compile/CompilerArguments.scala index 8233c9f1d..cd27b15b5 100644 --- a/compile/CompilerArguments.scala +++ b/compile/CompilerArguments.scala @@ -22,7 +22,7 @@ class CompilerArguments(scalaInstance: ScalaInstance, cp: ClasspathOptions) exte def finishClasspath(classpath: Set[File]): Set[File] = classpath ++ include(cp.compiler, scalaInstance.compilerJar) ++ include(cp.extra, scalaInstance.extraJars : _*) private def include(flag: Boolean, jars: File*) = if(flag) jars else Nil - protected def abs(files: Set[File]) = files.map(_.getAbsolutePath).toList.sort(_ < _) + protected def abs(files: Set[File]) = files.map(_.getAbsolutePath).toList.sortWith(_ < _) protected def checkScalaHomeUnset() { val scalaHome = System.getProperty("scala.home") diff --git a/compile/ComponentCompiler.scala b/compile/ComponentCompiler.scala index 24a744990..b36a33bb8 100644 --- a/compile/ComponentCompiler.scala +++ b/compile/ComponentCompiler.scala @@ -18,7 +18,7 @@ object ComponentCompiler class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager) { import ComponentCompiler._ - import FileUtilities.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory} + import sbt.IO.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory} def apply(id: String): File = try { getPrecompiled(id) } catch { case _: InvalidComponent => getLocallyCompiled(id) } @@ -55,7 +55,6 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager) val isSource = (f: File) => isSourceName(f.getName) def keepIfSource(files: Set[File]): Set[File] = if(files.exists(isSource)) files else Set() - import Paths._ withTemporaryDirectory { dir => val extractedSources = (Set[File]() /: sourceJars) { (extracted, sourceJar)=> extracted ++ keepIfSource(unzip(sourceJar, dir)) } val (sourceFiles, resources) = extractedSources.partition(isSource) @@ -69,8 +68,9 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager) manager.log.info(" Compilation completed in " + (System.currentTimeMillis - start) / 1000.0 + " s") } catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling sbt component '" + id + "'") } - copy(resources x (FileMapper.rebase(dir, outputDirectory))) - zip((outputDirectory ***) x (PathMapper.relativeTo(outputDirectory)), targetJar) + import sbt.Path._ + copy(resources x rebase(dir, outputDirectory)) + zip((outputDirectory ***) x relativeTo(outputDirectory), targetJar) } } } diff --git a/compile/RawCompiler.scala b/compile/RawCompiler.scala index ec91eb181..6b25079fc 100644 --- a/compile/RawCompiler.scala +++ b/compile/RawCompiler.scala @@ -19,7 +19,7 @@ class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: C log.debug("Plain interface to Scala compiler " + scalaInstance.actualVersion + " with arguments: " + arguments.mkString("\n\t", "\n\t", "")) val mainClass = Class.forName("scala.tools.nsc.Main", true, scalaInstance.loader) val process = mainClass.getMethod("process", classOf[Array[String]]) - process.invoke(null, toJavaArray(arguments)) + process.invoke(null, arguments.toArray) checkForFailure(mainClass, arguments.toArray) } def compilerArguments = new CompilerArguments(scalaInstance, cp) @@ -29,12 +29,6 @@ class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: C val failed = reporter.getClass.getMethod("hasErrors").invoke(reporter).asInstanceOf[Boolean] if(failed) throw new CompileFailed(args, "Plain compile failed") } - protected def toJavaArray(arguments: Seq[String]): Array[String] = - { - val realArray: Array[String] = arguments.toArray - assert(realArray.getClass eq classOf[Array[String]]) - realArray - } } class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed { diff --git a/compile/api/SameAPI.scala b/compile/api/SameAPI.scala index 1c7d2dc2c..bbcd419ba 100644 --- a/compile/api/SameAPI.scala +++ b/compile/api/SameAPI.scala @@ -48,7 +48,7 @@ object SameAPI } def separateDefinitions(s: Seq[Definition]): (Seq[Definition], Seq[Definition]) = - s.toArray.partition(isValueDefinition) + s.partition(isValueDefinition) def isValueDefinition(d: Definition): Boolean = d match { @@ -59,12 +59,12 @@ object SameAPI def isValue(d: DefinitionType): Boolean = d == DefinitionType.Module || d == DefinitionType.PackageModule /** Puts the given definitions in a map according to their names.*/ - def byName(s: Seq[Definition]): scala.collection.Map[String, List[Definition]] = + def byName(s: Seq[Definition]): Map[String, List[Definition]] = { - val map = new mutable.HashMap[String, List[Definition]] + var map = Map[String, List[Definition]]() for(d <- s; name = d.name) - map(name) = d :: map.getOrElse(name, Nil) - map.readOnly + map = map.updated(name, d :: map.getOrElse(name, Nil) ) + map } } /** Used to implement API equality. All comparisons must be done between constructs in source files `a` and `b`. For example, when doing: @@ -358,7 +358,5 @@ private class SameAPI(a: Source, b: Source, includePrivate: Boolean) def sameStrings(a: scala.collection.Set[String], b: scala.collection.Set[String]): Boolean = a == b final def sameSeq[T](a: Seq[T], b: Seq[T])(eq: (T,T) => Boolean): Boolean = - sameArray(a.toArray, b.toArray)(eq) - final def sameArray[T](a: Array[T], b: Array[T])(eq: (T,T) => Boolean): Boolean = (a.length == b.length) && (a zip b).forall(tupled(eq)) } \ No newline at end of file diff --git a/compile/interface/API.scala b/compile/interface/API.scala index d0261a635..997ece0dc 100644 --- a/compile/interface/API.scala +++ b/compile/interface/API.scala @@ -9,13 +9,16 @@ import io.{AbstractFile, PlainFile, ZipArchive} import plugins.{Plugin, PluginComponent} import symtab.Flags import scala.collection.mutable.{HashMap, HashSet, ListBuffer} -//import xsbti.api.{ClassLike, DefinitionType, PathComponent, SimpleType} +import xsbti.api.{ClassLike, DefinitionType, PathComponent, SimpleType} object API { val name = "xsbt-api" + // for 2.7 compatibility: this class was removed in 2.8 + type ImplicitMethodType = AnyRef } -final class API(val global: Global, val callback: xsbti.AnalysisCallback) extends NotNull +import API._ // imports ImplicitMethodType, which will preserve source compatibility in 2.7 for defDef +final class API(val global: Global, val callback: xsbti.AnalysisCallback) extends Compat { import global._ def error(msg: String) = throw new RuntimeException(msg) @@ -35,7 +38,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend println("API phase took : " + ((stop - start)/1000.0) + " s") } } - /*def processUnit(unit: CompilationUnit) + def processUnit(unit: CompilationUnit) { val sourceFile = unit.source.file.file val traverser = new TopLevelHandler(sourceFile) @@ -43,9 +46,9 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend val packages = traverser.packages.toArray[String].map(p => new xsbti.api.Package(p)) val source = new xsbti.api.Source(packages, traverser.definitions.toArray[xsbti.api.Definition]) callback.api(sourceFile, source) - }*/ + } } - /*private def thisPath(sym: Symbol) = path(pathComponents(sym, Constants.thisPath :: Nil)) + private def thisPath(sym: Symbol) = path(pathComponents(sym, Constants.thisPath :: Nil)) private def path(components: List[PathComponent]) = new xsbti.api.Path(components.toArray[PathComponent]) private def pathComponents(sym: Symbol, postfix: List[PathComponent]): List[PathComponent] = { @@ -64,7 +67,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend if(pre == NoPrefix) { if(sym.isLocalClass) Constants.emptyType - else if(sym.isTypeParameterOrSkolem || sym.isExistential) new xsbti.api.ParameterRef(sym.id) + else if(sym.isTypeParameterOrSkolem || isExistential(sym)) new xsbti.api.ParameterRef(sym.id) else error("Unknown prefixless type: " + sym) } else if(sym.isRoot || sym.isRootPackage) Constants.emptyType @@ -178,7 +181,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend { if(sym.isClass) classLike(sym) else if(sym.isMethod) defDef(sym) - else if(sym.isTypeMember) typeDef(sym) + else if(isNonClassType(sym)) typeDef(sym) else if(sym.isVariable) fieldDef(sym, new xsbti.api.Var(_,_,_,_,_)) else fieldDef(sym, new xsbti.api.Val(_,_,_,_,_)) } @@ -316,6 +319,6 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend val annots = at.attributes if(annots.isEmpty) processType(at.underlying) else annotated(annots, at.underlying) } - private def fullName(s: Symbol): String = s.fullNameString - private def simpleName(s: Symbol): String = s.simpleName.toString.trim*/ + private def fullName(s: Symbol): String = nameString(s) + private def simpleName(s: Symbol): String = s.simpleName.toString.trim } \ No newline at end of file diff --git a/compile/interface/Analyzer.scala b/compile/interface/Analyzer.scala index 4b3e99ae4..7159d0624 100644 --- a/compile/interface/Analyzer.scala +++ b/compile/interface/Analyzer.scala @@ -17,10 +17,9 @@ object Analyzer { def name = "xsbt-analyzer" } -final class Analyzer(val global: Global, val callback: AnalysisCallback) extends NotNull +final class Analyzer(val global: Global, val callback: AnalysisCallback) extends Compat { import global._ - import Compat.{archive, hasAnnotation, linkedClass, nameString} def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev) private class AnalyzerPhase(prev: Phase) extends Phase(prev) @@ -216,35 +215,42 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends if(entry eq null) None else Some(entry.classFile) } } - private object Compat +} +abstract class Compat +{ + val global: Global + import global._ + def archive(s: ZipArchive#Entry): ZipFile = s.getArchive + def nameString(s: Symbol): String = s.fullNameString + def nameString(s: Symbol, sep: Char): String = s.fullNameString(sep) + def isExistential(s: Symbol): Boolean = s.isExistential + def isNonClassType(s: Symbol): Boolean = s.isTypeMember + + def linkedClass(s: Symbol): Symbol = s.linkedClassOfModule + + /** After 2.8.0.Beta1, fullNameString was renamed fullName. + * linkedClassOfModule was renamed companionClass. */ + private implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym) + private final class SymCompat(s: Symbol) { - def archive(s: ZipArchive#Entry): ZipFile = s.getArchive - def nameString(s: Symbol): String = s.fullNameString - def nameString(s: Symbol, sep: Char): String = s.fullNameString(sep) - - def linkedClass(s: Symbol): Symbol = s.linkedClassOfModule - - /** After 2.8.0.Beta1, fullNameString was renamed fullName. - * linkedClassOfModule was renamed companionClass. */ - private implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym) - private final class SymCompat(s: Symbol) - { - def fullNameString = s.fullName; def fullName = sourceCompatibilityOnly - def fullNameString(sep: Char) = s.fullName(sep); def fullName(sep: Char) = sourceCompatibilityOnly - - def linkedClassOfModule = s.companionClass; def companionClass = sourceCompatibilityOnly - // In 2.8, hasAttribute is renamed to hasAnnotation - def hasAnnotation(a: Symbol) = s.hasAttribute(a); def hasAttribute(a: Symbol) = sourceCompatibilityOnly - } - - def hasAnnotation(s: Symbol)(ann: Symbol) = atPhase(currentRun.typerPhase) { s.hasAnnotation(ann) } - - /** After 2.8.0.Beta1, getArchive was renamed archive.*/ - private implicit def zipCompat(z: ZipArchive#Entry): ZipCompat = new ZipCompat(z) - private final class ZipCompat(z: ZipArchive#Entry) - { - def getArchive = z.archive; def archive = sourceCompatibilityOnly - } - private def sourceCompatibilityOnly = error("For source compatibility only: should not get here.") + def fullNameString = s.fullName; def fullName = sourceCompatibilityOnly + def fullNameString(sep: Char) = s.fullName(sep); def fullName(sep: Char) = sourceCompatibilityOnly + + def isExistential: Boolean = s.isExistentiallyBound; def isExistentiallyBound = sourceCompatibilityOnly + def isTypeMember: Boolean = s.isNonClassType; def isNonClassType = sourceCompatibilityOnly + + def linkedClassOfModule = s.companionClass; def companionClass = sourceCompatibilityOnly + // In 2.8, hasAttribute is renamed to hasAnnotation + def hasAnnotation(a: Symbol) = s.hasAttribute(a); def hasAttribute(a: Symbol) = sourceCompatibilityOnly } + + def hasAnnotation(s: Symbol)(ann: Symbol) = atPhase(currentRun.typerPhase) { s.hasAnnotation(ann) } + + /** After 2.8.0.Beta1, getArchive was renamed archive.*/ + private implicit def zipCompat(z: ZipArchive#Entry): ZipCompat = new ZipCompat(z) + private final class ZipCompat(z: ZipArchive#Entry) + { + def getArchive = z.archive; def archive = sourceCompatibilityOnly + } + private def sourceCompatibilityOnly = error("For source compatibility only: should not get here.") } \ No newline at end of file diff --git a/ivy/ComponentManager.scala b/ivy/ComponentManager.scala index 79b83fc32..6e6e3d95e 100644 --- a/ivy/ComponentManager.scala +++ b/ivy/ComponentManager.scala @@ -25,7 +25,7 @@ class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentPr try { update(id); getOrElse(createAndCache) } catch { case e: NotInCache => createAndCache } } - def getOrElse(orElse: => Iterable[File]) = + def getOrElse(orElse: => Iterable[File]): Iterable[File] = { val existing = provider.component(id) if(existing.isEmpty) orElse else existing diff --git a/ivy/CustomXmlParser.scala b/ivy/CustomXmlParser.scala index a8b7d9b43..f773b1ce9 100644 --- a/ivy/CustomXmlParser.scala +++ b/ivy/CustomXmlParser.scala @@ -14,10 +14,10 @@ import plugins.repository.Resource import plugins.repository.url.URLResource /** Subclasses the default Ivy file parser in order to provide access to protected methods.*/ -private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser with NotNull +private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser { import XmlModuleDescriptorParser.Parser - class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings) with NotNull + class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings) { if(defaultConfig.isDefined) setDefaultConfMapping("*->default(compile)") diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala index b2d59c60d..e0d880a94 100644 --- a/ivy/Ivy.scala +++ b/ivy/Ivy.scala @@ -257,13 +257,7 @@ private object IvySbt javaMap(ea.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 - } + if(map.isEmpty) null else scala.collection.JavaConversions.asMap(map) private object javaMap { @@ -337,7 +331,7 @@ private object IvySbt lazy val allConfigurations = moduleID.getPublicConfigurationsNames for(artifact <- artifacts) { - val configurationStrings = + val configurationStrings: Iterable[String] = { val artifactConfigurations = artifact.configurations if(artifactConfigurations.isEmpty) diff --git a/ivy/IvyActions.scala b/ivy/IvyActions.scala index d80b12e13..b566258a5 100644 --- a/ivy/IvyActions.scala +++ b/ivy/IvyActions.scala @@ -60,8 +60,6 @@ object IvyActions } /** Creates a Maven pom from the given Ivy configuration*/ - @deprecated def makePom(module: IvySbt#Module, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], extra: NodeSeq, output: File): Unit = - makePom(module, MakePomConfiguration(extraDependencies, configurations, extra), output) def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, output: File) { import configuration.{configurations, extra, extraDependencies, filterRepositories, process} @@ -127,7 +125,7 @@ object IvyActions resolveOptions.setLog(ivyLogLevel(logging)) val resolveReport = ivy.resolve(module, resolveOptions) if(resolveReport.hasError) - throw new ResolveException(resolveReport.getAllProblemMessages.toArray.map(_.toString).toList.removeDuplicates) + throw new ResolveException(resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct) } import UpdateLogging.{Quiet, Full, DownloadOnly} @@ -140,4 +138,4 @@ object IvyActions case Full => LOG_DEFAULT } } -final class ResolveException(messages: List[String]) extends RuntimeException(messages.mkString("\n")) \ No newline at end of file +final class ResolveException(messages: Seq[String]) extends RuntimeException(messages.mkString("\n")) \ No newline at end of file diff --git a/launch/Boot.scala b/launch/Boot.scala index 3e246cafe..2bda82e66 100644 --- a/launch/Boot.scala +++ b/launch/Boot.scala @@ -27,7 +27,7 @@ object Boot catch { case b: BootException => errorAndExit(b.toString) - case r: xsbti.RetrieveException =>errorAndExit("Error: " + r.getMessage) + case r: xsbti.RetrieveException => errorAndExit("Error: " + r.getMessage) case r: xsbti.FullReload => r.arguments case e => e.printStackTrace diff --git a/launch/Configuration.scala b/launch/Configuration.scala index f4c6180be..9168986ad 100644 --- a/launch/Configuration.scala +++ b/launch/Configuration.scala @@ -6,6 +6,7 @@ package xsbt.boot import Pre._ import java.io.{File, FileInputStream, InputStreamReader} import java.net.{MalformedURLException, URI, URL} +import scala.collection.immutable.List object Configuration { @@ -21,7 +22,7 @@ object Configuration } def configurationOnClasspath: URL = { - resourcePaths.elements.map(getClass.getResource).find(_ ne null) getOrElse + resourcePaths.iterator.map(getClass.getResource).find(_ ne null) getOrElse ( multiPartError("Could not finder sbt launch configuration. Searched classpath for:", resourcePaths)) } def directConfiguration(path: String, baseDirectory: File): URL = @@ -39,7 +40,7 @@ object Configuration } val against = resolveAgainst(baseDirectory) // use Iterators so that resolution occurs lazily, for performance - val resolving = against.elements.flatMap(e => resolve(e).toList.elements) + val resolving = against.iterator.flatMap(e => resolve(e).toList.iterator) if(!resolving.hasNext) multiPartError("Could not find configuration file '" + path + "'. Searched:", against) resolving.next() } @@ -49,9 +50,9 @@ object Configuration val JarBasePath = "/sbt/" def userConfigurationPath = "/" + ConfigurationName def defaultConfigurationPath = JarBasePath + ConfigurationName - def resourcePaths: List[String] = List(userConfigurationPath, defaultConfigurationPath) - def resolveAgainst(baseDirectory: File): List[URI] = List(baseDirectory toURI, new File(System.getProperty("user.home")) toURI, - toDirectory(classLocation(getClass).toURI)) + def resourcePaths: List[String] = userConfigurationPath :: defaultConfigurationPath :: Nil + def resolveAgainst(baseDirectory: File): List[URI] = (baseDirectory toURI) :: (new File(System.getProperty("user.home")) toURI) :: + toDirectory(classLocation(getClass).toURI) :: Nil def classLocation(cl: Class[_]): URL = { diff --git a/launch/ConfigurationParser.scala b/launch/ConfigurationParser.scala index 242681fe4..c7e702249 100644 --- a/launch/ConfigurationParser.scala +++ b/launch/ConfigurationParser.scala @@ -9,6 +9,7 @@ import java.lang.Character.isWhitespace import java.io.{BufferedReader, File, FileInputStream, InputStreamReader, Reader, StringReader} import java.net.{MalformedURLException, URL} import java.util.regex.Pattern +import scala.collection.immutable.List class ConfigurationParser extends NotNull { diff --git a/launch/Create.scala b/launch/Create.scala index 488790631..3434938ca 100644 --- a/launch/Create.scala +++ b/launch/Create.scala @@ -6,6 +6,7 @@ package xsbt.boot import Pre._ import java.io.{File, FileInputStream, FileOutputStream} import java.util.Properties +import scala.collection.immutable.List object Initialize { @@ -41,7 +42,7 @@ object Initialize if(!uninitialized.isEmpty) { file.getParentFile.mkdirs() - Using(new FileOutputStream(file))( out => properties.save(out, "") ) + Using(new FileOutputStream(file))( out => properties.store(out, "") ) } } def initialize(properties: Properties, name: String, init: PropertyInit) diff --git a/launch/Enumeration.scala b/launch/Enumeration.scala index 046227e03..cb994f1e9 100644 --- a/launch/Enumeration.scala +++ b/launch/Enumeration.scala @@ -4,6 +4,7 @@ package xsbt.boot import Pre._ +import scala.collection.immutable.List class Enumeration extends NotNull { @@ -25,6 +26,5 @@ class Enumeration extends NotNull def value(s: String) = new Value(s, 0) def value(s: String, i: Int) = new Value(s, i) class Value(override val toString: String, val id: Int) extends NotNull - def toValue(s: String): Value = elements.find(_.toString == s).getOrElse(error("Expected one of " + elements.mkString(",") + " (got: " + s + ")")) } \ No newline at end of file diff --git a/launch/FilteredLoader.scala b/launch/FilteredLoader.scala index 53ad52d66..6b318066e 100644 --- a/launch/FilteredLoader.scala +++ b/launch/FilteredLoader.scala @@ -4,10 +4,11 @@ package xsbt.boot import BootConfiguration.{IvyPackage, JLinePackagePath, SbtBootPackage, ScalaPackage} +import scala.collection.immutable.Stream /** 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. */ -private[boot] final class BootFilteredLoader(parent: ClassLoader) extends ClassLoader(parent) with NotNull +private[boot] final class BootFilteredLoader(parent: ClassLoader) extends ClassLoader(parent) { @throws(classOf[ClassNotFoundException]) override final def loadClass(className: String, resolve: Boolean): Class[_] = diff --git a/launch/Find.scala b/launch/Find.scala index 39a7a369a..459689950 100644 --- a/launch/Find.scala +++ b/launch/Find.scala @@ -6,6 +6,7 @@ package xsbt.boot import Pre._ import java.io.File import java.net.URI +import scala.collection.immutable.List object Find { def apply(config: LaunchConfiguration, currentDirectory: File) = (new Find(config))(currentDirectory) } class Find(config: LaunchConfiguration) extends NotNull diff --git a/launch/Launch.scala b/launch/Launch.scala index 828f9ca0a..4a4ed9c15 100644 --- a/launch/Launch.scala +++ b/launch/Launch.scala @@ -7,6 +7,7 @@ import Pre._ import BootConfiguration.{CompilerModuleName, LibraryModuleName} import java.io.File import java.net.URL +import scala.collection.immutable.List object Launch { diff --git a/launch/LaunchConfiguration.scala b/launch/LaunchConfiguration.scala index e39d849b6..4b9c333bc 100644 --- a/launch/LaunchConfiguration.scala +++ b/launch/LaunchConfiguration.scala @@ -6,6 +6,7 @@ package xsbt.boot import Pre._ import java.io.File import java.net.URL +import scala.collection.immutable.List final case class LaunchConfiguration(scalaVersion: Version, ivyConfiguration: IvyOptions, app: Application, boot: BootSetup, logging: Logging, appProperties: List[AppProperty]) extends NotNull { diff --git a/launch/ListMap.scala b/launch/ListMap.scala index e35c748c5..0239c5320 100644 --- a/launch/ListMap.scala +++ b/launch/ListMap.scala @@ -4,9 +4,11 @@ package xsbt.boot import Pre._ +import scala.collection.{Iterable, Iterator} +import scala.collection.immutable.List // preserves iteration order -sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Iterable[(K,V)] with NotNull +sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Traversable[(K,V)] with NotNull { import ListMap.remove def update(k: K, v: V) = this.+( (k,v) ) @@ -16,7 +18,7 @@ sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Iterable[(K,V)] def keys: List[K] = backing.reverse.map(_._1) def apply(k: K): V = get(k).getOrElse(error("Key " + k + " not found")) def contains(k: K): Boolean = get(k).isDefined - def elements: Iterator[(K,V)] = backing.reverse.elements + def foreach[T](f: ((K,V)) => T) = backing.reverse.foreach(f) override def isEmpty: Boolean = backing.isEmpty override def toList = backing.reverse override def toSeq = toList @@ -30,7 +32,7 @@ sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Iterable[(K,V)] } object ListMap { - def apply[K,V](pairs: (K,V)*) = new ListMap[K,V](pairs.toList.removeDuplicates) + def apply[K,V](pairs: (K,V)*) = new ListMap[K,V](pairs.toList.distinct) def empty[K,V] = new ListMap[K,V](Nil) private def remove[K,V](backing: List[(K,V)], k: K) = backing.filter(_._1 != k) } diff --git a/launch/Locks.scala b/launch/Locks.scala index 21aedf934..eb4ced7b6 100644 --- a/launch/Locks.scala +++ b/launch/Locks.scala @@ -6,6 +6,7 @@ package xsbt.boot import java.io.{File, FileOutputStream} import java.nio.channels.FileChannel import java.util.concurrent.Callable +import scala.collection.immutable.List object GetLocks { diff --git a/launch/Pre.scala b/launch/Pre.scala index f08ead48d..b6c43ac90 100644 --- a/launch/Pre.scala +++ b/launch/Pre.scala @@ -2,6 +2,7 @@ * Copyright 2008, 2009, 2010 Mark Harrah */ package xsbt.boot +import scala.collection.immutable.List object Pre { @@ -19,7 +20,7 @@ object Pre def declined(msg: String): Nothing = throw new BootException(msg) def prefixError(msg: String): String = "Error during sbt execution: " + msg def toBoolean(s: String) = java.lang.Boolean.parseBoolean(s) - def toArray[T](list: List[T]) = + def toArray[T : ClassManifest](list: List[T]) = { val arr = new Array[T](list.length) def copy(i: Int, rem: List[T]): Unit = diff --git a/launch/Update.scala b/launch/Update.scala index 41aab12c7..fb1663ca9 100644 --- a/launch/Update.scala +++ b/launch/Update.scala @@ -309,7 +309,7 @@ import SbtIvyLogger.{acceptError, acceptMessage} /** A custom logger for Ivy to ignore the messages about not finding classes * intentionally filtered using proguard and about 'unknown resolver'. */ -private final class SbtIvyLogger(logWriter: PrintWriter) extends DefaultMessageLogger(Message.MSG_INFO) with NotNull +private final class SbtIvyLogger(logWriter: PrintWriter) extends DefaultMessageLogger(Message.MSG_INFO) { override def log(msg: String, level: Int) { diff --git a/launch/src/test/scala/ListMapTest.scala b/launch/src/test/scala/ListMapTest.scala index ff867101a..820371c69 100644 --- a/launch/src/test/scala/ListMapTest.scala +++ b/launch/src/test/scala/ListMapTest.scala @@ -35,5 +35,4 @@ object ListMapEmpty extends Properties("ListMap.empty") property("toSeq.isEmpty") = empty.toSeq.isEmpty property("toStream.isEmpty") = empty.toStream.isEmpty property("keys.isEmpty") = empty.keys.isEmpty - property("elements.isEmpty") = !empty.elements.hasNext } \ No newline at end of file diff --git a/launch/src/test/scala/LocksTest.scala b/launch/src/test/scala/LocksTest.scala index 16fc93bcf..e6ad95896 100644 --- a/launch/src/test/scala/LocksTest.scala +++ b/launch/src/test/scala/LocksTest.scala @@ -3,20 +3,21 @@ package xsbt.boot import org.scalacheck._ import Prop._ import java.io.File +import sbt.IO.withTemporaryDirectory /** These mainly test that things work in the uncontested case and that no OverlappingFileLockExceptions occur. * There is no real locking testing, just the coordination of locking.*/ object LocksTest extends Properties("Locks") { property("Lock in nonexisting directory") = spec { - FileUtilities.withTemporaryDirectory { dir => + withTemporaryDirectory { dir => val lockFile = new File(dir, "doesntexist/lock") Locks(lockFile, callTrue) } } property("Uncontested re-entrant lock") = spec { - FileUtilities.withTemporaryDirectory { dir => + withTemporaryDirectory { dir => val lockFile = new File(dir, "lock") Locks(lockFile, callLocked(lockFile)) && Locks(lockFile, callLocked(lockFile)) @@ -24,7 +25,7 @@ object LocksTest extends Properties("Locks") } property("Uncontested double lock") = spec { - FileUtilities.withTemporaryDirectory { dir => + withTemporaryDirectory { dir => val lockFileA = new File(dir, "lockA") val lockFileB = new File(dir, "lockB") Locks(lockFileA, callLocked(lockFileB)) && @@ -33,7 +34,7 @@ object LocksTest extends Properties("Locks") } property("Contested single lock") = spec { - FileUtilities.withTemporaryDirectory { dir => + withTemporaryDirectory { dir => val lockFile = new File(dir, "lock") forkFold(2000){i => Locks(lockFile, callTrue) } } diff --git a/launch/src/test/scala/ScalaProviderTest.scala b/launch/src/test/scala/ScalaProviderTest.scala index c15084aee..076f8cce2 100644 --- a/launch/src/test/scala/ScalaProviderTest.scala +++ b/launch/src/test/scala/ScalaProviderTest.scala @@ -5,6 +5,7 @@ import java.util.Properties import xsbti._ import org.specs._ import LaunchTest._ +import sbt.IO.{createDirectory, touch,withTemporaryDirectory} object ScalaProviderTest extends Specification { @@ -34,7 +35,7 @@ object ScalaProviderTest extends Specification def checkLoad(arguments: List[String], mainClassName: String): MainResult = checkLoad(arguments, mainClassName, _ => Array[File]()) def checkLoad(arguments: List[String], mainClassName: String, extra: File => Array[File]): MainResult = - FileUtilities.withTemporaryDirectory { currentDirectory => + withTemporaryDirectory { currentDirectory => withLauncher { launcher => Launch.run(launcher)( new RunConfiguration(mapScalaVersion(LaunchTest.getScalaVersion), LaunchTest.testApp(mainClassName, extra(currentDirectory)).toID, currentDirectory, arguments) @@ -45,8 +46,8 @@ object ScalaProviderTest extends Specification private def createExtra(currentDirectory: File) = { val resourceDirectory = new File(currentDirectory, "resources") - FileUtilities.createDirectory(resourceDirectory) - testResources.foreach(resource => FileUtilities.touch(new File(resourceDirectory, resource.replace('/', File.separatorChar)))) + createDirectory(resourceDirectory) + testResources.foreach(resource => touch(new File(resourceDirectory, resource.replace('/', File.separatorChar)))) Array(resourceDirectory) } private def checkScalaLoader(version: String): Unit = withLauncher( checkLauncher(version, scalaVersionMap(version)) ) @@ -67,7 +68,7 @@ object LaunchTest import Repository.Predefined._ def testRepositories = List(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined.apply) def withLauncher[T](f: xsbti.Launcher => T): T = - FileUtilities.withTemporaryDirectory { bootDirectory => + withTemporaryDirectory { bootDirectory => f(Launcher(bootDirectory, testRepositories)) } diff --git a/notes b/notes index 5f336d8e4..83d6d29f9 100644 --- a/notes +++ b/notes @@ -1,3 +1,13 @@ +Issues moving Launcher to 2.8: + creating an Array requires a Manifest, which brings in 40k of classes in scala.reflect + scala.package$ is 3k (import scala.collection.immutable.List) and brings in scala.xml + RichInt 2k. scala.collection.mutable.StringBuilder.ensureCapacity uses it (max), which is needed for string concat + scala.xml brings in 50k of classes + scala.math brought in 30k, can't remove because RichInt apparently uses it + 100k additional size adds 50ms to startup time (on my faster machine) + difference between classpaths a) just launcher jar b) current directory + launcher jar is that b) is 50 ms slower than a) + was able to return to old size by enabling optimize/obfuscate phases of ProGuard + - script tasks (in 'scripts' branch). To use: 1) add implementation of jsr223 to project/build/lib, declare in project/plugins, or add to sbt startup classpath 2) Mix sbt.scripts.Scripts into your project definition diff --git a/project/build/LauncherProguard.scala b/project/build/LauncherProguard.scala index 60dd97431..17c6eeef3 100644 --- a/project/build/LauncherProguard.scala +++ b/project/build/LauncherProguard.scala @@ -3,20 +3,27 @@ import java.io.File trait ProguardLaunch extends ProguardProject { + override def optimize = 2 override def basicOptions = super.basicOptions ++ Seq(keepJLine) def outputJar = rootProject.outputPath / ("sbt-launch-" + version + ".jar") - override def keepClasses = + override def keepFullClasses = + "xsbti.**" :: + "jline.**" :: + Nil + 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 jlineJars = runClasspath.getFiles.filter(isJLineJar) // pull out Ivy in order to exclude resources inside val (ivyJars, notIvy) = inJars.filter(jar => !isJLineJar(jar)).partition(isIvyJar) - val otherJars = notIvy.filter(jar => !isJarX(jar, "scala-compiler")) + val (libraryJar, remaining) = notIvy.partition(isScalaJar) + + val otherJars = remaining.filter(jar => !isJarX(jar, "scala-compiler")) log.debug("proguard configuration:") log.debug("\tJLline jar location: " + jlineJars.mkString(", ")) @@ -24,8 +31,9 @@ trait ProguardLaunch extends ProguardProject log.debug("\tOther jars:\n\t" + otherJars.mkString("\n\t")) val excludeIvyResourcesString = excludeString(excludeIvyResources) ((withJar(ivyJars.toSeq, "Ivy") + excludeIvyResourcesString) :: - (withJar(jlineJars, "JLine") + "(!META-INF/**)" ) :: - otherJars.map(jar => mkpath(jar) + "(!META-INF/**,!*.properties)").toList) map { "-injars " + _ } + (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("(",",",")") @@ -41,9 +49,14 @@ trait ProguardLaunch extends ProguardProject "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: Iterable[File], name: String) = mkpath(files.toSeq.firstOption.getOrElse(error(name + " not present (try running update)"))) private def isJLineJar(file: File) = isJarX(file, "jline") private def isIvyJar(file: File) = isJarX(file, "ivy") + private def isScalaJar(file: File) = isJarX(file, "scala-library") private def isJarX(file: File, x: String) = { val name = file.getName diff --git a/project/build/ProguardProject.scala b/project/build/ProguardProject.scala index b39661b1d..b9cd9145d 100644 --- a/project/build/ProguardProject.scala +++ b/project/build/ProguardProject.scala @@ -18,7 +18,7 @@ trait ProguardProject extends BasicScalaProject def rootProjectDirectory = rootProject.info.projectPath val toolsConfig = config("tools") hide - val proguardJar = "net.sf.proguard" % "proguard" % "4.3" % "tools" + val proguardJar = "net.sf.proguard" % "proguard" % "4.4" % "tools" lazy val proguard = proguardAction def proguardAction = proguardTask dependsOn(writeProguardConfiguration) describedAs(ProguardDescription) @@ -27,12 +27,17 @@ trait ProguardProject extends BasicScalaProject def basicOptions: Seq[String] = Seq( - "-dontoptimize", - "-dontobfuscate", + "-keep,allowoptimization,allowshrinking class * { *; }", + "-keepattributes SourceFile,LineNumberTable", "-dontnote", "-dontwarn", - "-ignorewarnings") + "-ignorewarnings") ++ + optimizeOptions + + def keepFullClasses: Seq[String] = Nil def keepClasses: Seq[String] = Nil + def optimize: Int = 0 + def optimizeOptions = if(optimize <= 0) Seq("-dontoptimize") else Seq( "-optimizationpasses 2", "-optimizations !code/allocation/variable") def mapInJars(inJars: Seq[File]): Seq[String] = inJars.map(f => "-injars " + mkpath(f)) def mapLibraryJars(libraryJars: Seq[File]): Seq[String] = libraryJars.map(f => "-libraryjars " + mkpath(f)) @@ -47,7 +52,8 @@ trait ProguardProject extends BasicScalaProject val lines = options ++ - keepClasses.map("-keep public class " + _ + " {\n public * ;\n}") ++ + keepFullClasses.map("-keep public class " + _ + " {\n public protected * ;\n}") ++ + keepClasses.map("-keep class " + _ + " {}") ++ mapInJars(inJars) ++ Seq("-injars " + mkpath(rawJarPath.asFile), mapOutJar(outJar)) ++ diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala index bca223f91..d1ecb133a 100644 --- a/project/build/XSbt.scala +++ b/project/build/XSbt.scala @@ -113,7 +113,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths { override def scratch = true override def consoleClasspath = testClasspath - override def compileOptions = super.compileOptions ++ compileOptions("-Xelide-below", "3000") + override def compileOptions = super.compileOptions ++ compileOptions("-Xelide-below", "0") } trait Licensed extends BasicScalaProject { @@ -128,7 +128,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths { override def testCompileAction = super.testCompileAction dependsOn(compileInterfaceSub.`package`, interfaceSub.`package`) override def testClasspath = super.testClasspath +++ compileInterfaceSub.packageSrcJar +++ interfaceSub.jarPath --- compilerInterfaceClasspath --- interfaceSub.mainCompilePath - override def compileOptions = super.compileOptions ++ Seq(CompileOption("-Xno-varargs-conversion")) //needed for invoking nsc.scala.tools.Main.process(Array[String]) } class IvyProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestWithLog with TestWithLaunch { @@ -240,4 +239,4 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths override def testCompileAction = super.testCompileAction dependsOn((testWithTestClasspath.map(_.testCompile) ++ testWithCompileClasspath.map(_.compile)) : _*) override def testClasspath = (super.testClasspath /: (testWithTestClasspath.map(_.testClasspath) ++ testWithCompileClasspath.map(_.compileClasspath) ))(_ +++ _) } -} \ No newline at end of file +} diff --git a/util/io/IO.scala b/util/io/IO.scala index 7113e7aea..526f2ed67 100644 --- a/util/io/IO.scala +++ b/util/io/IO.scala @@ -68,7 +68,7 @@ object IO (name, "") } - def touch(files: Iterable[File]): Unit = files.foreach(touch) + def touch(files: Traversable[File]): Unit = files.foreach(touch) /** Creates a file at the given location.*/ def touch(file: File) { @@ -79,7 +79,7 @@ object IO else if(!file.setLastModified(System.currentTimeMillis)) error("Could not update last modified time for file " + file) } - def createDirectories(dirs: Iterable[File]): Unit = + def createDirectories(dirs: Traversable[File]): Unit = dirs.foreach(createDirectory) def createDirectory(dir: File): Unit = { @@ -262,12 +262,12 @@ object IO * @param sources The files to include in the jar file paired with the entry name in the jar. * @param outputJar The file to write the jar to. * @param manifest The manifest for the jar.*/ - def jar(sources: Iterable[(File,String)], outputJar: File, manifest: Manifest): Unit = + def jar(sources: Traversable[(File,String)], outputJar: File, manifest: Manifest): Unit = archive(sources.toSeq, outputJar, Some(manifest)) /** Creates a zip file. * @param sources The files to include in the zip file paired with the entry name in the zip. * @param outputZip The file to write the zip to.*/ - def zip(sources: Iterable[(File,String)], outputZip: File): Unit = + def zip(sources: Traversable[(File,String)], outputZip: File): Unit = archive(sources.toSeq, outputZip, None) private def archive(sources: Seq[(File,String)], outputFile: File, manifest: Option[Manifest]) @@ -360,7 +360,7 @@ object IO else None } - def copy(sources: Iterable[(File,File)], overwrite: Boolean = false, preserveLastModified: Boolean = false): Set[File] = + def copy(sources: Traversable[(File,File)], overwrite: Boolean = false, preserveLastModified: Boolean = false): Set[File] = sources.map( tupled(copyImpl(overwrite, preserveLastModified)) ).toSet private def copyImpl(overwrite: Boolean, preserveLastModified: Boolean)(from: File, to: File): File = { @@ -469,7 +469,7 @@ object IO for( (file, index) <- files.zipWithIndex) yield (file, new File(dir, index.toHexString)) - def move(files: Iterable[(File, File)]): Unit = + def move(files: Traversable[(File, File)]): Unit = files.foreach(Function.tupled(move)) def move(a: File, b: File): Unit = diff --git a/util/io/Path.scala b/util/io/Path.scala index c2b5e4e64..207ce1203 100644 --- a/util/io/Path.scala +++ b/util/io/Path.scala @@ -131,6 +131,8 @@ object Path extends Alternatives with Mapper implicit def pathToFile(path: Path): File = path.asFile implicit def pathsToFiles[CC[X] <: TraversableLike[X,CC[X]]](cc: CC[Path])(implicit cb: generic.CanBuildFrom[CC[Path], File, CC[File]]): CC[File] = cc.map(_.asFile) + implicit def filesToFinder(cc: Traversable[File]): PathFinder = finder(cc) + implicit def pathsToFinder(cc: Traversable[Path]): PathFinder = lazyPathFinder(cc) def fileProperty(name: String) = Path.fromFile(System.getProperty(name)) def userHome = fileProperty("user.home") @@ -161,12 +163,12 @@ object Path extends Alternatives with Mapper } /** A PathFinder that selects the paths provided by the paths argument, which is * reevaluated on each call to the PathFinder's get method. */ - def lazyPathFinder(paths: => Iterable[Path]): PathFinder = + def lazyPathFinder(paths: => Traversable[Path]): PathFinder = new PathFinder { private[sbt] def addTo(pathSet: mutable.Set[Path]) = pathSet ++= paths } - def finder(files: => Iterable[File]): PathFinder = lazyPathFinder { fromFiles(files) } + def finder(files: => Traversable[File]): PathFinder = lazyPathFinder { fromFiles(files) } /** The separator character of the platform.*/ val sep = java.io.File.separatorChar @@ -244,7 +246,7 @@ object Path extends Alternatives with Mapper } def fromFile(file: String): Path = fromFile(new File(file)) def fromFile(file: File): Path = new FilePath(file) - def fromFiles(files: Iterable[File]): Iterable[Path] = files.map(fromFile) + def fromFiles(files: Traversable[File]): Traversable[Path] = files.map(fromFile) def getFiles(files: Traversable[Path]): immutable.Set[File] = files.map(_.asFile).toSet def getURLs(files: Traversable[Path]): Array[URL] = files.map(_.asURL).toArray