mirror of https://github.com/sbt/sbt.git
Corrections for "session save"
This commit is contained in:
parent
4a33fd2225
commit
c720a973a6
|
|
@ -12,6 +12,8 @@ import compiler.Eval
|
|||
|
||||
import SessionSettings._
|
||||
|
||||
import scala.collection.immutable.SortedMap
|
||||
|
||||
final case class SessionSettings(currentBuild: URI, currentProject: Map[URI, String], original: Seq[Setting[_]], append: SessionMap, rawAppend: Seq[Setting[_]], currentEval: () => Eval) {
|
||||
assert(currentProject contains currentBuild, "Current build (" + currentBuild + ") not associated with a current project.")
|
||||
def setCurrent(build: URI, project: String, eval: () => Eval): SessionSettings = copy(currentBuild = build, currentProject = currentProject.updated(build, project), currentEval = eval)
|
||||
|
|
@ -100,21 +102,23 @@ object SessionSettings {
|
|||
}
|
||||
}
|
||||
|
||||
val (_, oldShifted, replace, lineMap) = ((0, List[Setting[_]](), List[SessionSetting](), Map.empty[Int, (Int, List[String])]) /: inFile) {
|
||||
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 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))
|
||||
(offs + end - start - newLines.size, shifted :: olds, ss :: repl, lineMap + (start -> (end, newLines)))
|
||||
val head = (end, newLines)
|
||||
val seq = lineMap.getOrElse(start, List())
|
||||
(offs + end - start - newLines.size, shifted :: olds, ss :: repl, lineMap + (start -> (head +: seq)))
|
||||
case _ =>
|
||||
val shifted = s withPos RangePosition(path, r shift -offs)
|
||||
(offs, shifted :: olds, repl, lineMap)
|
||||
}
|
||||
}
|
||||
val newSettings = settings diff replace
|
||||
val oldContentWithIndex = IO.readLines(writeTo).zipWithIndex
|
||||
val exist: List[String] = toLines(oldContentWithIndex, lineMap)
|
||||
val oldContent = IO.readLines(writeTo)
|
||||
val exist: List[String] = SessionSettingsNoBlankies.oldLinesToNew(oldContent, lineMap)
|
||||
val adjusted = if (!newSettings.isEmpty && needsTrailingBlank(exist)) exist :+ "" else exist
|
||||
val lines = adjusted ++ newSettings.flatMap(_._2 ::: "" :: Nil)
|
||||
IO.writeLines(writeTo, lines)
|
||||
|
|
@ -126,18 +130,6 @@ object SessionSettings {
|
|||
(newWithPos.reverse, other ++ oldShifted)
|
||||
}
|
||||
|
||||
private[sbt] def toLines(oldContentWithIndex: List[(String,Int)], lineMap: Map[Int, (Int, List[String])]): List[String] = {
|
||||
val (tmpLines, _) = ((List[String](), 1) /: oldContentWithIndex) {
|
||||
case ((accLines, n), (line, m)) if n == m + 1 =>
|
||||
lineMap.get(n) match {
|
||||
case Some(Pair(end, lines)) => (lines reverse_::: accLines, end)
|
||||
case None => (line :: accLines, n + 1)
|
||||
}
|
||||
case (res, _) => res
|
||||
}
|
||||
tmpLines.reverse
|
||||
}
|
||||
|
||||
def needsTrailingBlank(lines: Seq[String]) = !lines.isEmpty && !lines.takeRight(1).exists(_.trim.isEmpty)
|
||||
def printAllSettings(s: State): State =
|
||||
withSettings(s) { session =>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
|
||||
import scala.collection.immutable.SortedMap
|
||||
import scala.reflect.runtime.universe._
|
||||
|
||||
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], tuple: (Int, List[(Int, List[String])])): List[String] = {
|
||||
val (from, newSettingSeq) = tuple
|
||||
|
||||
val newTreeStringSeqMap = newSettingSeq.seq.map {
|
||||
case (_, lines) => toTreeStringMap(lines)
|
||||
}
|
||||
val to = newSettingSeq.map(_._1).max
|
||||
val originalLine = content.slice(from - 1, to - 1)
|
||||
|
||||
val operations = newTreeStringSeqMap.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 = 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 def cutExpression(l: List[String], name: String): List[String] = l match {
|
||||
case h +: t =>
|
||||
val array = h.split(";").filter(_.contains(name))
|
||||
array.mkString(";") +: t
|
||||
case _ =>
|
||||
l
|
||||
}
|
||||
|
||||
private def toTreeStringMap(lines: List[String]) = {
|
||||
|
||||
val trees = SplitExpressionsNoBlankies(new File("fake"), lines).settingsTrees
|
||||
val seq = trees.map {
|
||||
case (statement, tree) =>
|
||||
(extractSettingName(tree), (tree.pos.start, statement))
|
||||
}
|
||||
seq.toMap
|
||||
}
|
||||
|
||||
private def extractSettingName(tree: Tree): String = {
|
||||
tree.children match {
|
||||
case h :: _ =>
|
||||
extractSettingName(h)
|
||||
case _ =>
|
||||
tree.toString()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import java.io.File
|
|||
|
||||
import scala.annotation.tailrec
|
||||
import SplitExpressionsNoBlankies._
|
||||
import scala.reflect.runtime.universe._
|
||||
|
||||
object SplitExpressionsNoBlankies {
|
||||
val END_OF_LINE_CHAR = '\n'
|
||||
|
|
@ -11,11 +12,12 @@ object SplitExpressionsNoBlankies {
|
|||
}
|
||||
|
||||
case class SplitExpressionsNoBlankies(file: File, lines: Seq[String]) {
|
||||
val (imports, settings) = splitExpressions(file, lines)
|
||||
//settingsTrees needed for "session save"
|
||||
val (imports, settings, settingsTrees) = splitExpressions(file, lines)
|
||||
|
||||
private def splitExpressions(file: File, lines: Seq[String]): (Seq[(String, Int)], Seq[(String, LineRange)]) = {
|
||||
private def splitExpressions(file: File, lines: Seq[String]): (Seq[(String, Int)], Seq[(String, LineRange)], Seq[(String, Tree)]) = {
|
||||
import scala.reflect.runtime._
|
||||
import scala.reflect.runtime.universe._
|
||||
|
||||
import scala.tools.reflect.ToolBoxError
|
||||
import scala.tools.reflect.ToolBox
|
||||
import scala.compat.Platform.EOL
|
||||
|
|
@ -34,12 +36,14 @@ case class SplitExpressionsNoBlankies(file: File, lines: Seq[String]) {
|
|||
toolbox.parse(merged)
|
||||
} catch {
|
||||
case e: ToolBoxError =>
|
||||
ConsoleLogger(System.err).trace(e)
|
||||
val seq = toolbox.frontEnd.infos.map { i =>
|
||||
s"""[$fileName]:${i.pos.line}: ${i.msg}"""
|
||||
}
|
||||
throw new MessageOnlyException(
|
||||
s"""${seq.mkString(EOL)}""".stripMargin)
|
||||
s"""======
|
||||
|$merged
|
||||
|======
|
||||
|${seq.mkString(EOL)}""".stripMargin)
|
||||
}
|
||||
val parsedTrees = parsed match {
|
||||
case Block(stmt, expr) =>
|
||||
|
|
@ -73,19 +77,18 @@ case class SplitExpressionsNoBlankies(file: File, lines: Seq[String]) {
|
|||
statement
|
||||
}
|
||||
|
||||
def convertStatement(t: Tree): Option[(String, LineRange)] =
|
||||
def convertStatement(t: Tree): Option[(String, Tree, LineRange)] =
|
||||
if (t.pos.isDefined) {
|
||||
val originalStatement = merged.substring(t.pos.start, t.pos.end)
|
||||
val statement = parseStatementAgain(t, originalStatement)
|
||||
val numberLines = statement.count(c => c == END_OF_LINE_CHAR)
|
||||
Some((statement, LineRange(t.pos.line - 1, t.pos.line + numberLines)))
|
||||
Some((statement, t, LineRange(t.pos.line - 1, t.pos.line + numberLines)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
(imports map convertImport, 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)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -143,14 +146,14 @@ private[sbt] object BugInParser {
|
|||
/**
|
||||
* #ToolBox#parse(String) will fail for xml sequence:
|
||||
* <pre>
|
||||
* val xml = <div>txt</div>
|
||||
* <a>rr</a>
|
||||
* </pre>
|
||||
* At least brackets have to be added
|
||||
* val xml = <div>txt</div>
|
||||
* <a>rr</a>
|
||||
* </pre>
|
||||
* At least brackets have to be added
|
||||
* <pre>
|
||||
* val xml = (<div>txt</div>
|
||||
* <a>rr</a>)
|
||||
* </pre>
|
||||
* val xml = (<div>txt</div>
|
||||
* <a>rr</a>)
|
||||
* </pre>
|
||||
*/
|
||||
private object XmlContent {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
name := "newName"
|
||||
libraryDependencies := Seq("org.scala-sbt" %% "sbinary" % "0.4.1")
|
||||
|
||||
lazy val checkPom = taskKey[Unit]("check pom to ensure no <type> sections are generated"); checkPom := {
|
||||
val pomFile = makePom.value
|
||||
val pom = xml.XML.loadFile(pomFile)
|
||||
val tpe = pom \\ "type"
|
||||
if(!tpe.isEmpty)
|
||||
sys.error("Expected no <type> sections, got: " + tpe + " in \n\n" + pom)
|
||||
};scalacOptions := Seq("-deprecation")
|
||||
|
||||
val b = ( <b/>)
|
||||
val a = <aaa>
|
||||
|
||||
</aaa>
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
organization := "jozwikr" // OK
|
||||
|
||||
scalaVersion := "2.9.2"
|
||||
|
||||
organization := "ololol"
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<settings>
|
||||
<setting>
|
||||
<start>1</start>
|
||||
<end>2</end>
|
||||
<set>name := "alaMaKota"</set>
|
||||
</setting>
|
||||
</settings>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
name := "alaMaKota"
|
||||
libraryDependencies := Seq("org.scala-sbt" %% "sbinary" % "0.4.1")
|
||||
|
||||
lazy val checkPom = taskKey[Unit]("check pom to ensure no <type> sections are generated"); checkPom := {
|
||||
val pomFile = makePom.value
|
||||
val pom = xml.XML.loadFile(pomFile)
|
||||
val tpe = pom \\ "type"
|
||||
if(!tpe.isEmpty)
|
||||
sys.error("Expected no <type> sections, got: " + tpe + " in \n\n" + pom)
|
||||
};scalacOptions := Seq("-deprecation")
|
||||
|
||||
val b = ( <b/>)
|
||||
val a = <aaa>
|
||||
|
||||
</aaa>
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
organization := "jozwikr" // OK
|
||||
|
||||
scalaVersion := "2.9.2"
|
||||
|
||||
organization := "ololol"
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<settings>
|
||||
<setting>
|
||||
<start>1</start>
|
||||
<end>2</end>
|
||||
<set>name := "alaMaKota"</set>
|
||||
</setting>
|
||||
<setting>
|
||||
<start>25</start>
|
||||
<end>26</end>
|
||||
<set>organization := "scalania"</set>
|
||||
</setting>
|
||||
</settings>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
name := "alaMaKota"
|
||||
libraryDependencies := Seq("org.scala-sbt" %% "sbinary" % "0.4.1")
|
||||
|
||||
lazy val checkPom = taskKey[Unit]("check pom to ensure no <type> sections are generated"); checkPom := {
|
||||
val pomFile = makePom.value
|
||||
val pom = xml.XML.loadFile(pomFile)
|
||||
val tpe = pom \\ "type"
|
||||
if(!tpe.isEmpty)
|
||||
sys.error("Expected no <type> sections, got: " + tpe + " in \n\n" + pom)
|
||||
};scalacOptions := Seq("-deprecation")
|
||||
|
||||
val b = ( <b/>)
|
||||
val a = <aaa>
|
||||
|
||||
</aaa>
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
organization := "jozwikr" // OK
|
||||
|
||||
scalaVersion := "2.9.2"
|
||||
|
||||
organization := "scalania"
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
name := "newName";scalaVersion := "2.9.2"; organization := "jozwikr"
|
||||
libraryDependencies := Seq("org.scala-sbt" %% "sbinary" % "0.4.1")
|
||||
|
||||
lazy val checkPom = taskKey[Unit]("check pom to ensure no <type> sections are generated"); checkPom := {
|
||||
val pomFile = makePom.value
|
||||
val pom = xml.XML.loadFile(pomFile)
|
||||
val tpe = pom \\ "type"
|
||||
if(!tpe.isEmpty)
|
||||
sys.error("Expected no <type> sections, got: " + tpe + " in \n\n" + pom)
|
||||
};scalacOptions := Seq("-deprecation")
|
||||
|
||||
val b = ( <b/>)
|
||||
val a = <aaa>
|
||||
|
||||
</aaa>
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<settings>
|
||||
<setting>
|
||||
<start>1</start>
|
||||
<end>2</end>
|
||||
<set>name := "alaMaKota"</set>
|
||||
</setting>
|
||||
</settings>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
name := "alaMaKota";scalaVersion := "2.9.2"; organization := "jozwikr"
|
||||
libraryDependencies := Seq("org.scala-sbt" %% "sbinary" % "0.4.1")
|
||||
|
||||
lazy val checkPom = taskKey[Unit]("check pom to ensure no <type> sections are generated"); checkPom := {
|
||||
val pomFile = makePom.value
|
||||
val pom = xml.XML.loadFile(pomFile)
|
||||
val tpe = pom \\ "type"
|
||||
if(!tpe.isEmpty)
|
||||
sys.error("Expected no <type> sections, got: " + tpe + " in \n\n" + pom)
|
||||
};scalacOptions := Seq("-deprecation")
|
||||
|
||||
val b = ( <b/>)
|
||||
val a = <aaa>
|
||||
|
||||
</aaa>
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package sbt
|
||||
|
||||
import java.io.{ File, FilenameFilter }
|
||||
|
||||
import org.specs2.matcher.MatchResult
|
||||
|
||||
import scala.collection.GenTraversableOnce
|
||||
import scala.collection.immutable.{ SortedMap, TreeMap }
|
||||
import scala.io.Source
|
||||
import scala.xml.XML
|
||||
|
||||
abstract class AbstractSessionSettingsSpec(folder: String) extends AbstractSpec {
|
||||
protected val rootPath = getClass.getResource("").getPath + folder
|
||||
println(s"Reading files from: $rootPath")
|
||||
protected val rootDir = new File(rootPath)
|
||||
|
||||
"SessionSettings " should {
|
||||
"Be identical for empty map " in {
|
||||
def unit(f: File) = Seq((Source.fromFile(f).getLines().toSeq, SortedMap.empty[Int, List[(Int, List[String])]]))
|
||||
runTestOnFiles(unit)
|
||||
}
|
||||
|
||||
"Replace statements " in {
|
||||
runTestOnFiles(replace)
|
||||
}
|
||||
}
|
||||
|
||||
private def runTestOnFiles(expectedResultAndMap: File => Seq[(Seq[String], SortedMap[Int, List[(Int, List[String])]])]): MatchResult[GenTraversableOnce[File]] = {
|
||||
|
||||
val allFiles = rootDir.listFiles(new FilenameFilter() {
|
||||
def accept(dir: File, name: String) = name.endsWith(".sbt.txt")
|
||||
}).toList
|
||||
foreach(allFiles) {
|
||||
file =>
|
||||
val originalLines = Source.fromFile(file).getLines().toList
|
||||
foreach(expectedResultAndMap(file)) {
|
||||
case (expectedResult, map) =>
|
||||
val result = SessionSettingsNoBlankies.oldLinesToNew(originalLines, map)
|
||||
expectedResult === result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def replace(f: File) = {
|
||||
val dirs = rootDir.listFiles(new FilenameFilter() {
|
||||
def accept(dir: File, name: String) = {
|
||||
val startsWith = f.getName + "_"
|
||||
name.startsWith(startsWith)
|
||||
}
|
||||
}).toList
|
||||
dirs.flatMap {
|
||||
dir =>
|
||||
val files = dir.listFiles(new FilenameFilter {
|
||||
override def accept(dir: File, name: String) = name.endsWith(".xml")
|
||||
})
|
||||
files.map { xmlFile =>
|
||||
val xml = XML.loadFile(xmlFile)
|
||||
val result = Source.fromFile(xmlFile.getAbsolutePath + ".result").getLines().toSeq
|
||||
val tupleCollection = (xml \\ "settings" \\ "setting").map {
|
||||
node =>
|
||||
val set = (node \\ "set").text
|
||||
val start = (node \\ "start").text.toInt
|
||||
val end = (node \\ "end").text.toInt
|
||||
(start, (end, 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SessionSettingsSpec extends AbstractSessionSettingsSpec("../session-settings")
|
||||
Loading…
Reference in New Issue