All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sbt.Defaults.scala Maven / Gradle / Ivy

The newest version!
/* sbt -- Simple Build Tool
 * Copyright 2011 Mark Harrah
 */
package sbt

import scala.concurrent.duration.{ FiniteDuration, Duration }
import sbt.internal._
import sbt.internal.util.Attributed
import sbt.internal.util.Attributed.data
import Scope.{ fillTaskAxis, GlobalScope, ThisScope }
import sbt.internal.librarymanagement.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties }
import xsbt.api.Discovery
import xsbti.compile.{ CompileAnalysis, CompileOptions, CompileOrder, CompileResult, DefinesClass, IncOptions, IncOptionsUtil, Inputs, MiniSetup, PreviousResult, Setup, TransactionalManagerType }
import Project.{ inConfig, inScope, inTask, richInitialize, richInitializeTask, richTaskSessionVar }
import Def.{ Initialize, ScopedKey, Setting, SettingsDefinition }
import sbt.internal.librarymanagement.{ CustomPomParser, DependencyFilter }
import sbt.librarymanagement.Artifact.{ DocClassifier, SourceClassifier }
import sbt.librarymanagement.{ Configuration, Configurations, ConflictManager, CrossVersion, MavenRepository, Resolver, ScalaArtifacts, UpdateOptions }
import sbt.librarymanagement.Configurations.{ Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test }
import sbt.librarymanagement.CrossVersion.{ binarySbtVersion, binaryScalaVersion, partialVersion }
import sbt.internal.util.complete._
import std.TaskExtra._
import sbt.internal.inc.{ Analysis, ClassfileManager, ClasspathOptions, CompilerCache, FileValueCache, IncrementalCompilerImpl, Locate, LoggerReporter, MixedAnalyzingCompiler, ScalaInstance }
import testing.{ Framework, Runner, AnnotatedFingerprint, SubclassFingerprint }

import sbt.librarymanagement.{ `package` => _, _ }
import sbt.internal.librarymanagement._
import sbt.internal.librarymanagement.syntax._
import sbt.internal.util._
import sbt.util.Level

import sys.error
import scala.xml.NodeSeq
import org.apache.ivy.core.module.{ descriptor, id }
import descriptor.ModuleDescriptor, id.ModuleRevisionId
import java.io.{ File, PrintWriter }
import java.net.{ URI, URL, MalformedURLException }
import java.util.concurrent.{ TimeUnit, Callable }
import sbinary.DefaultProtocol.StringFormat
import sbt.internal.util.Cache.seqFormat
import sbt.util.Logger
import sbt.internal.CommandStrings.ExportStream

import xsbti.Maybe
import sbt.util.InterfaceUtil.{ f1, o2m }

import sbt.internal.util.Types._

import sbt.internal.io.WatchState
import sbt.io.{ AllPassFilter, FileFilter, GlobFilter, HiddenFileFilter, IO, NameFilter, NothingFilter, Path, PathFinder, SimpleFileFilter, DirectoryFilter }

import Path._
import sbt.io.syntax._
import Keys._

object Defaults extends BuildCommon {
  final val CacheDirectoryName = "cache"

  def configSrcSub(key: SettingKey[File]): Initialize[File] = (key in ThisScope.copy(config = Global), configuration) { (src, conf) => src / nameForSrc(conf.name) }
  def nameForSrc(config: String) = if (config == Configurations.Compile.name) "main" else config
  def prefix(config: String) = if (config == Configurations.Compile.name) "" else config + "-"

  def lock(app: xsbti.AppConfiguration): xsbti.GlobalLock = app.provider.scalaProvider.launcher.globalLock

  def extractAnalysis[T](a: Attributed[T]): (T, CompileAnalysis) =
    (a.data, a.metadata get Keys.analysis getOrElse Analysis.Empty)

  def analysisMap[T](cp: Seq[Attributed[T]]): T => Option[CompileAnalysis] =
    {
      val m = (for (a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an)).toMap
      m.get _
    }
  private[sbt] def globalDefaults(ss: Seq[Setting[_]]): Seq[Setting[_]] = Def.defaultSettings(inScope(GlobalScope)(ss))

  def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
  def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
    managedDirectory := baseDirectory.value / "lib_managed"
  ))
  @deprecated("Use AutoPlugins and globalSbtCore instead.", "0.13.2")
  lazy val globalCore: Seq[Setting[_]] = globalDefaults(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq(
    excludeFilter :== HiddenFileFilter
  ) ++ globalIvyCore ++ globalJvmCore) ++ globalSbtCore

  private[sbt] lazy val globalJvmCore: Seq[Setting[_]] =
    Seq(
      compilerCache := state.value get Keys.stateCompilerCache getOrElse CompilerCache.fresh,
      sourcesInBase :== true,
      autoAPIMappings := false,
      apiMappings := Map.empty,
      autoScalaLibrary :== true,
      managedScalaInstance :== true,
      definesClass :== FileValueCache(Locate.definesClass _).get,
      traceLevel in run :== 0,
      traceLevel in runMain :== 0,
      traceLevel in console :== Int.MaxValue,
      traceLevel in consoleProject :== Int.MaxValue,
      autoCompilerPlugins :== true,
      scalaHome :== None,
      apiURL := None,
      javaHome :== None,
      testForkedParallel :== false,
      javaOptions :== Nil,
      sbtPlugin :== false,
      crossPaths :== true,
      sourcePositionMappers :== Nil,
      artifactClassifier in packageSrc :== Some(SourceClassifier),
      artifactClassifier in packageDoc :== Some(DocClassifier),
      includeFilter :== NothingFilter,
      includeFilter in unmanagedSources :== ("*.java" | "*.scala") && new SimpleFileFilter(_.isFile),
      includeFilter in unmanagedJars :== "*.jar" | "*.so" | "*.dll" | "*.jnilib" | "*.zip",
      includeFilter in unmanagedResources :== AllPassFilter
    )

  private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =
    Seq(
      internalConfigurationMap :== Configurations.internalMap _,
      credentials :== Nil,
      exportJars :== false,
      trackInternalDependencies :== TrackLevel.TrackAlways,
      exportToInternal :== TrackLevel.TrackAlways,
      retrieveManaged :== false,
      retrieveManagedSync :== false,
      configurationsToRetrieve :== None,
      scalaOrganization :== ScalaArtifacts.Organization,
      sbtResolver := { if (sbtVersion.value endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeReleases },
      crossVersion :== CrossVersion.Disabled,
      buildDependencies <<= Classpaths.constructBuildDependencies,
      version :== "0.1-SNAPSHOT",
      classpathTypes :== Set("jar", "bundle") ++ CustomPomParser.JarPackagings,
      artifactClassifier :== None,
      checksums := Classpaths.bootChecksums(appConfiguration.value),
      conflictManager := ConflictManager.default,
      pomExtra :== NodeSeq.Empty,
      pomPostProcess :== idFun,
      pomAllRepositories :== false,
      pomIncludeRepository :== Classpaths.defaultRepositoryFilter,
      updateOptions := UpdateOptions(),
      forceUpdatePeriod :== None
    )

  /** Core non-plugin settings for sbt builds.  These *must* be on every build or the sbt engine will fail to run at all. */
  private[sbt] lazy val globalSbtCore: Seq[Setting[_]] = globalDefaults(Seq(
    outputStrategy :== None, // TODO - This might belong elsewhere.
    buildStructure := Project.structure(state.value),
    settingsData := buildStructure.value.data,
    trapExit :== true,
    connectInput :== false,
    cancelable :== false,
    taskCancelStrategy := { state: State =>
      if (cancelable.value) TaskCancellationStrategy.Signal
      else TaskCancellationStrategy.Null
    },
    envVars :== Map.empty,
    sbtVersion := appConfiguration.value.provider.id.version,
    sbtBinaryVersion := binarySbtVersion(sbtVersion.value),
    watchingMessage := Watched.defaultWatchingMessage,
    triggeredMessage := Watched.defaultTriggeredMessage,
    onLoad := idFun[State],
    onUnload := idFun[State],
    onUnload := { s => try onUnload.value(s) finally IO.delete(taskTemporaryDirectory.value) },
    extraLoggers :== { _ => Nil },
    watchSources :== Nil,
    skip :== false,
    taskTemporaryDirectory := { val dir = IO.createTemporaryDirectory; dir.deleteOnExit(); dir },
    onComplete := { val dir = taskTemporaryDirectory.value; () => { IO.delete(dir); IO.createDirectory(dir) } },
    Previous.cache <<= Previous.cacheSetting,
    Previous.references :== new Previous.References,
    concurrentRestrictions <<= defaultRestrictions,
    parallelExecution :== true,
    pollInterval :== 500,
    logBuffered :== false,
    commands :== Nil,
    showSuccess :== true,
    showTiming :== true,
    timingFormat :== Aggregation.defaultFormat,
    aggregate :== true,
    maxErrors :== 100,
    fork :== false,
    initialize :== {},
    forcegc :== sys.props.get("sbt.task.forcegc").map(java.lang.Boolean.parseBoolean).getOrElse(GCUtil.defaultForceGarbageCollection),
    minForcegcInterval :== GCUtil.defaultMinForcegcInterval
  ))
  def defaultTestTasks(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq(
    tags := Seq(Tags.Test -> 1),
    logBuffered := true
  ))
  // TODO: This should be on the new default settings for a project.
  def projectCore: Seq[Setting[_]] = Seq(
    name := thisProject.value.id,
    logManager := LogManager.defaults(extraLoggers.value, StandardMain.console),
    onLoadMessage <<= onLoadMessage or (name, thisProjectRef)("Set current project to " + _ + " (in build " + _.build + ")")
  )
  def paths = Seq(
    baseDirectory := thisProject.value.base,
    target := baseDirectory.value / "target",
    historyPath <<= historyPath or target(t => Some(t / ".history")),
    sourceDirectory := baseDirectory.value / "src",
    sourceManaged := crossTarget.value / "src_managed",
    resourceManaged := crossTarget.value / "resource_managed",
    cacheDirectory := crossTarget.value / CacheDirectoryName / thisProject.value.id / "global"
  )

  lazy val configPaths = sourceConfigPaths ++ resourceConfigPaths ++ outputConfigPaths
  lazy val sourceConfigPaths = Seq(
    sourceDirectory <<= configSrcSub(sourceDirectory),
    sourceManaged <<= configSrcSub(sourceManaged),
    scalaSource := sourceDirectory.value / "scala",
    javaSource := sourceDirectory.value / "java",
    unmanagedSourceDirectories := makeCrossSources(scalaSource.value, javaSource.value, scalaBinaryVersion.value, crossPaths.value),
    unmanagedSources <<= collectFiles(unmanagedSourceDirectories, includeFilter in unmanagedSources, excludeFilter in unmanagedSources),
    watchSources in ConfigGlobal <++= unmanagedSources,
    managedSourceDirectories := Seq(sourceManaged.value),
    managedSources <<= generate(sourceGenerators),
    sourceGenerators :== Nil,
    sourceDirectories <<= Classpaths.concatSettings(unmanagedSourceDirectories, managedSourceDirectories),
    sources <<= Classpaths.concat(unmanagedSources, managedSources)
  )
  lazy val resourceConfigPaths = Seq(
    resourceDirectory := sourceDirectory.value / "resources",
    resourceManaged <<= configSrcSub(resourceManaged),
    unmanagedResourceDirectories := Seq(resourceDirectory.value),
    managedResourceDirectories := Seq(resourceManaged.value),
    resourceDirectories <<= Classpaths.concatSettings(unmanagedResourceDirectories, managedResourceDirectories),
    unmanagedResources <<= collectFiles(unmanagedResourceDirectories, includeFilter in unmanagedResources, excludeFilter in unmanagedResources),
    watchSources in ConfigGlobal ++= unmanagedResources.value,
    resourceGenerators :== Nil,
    resourceGenerators <+= (discoveredSbtPlugins, resourceManaged) map PluginDiscovery.writeDescriptors,
    managedResources <<= generate(resourceGenerators),
    resources <<= Classpaths.concat(managedResources, unmanagedResources)
  )
  lazy val outputConfigPaths = Seq(
    cacheDirectory := crossTarget.value / CacheDirectoryName / thisProject.value.id / configuration.value.name,
    classDirectory := crossTarget.value / (prefix(configuration.value.name) + "classes"),
    target in doc := crossTarget.value / (prefix(configuration.value.name) + "api")
  )
  def addBaseSources = Seq(
    unmanagedSources := {
      val srcs = unmanagedSources.value
      val f = (includeFilter in unmanagedSources).value
      val excl = (excludeFilter in unmanagedSources).value
      if (sourcesInBase.value) (srcs +++ baseDirectory.value * (f -- excl)).get else srcs
    }
  )

  def compileBase = inTask(console)(compilersSetting :: Nil) ++ compileBaseGlobal ++ Seq(
    incOptions := incOptions.value.withClassfileManagerType(
      Maybe.just(new TransactionalManagerType(crossTarget.value / "classes.bak", sbt.util.Logger.Null))),
    scalaInstance <<= scalaInstanceTask,
    crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.Disabled),
    crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, sbtBinaryVersion.value, sbtPlugin.value, crossPaths.value),
    clean := {
      val _ = clean.value
      IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
    },
    scalaCompilerBridgeSource := Compiler.defaultCompilerBridgeSource(scalaVersion.value)
  )
  // must be a val: duplication detected by object identity
  private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(Seq(
    incOptions := IncOptionsUtil.defaultIncOptions,
    classpathOptions :== ClasspathOptions.boot,
    classpathOptions in console :== ClasspathOptions.repl,
    compileOrder :== CompileOrder.Mixed,
    javacOptions :== Nil,
    scalacOptions :== Nil,
    scalaVersion := appConfiguration.value.provider.scalaProvider.version,
    derive(crossScalaVersions := Seq(scalaVersion.value)),
    derive(compilersSetting),
    derive(scalaBinaryVersion := binaryScalaVersion(scalaVersion.value))
  ))

  def makeCrossSources(scalaSrcDir: File, javaSrcDir: File, sv: String, cross: Boolean): Seq[File] = {
    if (cross)
      Seq(scalaSrcDir.getParentFile / s"${scalaSrcDir.name}-$sv", scalaSrcDir, javaSrcDir)
    else
      Seq(scalaSrcDir, javaSrcDir)
  }

  def makeCrossTarget(t: File, sv: String, sbtv: String, plugin: Boolean, cross: Boolean): File =
    {
      val scalaBase = if (cross) t / ("scala-" + sv) else t
      if (plugin) scalaBase / ("sbt-" + sbtv) else scalaBase
    }

  def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value,
    bootIvyConfiguration.value, scalaCompilerBridgeSource.value)(appConfiguration.value, streams.value.log)

  lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ compileAnalysisSettings ++ Seq(
    compile <<= compileTask,
    manipulateBytecode := compileIncremental.value,
    compileIncremental <<= compileIncrementalTask tag (Tags.Compile, Tags.CPU),
    printWarnings <<= printWarningsTask,
    compileAnalysisFilename := {
      // Here, if the user wants cross-scala-versioning, we also append it
      // to the analysis cache, so we keep the scala versions separated.
      val extra =
        if (crossPaths.value) s"_${scalaBinaryVersion.value}"
        else ""
      s"inc_compile${extra}"
    },
    compileIncSetup <<= compileIncSetupTask,
    console <<= consoleTask,
    consoleQuick <<= consoleQuickTask,
    discoveredMainClasses <<= compile map discoverMainClasses storeAs discoveredMainClasses xtriggeredBy compile,
    // definedSbtPlugins <<= discoverPlugins,
    discoveredSbtPlugins <<= discoverSbtPluginNames,
    inTask(run)(runnerTask :: Nil).head,
    selectMainClass := mainClass.value orElse askForMainClass(discoveredMainClasses.value),
    mainClass in run := (selectMainClass in run).value,
    mainClass := pickMainClassOrWarn(discoveredMainClasses.value, streams.value.log),
    run <<= runTask(fullClasspath, mainClass in run, runner in run),
    runMain <<= runMainTask(fullClasspath, runner in run),
    copyResources <<= copyResourcesTask
  )

  private[this] lazy val configGlobal = globalDefaults(Seq(
    initialCommands :== "",
    cleanupCommands :== ""
  ))

  lazy val projectTasks: Seq[Setting[_]] = Seq(
    cleanFiles := Seq(managedDirectory.value, target.value),
    cleanKeepFiles := historyPath.value.toList,
    clean := doClean(cleanFiles.value, cleanKeepFiles.value),
    consoleProject <<= consoleProjectTask,
    watchTransitiveSources <<= watchTransitiveSourcesTask,
    watch <<= watchSetting
  )

  def generate(generators: SettingKey[Seq[Task[Seq[File]]]]): Initialize[Task[Seq[File]]] = generators { _.join.map(_.flatten) }

  @deprecated("Use the new .all() API", "0.13.0")
  def inAllConfigurations[T](key: TaskKey[T]): Initialize[Task[Seq[T]]] = (state, thisProjectRef) flatMap { (state, ref) =>
    val structure = Project structure state
    val configurations = Project.getProject(ref, structure).toList.flatMap(_.configurations)
    configurations.flatMap { conf =>
      key in (ref, conf) get structure.data
    } join
  }
  def watchTransitiveSourcesTask: Initialize[Task[Seq[File]]] = {
    import ScopeFilter.Make.{ inDependencies => inDeps, _ }
    val selectDeps = ScopeFilter(inAggregates(ThisProject) || inDeps(ThisProject))
    val allWatched = (watchSources ?? Nil).all(selectDeps)
    Def.task { allWatched.value.flatten }
  }

  def transitiveUpdateTask: Initialize[Task[Seq[UpdateReport]]] = {
    import ScopeFilter.Make.{ inDependencies => inDeps, _ }
    val selectDeps = ScopeFilter(inDeps(ThisProject, includeRoot = false))
    val allUpdates = update.?.all(selectDeps)
    // If I am a "build" (a project inside project/) then I have a globalPluginUpdate.
    Def.task { allUpdates.value.flatten ++ globalPluginUpdate.?.value }
  }

  def watchSetting: Initialize[Watched] = (pollInterval, thisProjectRef, watchingMessage, triggeredMessage) { (interval, base, msg, trigMsg) =>
    new Watched {
      val scoped = watchTransitiveSources in base
      val key = ScopedKey(scoped.scope, scoped.key)
      override def pollInterval = interval
      override def watchingMessage(s: WatchState) = msg(s)
      override def triggeredMessage(s: WatchState) = trigMsg(s)
      override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match {
        case Some(Value(ps)) => ps
        case Some(Inc(i))    => throw i
        case None            => sys.error("key not found: " + Def.displayFull(key))
      }
    }
  }

  @deprecated("Use scalaInstanceTask.", "0.13.0")
  def scalaInstanceSetting = scalaInstanceTask
  def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Def.taskDyn {
    // if this logic changes, ensure that `unmanagedScalaInstanceOnly` and `update` are changed
    //  appropriately to avoid cycles
    scalaHome.value match {
      case Some(h) => scalaInstanceFromHome(h)
      case None =>
        val scalaProvider = appConfiguration.value.provider.scalaProvider
        val version = scalaVersion.value
        if (version == scalaProvider.version) // use the same class loader as the Scala classes used by sbt
          Def.task(ScalaInstance(version, scalaProvider))
        else
          scalaInstanceFromUpdate
    }
  }
  // Returns the ScalaInstance only if it was not constructed via `update`
  //  This is necessary to prevent cycles between `update` and `scalaInstance`
  private[sbt] def unmanagedScalaInstanceOnly: Initialize[Task[Option[ScalaInstance]]] = Def.taskDyn {
    if (scalaHome.value.isDefined) Def.task(Some(scalaInstance.value)) else Def.task(None)
  }

  private[this] def noToolConfiguration(autoInstance: Boolean): String =
    {
      val pre = "Missing Scala tool configuration from the 'update' report.  "
      val post =
        if (autoInstance)
          "'scala-tool' is normally added automatically, so this may indicate a bug in sbt or you may be removing it from ivyConfigurations, for example."
        else
          "Explicitly define scalaInstance or scalaHome or include Scala dependencies in the 'scala-tool' configuration."
      pre + post
    }

  def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = Def.task {
    val toolReport = update.value.configuration(Configurations.ScalaTool.name) getOrElse
      sys.error(noToolConfiguration(managedScalaInstance.value))
    def files(id: String) =
      for {
        m <- toolReport.modules if m.module.name == id;
        (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType
      } yield file
    def file(id: String) = files(id).headOption getOrElse sys.error(s"Missing ${id}.jar")
    val allFiles = toolReport.modules.flatMap(_.artifacts.map(_._2))
    val libraryJar = file(ScalaArtifacts.LibraryID)
    val compilerJar =
      if (ScalaInstance.isDotty(scalaVersion.value))
        file(ScalaArtifacts.dottyID(scalaBinaryVersion.value))
      else
        file(ScalaArtifacts.CompilerID)
    val otherJars = allFiles.filterNot(x => x == libraryJar || x == compilerJar)
    new ScalaInstance(scalaVersion.value, makeClassLoader(state.value)(libraryJar :: compilerJar :: otherJars.toList), libraryJar, compilerJar, otherJars.toArray, None)
  }
  def scalaInstanceFromHome(dir: File): Initialize[Task[ScalaInstance]] = Def.task {
    ScalaInstance(dir)(makeClassLoader(state.value))
  }
  private[this] def makeClassLoader(state: State) = state.classLoaderCache.apply _

  private[this] def testDefaults = Defaults.globalDefaults(Seq(
    testFrameworks :== {
      import sbt.TestFrameworks._
      Seq(ScalaCheck, Specs2, Specs, ScalaTest, JUnit)
    },
    testListeners :== Nil,
    testOptions :== Nil,
    testResultLogger :== TestResultLogger.Default,
    testFilter in testOnly :== (selectedFilter _)
  ))
  lazy val testTasks: Seq[Setting[_]] = testTaskOptions(test) ++ testTaskOptions(testOnly) ++ testTaskOptions(testQuick) ++ testDefaults ++ Seq(
    testLoader := TestFramework.createTestLoader(data(fullClasspath.value), scalaInstance.value, IO.createUniqueDirectory(taskTemporaryDirectory.value)),
    loadedTestFrameworks := testFrameworks.value.flatMap(f => f.create(testLoader.value, streams.value.log).map(x => (f, x)).toIterable).toMap,
    definedTests <<= detectTests,
    definedTestNames <<= definedTests map (_.map(_.name).distinct) storeAs definedTestNames triggeredBy compile,
    testFilter in testQuick <<= testQuickFilter,
    executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test, testForkedParallel, javaOptions in test) flatMap allTestGroupsTask,
    testResultLogger in (Test, test) :== TestResultLogger.SilentWhenNoTests, // https://github.com/sbt/sbt/issues/1185
    test := {
      val trl = (testResultLogger in (Test, test)).value
      val taskName = Project.showContextKey(state.value)(resolvedScoped.value)
      trl.run(streams.value.log, executeTests.value, taskName)
    },
    testOnly <<= inputTests(testOnly),
    testQuick <<= inputTests(testQuick)
  )
  lazy val TaskGlobal: Scope = ThisScope.copy(task = Global)
  lazy val ConfigGlobal: Scope = ThisScope.copy(config = Global)
  def testTaskOptions(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq(
    testListeners := {
      TestLogger.make(streams.value.log, closeableTestLogger(streamsManager.value, test in resolvedScoped.value.scope, logBuffered.value)) +:
        new TestStatusReporter(succeededFile(streams.in(test).value.cacheDirectory)) +:
        testListeners.in(TaskGlobal).value
    },
    testOptions := Tests.Listeners(testListeners.value) +: (testOptions in TaskGlobal).value,
    testExecution <<= testExecutionTask(key)
  )) ++ inScope(GlobalScope)(Seq(
    derive(testGrouping <<= singleTestGroupDefault)
  ))
  @deprecated("Doesn't provide for closing the underlying resources.", "0.13.1")
  def testLogger(manager: Streams, baseKey: Scoped)(tdef: TestDefinition): Logger =
    {
      val scope = baseKey.scope
      val extra = scope.extra match { case Select(x) => x; case _ => AttributeMap.empty }
      val key = ScopedKey(scope.copy(extra = Select(testExtra(extra, tdef))), baseKey.key)
      manager(key).log
    }
  private[this] def closeableTestLogger(manager: Streams, baseKey: Scoped, buffered: Boolean)(tdef: TestDefinition): TestLogger.PerTest =
    {
      val scope = baseKey.scope
      val extra = scope.extra match { case Select(x) => x; case _ => AttributeMap.empty }
      val key = ScopedKey(scope.copy(extra = Select(testExtra(extra, tdef))), baseKey.key)
      val s = manager(key)
      new TestLogger.PerTest(s.log, () => s.close(), buffered)
    }
  def buffered(log: Logger): Logger = new BufferedLogger(FullLogger(log))
  def testExtra(extra: AttributeMap, tdef: TestDefinition): AttributeMap =
    {
      val mod = tdef.fingerprint match { case f: SubclassFingerprint => f.isModule; case f: AnnotatedFingerprint => f.isModule; case _ => false }
      extra.put(name.key, tdef.name).put(isModule, mod)
    }
  def singleTestGroup(key: Scoped): Initialize[Task[Seq[Tests.Group]]] = inTask(key, singleTestGroupDefault)
  def singleTestGroupDefault: Initialize[Task[Seq[Tests.Group]]] = Def.task {
    val tests = definedTests.value
    val fk = fork.value
    val opts = forkOptions.value
    Seq(new Tests.Group("", tests, if (fk) Tests.SubProcess(opts) else Tests.InProcess))
  }
  private[this] def forkOptions: Initialize[Task[ForkOptions]] =
    (baseDirectory, javaOptions, outputStrategy, envVars, javaHome, connectInput) map {
      (base, options, strategy, env, javaHomeDir, connectIn) =>
        // bootJars is empty by default because only jars on the user's classpath should be on the boot classpath
        ForkOptions(bootJars = Nil, javaHome = javaHomeDir, connectInput = connectIn, outputStrategy = strategy, runJVMOptions = options, workingDirectory = Some(base), envVars = env)
    }

  def testExecutionTask(task: Scoped): Initialize[Task[Tests.Execution]] =
    (testOptions in task, parallelExecution in task, tags in task) map {
      (opts, par, ts) =>
        new Tests.Execution(opts, par, ts)
    }

  def testQuickFilter: Initialize[Task[Seq[String] => Seq[String => Boolean]]] =
    (fullClasspath in test, streams in test) map {
      (cp, s) =>
        val ans: Seq[Analysis] = cp.flatMap(_.metadata get Keys.analysis) map { case a0: Analysis => a0 }
        val succeeded = TestStatus.read(succeededFile(s.cacheDirectory))
        val stamps = collection.mutable.Map.empty[String, Long]
        def stamp(dep: String): Long = {
          val stamps = for (a <- ans) yield intlStamp(dep, a, Set.empty)
          if (stamps.isEmpty) Long.MinValue
          else stamps.max
        }
        def intlStamp(c: String, analysis: Analysis, s: Set[String]): Long = {
          if (s contains c) Long.MinValue
          else {
            val x = {
              import analysis.{ relations => rel, apis }
              rel.internalClassDeps(c).map(intlStamp(_, analysis, s + c)) ++
                rel.externalDeps(c).map(stamp) +
                (apis.internal.get(c) match {
                  case Some(x) => x.compilation.startTime
                  case _       => Long.MinValue
                })
            }.max
            if (x != Long.MinValue) {
              stamps(c) = x
            }
            x
          }
        }
        def noSuccessYet(test: String) = succeeded.get(test) match {
          case None     => true
          case Some(ts) => stamp(test) > ts
        }

        args => for (filter <- selectedFilter(args)) yield (test: String) => filter(test) && noSuccessYet(test)
    }
  def succeededFile(dir: File) = dir / "succeeded_tests"

  def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] = inputTests0.mapReferenced(Def.mapScope(_ in key.key))
  private[this] lazy val inputTests0: Initialize[InputTask[Unit]] =
    {
      val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
      Def.inputTaskDyn {
        val (selected, frameworkOptions) = parser.parsed
        val s = streams.value
        val filter = testFilter.value
        val config = testExecution.value

        implicit val display = Project.showContextKey(state.value)
        val modifiedOpts = Tests.Filters(filter(selected)) +: Tests.Argument(frameworkOptions: _*) +: config.options
        val newConfig = config.copy(options = modifiedOpts)
        val output = allTestGroupsTask(s, loadedTestFrameworks.value, testLoader.value, testGrouping.value, newConfig, fullClasspath.value, javaHome.value, testForkedParallel.value, javaOptions.value)
        val taskName = display(resolvedScoped.value)
        val trl = testResultLogger.value
        val processed = output.map(out => trl.run(s.log, out, taskName))
        Def.value(processed)
      }
    }

  def createTestRunners(frameworks: Map[TestFramework, Framework], loader: ClassLoader, config: Tests.Execution): Map[TestFramework, Runner] = {
    import Tests.Argument
    val opts = config.options.toList
    frameworks.map {
      case (tf, f) =>
        val args = opts.flatMap {
          case Argument(None | Some(`tf`), args) => args
          case _                                 => Nil
        }
        val mainRunner = f.runner(args.toArray, Array.empty[String], loader)
        tf -> mainRunner
    }
  }

  def allTestGroupsTask(s: TaskStreams, frameworks: Map[TestFramework, Framework], loader: ClassLoader, groups: Seq[Tests.Group], config: Tests.Execution, cp: Classpath, javaHome: Option[File]): Task[Tests.Output] = {
    allTestGroupsTask(s, frameworks, loader, groups, config, cp, javaHome, forkedParallelExecution = false, javaOptions = Nil)
  }

  def allTestGroupsTask(s: TaskStreams, frameworks: Map[TestFramework, Framework], loader: ClassLoader, groups: Seq[Tests.Group], config: Tests.Execution, cp: Classpath, javaHome: Option[File], forkedParallelExecution: Boolean): Task[Tests.Output] = {
    allTestGroupsTask(s, frameworks, loader, groups, config, cp, javaHome, forkedParallelExecution, javaOptions = Nil)
  }

  def allTestGroupsTask(s: TaskStreams, frameworks: Map[TestFramework, Framework], loader: ClassLoader, groups: Seq[Tests.Group], config: Tests.Execution, cp: Classpath, javaHome: Option[File], forkedParallelExecution: Boolean, javaOptions: Seq[String]): Task[Tests.Output] = {
    val runners = createTestRunners(frameworks, loader, config)
    val groupTasks = groups map {
      case Tests.Group(name, tests, runPolicy) =>
        runPolicy match {
          case Tests.SubProcess(opts) =>
            s.log.debug(s"javaOptions: ${opts.runJVMOptions}")
            val forkedConfig = config.copy(parallel = config.parallel && forkedParallelExecution)
            s.log.debug(s"Forking tests - parallelism = ${forkedConfig.parallel}")
            ForkTests(runners, tests.toList, forkedConfig, cp.files, opts, s.log) tag Tags.ForkedTestGroup
          case Tests.InProcess =>
            if (javaOptions.nonEmpty) {
              s.log.warn("javaOptions will be ignored, fork is set to false")
            }
            Tests(frameworks, loader, runners, tests, config, s.log)
        }
    }
    val output = Tests.foldTasks(groupTasks, config.parallel)
    output map { out =>
      val summaries =
        runners map {
          case (tf, r) =>
            Tests.Summary(frameworks(tf).name, r.done())
        }
      out.copy(summaries = summaries)
    }
  }

  def selectedFilter(args: Seq[String]): Seq[String => Boolean] =
    {
      def matches(nfs: Seq[NameFilter], s: String) = nfs.exists(_.accept(s))

      val (excludeArgs, includeArgs) = args.partition(_.startsWith("-"))

      val includeFilters = includeArgs map GlobFilter.apply
      val excludeFilters = excludeArgs.map(_.substring(1)).map(GlobFilter.apply)

      if (includeFilters.isEmpty && excludeArgs.isEmpty) {
        Seq(const(true))
      } else if (includeFilters.isEmpty) {
        Seq({ (s: String) => !matches(excludeFilters, s) })
      } else {
        includeFilters.map { f => (s: String) => (f.accept(s) && !matches(excludeFilters, s)) }
      }
    }
  def detectTests: Initialize[Task[Seq[TestDefinition]]] = (loadedTestFrameworks, compile, streams) map { (frameworkMap, analysis, s) =>
    Tests.discover(frameworkMap.values.toList, analysis, s.log)._1
  }
  def defaultRestrictions: Initialize[Seq[Tags.Rule]] = parallelExecution { par =>
    val max = EvaluateTask.SystemProcessors
    Tags.limitAll(if (par) max else 1) :: Tags.limit(Tags.ForkedTestGroup, 1) :: Nil
  }

  lazy val packageBase: Seq[Setting[_]] = Seq(
    artifact := Artifact(moduleName.value)
  ) ++ Defaults.globalDefaults(Seq(
      packageOptions :== Nil,
      artifactName :== (Artifact.artifactName _)
    ))

  lazy val packageConfig: Seq[Setting[_]] =
    inTask(packageBin)(Seq(
      packageOptions <<= (name, version, homepage, organization, organizationName, mainClass, packageOptions) map { (name, ver, h, org, orgName, main, p) => Package.addSpecManifestAttributes(name, ver, orgName) +: Package.addImplManifestAttributes(name, ver, h, org, orgName) +: main.map(Package.MainClass.apply) ++: p })) ++
      inTask(packageSrc)(Seq(
        packageOptions := Package.addSpecManifestAttributes(name.value, version.value, organizationName.value) +: packageOptions.value)) ++
      packageTaskSettings(packageBin, packageBinMappings) ++
      packageTaskSettings(packageSrc, packageSrcMappings) ++
      packageTaskSettings(packageDoc, packageDocMappings) ++
      Seq(`package` := packageBin.value)

  def packageBinMappings = products map { _ flatMap Path.allSubpaths }
  def packageDocMappings = doc map { Path.allSubpaths(_).toSeq }
  def packageSrcMappings = concatMappings(resourceMappings, sourceMappings)

  @deprecated("Use `packageBinMappings` instead", "0.12.0")
  def packageBinTask = packageBinMappings
  @deprecated("Use `packageDocMappings` instead", "0.12.0")
  def packageDocTask = packageDocMappings
  @deprecated("Use `packageSrcMappings` instead", "0.12.0")
  def packageSrcTask = packageSrcMappings

  private type Mappings = Initialize[Task[Seq[(File, String)]]]
  def concatMappings(as: Mappings, bs: Mappings) = (as zipWith bs)((a, b) => (a, b) map { case (a, b) => a ++ b })

  // drop base directories, since there are no valid mappings for these
  def sourceMappings = (unmanagedSources, unmanagedSourceDirectories, baseDirectory) map { (srcs, sdirs, base) =>
    (srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)
  }
  def resourceMappings = relativeMappings(unmanagedResources, unmanagedResourceDirectories)
  def relativeMappings(files: ScopedTaskable[Seq[File]], dirs: ScopedTaskable[Seq[File]]): Initialize[Task[Seq[(File, String)]]] =
    (files, dirs) map { (rs, rdirs) =>
      (rs --- rdirs) pair (relativeTo(rdirs) | flat)
    }

  def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] =
    (dirs, filter, excludes) map { (d, f, excl) => d.descendantsExcept(f, excl).get }

  def artifactPathSetting(art: SettingKey[Artifact]) = (crossTarget, projectID, art, scalaVersion in artifactName, scalaBinaryVersion in artifactName, artifactName) {
    (t, module, a, sv, sbv, toString) =>
      t / toString(ScalaVersion(sv, sbv), module, a) asFile
  }
  def artifactSetting = ((artifact, artifactClassifier).identity zipWith configuration.?) {
    case ((a, classifier), cOpt) =>
      val cPart = cOpt flatMap {
        case Compile => None
        case Test    => Some(Artifact.TestsClassifier)
        case c       => Some(c.name)
      }
      val combined = cPart.toList ++ classifier.toList
      if (combined.isEmpty) a.copy(classifier = None, configurations = cOpt.toList) else {
        val classifierString = combined mkString "-"
        val confs = cOpt.toList flatMap { c => artifactConfigurations(a, c, classifier) }
        a.copy(classifier = Some(classifierString), `type` = Artifact.classifierType(classifierString), configurations = confs)
      }
  }
  @deprecated("The configuration(s) should not be decided based on the classifier.", "1.0")
  def artifactConfigurations(base: Artifact, scope: Configuration, classifier: Option[String]): Iterable[Configuration] =
    classifier match {
      case Some(c) => Artifact.classifierConf(c) :: Nil
      case None    => scope :: Nil
    }

  @deprecated("Use `Util.pairID` instead", "0.12.0")
  def pairID = Util.pairID

  @deprecated("Use the cacheDirectory val on streams.", "0.13.0")
  def perTaskCache(key: TaskKey[_]): Setting[File] =
    cacheDirectory ~= { _ / ("for_" + key.key.label) }

  @deprecated("Use `packageTaskSettings` instead", "0.12.0")
  def packageTasks(key: TaskKey[File], mappingsTask: Initialize[Task[Seq[(File, String)]]]) = packageTaskSettings(key, mappingsTask)
  def packageTaskSettings(key: TaskKey[File], mappingsTask: Initialize[Task[Seq[(File, String)]]]) =
    inTask(key)(Seq(
      key in TaskGlobal <<= packageTask,
      packageConfiguration <<= packageConfigurationTask,
      mappings <<= mappingsTask,
      packagedArtifact := (artifact.value -> key.value),
      artifact <<= artifactSetting,
      artifactPath <<= artifactPathSetting(artifact)
    ))
  def packageTask: Initialize[Task[File]] =
    (packageConfiguration, streams) map { (config, s) =>
      Package(config, s.cacheDirectory, s.log)
      config.jar
    }
  def packageConfigurationTask: Initialize[Task[Package.Configuration]] =
    (mappings, artifactPath, packageOptions) map { (srcs, path, options) =>
      new Package.Configuration(srcs, path, options)
    }

  @deprecated("use Defaults.askForMainClass", "0.13.7")
  def selectRunMain(classes: Seq[String]): Option[String] = askForMainClass(classes)
  @deprecated("use Defaults.pickMainClass", "0.13.7")
  def selectPackageMain(classes: Seq[String]): Option[String] = pickMainClass(classes)
  def askForMainClass(classes: Seq[String]): Option[String] =
    sbt.SelectMainClass(Some(SimpleReader readLine _), classes)
  def pickMainClass(classes: Seq[String]): Option[String] =
    sbt.SelectMainClass(None, classes)
  private def pickMainClassOrWarn(classes: Seq[String], logger: Logger): Option[String] = {
    classes match {
      case multiple if multiple.size > 1 => logger.warn("Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list")
      case _                             =>
    }
    pickMainClass(classes)
  }

  def doClean(clean: Seq[File], preserve: Seq[File]): Unit =
    IO.withTemporaryDirectory { temp =>
      val (dirs, files) = preserve.filter(_.exists).flatMap(_.allPaths.get).partition(_.isDirectory)
      val mappings = files.zipWithIndex map { case (f, i) => (f, new File(temp, i.toHexString)) }
      IO.move(mappings)
      IO.delete(clean)
      IO.createDirectories(dirs) // recreate empty directories
      IO.move(mappings.map(_.swap))
    }
  def runMainTask(classpath: Initialize[Task[Classpath]], scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] =
    {
      import DefaultParsers._
      val parser = loadForParser(discoveredMainClasses)((s, names) => runMainParser(s, names getOrElse Nil))
      Def.inputTask {
        val (mainClass, args) = parser.parsed
        toError(scalaRun.value.run(mainClass, data(classpath.value), args, streams.value.log))
      }
    }

  def runTask(classpath: Initialize[Task[Classpath]], mainClassTask: Initialize[Task[Option[String]]], scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] =
    {
      import Def.parserToInput
      val parser = Def.spaceDelimited()
      Def.inputTask {
        val mainClass = mainClassTask.value getOrElse sys.error("No main class detected.")
        toError(scalaRun.value.run(mainClass, data(classpath.value), parser.parsed, streams.value.log))
      }
    }

  def runnerTask = runner <<= runnerInit
  def runnerInit: Initialize[Task[ScalaRun]] = Def.task {
    val tmp = taskTemporaryDirectory.value
    val resolvedScope = resolvedScoped.value.scope
    val structure = buildStructure.value
    val si = scalaInstance.value
    val s = streams.value
    val options = javaOptions.value
    if (fork.value) {
      s.log.debug(s"javaOptions: $options")
      new ForkRun(forkOptions.value)
    } else {
      if (options.nonEmpty) {
        val mask = ScopeMask(project = false)
        val showJavaOptions = Scope.displayMasked((javaOptions in resolvedScope).scopedKey.scope, (javaOptions in resolvedScope).key.label, mask)
        val showFork = Scope.displayMasked((fork in resolvedScope).scopedKey.scope, (fork in resolvedScope).key.label, mask)
        s.log.warn(s"$showJavaOptions will be ignored, $showFork is set to false")
      }
      new Run(si, trapExit.value, tmp)
    }
  }

  @deprecated("Use `docTaskSettings` instead", "0.12.0")
  def docSetting(key: TaskKey[File]) = docTaskSettings(key)
  def docTaskSettings(key: TaskKey[File] = doc): Seq[Setting[_]] = inTask(key)(Seq(
    apiMappings ++= { if (autoAPIMappings.value) APIMappings.extract(dependencyClasspath.value, streams.value.log).toMap else Map.empty[File, URL] },
    fileInputOptions := Seq("-doc-root-content", "-diagrams-dot-path"),
    key in TaskGlobal := {
      val s = streams.value
      val cs: IncrementalCompilerImpl.Compilers = compilers.value match { case c: IncrementalCompilerImpl.Compilers => c }
      val srcs = sources.value
      val out = target.value
      val sOpts = scalacOptions.value
      val xapis = apiMappings.value
      val hasScala = srcs.exists(_.name.endsWith(".scala"))
      val hasJava = srcs.exists(_.name.endsWith(".java"))
      val cp = data(dependencyClasspath.value).toList
      val label = nameForSrc(configuration.value.name)
      val fiOpts = fileInputOptions.value
      val logger: Logger = s.log
      val maxer = maxErrors.value
      val spms = sourcePositionMappers.value
      val reporter = (compilerReporter in compile).value
      (hasScala, hasJava) match {
        case (true, _) =>
          val options = sOpts ++ Opts.doc.externalAPI(xapis)
          val runDoc = Doc.scaladoc(label, s.cacheDirectory / "scala", cs.scalac.onArgs(exported(s, "scaladoc")), fiOpts)
          runDoc(srcs, cp, out, options, maxErrors.value, s.log)
        case (_, true) =>
          val javadoc = sbt.inc.Doc.cachedJavadoc(label, s.cacheDirectory / "java", cs.javac)
          javadoc.run(srcs.toList, cp, out, javacOptions.value.toList, s.log, reporter)
        case _ => () // do nothing
      }
      out
    }
  ))

  def mainRunTask = run <<= runTask(fullClasspath in Runtime, mainClass in run, runner in run)
  def mainRunMainTask = runMain <<= runMainTask(fullClasspath in Runtime, runner in run)

  def discoverMainClasses(analysis: CompileAnalysis): Seq[String] =
    Discovery.applications(Tests.allDefs(analysis)).collect({ case (definition, discovered) if discovered.hasMain => definition.name }).sorted

  def consoleProjectTask = (state, streams, initialCommands in consoleProject) map { (state, s, extra) => ConsoleProject(state, extra)(s.log); println() }
  def consoleTask: Initialize[Task[Unit]] = consoleTask(fullClasspath, console)
  def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick)
  def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[_]): Initialize[Task[Unit]] =
    (compilers in task, classpath in task, scalacOptions in task, initialCommands in task, cleanupCommands in task, taskTemporaryDirectory in task, scalaInstance in task, streams) map {
      case (cs: IncrementalCompilerImpl.Compilers, cp, options, initCommands, cleanup, temp, si, s) =>
        val cpFiles = data(cp)
        val fullcp = (cpFiles ++ si.allJars).distinct
        val loader = sbt.internal.inc.classpath.ClasspathUtilities.makeLoader(fullcp, si, IO.createUniqueDirectory(temp))
        val compiler = cs.scalac.onArgs(exported(s, "scala"))
        (new Console(compiler))(cpFiles, options, loader, initCommands, cleanup)()(s.log).foreach(msg => sys.error(msg))
        println()
    }

  private[this] def exported(w: PrintWriter, command: String): Seq[String] => Unit = args =>
    w.println((command +: args).mkString(" "))
  private[this] def exported(s: TaskStreams, command: String): Seq[String] => Unit = args => {
    val w = s.text(ExportStream)
    try exported(w, command)
    finally w.close() // workaround for #937
  }

  @deprecated("Use inTask(compile)(compileInputsSettings)", "0.13.0")
  def compileTaskSettings: Seq[Setting[_]] = inTask(compile)(compileInputsSettings)

  def compileTask: Initialize[Task[CompileAnalysis]] = Def.task {
    val setup: Setup = compileIncSetup.value
    // TODO - expose bytecode manipulation phase.
    val analysisResult: CompileResult = manipulateBytecode.value
    if (analysisResult.hasModified) {
      val store = MixedAnalyzingCompiler.staticCachedStore(setup.cacheFile)
      store.set(analysisResult.analysis, analysisResult.setup)
    }
    analysisResult.analysis
  }
  def compileIncrementalTask = Def.task {
    // TODO - Should readAnalysis + saveAnalysis be scoped by the compile task too?
    compileIncrementalTaskImpl(streams.value, (compileInputs in compile).value)
  }
  private[this] def compileIncrementalTaskImpl(s: TaskStreams, ci: Inputs): CompileResult =
    {
      lazy val x = s.text(ExportStream)
      def onArgs(cs: IncrementalCompilerImpl.Compilers) = cs.copy(scalac = cs.scalac.onArgs(exported(x, "scalac")), javac = cs.javac /*.onArgs(exported(x, "javac"))*/ )
      val compilers: IncrementalCompilerImpl.Compilers = ci.compilers match { case compilers: IncrementalCompilerImpl.Compilers => compilers }
      val i = ci.withCompilers(onArgs(compilers))
      try Compiler.compile(i, s.log)
      finally x.close() // workaround for #937
    }
  def compileIncSetupTask = Def.task {
    val dc: File => DefinesClass = {
      val dc = definesClass.value
      f => new DefinesClass { override def apply(className: String): Boolean = dc(f)(className) }
    }
    new Setup(
      f1(t => o2m(analysisMap(dependencyClasspath.value)(t))),
      f1(dc),
      (skip in compile).value,
      // TODO - this is kind of a bad way to grab the cache directory for streams...
      streams.value.cacheDirectory / compileAnalysisFilename.value,
      compilerCache.value,
      incOptions.value,
      (compilerReporter in compile).value,
      // TODO - task / setting for extra,
      Array.empty)
  }
  def compileInputsSettings: Seq[Setting[_]] = {
    Seq(
      compileOptions := new CompileOptions(
        (classDirectory.value +: data(dependencyClasspath.value)).toArray,
        sources.value.toArray,
        classDirectory.value,
        scalacOptions.value.toArray,
        javacOptions.value.toArray,
        maxErrors.value,
        f1(Compiler.foldMappers(sourcePositionMappers.value)),
        compileOrder.value),
      compilerReporter := new LoggerReporter(maxErrors.value, streams.value.log, Compiler.foldMappers(sourcePositionMappers.value)),
      compileInputs := new Inputs(
        compilers.value,
        compileOptions.value,
        compileIncSetup.value,
        previousCompile.value)
    )
  }
  def compileAnalysisSettings: Seq[Setting[_]] = Seq(
    previousCompile := {
      val setup = compileIncSetup.value
      val store = MixedAnalyzingCompiler.staticCachedStore(setup.cacheFile)
      store.get() match {
        case Some((an, setup)) => new PreviousResult(Maybe.just(an), Maybe.just(setup))
        case None              => new PreviousResult(Maybe.nothing[CompileAnalysis], Maybe.nothing[MiniSetup])
      }
    }
  )

  def printWarningsTask: Initialize[Task[Unit]] =
    (streams, compile, maxErrors, sourcePositionMappers) map {
      case (s, analysis: Analysis, max, spms) =>
        val problems = analysis.infos.allInfos.values.flatMap(i => i.reportedProblems ++ i.unreportedProblems)
        val reporter = new LoggerReporter(max, s.log, Compiler.foldMappers(spms))
        problems foreach { p => reporter.display(p.position, p.message, p.severity) }
    }

  def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID =
    m.extra(PomExtraDependencyAttributes.SbtVersionKey -> sbtV, PomExtraDependencyAttributes.ScalaVersionKey -> scalaV).copy(crossVersion = CrossVersion.Disabled)

  @deprecated("Use PluginDiscovery.writeDescriptor.", "0.13.2")
  def writePluginsDescriptor(plugins: Set[String], dir: File): Seq[File] =
    PluginDiscovery.writeDescriptor(plugins.toSeq, dir, PluginDiscovery.Paths.Plugins).toList

  def discoverSbtPluginNames: Initialize[Task[PluginDiscovery.DiscoveredNames]] = Def.task {
    if (sbtPlugin.value) PluginDiscovery.discoverSourceAll(compile.value) else PluginDiscovery.emptyDiscoveredNames
  }

  def copyResourcesTask =
    (classDirectory, resources, resourceDirectories, streams) map { (target, resrcs, dirs, s) =>
      val cacheFile = s.cacheDirectory / "copy-resources"
      val mappings = (resrcs --- dirs) pair (rebase(dirs, target) | flat(target))
      s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t", "\n\t", ""))
      Sync(cacheFile)(mappings)
      mappings
    }

  def runMainParser: (State, Seq[String]) => Parser[(String, Seq[String])] =
    {
      import DefaultParsers._
      (state, mainClasses) => Space ~> token(NotSpace examples mainClasses.toSet) ~ spaceDelimited("")
    }

  def testOnlyParser: (State, Seq[String]) => Parser[(Seq[String], Seq[String])] =
    { (state, tests) =>
      import DefaultParsers._
      val selectTests = distinctParser(tests.toSet, true)
      val options = (token(Space) ~> token("--") ~> spaceDelimited("




© 2015 - 2025 Weber Informatics LLC | Privacy Policy