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.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import Def.{ ScopedKey, Setting }
|
import Def.{ ScopedKey, Setting }
|
||||||
import Project._
|
|
||||||
import Types.Endo
|
import Types.Endo
|
||||||
import compiler.Eval
|
import compiler.Eval
|
||||||
|
|
||||||
import SessionSettings._
|
import SessionSettings._
|
||||||
|
|
||||||
import scala.collection.immutable.SortedMap
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents (potentially) transient settings added into a build via commands/user.
|
* Represents (potentially) transient settings added into a build via commands/user.
|
||||||
*
|
*
|
||||||
|
|
@ -85,13 +81,15 @@ object SessionSettings {
|
||||||
type SessionSetting = (Setting[_], List[String])
|
type SessionSetting = (Setting[_], List[String])
|
||||||
type SessionMap = Map[ProjectRef, Seq[SessionSetting]]
|
type SessionMap = Map[ProjectRef, Seq[SessionSetting]]
|
||||||
|
|
||||||
/** This will re-evaluate all Setting[_]'s on this session against the current build state and
|
/**
|
||||||
|
* This will re-evaluate all Setting[_]'s on this session against the current build state and
|
||||||
* return the new build state.
|
* return the new build state.
|
||||||
*/
|
*/
|
||||||
def reapply(session: SessionSettings, s: State): State =
|
def reapply(session: SessionSettings, s: State): State =
|
||||||
BuiltinCommands.reapply(session, Project.structure(s), s)
|
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.
|
/**
|
||||||
|
* 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
|
* Note: Does not clear `rawAppend` settings
|
||||||
*/
|
*/
|
||||||
|
|
@ -128,9 +126,6 @@ object SessionSettings {
|
||||||
if (newSession.append.isEmpty && !oldSettings.isEmpty)
|
if (newSession.append.isEmpty && !oldSettings.isEmpty)
|
||||||
oldState.log.warn("Discarding " + pluralize(oldSettings.size, " session setting") + ". Use 'session save' to persist session settings.")
|
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] =
|
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) }
|
val asSet = (Set.empty[Int] /: ranges) { case (s, (hi, lo)) => s ++ (hi to lo) }
|
||||||
|
|
@ -151,7 +146,8 @@ object SessionSettings {
|
||||||
saveSomeSettings(s)(_ == current)
|
saveSomeSettings(s)(_ == current)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Saves session settings to disk if they match the filter.
|
/**
|
||||||
|
* Saves session settings to disk if they match the filter.
|
||||||
* @param s The build state
|
* @param s The build state
|
||||||
* @param include A filter function to determine which project's settings to persist.
|
* @param include A filter function to determine which project's settings to persist.
|
||||||
* @return The new build state.
|
* @return The new build state.
|
||||||
|
|
@ -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) {
|
val (_, oldShifted, replace, statements) = ((0, List[Setting[_]](), List[SessionSetting](), List[List[String]]()) /: inFile) {
|
||||||
case ((offs, olds, repl, lineMap), s) =>
|
case ((offs, olds, repl, statements), s) =>
|
||||||
val RangePosition(_, r @ LineRange(start, end)) = s.pos
|
val RangePosition(_, r @ LineRange(start, end)) = s.pos
|
||||||
settings find (_._1.key == s.key) match {
|
settings find (_._1.key == s.key) match {
|
||||||
case Some(ss @ (ns, newLines)) if !ns.init.dependencies.contains(ns.key) =>
|
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 shifted = ns withPos RangePosition(path, LineRange(start - offs, start - offs + newLines.size))
|
||||||
val head = (end, newLines)
|
(offs + end - start - newLines.size, shifted :: olds, ss :: repl, newLines +: statements)
|
||||||
val seq = lineMap.getOrElse(start, List())
|
|
||||||
(offs + end - start - newLines.size, shifted :: olds, ss :: repl, lineMap + (start -> (head +: seq)))
|
|
||||||
case _ =>
|
case _ =>
|
||||||
val shifted = s withPos RangePosition(path, r shift -offs)
|
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 newSettings = settings diff replace
|
||||||
val oldContent = IO.readLines(writeTo)
|
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 adjusted = if (!newSettings.isEmpty && needsTrailingBlank(exist)) exist :+ "" else exist
|
||||||
val lines = adjusted ++ newSettings.flatMap(_._2 ::: "" :: Nil)
|
val lines = adjusted ++ newSettings.flatMap(_._2 ::: "" :: Nil)
|
||||||
IO.writeLines(writeTo, lines)
|
IO.writeLines(writeTo, lines)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
import sbt.internals.parser.{ XmlContent, SplitExpressionsNoBlankies }
|
|
||||||
import scala.collection.immutable.SortedMap
|
|
||||||
import scala.reflect.runtime.universe._
|
import scala.reflect.runtime.universe._
|
||||||
|
import sbt.internals.parser.{ XmlContent, SplitExpressionsNoBlankies }
|
||||||
|
|
||||||
object SessionSettingsNoBlankies {
|
object SessionSettingsNoBlankies {
|
||||||
|
|
||||||
|
|
@ -12,65 +9,43 @@ object SessionSettingsNoBlankies {
|
||||||
|
|
||||||
val REVERSE_ORDERING_INT = Ordering[Int].reverse
|
val REVERSE_ORDERING_INT = Ordering[Int].reverse
|
||||||
|
|
||||||
def oldLinesToNew(content: List[String], lineMap: SortedMap[Int, List[(Int, List[String])]]): List[String] =
|
def oldLinesToNew(lines: List[String], setCommands: List[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 =>
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 newLines = newContent.lines.toList
|
|
||||||
content.take(from - 1) ++ newLines ++ content.drop(to - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
val split = SplitExpressionsNoBlankies(FAKE_FILE, lines)
|
||||||
|
val recordedCommand = setCommands.flatMap {
|
||||||
|
command =>
|
||||||
|
val map = toTreeStringMap(command)
|
||||||
|
map.flatMap {
|
||||||
|
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 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)
|
||||||
|
}
|
||||||
|
newContent.lines.toList
|
||||||
|
}
|
||||||
|
|
||||||
|
private def toTreeStringMap(command: List[String]) = {
|
||||||
|
val split = SplitExpressionsNoBlankies(FAKE_FILE, command)
|
||||||
val trees = split.settingsTrees
|
val trees = split.settingsTrees
|
||||||
val seq = trees.map {
|
val seq = trees.map {
|
||||||
case (statement, tree) =>
|
case (statement, tree) =>
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@ package parser
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import sbt.internals.parser.SplitExpressionsNoBlankies._
|
import SplitExpressionsNoBlankies._
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.reflect.runtime.universe
|
|
||||||
import scala.reflect.runtime.universe._
|
import scala.reflect.runtime.universe._
|
||||||
|
|
||||||
private[sbt] object SplitExpressionsNoBlankies {
|
private[sbt] object SplitExpressionsNoBlankies {
|
||||||
|
|
@ -17,14 +16,14 @@ private[sbt] object SplitExpressionsNoBlankies {
|
||||||
|
|
||||||
private[sbt] case class SplitExpressionsNoBlankies(file: File, lines: Seq[String]) {
|
private[sbt] case class SplitExpressionsNoBlankies(file: File, lines: Seq[String]) {
|
||||||
//settingsTrees needed for "session save"
|
//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)]) = {
|
private def splitExpressions(file: File, lines: Seq[String]): (Seq[(String, Int)], Seq[(String, LineRange)], Seq[(String, Tree)], String) = {
|
||||||
import sbt.internals.parser.BugInParser._
|
import scala.reflect.runtime._
|
||||||
import sbt.internals.parser.XmlContent._
|
|
||||||
|
|
||||||
import scala.compat.Platform.EOL
|
import scala.compat.Platform.EOL
|
||||||
import BugInParser._
|
import BugInParser._
|
||||||
|
import XmlContent._
|
||||||
import scala.tools.reflect.{ ToolBox, ToolBoxError }
|
import scala.tools.reflect.{ ToolBox, ToolBoxError }
|
||||||
|
|
||||||
val mirror = universe.runtimeMirror(this.getClass.getClassLoader)
|
val mirror = universe.runtimeMirror(this.getClass.getClassLoader)
|
||||||
|
|
@ -90,7 +89,7 @@ private[sbt] case class SplitExpressionsNoBlankies(file: File, lines: Seq[String
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
val statementsTreeLineRange = statements flatMap convertStatement
|
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 = {
|
private def addExplicitXmlContent(content: String, xmlParts: Seq[(String, Int, Int)]): String = {
|
||||||
val statements: Seq[(String, Boolean)] = splitFile(content, xmlParts)
|
val statements: Seq[(String, Boolean)] = splitFile(content, xmlParts)
|
||||||
val (builder, wasPreviousXml, wasXml, _) = statements.foldLeft((Seq.empty[String], false, false, "")) {
|
val (builder, addCloseBrackets, wasXml, _) = statements.foldLeft((Seq.empty[String], false, false, "")) {
|
||||||
(acc, el) =>
|
case ((bAcc, addCloseBrackets, wasXml, previous), (content, isXml)) =>
|
||||||
val (bAcc, wasXml, _, previous) = acc
|
if (content.trim.isEmpty) {
|
||||||
val (content, isXml) = el
|
(content +: bAcc, addCloseBrackets, wasXml, content)
|
||||||
val contentEmpty = content.trim.isEmpty
|
} else {
|
||||||
val (isNotCommentedXml, newAcc) = if (isXml) {
|
val (newAddCloseBrackets, newAcc) = if (isXml) {
|
||||||
if (!wasXml) {
|
if (wasXml) {
|
||||||
|
(addCloseBrackets, bAcc)
|
||||||
|
} else {
|
||||||
if (areBracketsNecessary(previous)) {
|
if (areBracketsNecessary(previous)) {
|
||||||
(true, " ( " +: bAcc)
|
(true, " ( " +: bAcc)
|
||||||
} else {
|
} else {
|
||||||
(false, bAcc)
|
(false, bAcc)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
(true, bAcc)
|
|
||||||
}
|
}
|
||||||
} else if (wasXml && !contentEmpty) {
|
} else if (addCloseBrackets) {
|
||||||
(false, " ) " +: bAcc)
|
(false, " ) " +: bAcc)
|
||||||
} else {
|
} else {
|
||||||
(false, bAcc)
|
(false, bAcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
(content +: newAcc, isNotCommentedXml || (wasXml && contentEmpty), isXml, content)
|
(content +: newAcc, newAddCloseBrackets, isXml, content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val closeIfNecessaryBuilder =
|
val closeIfNecessaryBuilder =
|
||||||
if (wasPreviousXml && !wasXml) {
|
if (addCloseBrackets && wasXml) {
|
||||||
builder.head +: " ) " +: builder.tail
|
builder.head +: " ) " +: builder.tail
|
||||||
} else {
|
} else {
|
||||||
builder
|
builder
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ val a = <aaa>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
organization := "jozwikr" // OK
|
organization := "scalania" // OK
|
||||||
|
|
||||||
scalaVersion := "2.9.2"
|
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 sbt.internals.parser.{ AbstractSpec, SplitExpressionsNoBlankies }
|
||||||
|
|
||||||
import scala.collection.GenTraversableOnce
|
import scala.collection.GenTraversableOnce
|
||||||
import scala.collection.immutable.{ SortedMap, TreeMap }
|
|
||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
import scala.xml.XML
|
import scala.xml.XML
|
||||||
|
|
||||||
|
|
@ -17,7 +16,7 @@ abstract class AbstractSessionSettingsSpec(folder: String, printDetails: Boolean
|
||||||
|
|
||||||
"SessionSettings " should {
|
"SessionSettings " should {
|
||||||
"Be identical for empty map " in {
|
"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)
|
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() {
|
val allFiles = rootDir.listFiles(new FilenameFilter() {
|
||||||
def accept(dir: File, name: String) = name.endsWith(".sbt.txt")
|
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 set = (node \\ "set").text
|
||||||
val start = (node \\ "start").text.toInt
|
val start = (node \\ "start").text.toInt
|
||||||
val end = (node \\ "end").text.toInt
|
val end = (node \\ "end").text.toInt
|
||||||
(start, (end, List(set)))
|
List(set)
|
||||||
}.toList
|
}.toList
|
||||||
val map = tupleCollection.groupBy(el => el._1).map {
|
|
||||||
case (k, seq) => (k, seq.map(el => el._2))
|
(result, tupleCollection)
|
||||||
}
|
|
||||||
(result, TreeMap(map.toArray: _*)(SessionSettingsNoBlankies.REVERSE_ORDERING_INT))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue