/
Cross.scala
126 lines (111 loc) · 5.25 KB
/
Cross.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import Keys._
import complete.{ DefaultParsers, Parser }
import DefaultParsers._
import Def.{ ScopedKey, Setting }
import Scope.GlobalScope
import CommandStrings.{ CrossCommand, crossHelp, SwitchCommand, switchHelp }
import java.io.File
object Cross {
@deprecated("Moved to CommandStrings.Switch", "0.13.0")
final val Switch = CommandStrings.SwitchCommand
@deprecated("Moved to CommandStrings.Cross", "0.13.0")
final val Cross = CommandStrings.CrossCommand
def switchParser(state: State): Parser[(String, String)] =
{
def versionAndCommand(spacePresent: Boolean) = {
val knownVersions = crossVersions(state)
val version = token(StringBasic.examples(knownVersions: _*))
val spacedVersion = if (spacePresent) version else version & spacedFirst(SwitchCommand)
val optionalCommand = token(Space ~> matched(state.combinedParser)) ?? ""
spacedVersion ~ optionalCommand
}
token(SwitchCommand ~> OptSpace) flatMap { sp => versionAndCommand(sp.nonEmpty) }
}
def spacedFirst(name: String) = opOrIDSpaced(name) ~ any.+
lazy val switchVersion = Command.arb(requireSession(switchParser), switchHelp) {
case (state, (arg, command)) =>
val x = Project.extract(state)
import x._
val (resolveVersion, homePath) = arg.split("=") match {
case Array(v, h) => (v, h)
case _ => ("", arg)
}
val home = IO.resolve(x.currentProject.base, new File(homePath))
// Basic Algorithm.
// 1. First we figure out what the new scala instances should be, create settings for them.
// 2. Find any non-overridden scalaVersion setting in the whole build and force it to delegate
// to the new global settings.
// 3. Append these to the session, so that the session is up-to-date and
// things like set/session clear, etc. work.
val (add, exclude) =
if (home.exists) {
val instance = ScalaInstance(home)(state.classLoaderCache.apply _)
state.log.info("Setting Scala home to " + home + " with actual version " + instance.actualVersion)
val version = if (resolveVersion.isEmpty) instance.actualVersion else resolveVersion
state.log.info("\tand using " + version + " for resolving dependencies.")
val settings = Seq(
scalaVersion in GlobalScope :== version,
scalaHome in GlobalScope :== Some(home),
scalaInstance in GlobalScope :== instance
)
(settings, excludeKeys(Set(scalaVersion.key, scalaHome.key, scalaInstance.key)))
} else if (!resolveVersion.isEmpty) {
sys.error("Scala home directory did not exist: " + home)
} else {
state.log.info("Setting version to " + arg)
val settings = Seq(
scalaVersion in GlobalScope :== arg,
scalaHome in GlobalScope :== None
)
(settings, excludeKeys(Set(scalaVersion.key, scalaHome.key)))
}
val isForceGc = getOpt(Keys.forcegc in Global) getOrElse GCUtil.defaultForceGarbageCollection
// This is how to get the interval, but ignore it, and just forcegc
// val gcInterval = getOpt(Keys.minForcegcInterval in Global) getOrElse GCUtil.defaultMinForcegcInterval
if (isForceGc) {
GCUtil.forceGc(state.log)
}
// TODO - Track delegates and avoid regenerating.
val delegates: Seq[Setting[_]] = session.mergeSettings collect {
case x if exclude(x) => delegateToGlobal(x.key)
}
val fixedSession = session.appendRaw(add ++ delegates)
val fixedState = BuiltinCommands.reapply(fixedSession, structure, state)
if (!command.isEmpty) command :: fixedState
else fixedState
}
// Creates a delegate for a scoped key that pulls the setting from the global scope.
private[this] def delegateToGlobal[T](key: ScopedKey[T]): Setting[_] =
SettingKey[T](key.key) in key.scope := (SettingKey[T](key.key) in GlobalScope).value
@deprecated("No longer used.", "0.13.0")
def crossExclude(s: Setting[_]): Boolean = excludeKeys(Set(scalaVersion.key, scalaHome.key))(s)
private[this] def excludeKeys(keys: Set[AttributeKey[_]]): Setting[_] => Boolean =
_.key match {
case ScopedKey(Scope(_, Global, Global, _), key) if keys.contains(key) => true
case _ => false
}
def crossParser(state: State): Parser[String] =
token(CrossCommand <~ OptSpace) flatMap { _ => token(matched(state.combinedParser & spacedFirst(CrossCommand))) }
lazy val crossBuild = Command.arb(requireSession(crossParser), crossHelp) { (state, command) =>
val x = Project.extract(state)
import x._
val versions = crossVersions(state)
val current = scalaVersion in currentRef get structure.data map (SwitchCommand + " " + _) toList;
if (versions.isEmpty) command :: state
else {
versions.map(v => s"$SwitchCommand $v $command") ::: current ::: state
}
}
def crossVersions(state: State): Seq[String] =
{
val x = Project.extract(state)
import x._
crossScalaVersions in currentRef get structure.data getOrElse Nil
}
def requireSession[T](p: State => Parser[T]): State => Parser[T] = s =>
if (s get sessionSettings isEmpty) failure("No project loaded") else p(s)
}