mirror of https://github.com/sbt/sbt.git
cache calls to definesClass within a run. closes #67
This commit is contained in:
parent
3bd43e81eb
commit
c919a9c3fd
|
|
@ -10,6 +10,8 @@ import Function.const
|
|||
|
||||
object Locate
|
||||
{
|
||||
type DefinesClass = File => String => Boolean
|
||||
|
||||
/** Right(src) provides the value for the found class
|
||||
* Left(true) means that the class was found, but it had no associated value
|
||||
* Left(false) means that the class was not found */
|
||||
|
|
@ -31,9 +33,9 @@ object Locate
|
|||
|
||||
/** Returns a function that searches the provided class path for
|
||||
* a class name and returns the entry that defines that class.*/
|
||||
def entry(classpath: Seq[File]): String => Option[File] =
|
||||
def entry(classpath: Seq[File], f: DefinesClass): String => Option[File] =
|
||||
{
|
||||
val entries = classpath.toStream.map { entry => (entry, definesClass(entry)) }
|
||||
val entries = classpath.toStream.map { entry => (entry, f(entry)) }
|
||||
className => entries collect { case (entry, defines) if defines(className) => entry } headOption;
|
||||
}
|
||||
def resolve(f: File, className: String): File = if(f.isDirectory) classFile(f, className) else f
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ package sbt
|
|||
import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Runtime, Test}
|
||||
import complete._
|
||||
import std.TaskExtra._
|
||||
import inc.{FileValueCache, Locate}
|
||||
import org.scalatools.testing.{AnnotatedFingerprint, SubclassFingerprint}
|
||||
|
||||
import scala.xml.{Node => XNode,NodeSeq}
|
||||
|
|
@ -50,6 +51,7 @@ object Defaults extends BuildCommon
|
|||
pollInterval :== 500,
|
||||
logBuffered :== false,
|
||||
autoScalaLibrary :== true,
|
||||
definesClass := FileValueCache(Locate.definesClass _ ).get,
|
||||
trapExit :== false,
|
||||
trapExit in run :== true,
|
||||
logBuffered in testOnly :== true,
|
||||
|
|
@ -162,6 +164,7 @@ object Defaults extends BuildCommon
|
|||
initialCommands in GlobalScope :== "",
|
||||
compile <<= compileTask,
|
||||
compileInputs <<= compileInputsTask,
|
||||
compileIncSetup <<= compileIncSetupTask,
|
||||
console <<= consoleTask,
|
||||
consoleQuick <<= consoleQuickTask,
|
||||
discoveredMainClasses <<= TaskData.write(compile map discoverMainClasses) triggeredBy compile,
|
||||
|
|
@ -412,13 +415,15 @@ object Defaults extends BuildCommon
|
|||
}
|
||||
|
||||
def compileTask = (compileInputs, streams) map { (i,s) => Compiler(i,s.log) }
|
||||
def compileIncSetupTask =
|
||||
(dependencyClasspath, cacheDirectory, definesClass) map { (cp, cacheDir, definesC) =>
|
||||
Compiler.IncSetup(analysisMap(cp), definesC, cacheDir / "compile")
|
||||
}
|
||||
def compileInputsTask =
|
||||
(dependencyClasspath, sources, compilers, javacOptions, scalacOptions, cacheDirectory, classDirectory, compileOrder, streams) map {
|
||||
(cp, srcs, cs, javacOpts, scalacOpts, cacheDir, classes, order, s) =>
|
||||
(dependencyClasspath, sources, compilers, javacOptions, scalacOptions, classDirectory, compileOrder, compileIncSetup, streams) map {
|
||||
(cp, srcs, cs, javacOpts, scalacOpts, classes, order, incSetup, s) =>
|
||||
val classpath = classes +: data(cp)
|
||||
val analysis = analysisMap(cp)
|
||||
val cache = cacheDir / "compile"
|
||||
Compiler.inputs(classpath, srcs, classes, scalacOpts, javacOpts, analysis, cache, 100, order)(cs, s.log)
|
||||
Compiler.inputs(classpath, srcs, classes, scalacOpts, javacOpts, 100, order)(cs, incSetup, s.log)
|
||||
}
|
||||
|
||||
def writePluginsDescriptor(plugins: Set[String], dir: File): List[File] =
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package sbt
|
|||
import Project.ScopedKey
|
||||
import complete._
|
||||
import inc.Analysis
|
||||
import inc.Locate.DefinesClass
|
||||
import std.TaskExtra._
|
||||
import scala.xml.{Node => XNode, NodeSeq}
|
||||
import org.apache.ivy.core.module.{descriptor, id}
|
||||
|
|
@ -120,6 +121,8 @@ object Keys
|
|||
val consoleProject = TaskKey[Unit]("console-project", "Starts the Scala interpreter with the sbt and the build definition on the classpath and useful imports.")
|
||||
val compile = TaskKey[Analysis]("compile", "Compiles sources.")
|
||||
val compilers = TaskKey[Compiler.Compilers]("compilers", "Defines the Scala and Java compilers to use for compilation.")
|
||||
val compileIncSetup = TaskKey[Compiler.IncSetup]("inc-compile-setup", "Configurations aspects of incremental compilation.")
|
||||
val definesClass = TaskKey[DefinesClass]("defines-class", "Internal use: provides a function that determines whether the provided file contains a given class.")
|
||||
val doc = TaskKey[File]("doc", "Generates API documentation.")
|
||||
val copyResources = TaskKey[Seq[(File,File)]]("copy-resources", "Copies resources to the output directory.")
|
||||
val aggregate = SettingKey[Aggregation]("aggregate", "Configures task aggregation.")
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package sbt
|
|||
import scala.annotation.tailrec
|
||||
import collection.mutable
|
||||
import Compiler.{Compilers,Inputs}
|
||||
import inc.{FileValueCache, Locate}
|
||||
import Project.{inScope, ScopedKey, ScopeLocal, Setting}
|
||||
import Keys.{appConfiguration, baseDirectory, configuration, streams, Streams, thisProject, thisProjectRef}
|
||||
import Keys.{isDummy, parseResult, resolvedScoped, taskDefinitionKey}
|
||||
|
|
@ -21,6 +22,7 @@ object Load
|
|||
{
|
||||
import BuildPaths._
|
||||
import BuildStreams._
|
||||
import Locate.DefinesClass
|
||||
|
||||
// note that there is State passed in but not pulled out
|
||||
def defaultLoad(state: State, baseDirectory: File, log: Logger): (() => Eval, BuildStructure) =
|
||||
|
|
@ -35,10 +37,13 @@ object Load
|
|||
val evalPluginDef = EvaluateTask.evalPluginDef(log) _
|
||||
val delegates = defaultDelegates
|
||||
val inject: Seq[Project.Setting[_]] = ((appConfiguration in GlobalScope) :== state.configuration) +: EvaluateTask.injectSettings
|
||||
val rawConfig = new LoadBuildConfiguration(stagingDirectory, Nil, classpath, loader, compilers, evalPluginDef, delegates, EvaluateTask.injectStreams, inject, log)
|
||||
val definesClass = FileValueCache(Locate.definesClass _)
|
||||
val rawConfig = new LoadBuildConfiguration(stagingDirectory, Nil, classpath, loader, compilers, evalPluginDef, definesClass.get, delegates, EvaluateTask.injectStreams, inject, log)
|
||||
val commonPlugins = if(baseDirectory == defaultGlobalPlugins) Nil else buildGlobalPlugins(defaultGlobalPlugins, state, rawConfig)
|
||||
val config = rawConfig.copy(commonPluginClasspath = commonPlugins)
|
||||
apply(base, state, config)
|
||||
val result = apply(base, state, config)
|
||||
definesClass.clear()
|
||||
result
|
||||
}
|
||||
def buildGlobalPlugins(baseDirectory: File, state: State, config: LoadBuildConfiguration): Seq[Attributed[File]] =
|
||||
if(baseDirectory.isDirectory) buildPluginDefinition(baseDirectory, state, config) else Nil
|
||||
|
|
@ -324,7 +329,7 @@ object Load
|
|||
if(defs.isEmpty)
|
||||
new LoadedDefinitions(defDir, target, plugs.loader, Build.default :: Nil, Nil)
|
||||
else
|
||||
definitions(defDir, target, defs, plugs, config.compilers, config.log, normBase)
|
||||
definitions(defDir, target, defs, plugs, config.definesClass, config.compilers, config.log, normBase)
|
||||
|
||||
new BuildUnit(uri, normBase, loadedDefs, plugs)
|
||||
}
|
||||
|
|
@ -348,9 +353,9 @@ object Load
|
|||
(thisPluginClasspath ++ config.commonPluginClasspath).distinct
|
||||
}
|
||||
|
||||
def definitions(base: File, targetBase: File, srcs: Seq[File], plugins: LoadedPlugins, compilers: Compilers, log: Logger, buildBase: File): LoadedDefinitions =
|
||||
def definitions(base: File, targetBase: File, srcs: Seq[File], plugins: LoadedPlugins, definesClass: DefinesClass, compilers: Compilers, log: Logger, buildBase: File): LoadedDefinitions =
|
||||
{
|
||||
val (inputs, defAnalysis) = build(plugins.classpath, srcs, targetBase, compilers, log)
|
||||
val (inputs, defAnalysis) = build(plugins.classpath, srcs, targetBase, compilers, definesClass, log)
|
||||
val target = inputs.config.classesDirectory
|
||||
val definitionLoader = ClasspathUtilities.toLoader(target :: Nil, plugins.loader)
|
||||
val defNames = findDefinitions(defAnalysis)
|
||||
|
|
@ -363,9 +368,9 @@ object Load
|
|||
def loadDefinition(loader: ClassLoader, definition: String): Build =
|
||||
ModuleUtilities.getObject(definition, loader).asInstanceOf[Build]
|
||||
|
||||
def build(classpath: Seq[File], sources: Seq[File], target: File, compilers: Compilers, log: Logger): (Inputs, inc.Analysis) =
|
||||
def build(classpath: Seq[File], sources: Seq[File], target: File, compilers: Compilers, definesClass: DefinesClass, log: Logger): (Inputs, inc.Analysis) =
|
||||
{
|
||||
val inputs = Compiler.inputs(classpath, sources, target, Nil, Nil, Compiler.DefaultMaxErrors, CompileOrder.Mixed)(compilers, log)
|
||||
val inputs = Compiler.inputs(classpath, sources, target, Nil, Nil, definesClass, Compiler.DefaultMaxErrors, CompileOrder.Mixed)(compilers, log)
|
||||
val analysis =
|
||||
try { Compiler(inputs, log) }
|
||||
catch { case _: xsbti.CompileFailed => throw new NoMessageException } // compiler already logged errors
|
||||
|
|
@ -470,7 +475,7 @@ object Load
|
|||
def allProjectRefs(build: URI): Seq[ProjectRef] = refs(build, allProjects(build))
|
||||
private[this] def refs(build: URI, projects: Seq[ResolvedProject]): Seq[ProjectRef] = projects.map { p => ProjectRef(build, p.id) }
|
||||
}
|
||||
final case class LoadBuildConfiguration(stagingDirectory: File, commonPluginClasspath: Seq[Attributed[File]], classpath: Seq[File], loader: ClassLoader, compilers: Compilers, evalPluginDef: (BuildStructure, State) => Seq[Attributed[File]], delegates: LoadedBuild => Scope => Seq[Scope], scopeLocal: ScopeLocal, injectSettings: Seq[Setting[_]], log: Logger)
|
||||
final case class LoadBuildConfiguration(stagingDirectory: File, commonPluginClasspath: Seq[Attributed[File]], classpath: Seq[File], loader: ClassLoader, compilers: Compilers, evalPluginDef: (BuildStructure, State) => Seq[Attributed[File]], definesClass: DefinesClass, delegates: LoadedBuild => Scope => Seq[Scope], scopeLocal: ScopeLocal, injectSettings: Seq[Setting[_]], log: Logger)
|
||||
// information that is not original, but can be reconstructed from the rest of BuildStructure
|
||||
final class StructureIndex(val keyMap: Map[String, AttributeKey[_]], val taskToKey: Map[Task[_], ScopedKey[Task[_]]], val triggers: Triggers[Task], val keyIndex: KeyIndex)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,29 +11,30 @@ import inc._
|
|||
import classfile.Analyze
|
||||
import xsbti.api.Source
|
||||
import xsbti.AnalysisCallback
|
||||
import inc.Locate.DefinesClass
|
||||
import CompileSetup._
|
||||
import CompileOrder.{JavaThenScala, Mixed, ScalaThenJava}
|
||||
import sbinary.DefaultProtocol.{ immutableMapFormat, immutableSetFormat, StringFormat }
|
||||
|
||||
final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File],
|
||||
val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val getAnalysis: File => Option[Analysis],
|
||||
val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val getAnalysis: File => Option[Analysis], val definesClass: DefinesClass,
|
||||
val maxErrors: Int, val compiler: AnalyzingCompiler, val javac: JavaCompiler)
|
||||
|
||||
class AggressiveCompile(cacheDirectory: File)
|
||||
{
|
||||
def apply(compiler: AnalyzingCompiler, javac: JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: Map[File, Analysis] = Map.empty, maxErrors: Int = 100, compileOrder: CompileOrder.Value = Mixed)(implicit log: Logger): Analysis =
|
||||
def apply(compiler: AnalyzingCompiler, javac: JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: Map[File, Analysis] = Map.empty, definesClass: DefinesClass = Locate.definesClass _, maxErrors: Int = 100, compileOrder: CompileOrder.Value = Mixed)(implicit log: Logger): Analysis =
|
||||
{
|
||||
val setup = new CompileSetup(outputDirectory, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, compileOrder)
|
||||
compile1(sources, classpath, setup, store, analysisMap, compiler, javac, maxErrors)
|
||||
compile1(sources, classpath, setup, store, analysisMap, definesClass, compiler, javac, maxErrors)
|
||||
}
|
||||
|
||||
def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] =
|
||||
args.bootClasspath ++ args.finishClasspath(classpath)
|
||||
|
||||
def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], compiler: AnalyzingCompiler, javac: JavaCompiler, maxErrors: Int)(implicit log: Logger): Analysis =
|
||||
def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: JavaCompiler, maxErrors: Int)(implicit log: Logger): Analysis =
|
||||
{
|
||||
val (previousAnalysis, previousSetup) = extract(store.get())
|
||||
val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis.get _, maxErrors, compiler, javac)
|
||||
val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis.get _, definesClass, maxErrors, compiler, javac)
|
||||
val (modified, result) = compile2(config)
|
||||
if(modified)
|
||||
store.set(result, setup)
|
||||
|
|
@ -51,7 +52,7 @@ class AggressiveCompile(cacheDirectory: File)
|
|||
val apiOption= (api: Either[Boolean, Source]) => api.right.toOption
|
||||
val cArgs = new CompilerArguments(compiler.scalaInstance, compiler.cp)
|
||||
val searchClasspath = withBootclasspath(cArgs, absClasspath)
|
||||
val entry = Locate.entry(searchClasspath)
|
||||
val entry = Locate.entry(searchClasspath, definesClass)
|
||||
|
||||
val compile0 = (include: Set[File], callback: AnalysisCallback) => {
|
||||
IO.createDirectory(outputDirectory)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package sbt
|
|||
import xsbti.{Logger => _,_}
|
||||
import compiler._
|
||||
import inc._
|
||||
import Locate.DefinesClass
|
||||
import java.io.File
|
||||
|
||||
object Compiler
|
||||
|
|
@ -24,22 +25,23 @@ object Compiler
|
|||
|
||||
final case class Inputs(compilers: Compilers, config: Options, incSetup: IncSetup)
|
||||
final case class Options(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value)
|
||||
final case class IncSetup(analysisMap: Map[File, Analysis], cacheDirectory: File)
|
||||
final case class IncSetup(analysisMap: Map[File, Analysis], definesClass: DefinesClass, cacheDirectory: File)
|
||||
final case class Compilers(scalac: AnalyzingCompiler, javac: JavaCompiler)
|
||||
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], definesClass: DefinesClass, maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
{
|
||||
import Path._
|
||||
val classesDirectory = outputDirectory / "classes"
|
||||
val cacheDirectory = outputDirectory / "cache"
|
||||
val augClasspath = classesDirectory.asFile +: classpath
|
||||
inputs(augClasspath, sources, classesDirectory, options, javacOptions, Map.empty, cacheDirectory, maxErrors, order)
|
||||
val incSetup = IncSetup(Map.empty, definesClass, cacheDirectory)
|
||||
inputs(augClasspath, sources, classesDirectory, options, javacOptions, maxErrors, order)(compilers, incSetup, log)
|
||||
}
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], analysisMap: Map[File, Analysis], cacheDirectory: File, maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, incSetup: IncSetup, log: Logger): Inputs =
|
||||
new Inputs(
|
||||
compilers,
|
||||
new Options(classpath, sources, classesDirectory, options, javacOptions, maxErrors, order),
|
||||
new IncSetup(analysisMap, cacheDirectory)
|
||||
incSetup
|
||||
)
|
||||
|
||||
def compilers(cpOptions: ClasspathOptions)(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
|
|
@ -95,6 +97,6 @@ object Compiler
|
|||
import in.incSetup._
|
||||
|
||||
val agg = new AggressiveCompile(cacheDirectory)
|
||||
agg(scalac, javac, sources, classpath, classesDirectory, options, javacOptions, analysisMap, maxErrors, order)(log)
|
||||
agg(scalac, javac, sources, classpath, classesDirectory, options, javacOptions, analysisMap, definesClass, maxErrors, order)(log)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue