diff --git a/project/build.properties b/project/build.properties index cafdc2955..ea56294fa 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1,5 +1,5 @@ project.organization=org.scala-tools.sbt project.name=Simple Build Tool sbt.version=0.5.6 -project.version=0.6.13 +project.version=0.7.0-SNAPSHOT scala.version=2.7.7 diff --git a/src/main/scala/sbt/BasicProjectTypes.scala b/src/main/scala/sbt/BasicProjectTypes.scala index 83c168e3c..0856079db 100644 --- a/src/main/scala/sbt/BasicProjectTypes.scala +++ b/src/main/scala/sbt/BasicProjectTypes.scala @@ -576,7 +576,7 @@ object Reflective { 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)) mappings(ReflectUtilities.transformCamelCase(name, '-')) = value mappings diff --git a/src/main/scala/sbt/BuilderProject.scala b/src/main/scala/sbt/BuilderProject.scala index 9545b04bc..0697659e8 100644 --- a/src/main/scala/sbt/BuilderProject.scala +++ b/src/main/scala/sbt/BuilderProject.scala @@ -59,7 +59,7 @@ private sealed abstract class BasicBuilderProject extends InternalProject 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) { type AnalysisType = BuilderCompileAnalysis @@ -111,9 +111,9 @@ private sealed abstract class BasicBuilderProject extends InternalProject override final def methods = Map.empty } /** 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) 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 } override def projectClasspath = super.projectClasspath +++ - pluginProject.map(_.pluginClasspath).getOrElse(Path.emptyPathFinder) +++ - additional + pluginProject.map(_.pluginClasspath).getOrElse(Path.emptyPathFinder) def tpe = "project definition" override def compileTask = super.compileTask dependsOn(pluginProject.map(_.syncPlugins).toList : _*) final class PluginBuilderProject(val info: ProjectInfo) extends BasicBuilderProject { - val pluginUptodate = propertyOptional[Boolean](false) + lazy val pluginUptodate = propertyOptional[Boolean](false) def tpe = "plugin definition" def managedSourcePath = path(BasicDependencyPaths.DefaultManagedSourceDirectoryName) def managedDependencyPath = crossPath(BasicDependencyPaths.DefaultManagedDirectoryName) diff --git a/src/main/scala/sbt/LineReader.scala b/src/main/scala/sbt/LineReader.scala index b67651b62..476621ea5 100644 --- a/src/main/scala/sbt/LineReader.scala +++ b/src/main/scala/sbt/LineReader.scala @@ -10,8 +10,15 @@ trait LineReader extends NotNull class Completors(val projectAction: String, val projectNames: Iterable[String], val generalCommands: Iterable[String], val propertyActions: Iterable[String], val specificPrefix: String, val scalaVersions: Iterable[String], - val prefixes: Iterable[String], val taskNames: Iterable[String], - val propertyNames: Iterable[String], val extra: Iterable[(String, Iterable[String])]) extends NotNull + val prefixes: Iterable[String], val taskNames: Iterable[String], + 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} abstract class JLine extends LineReader @@ -91,8 +98,10 @@ object MainCompletor val specific = simpleCompletor(specificPrefix :: Nil) // TODO 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 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 baseCompletor = new MultiCompletor(baseCompletors.toArray) diff --git a/src/main/scala/sbt/Main.scala b/src/main/scala/sbt/Main.scala index 38c9e8c0d..884a2147b 100755 --- a/src/main/scala/sbt/Main.scala +++ b/src/main/scala/sbt/Main.scala @@ -310,7 +310,8 @@ class xMain extends xsbti.AppMain lazy val projectNames = baseProject.projectClosure.map(_.name) val prefixes = ContinuousExecutePrefix :: CrossBuildPrefix :: Nil 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) val reader = new LazyJLineReader(baseProject.historyPath, MainCompletor(completors), baseProject.log) reader.readLine("> ").getOrElse(ExitCommand) diff --git a/src/main/scala/sbt/Project.scala b/src/main/scala/sbt/Project.scala index 0ff98d73d..c14978333 100644 --- a/src/main/scala/sbt/Project.scala +++ b/src/main/scala/sbt/Project.scala @@ -233,16 +233,21 @@ trait Project extends TaskManager with Dag[Project] with BasicEnvironment def buildScalaInstance = buildScalaInstance0 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 log.error(e.getMessage) 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 } } } + private def replace(originalV: String, newV: String) = buildScalaVersions.value.replaceAll("""\b\Q""" + originalV + """\E\b""", newV) def getScalaInstance(version: String) = localScalaInstances.find(_.version == version) getOrElse xsbt.ScalaInstance(version, info.launcher) @@ -407,28 +412,40 @@ object Project } val useName = p.projectName.get.getOrElse("at " + p.info.projectDirectory.getAbsolutePath) checkDependencies(useName, p.info.dependencies, log) + p.buildScalaInstance // done so that build Scala version is initialized on project startup p } /** Compiles the project definition classes and returns the project definition class name * 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 }] = - { - val builderProjectPath = info.builderPath / BuilderProjectDirectoryName - if(builderProjectPath.asFile.isDirectory) + getProjectBuilder(info, buildLog) match { - val pluginProjectPath = info.builderPath / PluginProjectDirectoryName - val additionalPaths = info.sbtClasspath - val builderInfo = ProjectInfo(builderProjectPath.asFile, Nil, None)(buildLog, info.app, Some(info.definitionScalaVersion)) - val builderProject = new BuilderProject(builderInfo, pluginProjectPath, additionalPaths, buildLog) - builderProject.compile.run.toLeft(()).right.flatMap { ignore => - builderProject.projectDefinition.right.map { - case Some(definition) => getProjectClass[Project](definition, builderProject.projectClasspath, getClass.getClassLoader) - case None => DefaultBuilderClass - } + case Some(builder) => buildProjectDefinition(builder) + case None => Right(DefaultBuilderClass) + } + private def buildProjectDefinition(builderProject: BuilderProject): Either[String, Class[P] forSome { type P <: Project }] = + builderProject.compile.run.toLeft(()).right.flatMap { ignore => + builderProject.projectDefinition.right.map { + case Some(definition) => getProjectClass[Project](definition, builderProject.projectClasspath, getClass.getClassLoader) + 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 - Right(DefaultBuilderClass) + None } /** Verifies that the given list of project dependencies contains no nulls. The * String argument should be the project name with the dependencies.*/ diff --git a/src/main/scala/sbt/Run.scala b/src/main/scala/sbt/Run.scala index 3a04533a4..9be5b208e 100644 --- a/src/main/scala/sbt/Run.scala +++ b/src/main/scala/sbt/Run.scala @@ -109,11 +109,8 @@ object Run override def createInterpreter() { val projectLoader = project.getClass.getClassLoader - val launcherJar = FileUtilities.classLocationFile[xsbti.Launcher] - val app = project.info.app - 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) + val classpath = Project.getProjectClasspath(project) + compilerSettings.classpath.value = Path.makeString(classpath.get ++ Path.fromFiles(project.info.app.scalaProvider.jars)) project.log.debug(" Compiler classpath: " + compilerSettings.classpath.value) in = InteractiveReader.createDefault() diff --git a/src/main/scala/sbt/ScalaProject.scala b/src/main/scala/sbt/ScalaProject.scala index 8b8d2c491..ad2aa4075 100644 --- a/src/main/scala/sbt/ScalaProject.scala +++ b/src/main/scala/sbt/ScalaProject.scala @@ -125,7 +125,7 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje val Private = Value("private") } - def javapTask(classpath: PathFinder, conditional: CompileConditional, compilePath: Path) = + def javapTask(classpath: PathFinder, conditional: => CompileConditional, compilePath: Path) = task { args => val cp = classpath +++ Path.fromFile(FileUtilities.scalaLibraryJar) +++ Path.fromFile(FileUtilities.scalaCompilerJar) 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) - 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) } - 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) } def scaladocTask(label: String, sources: PathFinder, outputDirectory: Path, classpath: PathFinder, options: ScaladocOption*): Task = scaladocTask(label, sources, outputDirectory, classpath, options)