* Make tab completion of method tasks lazy, so that javap and test-only don't slow down initial tab completion.

* cleanup of builder related code, including removing duplication from classpath in console-project
 * only replace relevant version in build.scala.versions when user enters new Scala version to replace bad entry
This commit is contained in:
Mark Harrah
2010-02-13 16:29:09 -05:00
parent a863e866d5
commit 8bea7ec316
8 changed files with 58 additions and 35 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
project.organization=org.scala-tools.sbt project.organization=org.scala-tools.sbt
project.name=Simple Build Tool project.name=Simple Build Tool
sbt.version=0.5.6 sbt.version=0.5.6
project.version=0.6.13 project.version=0.7.0-SNAPSHOT
scala.version=2.7.7 scala.version=2.7.7
+1 -1
View File
@@ -576,7 +576,7 @@ object Reflective
{ {
def reflectiveMappings[T](obj: AnyRef)(implicit m: scala.reflect.Manifest[T]): Map[String, T] = def reflectiveMappings[T](obj: AnyRef)(implicit m: scala.reflect.Manifest[T]): Map[String, T] =
{ {
val mappings = new mutable.OpenHashMap[String, T] val mappings = new mutable.HashMap[String, T]
for ((name, value) <- ReflectUtilities.allVals[T](obj)) for ((name, value) <- ReflectUtilities.allVals[T](obj))
mappings(ReflectUtilities.transformCamelCase(name, '-')) = value mappings(ReflectUtilities.transformCamelCase(name, '-')) = value
mappings mappings
+5 -6
View File
@@ -59,7 +59,7 @@ private sealed abstract class BasicBuilderProject extends InternalProject
import xsbt.ScalaInstance import xsbt.ScalaInstance
val definitionCompileConditional = new BuilderCompileConditional(definitionCompileConfiguration, buildCompiler, tpe) lazy val definitionCompileConditional = new BuilderCompileConditional(definitionCompileConfiguration, buildCompiler, tpe)
final class BuilderCompileConditional(config: BuilderCompileConfiguration, compiler: xsbt.AnalyzingCompiler, tpe: String) extends AbstractCompileConditional(config, compiler) final class BuilderCompileConditional(config: BuilderCompileConfiguration, compiler: xsbt.AnalyzingCompiler, tpe: String) extends AbstractCompileConditional(config, compiler)
{ {
type AnalysisType = BuilderCompileAnalysis type AnalysisType = BuilderCompileAnalysis
@@ -111,9 +111,9 @@ private sealed abstract class BasicBuilderProject extends InternalProject
override final def methods = Map.empty override final def methods = Map.empty
} }
/** The project definition used to build project definitions. */ /** The project definition used to build project definitions. */
private final class BuilderProject(val info: ProjectInfo, val pluginPath: Path, additional: PathFinder, rawLogger: Logger) extends BasicBuilderProject private final class BuilderProject(val info: ProjectInfo, val pluginPath: Path, rawLogger: Logger) extends BasicBuilderProject
{ {
private lazy val pluginProject = lazy val pluginProject =
{ {
if(pluginPath.exists) if(pluginPath.exists)
Some(new PluginBuilderProject(ProjectInfo(pluginPath.asFile, Nil, None)(rawLogger, info.app, info.buildScalaVersion))) Some(new PluginBuilderProject(ProjectInfo(pluginPath.asFile, Nil, None)(rawLogger, info.app, info.buildScalaVersion)))
@@ -121,15 +121,14 @@ private final class BuilderProject(val info: ProjectInfo, val pluginPath: Path,
None None
} }
override def projectClasspath = super.projectClasspath +++ override def projectClasspath = super.projectClasspath +++
pluginProject.map(_.pluginClasspath).getOrElse(Path.emptyPathFinder) +++ pluginProject.map(_.pluginClasspath).getOrElse(Path.emptyPathFinder)
additional
def tpe = "project definition" def tpe = "project definition"
override def compileTask = super.compileTask dependsOn(pluginProject.map(_.syncPlugins).toList : _*) override def compileTask = super.compileTask dependsOn(pluginProject.map(_.syncPlugins).toList : _*)
final class PluginBuilderProject(val info: ProjectInfo) extends BasicBuilderProject final class PluginBuilderProject(val info: ProjectInfo) extends BasicBuilderProject
{ {
val pluginUptodate = propertyOptional[Boolean](false) lazy val pluginUptodate = propertyOptional[Boolean](false)
def tpe = "plugin definition" def tpe = "plugin definition"
def managedSourcePath = path(BasicDependencyPaths.DefaultManagedSourceDirectoryName) def managedSourcePath = path(BasicDependencyPaths.DefaultManagedSourceDirectoryName)
def managedDependencyPath = crossPath(BasicDependencyPaths.DefaultManagedDirectoryName) def managedDependencyPath = crossPath(BasicDependencyPaths.DefaultManagedDirectoryName)
+12 -3
View File
@@ -10,8 +10,15 @@ trait LineReader extends NotNull
class Completors(val projectAction: String, val projectNames: Iterable[String], class Completors(val projectAction: String, val projectNames: Iterable[String],
val generalCommands: Iterable[String], val propertyActions: Iterable[String], val generalCommands: Iterable[String], val propertyActions: Iterable[String],
val specificPrefix: String, val scalaVersions: Iterable[String], val specificPrefix: String, val scalaVersions: Iterable[String],
val prefixes: Iterable[String], val taskNames: Iterable[String], val prefixes: Iterable[String], val taskNames: Iterable[String],
val propertyNames: Iterable[String], val extra: Iterable[(String, Iterable[String])]) extends NotNull val propertyNames: Iterable[String], val extra: ExtraCompletions) extends NotNull
trait ExtraCompletions extends NotNull
{
def names: Iterable[String]
def completions(name: String): Iterable[String]
}
import jline.{Completor, ConsoleReader} import jline.{Completor, ConsoleReader}
abstract class JLine extends LineReader abstract class JLine extends LineReader
@@ -91,8 +98,10 @@ object MainCompletor
val specific = simpleCompletor(specificPrefix :: Nil) // TODO val specific = simpleCompletor(specificPrefix :: Nil) // TODO
new ArgumentCompletor( Array( specific, simpleCompletor(scalaVersions), baseCompletor ) ) new ArgumentCompletor( Array( specific, simpleCompletor(scalaVersions), baseCompletor ) )
} }
def extraCompletor(name: String) =
repeatedArgumentCompletor(simpleCompletor(name :: Nil), new LazyCompletor(simpleCompletor(extra.completions(name))))
val taskCompletor = simpleCompletor(TreeSet(taskNames.toSeq : _*)) val taskCompletor = simpleCompletor(TreeSet(taskNames.toSeq : _*))
val extraCompletors = for( (first, repeat) <- extra) yield repeatedArgumentCompletor(simpleCompletor(first :: Nil), simpleCompletor(repeat)) val extraCompletors = extra.names.map(extraCompletor)
val baseCompletors = generalCompletor :: taskCompletor :: projectCompletor :: propertyCompletor(propertyNames) :: extraCompletors.toList val baseCompletors = generalCompletor :: taskCompletor :: projectCompletor :: propertyCompletor(propertyNames) :: extraCompletors.toList
val baseCompletor = new MultiCompletor(baseCompletors.toArray) val baseCompletor = new MultiCompletor(baseCompletors.toArray)
+2 -1
View File
@@ -310,7 +310,8 @@ class xMain extends xsbti.AppMain
lazy val projectNames = baseProject.projectClosure.map(_.name) lazy val projectNames = baseProject.projectClosure.map(_.name)
val prefixes = ContinuousExecutePrefix :: CrossBuildPrefix :: Nil val prefixes = ContinuousExecutePrefix :: CrossBuildPrefix :: Nil
lazy val scalaVersions = baseProject.crossScalaVersions ++ Seq(baseProject.defScalaVersion.value) lazy val scalaVersions = baseProject.crossScalaVersions ++ Seq(baseProject.defScalaVersion.value)
lazy val methodCompletions = for( (name, method) <- project.methods) yield (name, method.completions) lazy val methods = project.methods
lazy val methodCompletions = new ExtraCompletions { def names = methods.keys.toList; def completions(name: String) = methods(name).completions }
lazy val completors = new Completors(ProjectAction, projectNames, interactiveCommands, List(GetAction, SetAction), SpecificBuildPrefix, scalaVersions, prefixes, project.taskNames, project.propertyNames, methodCompletions) lazy val completors = new Completors(ProjectAction, projectNames, interactiveCommands, List(GetAction, SetAction), SpecificBuildPrefix, scalaVersions, prefixes, project.taskNames, project.propertyNames, methodCompletions)
val reader = new LazyJLineReader(baseProject.historyPath, MainCompletor(completors), baseProject.log) val reader = new LazyJLineReader(baseProject.historyPath, MainCompletor(completors), baseProject.log)
reader.readLine("> ").getOrElse(ExitCommand) reader.readLine("> ").getOrElse(ExitCommand)
+32 -15
View File
@@ -233,16 +233,21 @@ trait Project extends TaskManager with Dag[Project] with BasicEnvironment
def buildScalaInstance = buildScalaInstance0 def buildScalaInstance = buildScalaInstance0
final def buildScalaInstance0: ScalaInstance = final def buildScalaInstance0: ScalaInstance =
{ {
try { getScalaInstance(buildScalaVersion) } val scalaVersion = buildScalaVersion
try { getScalaInstance(scalaVersion) }
catch { case e: xsbti.RetrieveException if info.buildScalaVersion.isEmpty => // only catch the exception if this is the default Scala version catch { case e: xsbti.RetrieveException if info.buildScalaVersion.isEmpty => // only catch the exception if this is the default Scala version
log.error(e.getMessage) log.error(e.getMessage)
SimpleReader.readLine("\nProvide a new Scala version or press enter to exit: ") match SimpleReader.readLine("\nProvide a new Scala version or press enter to exit: ") match
{ {
case Some(v) if v.length > 0=> buildScalaVersions() = v; saveEnvironment(); buildScalaInstance0 case Some(v) if v.length > 0=>
buildScalaVersions() = replace(scalaVersion, v)
saveEnvironment()
buildScalaInstance0
case _ => throw e case _ => throw e
} }
} }
} }
private def replace(originalV: String, newV: String) = buildScalaVersions.value.replaceAll("""\b\Q""" + originalV + """\E\b""", newV)
def getScalaInstance(version: String) = def getScalaInstance(version: String) =
localScalaInstances.find(_.version == version) getOrElse localScalaInstances.find(_.version == version) getOrElse
xsbt.ScalaInstance(version, info.launcher) xsbt.ScalaInstance(version, info.launcher)
@@ -407,28 +412,40 @@ object Project
} }
val useName = p.projectName.get.getOrElse("at " + p.info.projectDirectory.getAbsolutePath) val useName = p.projectName.get.getOrElse("at " + p.info.projectDirectory.getAbsolutePath)
checkDependencies(useName, p.info.dependencies, log) checkDependencies(useName, p.info.dependencies, log)
p.buildScalaInstance // done so that build Scala version is initialized on project startup
p p
} }
/** Compiles the project definition classes and returns the project definition class name /** Compiles the project definition classes and returns the project definition class name
* and the class loader that should be used to load the definition. */ * and the class loader that should be used to load the definition. */
private def getProjectDefinition(info: ProjectInfo, buildLog: Logger): Either[String, Class[P] forSome { type P <: Project }] = private def getProjectDefinition(info: ProjectInfo, buildLog: Logger): Either[String, Class[P] forSome { type P <: Project }] =
{ getProjectBuilder(info, buildLog) match
val builderProjectPath = info.builderPath / BuilderProjectDirectoryName
if(builderProjectPath.asFile.isDirectory)
{ {
val pluginProjectPath = info.builderPath / PluginProjectDirectoryName case Some(builder) => buildProjectDefinition(builder)
val additionalPaths = info.sbtClasspath case None => Right(DefaultBuilderClass)
val builderInfo = ProjectInfo(builderProjectPath.asFile, Nil, None)(buildLog, info.app, Some(info.definitionScalaVersion)) }
val builderProject = new BuilderProject(builderInfo, pluginProjectPath, additionalPaths, buildLog) private def buildProjectDefinition(builderProject: BuilderProject): Either[String, Class[P] forSome { type P <: Project }] =
builderProject.compile.run.toLeft(()).right.flatMap { ignore => builderProject.compile.run.toLeft(()).right.flatMap { ignore =>
builderProject.projectDefinition.right.map { builderProject.projectDefinition.right.map {
case Some(definition) => getProjectClass[Project](definition, builderProject.projectClasspath, getClass.getClassLoader) case Some(definition) => getProjectClass[Project](definition, builderProject.projectClasspath, getClass.getClassLoader)
case None => DefaultBuilderClass case None => DefaultBuilderClass
}
} }
} }
private[sbt] def getProjectClasspath(project: Project): PathFinder =
getProjectBuilder(project.info, project.log) match
{
case Some(builder) => builder.projectClasspath
case None => project.info.sbtClasspath
}
private[sbt] def getProjectBuilder(info: ProjectInfo, buildLog: Logger): Option[BuilderProject] =
{
if(info.builderProjectPath.asFile.isDirectory)
{
val builderInfo = ProjectInfo(info.builderProjectPath.asFile, Nil, None)(buildLog, info.app, Some(info.definitionScalaVersion))
val builderProject = new BuilderProject(builderInfo, info.pluginsPath, buildLog)
Some(builderProject)
}
else else
Right(DefaultBuilderClass) None
} }
/** Verifies that the given list of project dependencies contains no nulls. The /** Verifies that the given list of project dependencies contains no nulls. The
* String argument should be the project name with the dependencies.*/ * String argument should be the project name with the dependencies.*/
+2 -5
View File
@@ -109,11 +109,8 @@ object Run
override def createInterpreter() override def createInterpreter()
{ {
val projectLoader = project.getClass.getClassLoader val projectLoader = project.getClass.getClassLoader
val launcherJar = FileUtilities.classLocationFile[xsbti.Launcher] val classpath = Project.getProjectClasspath(project)
val app = project.info.app compilerSettings.classpath.value = Path.makeString(classpath.get ++ Path.fromFiles(project.info.app.scalaProvider.jars))
val projectJars: Array[File] = projectLoader.asInstanceOf[URLClassLoader].getURLs.flatMap(ClasspathUtilities.asFile).toArray[File]
val classpathFiles = app.mainClasspath ++ app.scalaProvider.jars ++ Array(launcherJar) ++ projectJars
compilerSettings.classpath.value = classpathFiles.map(_.getAbsolutePath).mkString(File.pathSeparator)
project.log.debug(" Compiler classpath: " + compilerSettings.classpath.value) project.log.debug(" Compiler classpath: " + compilerSettings.classpath.value)
in = InteractiveReader.createDefault() in = InteractiveReader.createDefault()
+3 -3
View File
@@ -125,7 +125,7 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
val Private = Value("private") val Private = Value("private")
} }
def javapTask(classpath: PathFinder, conditional: CompileConditional, compilePath: Path) = def javapTask(classpath: PathFinder, conditional: => CompileConditional, compilePath: Path) =
task { args => task { args =>
val cp = classpath +++ Path.fromFile(FileUtilities.scalaLibraryJar) +++ Path.fromFile(FileUtilities.scalaCompilerJar) val cp = classpath +++ Path.fromFile(FileUtilities.scalaLibraryJar) +++ Path.fromFile(FileUtilities.scalaCompilerJar)
execOut { Process("javap" :: "-classpath" :: Path.makeString(cp.get) :: args.toList) } execOut { Process("javap" :: "-classpath" :: Path.makeString(cp.get) :: args.toList) }
@@ -179,9 +179,9 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
} }
private def toTask(testTask: NamedTestTask) = task(testTask.run()) named(testTask.name) private def toTask(testTask: NamedTestTask) = task(testTask.run()) named(testTask.name)
def graphSourcesTask(outputDirectory: Path, roots: PathFinder, analysis: CompileAnalysis): Task = def graphSourcesTask(outputDirectory: Path, roots: PathFinder, analysis: => CompileAnalysis): Task =
task { DotGraph.sources(analysis, outputDirectory, roots.get, log) } task { DotGraph.sources(analysis, outputDirectory, roots.get, log) }
def graphPackagesTask(outputDirectory: Path, roots: PathFinder, analysis: CompileAnalysis): Task = def graphPackagesTask(outputDirectory: Path, roots: PathFinder, analysis: => CompileAnalysis): Task =
task { DotGraph.packages(analysis, outputDirectory, roots.get, log) } task { DotGraph.packages(analysis, outputDirectory, roots.get, log) }
def scaladocTask(label: String, sources: PathFinder, outputDirectory: Path, classpath: PathFinder, options: ScaladocOption*): Task = def scaladocTask(label: String, sources: PathFinder, outputDirectory: Path, classpath: PathFinder, options: ScaladocOption*): Task =
scaladocTask(label, sources, outputDirectory, classpath, options) scaladocTask(label, sources, outputDirectory, classpath, options)