mirror of https://github.com/sbt/sbt.git
This commit is contained in:
parent
48be806dd4
commit
9294351e24
|
|
@ -6,15 +6,11 @@ package sbt
|
|||
import java.io.File
|
||||
import java.net.URI
|
||||
import Def.{ ScopedKey, Setting }
|
||||
import Project._
|
||||
import Types.Endo
|
||||
import compiler.Eval
|
||||
|
||||
import SessionSettings._
|
||||
|
||||
import scala.collection.immutable.SortedMap
|
||||
|
||||
|
||||
/**
|
||||
* Represents (potentially) transient settings added into a build via commands/user.
|
||||
*
|
||||
|
|
@ -85,16 +81,18 @@ object SessionSettings {
|
|||
type SessionSetting = (Setting[_], List[String])
|
||||
type SessionMap = Map[ProjectRef, Seq[SessionSetting]]
|
||||
|
||||
/** This will re-evaluate all Setting[_]'s on this session against the current build state and
|
||||
* return the new build state.
|
||||
*/
|
||||
/**
|
||||
* This will re-evaluate all Setting[_]'s on this session against the current build state and
|
||||
* return the new build state.
|
||||
*/
|
||||
def reapply(session: SessionSettings, s: State): State =
|
||||
BuiltinCommands.reapply(session, Project.structure(s), s)
|
||||
|
||||
/** This will clear any user-added session settings for a given build state and return the new build state.
|
||||
*
|
||||
* Note: Does not clear `rawAppend` settings
|
||||
*/
|
||||
/**
|
||||
* This will clear any user-added session settings for a given build state and return the new build state.
|
||||
*
|
||||
* Note: Does not clear `rawAppend` settings
|
||||
*/
|
||||
def clearSettings(s: State): State =
|
||||
withSettings(s)(session => reapply(session.copy(append = session.append - session.current), s))
|
||||
/** This will clear ALL transient session settings in a given build state, returning the new build state. */
|
||||
|
|
@ -128,9 +126,6 @@ object SessionSettings {
|
|||
if (newSession.append.isEmpty && !oldSettings.isEmpty)
|
||||
oldState.log.warn("Discarding " + pluralize(oldSettings.size, " session setting") + ". Use 'session save' to persist session settings.")
|
||||
}
|
||||
|
||||
|
||||
|
||||
def removeRanges[T](in: Seq[T], ranges: Seq[(Int, Int)]): Seq[T] =
|
||||
{
|
||||
val asSet = (Set.empty[Int] /: ranges) { case (s, (hi, lo)) => s ++ (hi to lo) }
|
||||
|
|
@ -151,11 +146,12 @@ object SessionSettings {
|
|||
saveSomeSettings(s)(_ == current)
|
||||
}
|
||||
|
||||
/** Saves session settings to disk if they match the filter.
|
||||
* @param s The build state
|
||||
* @param include A filter function to determine which project's settings to persist.
|
||||
* @return The new build state.
|
||||
*/
|
||||
/**
|
||||
* Saves session settings to disk if they match the filter.
|
||||
* @param s The build state
|
||||
* @param include A filter function to determine which project's settings to persist.
|
||||
* @return The new build state.
|
||||
*/
|
||||
def saveSomeSettings(s: State)(include: ProjectRef => Boolean): State =
|
||||
withSettings(s) { session =>
|
||||
val newSettings =
|
||||
|
|
@ -182,23 +178,21 @@ object SessionSettings {
|
|||
}
|
||||
}
|
||||
|
||||
val (_, oldShifted, replace, lineMap) = ((0, List[Setting[_]](), List[SessionSetting](), SortedMap.empty[Int, List[(Int, List[String])]](Ordering[Int].reverse)) /: inFile) {
|
||||
case ((offs, olds, repl, lineMap), s) =>
|
||||
val (_, oldShifted, replace, statements) = ((0, List[Setting[_]](), List[SessionSetting](), List[List[String]]()) /: inFile) {
|
||||
case ((offs, olds, repl, statements), s) =>
|
||||
val RangePosition(_, r @ LineRange(start, end)) = s.pos
|
||||
settings find (_._1.key == s.key) match {
|
||||
case Some(ss @ (ns, newLines)) if !ns.init.dependencies.contains(ns.key) =>
|
||||
val shifted = ns withPos RangePosition(path, LineRange(start - offs, start - offs + newLines.size))
|
||||
val head = (end, newLines)
|
||||
val seq = lineMap.getOrElse(start, List())
|
||||
(offs + end - start - newLines.size, shifted :: olds, ss :: repl, lineMap + (start -> (head +: seq)))
|
||||
(offs + end - start - newLines.size, shifted :: olds, ss :: repl, newLines +: statements)
|
||||
case _ =>
|
||||
val shifted = s withPos RangePosition(path, r shift -offs)
|
||||
(offs, shifted :: olds, repl, lineMap)
|
||||
(offs, shifted :: olds, repl, statements)
|
||||
}
|
||||
}
|
||||
val newSettings = settings diff replace
|
||||
val oldContent = IO.readLines(writeTo)
|
||||
val exist: List[String] = SessionSettingsNoBlankies.oldLinesToNew(oldContent, lineMap)
|
||||
val exist: List[String] = SessionSettingsNoBlankies.oldLinesToNew(oldContent, statements)
|
||||
val adjusted = if (!newSettings.isEmpty && needsTrailingBlank(exist)) exist :+ "" else exist
|
||||
val lines = adjusted ++ newSettings.flatMap(_._2 ::: "" :: Nil)
|
||||
IO.writeLines(writeTo, lines)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
|
||||
import sbt.internals.parser.{ XmlContent, SplitExpressionsNoBlankies }
|
||||
import scala.collection.immutable.SortedMap
|
||||
import scala.reflect.runtime.universe._
|
||||
import sbt.internals.parser.{ XmlContent, SplitExpressionsNoBlankies }
|
||||
|
||||
object SessionSettingsNoBlankies {
|
||||
|
||||
|
|
@ -12,65 +9,43 @@ object SessionSettingsNoBlankies {
|
|||
|
||||
val REVERSE_ORDERING_INT = Ordering[Int].reverse
|
||||
|
||||
def oldLinesToNew(content: List[String], lineMap: SortedMap[Int, List[(Int, List[String])]]): List[String] =
|
||||
if (lineMap.isEmpty) {
|
||||
content
|
||||
} else {
|
||||
val head = lineMap.head
|
||||
val newContent = toNewContent(content, head)
|
||||
oldLinesToNew(newContent, lineMap.tail)
|
||||
}
|
||||
|
||||
private def toNewContent(content: List[String], setCommands: (Int, List[(Int, List[String])])): List[String] = {
|
||||
val (from, newSettings) = setCommands
|
||||
|
||||
val newTreeStringsMap = newSettings.map {
|
||||
case (_, lines) => toTreeStringMap(lines)
|
||||
}
|
||||
val to = newSettings.map(_._1).max
|
||||
val originalLine = content.slice(from - 1, to - 1)
|
||||
|
||||
val operations = newTreeStringsMap.flatMap {
|
||||
map =>
|
||||
def oldLinesToNew(lines: List[String], setCommands: List[List[String]]): List[String] = {
|
||||
val split = SplitExpressionsNoBlankies(FAKE_FILE, lines)
|
||||
val recordedCommand = setCommands.flatMap {
|
||||
command =>
|
||||
val map = toTreeStringMap(command)
|
||||
map.flatMap {
|
||||
case (name, (startIndex, statement)) =>
|
||||
val validLines = cutExpression(originalLine, name)
|
||||
val treeStringMap = toTreeStringMap(validLines)
|
||||
treeStringMap.get(name).map {
|
||||
case (t, oldContent) =>
|
||||
(startIndex, oldContent, statement)
|
||||
case (name, (startPos, statement)) =>
|
||||
split.settingsTrees.foldLeft(Seq.empty[(Int, String, String)]) {
|
||||
case (acc, (statement, tree)) =>
|
||||
val treeName = extractSettingName(tree)
|
||||
if (name == treeName) {
|
||||
val replacement = if (acc.isEmpty) {
|
||||
command.mkString("\n")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
(tree.pos.start, statement, replacement) +: acc
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val statements = XmlContent.handleXmlContent(originalLine.mkString("\n"))
|
||||
val sortedOperations = operations.sortBy(_._1)(REVERSE_ORDERING_INT)
|
||||
val newContent = sortedOperations.foldLeft(statements) {
|
||||
case (acc, (startIndex, old, newStatement)) =>
|
||||
acc.replace(old, newStatement)
|
||||
val sortedRecordedCommand = recordedCommand.sortBy(_._1)(REVERSE_ORDERING_INT)
|
||||
|
||||
val newContent = sortedRecordedCommand.foldLeft(split.modifiedContent) {
|
||||
case (acc, (from, old, replacement)) =>
|
||||
val before = acc.substring(0, from)
|
||||
val after = acc.substring(from + old.length, acc.length)
|
||||
before + replacement + after
|
||||
// acc.replace(old, replacement)
|
||||
}
|
||||
val newLines = newContent.lines.toList
|
||||
content.take(from - 1) ++ newLines ++ content.drop(to - 1)
|
||||
newContent.lines.toList
|
||||
}
|
||||
|
||||
private[sbt] def cutExpression(l: List[String], name: String): List[String] = l match {
|
||||
case h +: t =>
|
||||
val statements = SplitExpressionsNoBlankies(FAKE_FILE, l).settingsTrees
|
||||
val lastIndex = statements.lastIndexWhere {
|
||||
tuple => extractSettingName(tuple._2) == name
|
||||
}
|
||||
val (statement, tree) = statements(lastIndex)
|
||||
|
||||
if (tree.pos.end >= h.length) {
|
||||
l
|
||||
} else {
|
||||
statement +: t
|
||||
}
|
||||
case _ =>
|
||||
l
|
||||
}
|
||||
|
||||
private def toTreeStringMap(lines: List[String]) = {
|
||||
val split = SplitExpressionsNoBlankies(FAKE_FILE, lines)
|
||||
private def toTreeStringMap(command: List[String]) = {
|
||||
val split = SplitExpressionsNoBlankies(FAKE_FILE, command)
|
||||
val trees = split.settingsTrees
|
||||
val seq = trees.map {
|
||||
case (statement, tree) =>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ package parser
|
|||
|
||||
import java.io.File
|
||||
|
||||
import sbt.internals.parser.SplitExpressionsNoBlankies._
|
||||
import SplitExpressionsNoBlankies._
|
||||
import scala.annotation.tailrec
|
||||
import scala.reflect.runtime.universe
|
||||
import scala.reflect.runtime.universe._
|
||||
|
||||
private[sbt] object SplitExpressionsNoBlankies {
|
||||
|
|
@ -17,14 +16,14 @@ private[sbt] object SplitExpressionsNoBlankies {
|
|||
|
||||
private[sbt] case class SplitExpressionsNoBlankies(file: File, lines: Seq[String]) {
|
||||
//settingsTrees needed for "session save"
|
||||
val (imports, settings, settingsTrees) = splitExpressions(file, lines)
|
||||
val (imports, settings, settingsTrees, modifiedContent) = splitExpressions(file, lines)
|
||||
|
||||
private def splitExpressions(file: File, lines: Seq[String]): (Seq[(String, Int)], Seq[(String, LineRange)], Seq[(String, Tree)]) = {
|
||||
import sbt.internals.parser.BugInParser._
|
||||
import sbt.internals.parser.XmlContent._
|
||||
private def splitExpressions(file: File, lines: Seq[String]): (Seq[(String, Int)], Seq[(String, LineRange)], Seq[(String, Tree)], String) = {
|
||||
import scala.reflect.runtime._
|
||||
|
||||
import scala.compat.Platform.EOL
|
||||
import BugInParser._
|
||||
import XmlContent._
|
||||
import scala.tools.reflect.{ ToolBox, ToolBoxError }
|
||||
|
||||
val mirror = universe.runtimeMirror(this.getClass.getClassLoader)
|
||||
|
|
@ -90,7 +89,7 @@ private[sbt] case class SplitExpressionsNoBlankies(file: File, lines: Seq[String
|
|||
None
|
||||
}
|
||||
val statementsTreeLineRange = statements flatMap convertStatement
|
||||
(imports map convertImport, statementsTreeLineRange.map(t => (t._1, t._3)), statementsTreeLineRange.map(t => (t._1, t._2)))
|
||||
(imports map convertImport, statementsTreeLineRange.map(t => (t._1, t._3)), statementsTreeLineRange.map(t => (t._1, t._2)), modifiedContent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -302,31 +301,32 @@ private[sbt] object XmlContent {
|
|||
*/
|
||||
private def addExplicitXmlContent(content: String, xmlParts: Seq[(String, Int, Int)]): String = {
|
||||
val statements: Seq[(String, Boolean)] = splitFile(content, xmlParts)
|
||||
val (builder, wasPreviousXml, wasXml, _) = statements.foldLeft((Seq.empty[String], false, false, "")) {
|
||||
(acc, el) =>
|
||||
val (bAcc, wasXml, _, previous) = acc
|
||||
val (content, isXml) = el
|
||||
val contentEmpty = content.trim.isEmpty
|
||||
val (isNotCommentedXml, newAcc) = if (isXml) {
|
||||
if (!wasXml) {
|
||||
if (areBracketsNecessary(previous)) {
|
||||
(true, " ( " +: bAcc)
|
||||
} else {
|
||||
(false, bAcc)
|
||||
}
|
||||
} else {
|
||||
(true, bAcc)
|
||||
}
|
||||
} else if (wasXml && !contentEmpty) {
|
||||
(false, " ) " +: bAcc)
|
||||
val (builder, addCloseBrackets, wasXml, _) = statements.foldLeft((Seq.empty[String], false, false, "")) {
|
||||
case ((bAcc, addCloseBrackets, wasXml, previous), (content, isXml)) =>
|
||||
if (content.trim.isEmpty) {
|
||||
(content +: bAcc, addCloseBrackets, wasXml, content)
|
||||
} else {
|
||||
(false, bAcc)
|
||||
}
|
||||
val (newAddCloseBrackets, newAcc) = if (isXml) {
|
||||
if (wasXml) {
|
||||
(addCloseBrackets, bAcc)
|
||||
} else {
|
||||
if (areBracketsNecessary(previous)) {
|
||||
(true, " ( " +: bAcc)
|
||||
} else {
|
||||
(false, bAcc)
|
||||
}
|
||||
}
|
||||
} else if (addCloseBrackets) {
|
||||
(false, " ) " +: bAcc)
|
||||
} else {
|
||||
(false, bAcc)
|
||||
}
|
||||
|
||||
(content +: newAcc, isNotCommentedXml || (wasXml && contentEmpty), isXml, content)
|
||||
(content +: newAcc, newAddCloseBrackets, isXml, content)
|
||||
}
|
||||
}
|
||||
val closeIfNecessaryBuilder =
|
||||
if (wasPreviousXml && !wasXml) {
|
||||
if (addCloseBrackets && wasXml) {
|
||||
builder.head +: " ) " +: builder.tail
|
||||
} else {
|
||||
builder
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ val a = <aaa>
|
|||
*/
|
||||
|
||||
|
||||
organization := "jozwikr" // OK
|
||||
organization := "scalania" // OK
|
||||
|
||||
scalaVersion := "2.9.2"
|
||||
|
||||
organization := "scalania"
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
package sbt
|
||||
|
||||
import sbt.internals.parser.AbstractSpec
|
||||
|
||||
class SessionSettingsCutExpressionSpec extends AbstractSpec {
|
||||
|
||||
"Cut expression " should {
|
||||
|
||||
"Cut only statement which we are interesting " in {
|
||||
val name = "scalaVersion"
|
||||
val expression = s"""$name := "2.9.2""""
|
||||
val line = s"""name := "newName";$expression; organization := "jozwikr""""
|
||||
SessionSettingsNoBlankies.cutExpression(List(line), name) must_== List(expression)
|
||||
}
|
||||
|
||||
"Do not cut not valid expression " in {
|
||||
val name = "k4"
|
||||
val line = s"$name := { val x = $name.value; () }"
|
||||
SessionSettingsNoBlankies.cutExpression(List(line), name) must_== List(line)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import org.specs2.matcher.MatchResult
|
|||
import sbt.internals.parser.{ AbstractSpec, SplitExpressionsNoBlankies }
|
||||
|
||||
import scala.collection.GenTraversableOnce
|
||||
import scala.collection.immutable.{ SortedMap, TreeMap }
|
||||
import scala.io.Source
|
||||
import scala.xml.XML
|
||||
|
||||
|
|
@ -17,7 +16,7 @@ abstract class AbstractSessionSettingsSpec(folder: String, printDetails: Boolean
|
|||
|
||||
"SessionSettings " should {
|
||||
"Be identical for empty map " in {
|
||||
def unit(f: File) = Seq((Source.fromFile(f).getLines().toList, SortedMap.empty[Int, List[(Int, List[String])]]))
|
||||
def unit(f: File) = Seq((Source.fromFile(f).getLines().toList, Nil))
|
||||
runTestOnFiles(unit)
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +25,7 @@ abstract class AbstractSessionSettingsSpec(folder: String, printDetails: Boolean
|
|||
}
|
||||
}
|
||||
|
||||
private def runTestOnFiles(expectedResultAndMap: File => Seq[(List[String], SortedMap[Int, List[(Int, List[String])]])]): MatchResult[GenTraversableOnce[File]] = {
|
||||
private def runTestOnFiles(expectedResultAndMap: File => Seq[(List[String], List[List[String]])]): MatchResult[GenTraversableOnce[File]] = {
|
||||
|
||||
val allFiles = rootDir.listFiles(new FilenameFilter() {
|
||||
def accept(dir: File, name: String) = name.endsWith(".sbt.txt")
|
||||
|
|
@ -64,12 +63,10 @@ abstract class AbstractSessionSettingsSpec(folder: String, printDetails: Boolean
|
|||
val set = (node \\ "set").text
|
||||
val start = (node \\ "start").text.toInt
|
||||
val end = (node \\ "end").text.toInt
|
||||
(start, (end, List(set)))
|
||||
List(set)
|
||||
}.toList
|
||||
val map = tupleCollection.groupBy(el => el._1).map {
|
||||
case (k, seq) => (k, seq.map(el => el._2))
|
||||
}
|
||||
(result, TreeMap(map.toArray: _*)(SessionSettingsNoBlankies.REVERSE_ORDERING_INT))
|
||||
|
||||
(result, tupleCollection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue