mirror of https://github.com/sbt/sbt.git
Make analysis file portable.
Serializes CompileSetup as text instead of base64-encoded binary-serialized object. This is necessary so that file paths in the CompileSetup can be rebased when porting analysis files between systems.
This commit is contained in:
parent
c669606999
commit
2e1809e17e
|
|
@ -27,12 +27,14 @@ object CompileSetup
|
||||||
def equiv(a: File, b: File) = a.getAbsoluteFile == b.getAbsoluteFile
|
def equiv(a: File, b: File) = a.getAbsoluteFile == b.getAbsoluteFile
|
||||||
}
|
}
|
||||||
implicit val equivOutput: Equiv[APIOutput] = new Equiv[APIOutput] {
|
implicit val equivOutput: Equiv[APIOutput] = new Equiv[APIOutput] {
|
||||||
|
implicit val outputGroupsOrdering = Ordering.by((og: MultipleOutput.OutputGroup) => og.sourceDirectory)
|
||||||
def equiv(out1: APIOutput, out2: APIOutput) = (out1, out2) match {
|
def equiv(out1: APIOutput, out2: APIOutput) = (out1, out2) match {
|
||||||
case (m1: MultipleOutput, m2: MultipleOutput) =>
|
case (m1: MultipleOutput, m2: MultipleOutput) =>
|
||||||
m1.outputGroups zip (m2.outputGroups) forall {
|
(m1.outputGroups.length == m2.outputGroups.length) &&
|
||||||
|
(m1.outputGroups.sorted zip m2.outputGroups.sorted forall {
|
||||||
case (a,b) =>
|
case (a,b) =>
|
||||||
equivFile.equiv(a.sourceDirectory, b.sourceDirectory) && equivFile.equiv(a.outputDirectory, b.outputDirectory)
|
equivFile.equiv(a.sourceDirectory, b.sourceDirectory) && equivFile.equiv(a.outputDirectory, b.outputDirectory)
|
||||||
}
|
})
|
||||||
case (s1: SingleOutput, s2: SingleOutput) => equivFile.equiv(s1.outputDirectory, s2.outputDirectory)
|
case (s1: SingleOutput, s2: SingleOutput) => equivFile.equiv(s1.outputDirectory, s2.outputDirectory)
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package inc
|
||||||
import java.io._
|
import java.io._
|
||||||
import sbt.{CompileSetup, Relation}
|
import sbt.{CompileSetup, Relation}
|
||||||
import xsbti.api.{Compilation, Source}
|
import xsbti.api.{Compilation, Source}
|
||||||
|
import xsbti.compile.{MultipleOutput, SingleOutput}
|
||||||
import javax.xml.bind.DatatypeConverter
|
import javax.xml.bind.DatatypeConverter
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -80,7 +81,7 @@ object TextAnalysisFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] object VersionF {
|
private[this] object VersionF {
|
||||||
val currentVersion = "2"
|
val currentVersion = "4"
|
||||||
|
|
||||||
def write(out: Writer) {
|
def write(out: Writer) {
|
||||||
out.write("format version: %s\n".format(currentVersion))
|
out.write("format version: %s\n".format(currentVersion))
|
||||||
|
|
@ -306,23 +307,71 @@ object TextAnalysisFormat {
|
||||||
val compilationToString = ObjectStringifier.objToString[Compilation] _
|
val compilationToString = ObjectStringifier.objToString[Compilation] _
|
||||||
|
|
||||||
def write(out: Writer, compilations: Compilations) {
|
def write(out: Writer, compilations: Compilations) {
|
||||||
def toMapEntry(x: (Compilation, Int)): (String, Compilation) = "%03d".format(x._2) -> x._1
|
writeSeq(out)(Headers.compilations, compilations.allCompilations, compilationToString)
|
||||||
writeMap(out)(Headers.compilations, compilations.allCompilations.zipWithIndex.map(toMapEntry).toMap, compilationToString, inlineVals=false)
|
|
||||||
}
|
}
|
||||||
def read(in: BufferedReader): Compilations =
|
|
||||||
Compilations.make(readMap(in)(Headers.compilations, identity[String], stringToCompilation).values.toSeq)
|
def read(in: BufferedReader): Compilations = Compilations.make(
|
||||||
|
readSeq[Compilation](in)(Headers.compilations, stringToCompilation))
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] object CompileSetupF {
|
private[this] object CompileSetupF {
|
||||||
object Headers {
|
object Headers {
|
||||||
val setup = "compile setup"
|
val outputMode = "output mode"
|
||||||
|
val outputDir = "output directories"
|
||||||
|
val compileOptions = "compile options"
|
||||||
|
val javacOptions = "javac options"
|
||||||
|
val compilerVersion = "compiler version"
|
||||||
|
val compileOrder = "compile order"
|
||||||
}
|
}
|
||||||
|
|
||||||
val stringToSetup = ObjectStringifier.stringToObj[CompileSetup] _
|
private[this] val singleOutputMode = "single"
|
||||||
val setupToString = ObjectStringifier.objToString[CompileSetup] _
|
private[this] val multipleOutputMode = "multiple"
|
||||||
|
private[this] val singleOutputKey = new File("output dir")
|
||||||
|
|
||||||
def write(out: Writer, setup: CompileSetup) { writeMap(out)(Headers.setup, Map("1" -> setup), setupToString, inlineVals=false)}
|
def write(out: Writer, setup: CompileSetup) {
|
||||||
def read(in: BufferedReader): CompileSetup = readMap(in)(Headers.setup, identity[String], stringToSetup).head._2
|
val (mode, outputAsMap) = setup.output match {
|
||||||
|
case s: SingleOutput => (singleOutputMode, Map(singleOutputKey -> s.outputDirectory))
|
||||||
|
case m: MultipleOutput => (multipleOutputMode, m.outputGroups.map(x => x.sourceDirectory -> x.outputDirectory).toMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSeq(out)(Headers.outputMode, mode :: Nil, identity[String])
|
||||||
|
writeMap(out)(Headers.outputDir, outputAsMap, { f: File => f.getPath })
|
||||||
|
writeSeq(out)(Headers.compileOptions, setup.options.options, identity[String])
|
||||||
|
writeSeq(out)(Headers.javacOptions, setup.options.javacOptions, identity[String])
|
||||||
|
writeSeq(out)(Headers.compilerVersion, setup.compilerVersion :: Nil, identity[String])
|
||||||
|
writeSeq(out)(Headers.compileOrder, setup.order.name :: Nil, identity[String])
|
||||||
|
}
|
||||||
|
|
||||||
|
def read(in: BufferedReader): CompileSetup = {
|
||||||
|
def s2f(s: String) = new File(s)
|
||||||
|
val outputDirMode = readSeq(in)(Headers.outputMode, identity[String]).headOption
|
||||||
|
val outputAsMap = readMap(in)(Headers.outputDir, s2f, s2f)
|
||||||
|
val compileOptions = readSeq(in)(Headers.compileOptions, identity[String])
|
||||||
|
val javacOptions = readSeq(in)(Headers.javacOptions, identity[String])
|
||||||
|
val compilerVersion = readSeq(in)(Headers.compilerVersion, identity[String]).head
|
||||||
|
val compileOrder = readSeq(in)(Headers.compileOrder, identity[String]).head
|
||||||
|
|
||||||
|
val output = outputDirMode match {
|
||||||
|
case Some(s) => s match {
|
||||||
|
case `singleOutputMode` => new SingleOutput {
|
||||||
|
val outputDirectory = outputAsMap(singleOutputKey)
|
||||||
|
}
|
||||||
|
case `multipleOutputMode` => new MultipleOutput {
|
||||||
|
val outputGroups = outputAsMap.toArray.map {
|
||||||
|
case (src: File, out: File) => new MultipleOutput.OutputGroup {
|
||||||
|
val sourceDirectory = src
|
||||||
|
val outputDirectory = out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case str: String => throw new ReadException("Unrecognized output mode: " + str)
|
||||||
|
}
|
||||||
|
case None => throw new ReadException("No output mode specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
new CompileSetup(output, new CompileOptions(compileOptions, javacOptions), compilerVersion,
|
||||||
|
xsbti.compile.CompileOrder.valueOf(compileOrder))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] object ObjectStringifier {
|
private[this] object ObjectStringifier {
|
||||||
|
|
@ -365,6 +414,19 @@ object TextAnalysisFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private[this] def writeSeq[T](out: Writer)(header: String, s: Seq[T], t2s: T => String) {
|
||||||
|
// We write sequences as idx -> element maps, for uniformity with maps/relations.
|
||||||
|
def n = s.length
|
||||||
|
val numDigits = if (n < 2) 1 else math.log10(n - 1).toInt + 1
|
||||||
|
val fmtStr = "%%0%dd".format(numDigits)
|
||||||
|
// We only use this for relatively short seqs, so creating this extra map won't be a performance hit.
|
||||||
|
val m: Map[String, T] = s.zipWithIndex.map(x => fmtStr.format(x._2) -> x._1).toMap
|
||||||
|
writeMap(out)(header, m, t2s)
|
||||||
|
}
|
||||||
|
|
||||||
|
private[this] def readSeq[T](in: BufferedReader)(expectedHeader: String, s2t: String => T): Seq[T] =
|
||||||
|
(readPairs(in)(expectedHeader, identity[String], s2t) map(_._2)).toSeq
|
||||||
|
|
||||||
private[this] def writeMap[K, V](out: Writer)(header: String, m: Map[K, V], v2s: V => String, inlineVals: Boolean=true)(implicit ord: Ordering[K]) {
|
private[this] def writeMap[K, V](out: Writer)(header: String, m: Map[K, V], v2s: V => String, inlineVals: Boolean=true)(implicit ord: Ordering[K]) {
|
||||||
writeHeader(out, header)
|
writeHeader(out, header)
|
||||||
writeSize(out, m.size)
|
writeSize(out, m.size)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue