<commit_before>/* sbt -- Simple Build Tool
 * Copyright 2011 <NAME>
 */
package sbt

	import Build.data
	import Scope.{fillTaskAxis, GlobalScope, ThisScope}
	import xsbt.api.Discovery
	import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting, SettingsDefinition}
	import Load.LoadedBuild
	import Artifact.{DocClassifier, SourceClassifier}
	import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
	import CrossVersion.{binarySbtVersion, binaryScalaVersion, isStable, selectVersion}
	import complete._
	import std.TaskExtra._
	import inc.{FileValueCache, Locate}
	import org.scalatools.testing.{AnnotatedFingerprint, SubclassFingerprint}

	import sys.error
	import scala.xml.NodeSeq
	import org.apache.ivy.core.module.{descriptor, id}
	import descriptor.ModuleDescriptor, id.ModuleRevisionId
	import java.io.File
	import java.net.URL
	import java.util.concurrent.Callable
	import sbinary.DefaultProtocol.StringFormat
	import Cache.seqFormat

	import Types._
	import Path._
	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 == "compile") "main" else config
	def prefix(config: String) = if(config == "compile") "" else config + "-"

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

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

	def analysisMap[T](cp: Seq[Attributed[T]]): Map[T, inc.Analysis] =
		(for(a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an) ).toMap

	def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
	def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
		managedDirectory <<= baseDirectory(_ / "lib_managed")
	))
	def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq(
		crossVersion :== CrossVersion.Disabled,
		buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies,
		taskTemporaryDirectory := IO.createTemporaryDirectory,
		onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) },
		concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions,
		parallelExecution :== true,
		sbtVersion <<= appConfiguration { _.provider.id.version },
		sbtBinaryVersion <<= sbtVersion apply binarySbtVersion,
		sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeReleases },
		pollInterval :== 500,
		logBuffered :== false,
		connectInput :== false,
		cancelable :== false,
		autoScalaLibrary :== true,
		onLoad <<= onLoad ?? idFun[State],
		onUnload <<= (onUnload ?? idFun[State]),
		onUnload <<= (onUnload, taskTemporaryDirectory) { (f, dir) => s => { try f(s) finally IO.delete(dir) } },
		watchingMessage <<= watchingMessage ?? Watched.defaultWatchingMessage,
		triggeredMessage <<= triggeredMessage ?? Watched.defaultTriggeredMessage,
		definesClass :== FileValueCache(Locate.definesClass _ ).get,
		trapExit :== false,
		trapExit in run :== true,
		traceLevel in run :== 0,
		traceLevel in runMain :== 0,
		traceLevel in console :== Int.MaxValue,
		traceLevel in consoleProject :== Int.MaxValue,
		autoCompilerPlugins :== true,
		internalConfigurationMap :== Configurations.internalMap _,
		initialize :== (),
		credentials :== Nil,
		scalaHome :== None,
		javaHome :== None,
		extraLoggers :== { _ => Nil },
		skip :== false,
		watchSources :== Nil,
		version :== "0.1-SNAPSHOT",
		outputStrategy :== None,
		exportJars :== false,
		fork :== false,
		javaOptions :== Nil,
		sbtPlugin :== false,
		crossPaths :== true,
		classpathTypes :== Set("jar", "bundle"),
		aggregate :== true,
		maxErrors :== 100,
		showTiming :== true,
		timingFormat :== Aggregation.defaultFormat,
		showSuccess :== true,
		commands :== Nil,
		retrieveManaged :== false,
		buildStructure <<= state map Project.structure,
		settings <<= buildStructure map ( _.data ),
		artifactClassifier :== None,
		artifactClassifier in packageSrc :== Some(SourceClassifier),
		artifactClassifier in packageDoc :== Some(DocClassifier),
		checksums <<= appConfiguration(Classpaths.bootChecksums),
		pomExtra :== NodeSeq.Empty,
		pomPostProcess :== idFun,
		pomAllRepositories :== false,
		includeFilter :== NothingFilter,
		includeFilter in unmanagedSources :== "*.java" | "*.scala",
		includeFilter in unmanagedJars :== "*.jar" | "*.so" | "*.dll",
		includeFilter in unmanagedResources :== AllPassFilter,
		excludeFilter :== (".*"  - ".") || HiddenFileFilter,
		pomIncludeRepository :== Classpaths.defaultRepositoryFilter
	))
	def defaultTestTasks(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq(
		tags := Seq(Tags.Test -> 1),
		logBuffered := true
	))
	def projectCore: Seq[Setting[_]] = Seq(
		name <<= thisProject(_.id),
		logManager <<= extraLoggers(LogManager.defaults),
		onLoadMessage <<= onLoadMessage or (name, thisProjectRef)("Set current project to " + _ + " (in build " + _.build +")"),
		runnerTask
	)
	def paths = Seq(
		baseDirectory <<= thisProject(_.base),
		target <<= baseDirectory / "target",
		historyPath <<= target(t => Some(t / ".history")),
		sourceDirectory <<= baseDirectory / "src",
		sourceManaged <<= crossTarget / "src_managed",
		resourceManaged <<= crossTarget / "resource_managed",
		cacheDirectory <<= (crossTarget, thisProject)(_ / CacheDirectoryName / _.id / "global")
	)

	lazy val configPaths = sourceConfigPaths ++ resourceConfigPaths ++ outputConfigPaths
	lazy val sourceConfigPaths = Seq(
		sourceDirectory <<= configSrcSub(sourceDirectory),
		sourceManaged <<= configSrcSub(sourceManaged),
		scalaSource <<= sourceDirectory / "scala",
		javaSource <<= sourceDirectory / "java",
		unmanagedSourceDirectories <<= Seq(scalaSource, javaSource).join,
			// remove when sourceFilter, defaultExcludes are removed
		includeFilter in unmanagedSources <<= (sourceFilter in unmanagedSources) or (includeFilter in unmanagedSources),
		excludeFilter in unmanagedSources <<= (defaultExcludes in unmanagedSources) or (excludeFilter in unmanagedSources),
		unmanagedSources <<= collectFiles(unmanagedSourceDirectories, includeFilter in unmanagedSources, excludeFilter in unmanagedSources),
		watchSources in ConfigGlobal <++= unmanagedSources,
		managedSourceDirectories <<= Seq(sourceManaged).join,
		managedSources <<= generate(sourceGenerators),
		sourceGenerators :== Nil,
		sourceDirectories <<= Classpaths.concatSettings(unmanagedSourceDirectories, managedSourceDirectories),
		sources <<= Classpaths.concat(unmanagedSources, managedSources)
	)
	lazy val resourceConfigPaths = Seq(
		resourceDirectory <<= sourceDirectory / "resources",
		resourceManaged <<= configSrcSub(resourceManaged),
		unmanagedResourceDirectories <<= Seq(resourceDirectory).join,
		managedResourceDirectories <<= Seq(resourceManaged).join,
		resourceDirectories <<= Classpaths.concatSettings(unmanagedResourceDirectories, managedResourceDirectories),
			// remove when defaultExcludes are removed
		excludeFilter in unmanagedResources <<= (defaultExcludes in unmanagedResources) or (excludeFilter in unmanagedResources),
		unmanagedResources <<= collectFiles(unmanagedResourceDirectories, includeFilter in unmanagedResources, excludeFilter in unmanagedResources),
		watchSources in ConfigGlobal <++= unmanagedResources,
		resourceGenerators :== Nil,
		resourceGenerators <+= (definedSbtPlugins, resourceManaged) map writePluginsDescriptor,
		managedResources <<= generate(resourceGenerators),
		resources <<= Classpaths.concat(managedResources, unmanagedResources)
	)
	lazy val outputConfigPaths = Seq(
		cacheDirectory <<= (crossTarget, thisProject, configuration) { _ / CacheDirectoryName / _.id / _.name },
		classDirectory <<= (crossTarget, configuration) { (outDir, conf) => outDir / (prefix(conf.name) + "classes") },
		docDirectory <<= (crossTarget, configuration) { (outDir, conf) => outDir / (prefix(conf.name) + "api") }
	)
	def addBaseSources = Seq(
		unmanagedSources <<= (unmanagedSources, baseDirectory, includeFilter in unmanagedSources, excludeFilter in unmanagedSources) map {
			(srcs,b,f,excl) => (srcs +++ b * (f -- excl)).get
		}
	)

	def compileBase = inTask(console)(compilersSetting :: Nil) ++ Seq(
		classpathOptions in GlobalScope :== ClasspathOptions.boot,
		classpathOptions in GlobalScope in console :== ClasspathOptions.repl,
		compileOrder in GlobalScope :== CompileOrder.Mixed,
		compilersSetting,
		javacOptions in GlobalScope :== Nil,
		scalacOptions in GlobalScope :== Nil,
		scalaInstance <<= scalaInstanceSetting,
		scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version),
		scalaBinaryVersion in GlobalScope <<= scalaVersion apply binaryScalaVersion,
		crossVersion <<= (crossPaths, scalaVersion) { (enabled, sv) =>
			if(enabled)
				if(isStable(sv)) CrossVersion.binary else CrossVersion.full
			else
				CrossVersion.Disabled
		},
		crossScalaVersions in GlobalScope <<= Seq(scalaVersion).join,
		crossTarget <<= (target, scalaBinaryVersion, sbtBinaryVersion, sbtPlugin, crossPaths)(makeCrossTarget)
	)
	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 <<= (scalaInstance, appConfiguration, streams, classpathOptions, javaHome) map { (si, app, s, co, jh) => Compiler.compilers(si, co, jh)(app, s.log) }

	lazy val configTasks = docTaskSettings(doc) ++ compileTaskSettings ++ compileInputsSettings ++ Seq(
		initialCommands in GlobalScope :== "",
		cleanupCommands in GlobalScope :== "",
		compile <<= compileTask tag(Tags.Compile, Tags.CPU),
		printWarnings <<= printWarningsTask,
		compileIncSetup <<= compileIncSetupTask,
		console <<= consoleTask,
		consoleQuick <<= consoleQuickTask,
		discoveredMainClasses <<= compile map discoverMainClasses storeAs discoveredMainClasses triggeredBy compile,
		definedSbtPlugins <<= discoverPlugins,
		inTask(run)(runnerTask :: Nil).head,
		selectMainClass <<= (discoveredMainClasses, mainClass) map { (classes, explicit) => explicit orElse selectRunMain(classes) },
		mainClass in run <<= selectMainClass in run,
		mainClass <<= discoveredMainClasses map selectPackageMain,
		run <<= runTask(fullClasspath, mainClass in run, runner in run),
		runMain <<= runMainTask(fullClasspath, runner in run),
		copyResources <<= copyResourcesTask
	)

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

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

	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]]] =
		inDependencies[Task[Seq[File]]](watchSources.task, const(std.TaskExtra.constant(Nil)), aggregate = true, includeRoot = true) apply { _.join.map(_.flatten) }

	def transitiveUpdateTask: Initialize[Task[Seq[UpdateReport]]] =
		forDependencies(ref => (update.task in ref).?, aggregate = false, includeRoot = false) apply( _.flatten.join)

	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 => error("key not found: " + Project.displayFull(key))
			}
		}
	}
	def scalaInstanceSetting = (appConfiguration, scalaVersion, scalaHome) map { (app, version, home) =>
		val launcher = app.provider.scalaProvider.launcher
		home match {
			case None => ScalaInstance(version, launcher)
			case Some(h) => ScalaInstance(h, launcher)
		}
	}

	lazy val testTasks: Seq[Setting[_]] = testTaskOptions(test) ++ testTaskOptions(testOnly) ++ testTaskOptions(testQuick) ++ Seq(
		testLoader <<= (fullClasspath, scalaInstance, taskTemporaryDirectory) map { (cp, si, temp) => TestFramework.createTestLoader(data(cp), si, IO.createUniqueDirectory(temp)) },
		testFrameworks in GlobalScope :== {
			import sbt.TestFrameworks._
			Seq(ScalaCheck, Specs2, Specs, ScalaTest, JUnit)
		},
		loadedTestFrameworks <<= (testFrameworks, streams, testLoader) map { (frameworks, s, loader) =>
			frameworks.flatMap(f => f.create(loader, s.log).map( x => (f,x)).toIterable).toMap
		},
		definedTests <<= detectTests,
		definedTestNames <<= definedTests map ( _.map(_.name).distinct) storeAs definedTestNames triggeredBy compile,
		testListeners in GlobalScope :== Nil,
		testOptions in GlobalScope :== Nil,
		testFilter in testOnly :== (selectedFilter _),
		testFilter in testQuick <<= testQuickFilter,
		executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test) flatMap {
			(s, frameworkMap, loader, groups, config, cp, javaHome) =>
				val tasks = groups map {
					case Tests.Group(name, tests, runPolicy) =>
						runPolicy match {
							case Tests.SubProcess(javaOpts) =>
								ForkTests(frameworkMap.keys.toSeq, tests.toList, config, cp.files, javaHome, javaOpts, s.log) tag Tags.ForkedTestGroup
							case Tests.InProcess =>
								Tests(frameworkMap, loader, tests, config, s.log)
						}
				}
				Tests.foldTasks(tasks)
		},
		test <<= (executeTests, streams, resolvedScoped, state) map { 
			(results, s, scoped, st) =>
				implicit val display = Project.showContextKey(st)
				Tests.showResults(s.log, results, noTestsMessage(scoped))
		},
		testOnly <<= inputTests(testOnly),
		testQuick <<= inputTests(testQuick)
	)
	private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
		"No tests to run for " + display(scoped)

	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 <<= (streams, resolvedScoped, streamsManager, logBuffered, cacheDirectory in test, testListeners in TaskGlobal) map { (s, sco, sm, buff, dir, ls) =>
			TestLogger(s.log, testLogger(sm, test in sco.scope), buff) +: new TestStatusReporter(succeededFile(dir)) +: ls
		},
		testOptions <<= (testOptions in TaskGlobal, testListeners) map { (options, ls) => Tests.Listeners(ls) +: options },
		testExecution <<= testExecutionTask(key),
		testGrouping <<= testGrouping or singleTestGroup(key)
	) )
	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
	}
	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]]] =
		((definedTests in key, fork in key, javaOptions in key) map {
			(tests, fork, javaOpts) => Seq(new Tests.Group("<default>", tests, if (fork) Tests.SubProcess(javaOpts) else Tests.InProcess))
		})

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

	def testQuickFilter: Initialize[Task[Seq[String] => String => Boolean]] =
	  (fullClasspath in test, cacheDirectory) map {
			(cp, dir) =>
				val ans = cp.flatMap(_.metadata get Keys.analysis)
				val succeeded = TestStatus.read(succeededFile(dir))
				val stamps = collection.mutable.Map.empty[File, Long]
				def stamp(dep: String): Long = {
					val stamps = for (a <- ans; f <- a.relations.definesClass(dep)) yield intlStamp(f, a, Set.empty)
					if (stamps.isEmpty) Long.MinValue else stamps.max
				}
				def intlStamp(f: File, analysis: inc.Analysis, s: Set[File]): Long = {
					if (s contains f) Long.MinValue else
						stamps.getOrElseUpdate(f, {
							import analysis.{relations => rel, apis}
							rel.internalSrcDeps(f).map(intlStamp(_, analysis, s + f)) ++
							rel.externalDeps(f).map(stamp) +
							apis.internal(f).compilation.startTime
						}.max)
				}
				args => test => selectedFilter(args)(test) && {
					succeeded.get(test) match {
						case None => true
						case Some(ts) => stamp(test) > ts
					}
				}
		}
	def succeededFile(dir: File) = dir / "succeeded_tests"

	def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] =
		InputTask( loadForParser(definedTestNames)( (s, i) => testOnlyParser(s, i getOrElse Nil) ) ) { result =>
			(streams, loadedTestFrameworks, testFilter in key, testGrouping in key, testExecution in key, testLoader, resolvedScoped, result, fullClasspath in key, javaHome in key, state) flatMap {
				case (s, frameworks, filter, groups, config, loader, scoped, (selected, frameworkOptions), cp, javaHome, st) =>
					implicit val display = Project.showContextKey(st)
					val tasks = groups map {
						case Tests.Group(name, tests, runPolicy) =>
							val modifiedOpts = Tests.Filter(filter(selected)) +: Tests.Argument(frameworkOptions : _*) +: config.options
							val newConfig = config.copy(options = modifiedOpts)
							runPolicy match {
								case Tests.SubProcess(javaOpts) =>
									ForkTests(frameworks.keys.toSeq, tests.toList, newConfig, cp.files, javaHome, javaOpts, s.log) tag Tags.ForkedTestGroup
								case Tests.InProcess =>
									Tests(frameworks, loader, tests, newConfig, s.log)
							}
					}
					Tests.foldTasks(tasks) map (Tests.showResults(s.log, _, noTestsMessage(scoped)))
			}
		}

	def selectedFilter(args: Seq[String]): String => Boolean =
	{
		val filters = args map GlobFilter.apply
		s => filters.isEmpty || filters.exists { _ accept s }
	}
	def detectTests: Initialize[Task[Seq[TestDefinition]]] = (loadedTestFrameworks, compile, streams) map { (frameworkMap, analysis, s) =>
		Tests.discover(frameworkMap.values.toSeq, 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 <<= moduleName(n => Artifact(n)),
		packageOptions in GlobalScope :== Nil,
		artifactName in GlobalScope :== ( 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 <<= (name, version, organizationName, packageOptions) map { Package.addSpecManifestAttributes(_, _, _) +: _ })) ++
	packageTaskSettings(packageBin, packageBinMappings) ++<commit_msg>Extract common code to a separate method.<commit_after>/* sbt -- Simple Build Tool
 * Copyright 2011 <NAME>
 */
package sbt

	import Build.data
	import Scope.{fillTaskAxis, GlobalScope, ThisScope}
	import xsbt.api.Discovery
	import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting, SettingsDefinition}
	import Load.LoadedBuild
	import Artifact.{DocClassifier, SourceClassifier}
	import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
	import CrossVersion.{binarySbtVersion, binaryScalaVersion, isStable, selectVersion}
	import complete._
	import std.TaskExtra._
	import inc.{FileValueCache, Locate}
	import org.scalatools.testing.{Framework, AnnotatedFingerprint, SubclassFingerprint}

	import sys.error
	import scala.xml.NodeSeq
	import org.apache.ivy.core.module.{descriptor, id}
	import descriptor.ModuleDescriptor, id.ModuleRevisionId
	import java.io.File
	import java.net.URL
	import java.util.concurrent.Callable
	import sbinary.DefaultProtocol.StringFormat
	import Cache.seqFormat

	import Types._
	import Path._
	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 == "compile") "main" else config
	def prefix(config: String) = if(config == "compile") "" else config + "-"

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

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

	def analysisMap[T](cp: Seq[Attributed[T]]): Map[T, inc.Analysis] =
		(for(a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an) ).toMap

	def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
	def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
		managedDirectory <<= baseDirectory(_ / "lib_managed")
	))
	def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq(
		crossVersion :== CrossVersion.Disabled,
		buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies,
		taskTemporaryDirectory := IO.createTemporaryDirectory,
		onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) },
		concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions,
		parallelExecution :== true,
		sbtVersion <<= appConfiguration { _.provider.id.version },
		sbtBinaryVersion <<= sbtVersion apply binarySbtVersion,
		sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeReleases },
		pollInterval :== 500,
		logBuffered :== false,
		connectInput :== false,
		cancelable :== false,
		autoScalaLibrary :== true,
		onLoad <<= onLoad ?? idFun[State],
		onUnload <<= (onUnload ?? idFun[State]),
		onUnload <<= (onUnload, taskTemporaryDirectory) { (f, dir) => s => { try f(s) finally IO.delete(dir) } },
		watchingMessage <<= watchingMessage ?? Watched.defaultWatchingMessage,
		triggeredMessage <<= triggeredMessage ?? Watched.defaultTriggeredMessage,
		definesClass :== FileValueCache(Locate.definesClass _ ).get,
		trapExit :== false,
		trapExit in run :== true,
		traceLevel in run :== 0,
		traceLevel in runMain :== 0,
		traceLevel in console :== Int.MaxValue,
		traceLevel in consoleProject :== Int.MaxValue,
		autoCompilerPlugins :== true,
		internalConfigurationMap :== Configurations.internalMap _,
		initialize :== (),
		credentials :== Nil,
		scalaHome :== None,
		javaHome :== None,
		extraLoggers :== { _ => Nil },
		skip :== false,
		watchSources :== Nil,
		version :== "0.1-SNAPSHOT",
		outputStrategy :== None,
		exportJars :== false,
		fork :== false,
		javaOptions :== Nil,
		sbtPlugin :== false,
		crossPaths :== true,
		classpathTypes :== Set("jar", "bundle"),
		aggregate :== true,
		maxErrors :== 100,
		showTiming :== true,
		timingFormat :== Aggregation.defaultFormat,
		showSuccess :== true,
		commands :== Nil,
		retrieveManaged :== false,
		buildStructure <<= state map Project.structure,
		settings <<= buildStructure map ( _.data ),
		artifactClassifier :== None,
		artifactClassifier in packageSrc :== Some(SourceClassifier),
		artifactClassifier in packageDoc :== Some(DocClassifier),
		checksums <<= appConfiguration(Classpaths.bootChecksums),
		pomExtra :== NodeSeq.Empty,
		pomPostProcess :== idFun,
		pomAllRepositories :== false,
		includeFilter :== NothingFilter,
		includeFilter in unmanagedSources :== "*.java" | "*.scala",
		includeFilter in unmanagedJars :== "*.jar" | "*.so" | "*.dll",
		includeFilter in unmanagedResources :== AllPassFilter,
		excludeFilter :== (".*"  - ".") || HiddenFileFilter,
		pomIncludeRepository :== Classpaths.defaultRepositoryFilter
	))
	def defaultTestTasks(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq(
		tags := Seq(Tags.Test -> 1),
		logBuffered := true
	))
	def projectCore: Seq[Setting[_]] = Seq(
		name <<= thisProject(_.id),
		logManager <<= extraLoggers(LogManager.defaults),
		onLoadMessage <<= onLoadMessage or (name, thisProjectRef)("Set current project to " + _ + " (in build " + _.build +")"),
		runnerTask
	)
	def paths = Seq(
		baseDirectory <<= thisProject(_.base),
		target <<= baseDirectory / "target",
		historyPath <<= target(t => Some(t / ".history")),
		sourceDirectory <<= baseDirectory / "src",
		sourceManaged <<= crossTarget / "src_managed",
		resourceManaged <<= crossTarget / "resource_managed",
		cacheDirectory <<= (crossTarget, thisProject)(_ / CacheDirectoryName / _.id / "global")
	)

	lazy val configPaths = sourceConfigPaths ++ resourceConfigPaths ++ outputConfigPaths
	lazy val sourceConfigPaths = Seq(
		sourceDirectory <<= configSrcSub(sourceDirectory),
		sourceManaged <<= configSrcSub(sourceManaged),
		scalaSource <<= sourceDirectory / "scala",
		javaSource <<= sourceDirectory / "java",
		unmanagedSourceDirectories <<= Seq(scalaSource, javaSource).join,
			// remove when sourceFilter, defaultExcludes are removed
		includeFilter in unmanagedSources <<= (sourceFilter in unmanagedSources) or (includeFilter in unmanagedSources),
		excludeFilter in unmanagedSources <<= (defaultExcludes in unmanagedSources) or (excludeFilter in unmanagedSources),
		unmanagedSources <<= collectFiles(unmanagedSourceDirectories, includeFilter in unmanagedSources, excludeFilter in unmanagedSources),
		watchSources in ConfigGlobal <++= unmanagedSources,
		managedSourceDirectories <<= Seq(sourceManaged).join,
		managedSources <<= generate(sourceGenerators),
		sourceGenerators :== Nil,
		sourceDirectories <<= Classpaths.concatSettings(unmanagedSourceDirectories, managedSourceDirectories),
		sources <<= Classpaths.concat(unmanagedSources, managedSources)
	)
	lazy val resourceConfigPaths = Seq(
		resourceDirectory <<= sourceDirectory / "resources",
		resourceManaged <<= configSrcSub(resourceManaged),
		unmanagedResourceDirectories <<= Seq(resourceDirectory).join,
		managedResourceDirectories <<= Seq(resourceManaged).join,
		resourceDirectories <<= Classpaths.concatSettings(unmanagedResourceDirectories, managedResourceDirectories),
			// remove when defaultExcludes are removed
		excludeFilter in unmanagedResources <<= (defaultExcludes in unmanagedResources) or (excludeFilter in unmanagedResources),
		unmanagedResources <<= collectFiles(unmanagedResourceDirectories, includeFilter in unmanagedResources, excludeFilter in unmanagedResources),
		watchSources in ConfigGlobal <++= unmanagedResources,
		resourceGenerators :== Nil,
		resourceGenerators <+= (definedSbtPlugins, resourceManaged) map writePluginsDescriptor,
		managedResources <<= generate(resourceGenerators),
		resources <<= Classpaths.concat(managedResources, unmanagedResources)
	)
	lazy val outputConfigPaths = Seq(
		cacheDirectory <<= (crossTarget, thisProject, configuration) { _ / CacheDirectoryName / _.id / _.name },
		classDirectory <<= (crossTarget, configuration) { (outDir, conf) => outDir / (prefix(conf.name) + "classes") },
		docDirectory <<= (crossTarget, configuration) { (outDir, conf) => outDir / (prefix(conf.name) + "api") }
	)
	def addBaseSources = Seq(
		unmanagedSources <<= (unmanagedSources, baseDirectory, includeFilter in unmanagedSources, excludeFilter in unmanagedSources) map {
			(srcs,b,f,excl) => (srcs +++ b * (f -- excl)).get
		}
	)

	def compileBase = inTask(console)(compilersSetting :: Nil) ++ Seq(
		classpathOptions in GlobalScope :== ClasspathOptions.boot,
		classpathOptions in GlobalScope in console :== ClasspathOptions.repl,
		compileOrder in GlobalScope :== CompileOrder.Mixed,
		compilersSetting,
		javacOptions in GlobalScope :== Nil,
		scalacOptions in GlobalScope :== Nil,
		scalaInstance <<= scalaInstanceSetting,
		scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version),
		scalaBinaryVersion in GlobalScope <<= scalaVersion apply binaryScalaVersion,
		crossVersion <<= (crossPaths, scalaVersion) { (enabled, sv) =>
			if(enabled)
				if(isStable(sv)) CrossVersion.binary else CrossVersion.full
			else
				CrossVersion.Disabled
		},
		crossScalaVersions in GlobalScope <<= Seq(scalaVersion).join,
		crossTarget <<= (target, scalaBinaryVersion, sbtBinaryVersion, sbtPlugin, crossPaths)(makeCrossTarget)
	)
	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 <<= (scalaInstance, appConfiguration, streams, classpathOptions, javaHome) map { (si, app, s, co, jh) => Compiler.compilers(si, co, jh)(app, s.log) }

	lazy val configTasks = docTaskSettings(doc) ++ compileTaskSettings ++ compileInputsSettings ++ Seq(
		initialCommands in GlobalScope :== "",
		cleanupCommands in GlobalScope :== "",
		compile <<= compileTask tag(Tags.Compile, Tags.CPU),
		printWarnings <<= printWarningsTask,
		compileIncSetup <<= compileIncSetupTask,
		console <<= consoleTask,
		consoleQuick <<= consoleQuickTask,
		discoveredMainClasses <<= compile map discoverMainClasses storeAs discoveredMainClasses triggeredBy compile,
		definedSbtPlugins <<= discoverPlugins,
		inTask(run)(runnerTask :: Nil).head,
		selectMainClass <<= (discoveredMainClasses, mainClass) map { (classes, explicit) => explicit orElse selectRunMain(classes) },
		mainClass in run <<= selectMainClass in run,
		mainClass <<= discoveredMainClasses map selectPackageMain,
		run <<= runTask(fullClasspath, mainClass in run, runner in run),
		runMain <<= runMainTask(fullClasspath, runner in run),
		copyResources <<= copyResourcesTask
	)

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

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

	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]]] =
		inDependencies[Task[Seq[File]]](watchSources.task, const(std.TaskExtra.constant(Nil)), aggregate = true, includeRoot = true) apply { _.join.map(_.flatten) }

	def transitiveUpdateTask: Initialize[Task[Seq[UpdateReport]]] =
		forDependencies(ref => (update.task in ref).?, aggregate = false, includeRoot = false) apply( _.flatten.join)

	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 => error("key not found: " + Project.displayFull(key))
			}
		}
	}
	def scalaInstanceSetting = (appConfiguration, scalaVersion, scalaHome) map { (app, version, home) =>
		val launcher = app.provider.scalaProvider.launcher
		home match {
			case None => ScalaInstance(version, launcher)
			case Some(h) => ScalaInstance(h, launcher)
		}
	}

	lazy val testTasks: Seq[Setting[_]] = testTaskOptions(test) ++ testTaskOptions(testOnly) ++ testTaskOptions(testQuick) ++ Seq(
		testLoader <<= (fullClasspath, scalaInstance, taskTemporaryDirectory) map { (cp, si, temp) => TestFramework.createTestLoader(data(cp), si, IO.createUniqueDirectory(temp)) },
		testFrameworks in GlobalScope :== {
			import sbt.TestFrameworks._
			Seq(ScalaCheck, Specs2, Specs, ScalaTest, JUnit)
		},
		loadedTestFrameworks <<= (testFrameworks, streams, testLoader) map { (frameworks, s, loader) =>
			frameworks.flatMap(f => f.create(loader, s.log).map( x => (f,x)).toIterable).toMap
		},
		definedTests <<= detectTests,
		definedTestNames <<= definedTests map ( _.map(_.name).distinct) storeAs definedTestNames triggeredBy compile,
		testListeners in GlobalScope :== Nil,
		testOptions in GlobalScope :== Nil,
		testFilter in testOnly :== (selectedFilter _),
		testFilter in testQuick <<= testQuickFilter,
		executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test) flatMap allTestGroupsTask,
		test <<= (executeTests, streams, resolvedScoped, state) map { 
			(results, s, scoped, st) =>
				implicit val display = Project.showContextKey(st)
				Tests.showResults(s.log, results, noTestsMessage(scoped))
		},
		testOnly <<= inputTests(testOnly),
		testQuick <<= inputTests(testQuick)
	)
	private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
		"No tests to run for " + display(scoped)

	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 <<= (streams, resolvedScoped, streamsManager, logBuffered, cacheDirectory in test, testListeners in TaskGlobal) map { (s, sco, sm, buff, dir, ls) =>
			TestLogger(s.log, testLogger(sm, test in sco.scope), buff) +: new TestStatusReporter(succeededFile(dir)) +: ls
		},
		testOptions <<= (testOptions in TaskGlobal, testListeners) map { (options, ls) => Tests.Listeners(ls) +: options },
		testExecution <<= testExecutionTask(key),
		testGrouping <<= testGrouping or singleTestGroup(key)
	) )
	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
	}
	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]]] =
		((definedTests in key, fork in key, javaOptions in key) map {
			(tests, fork, javaOpts) => Seq(new Tests.Group("<default>", tests, if (fork) Tests.SubProcess(javaOpts) else Tests.InProcess))
		})

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

	def testQuickFilter: Initialize[Task[Seq[String] => String => Boolean]] =
	  (fullClasspath in test, cacheDirectory) map {
			(cp, dir) =>
				val ans = cp.flatMap(_.metadata get Keys.analysis)
				val succeeded = TestStatus.read(succeededFile(dir))
				val stamps = collection.mutable.Map.empty[File, Long]
				def stamp(dep: String): Long = {
					val stamps = for (a <- ans; f <- a.relations.definesClass(dep)) yield intlStamp(f, a, Set.empty)
					if (stamps.isEmpty) Long.MinValue else stamps.max
				}
				def intlStamp(f: File, analysis: inc.Analysis, s: Set[File]): Long = {
					if (s contains f) Long.MinValue else
						stamps.getOrElseUpdate(f, {
							import analysis.{relations => rel, apis}
							rel.internalSrcDeps(f).map(intlStamp(_, analysis, s + f)) ++
							rel.externalDeps(f).map(stamp) +
							apis.internal(f).compilation.startTime
						}.max)
				}
				args => test => selectedFilter(args)(test) && {
					succeeded.get(test) match {
						case None => true
						case Some(ts) => stamp(test) > ts
					}
				}
		}
	def succeededFile(dir: File) = dir / "succeeded_tests"

	def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] =
		InputTask( loadForParser(definedTestNames)( (s, i) => testOnlyParser(s, i getOrElse Nil) ) ) { result =>
			(streams, loadedTestFrameworks, testFilter in key, testGrouping in key, testExecution in key, testLoader, resolvedScoped, result, fullClasspath in key, javaHome in key, state) flatMap {
				case (s, frameworks, filter, groups, config, loader, scoped, (selected, frameworkOptions), cp, javaHome, st) =>
					implicit val display = Project.showContextKey(st)
					val modifiedOpts = Tests.Filter(filter(selected)) +: Tests.Argument(frameworkOptions : _*) +: config.options
					val newConfig = config.copy(options = modifiedOpts)
					allTestGroupsTask(s, frameworks, loader, groups, newConfig, cp, javaHome) map (Tests.showResults(s.log, _, noTestsMessage(scoped)))
			}
		}

	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] = {
		val groupTasks = groups map {
			case Tests.Group(name, tests, runPolicy) =>
				runPolicy match {
					case Tests.SubProcess(javaOpts) =>
						ForkTests(frameworks.keys.toSeq, tests.toList, config, cp.files, javaHome, javaOpts, s.log) tag Tags.ForkedTestGroup
					case Tests.InProcess =>
						Tests(frameworks, loader, tests, config, s.log)
				}
		}
		Tests.foldTasks(groupTasks)
	}

	def selectedFilter(args: Seq[String]): String => Boolean =
	{
		val filters = args map GlobFilter.apply
		s => filters.isEmpty || filters.exists { _ accept s }
	}
	def detectTests: Initialize[Task[Seq[TestDefinition]]] = (loadedTestFrameworks, compile, streams) map { (frameworkMap, analysis, s) =>
		Tests.discover(frameworkMap.values.toSeq, 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 <<= moduleName(n => Artifact(n)),
		packageOptions in GlobalScope :== Nil,
		artifactName in GlobalScope :== ( 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 <<= (name, version, organizationName, packageOptions) map { Package.addSpecManifestAttributes(_, _, _) +: _ })) ++
	packageTaskSettings(packageBin, packageBinMappings) ++
{'fraction_non_alphanumeric': 0.1287565211001984, 'fraction_numerical': 0.0009307110142300816, 'mean_word_length': 5.244074017433858, 'pattern_counts': {'":': 0, '<': 389, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1832725', 'n_tokens_mistral': 13663, 'n_tokens_neox': 12455, 'n_words': 3045}