From 2eab2548bdfe49f246cecfb8718632a84df68342 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 17 Oct 2017 20:44:14 -0700 Subject: Break up `Main.scala` --- src/main/scala/hbt/Hbt.scala | 105 ++++++++++++++++++++++++++++++++ src/main/scala/hbt/Main.scala | 138 +----------------------------------------- src/main/scala/hbt/Util.scala | 53 ++++++++++++++++ 3 files changed, 159 insertions(+), 137 deletions(-) create mode 100644 src/main/scala/hbt/Hbt.scala create mode 100644 src/main/scala/hbt/Util.scala diff --git a/src/main/scala/hbt/Hbt.scala b/src/main/scala/hbt/Hbt.scala new file mode 100644 index 00000000..c6035e55 --- /dev/null +++ b/src/main/scala/hbt/Hbt.scala @@ -0,0 +1,105 @@ +package hbt + +import java.io.FileOutputStream + +import collection.JavaConverters._ +import java.nio.{file => jnio} +import java.util.jar.JarEntry + +import sourcecode.Enclosing + +import scala.collection.mutable +class Args(val args: IndexedSeq[_]){ + def length = args.length + def apply[T](index: Int): T = { + if (index >= 0 && index < args.length) args(index).asInstanceOf[T] + else throw new IndexOutOfBoundsException(s"Index $index outside of range 0 - ${args.length}") + } +} +sealed trait Target[T]{ + val label: String + def evaluate(args: Args): T + val inputs: Seq[Target[_]] + + def map[V](f: T => V)(implicit path: Enclosing) = { + Target.Mapped(this, f, path.value) + } + def zip[V](other: Target[V])(implicit path: Enclosing) = { + Target.Zipped(this, other, path.value) + } + def ~[V, R](other: Target[V]) + (implicit s: Implicits.Sequencer[T, V, R]): Target[R] = { + this.zip(other).map(s.apply _ tupled) + } + +} + +object Target{ + def traverse[T](source: Seq[Target[T]])(implicit path: Enclosing) = { + Traverse(source, path.value) + } + case class Traverse[T](inputs: Seq[Target[T]], label: String) extends Target[Seq[T]]{ + def evaluate(args: Args) = { + for (i <- 0 until args.length) + yield args(i) + } + + } + case class Mapped[T, V](source: Target[T], f: T => V, + label: String) extends Target[V]{ + def evaluate(args: Args) = f(args(0)) + val inputs = List(source) + } + case class Zipped[T, V](source1: Target[T], + source2: Target[V], + label: String) extends Target[(T, V)]{ + def evaluate(args: Args) = (args(0), args(0)) + val inputs = List(source1, source1) + } + case class Path(path: jnio.Path, label: String) extends Target[jnio.Path]{ + def evaluate(args: Args) = path + val inputs = Nil + } +// case class Command(inputs: Seq[Target[jnio.Path]], +// output: Seq[Target[jnio.Path]], +// label: String) extends Target[Command.Result] +// object Command{ +// case class Result(stdout: String, +// stderr: String, +// writtenFiles: Seq[jnio.Path]) +// } +} +object Hbt{ + + + def evaluateTargetGraph[T](t: Target[T]): T = { + val targetSet = mutable.Set.empty[Target[_]] + def rec(t: Target[_]): Unit = { + if (targetSet.contains(t)) () // do nothing + else { + targetSet.add(t) + t.inputs.foreach(rec) + } + } + rec(t) + val targets = targetSet.toIndexedSeq + val targetIndices = targets.zipWithIndex.toMap + + val numberedEdges = + for(i <- targets.indices) + yield targets(i).inputs.map(targetIndices) + + val sortedClusters = Tarjans(numberedEdges) + val nonTrivialClusters = sortedClusters.filter(_.length > 1) + assert(nonTrivialClusters.isEmpty, nonTrivialClusters) + + val results = mutable.Map.empty[Target[_], Any] + for (cluster <- sortedClusters){ + val Seq(singletonIndex) = cluster + val singleton = targets(singletonIndex) + val inputResults = singleton.inputs.map(results) + results(singleton) = singleton.evaluate(new Args(inputResults.toIndexedSeq)) + } + results(t).asInstanceOf[T] + } +} \ No newline at end of file diff --git a/src/main/scala/hbt/Main.scala b/src/main/scala/hbt/Main.scala index c6323e8f..2cc59cc9 100644 --- a/src/main/scala/hbt/Main.scala +++ b/src/main/scala/hbt/Main.scala @@ -1,112 +1,7 @@ package hbt -import java.io.FileOutputStream - -import collection.JavaConverters._ import java.nio.{file => jnio} -import java.util.jar.JarEntry - -import sourcecode.Enclosing - -import scala.collection.mutable -class Args(val args: IndexedSeq[_]){ - def length = args.length - def apply[T](index: Int): T = { - if (index >= 0 && index < args.length) args(index).asInstanceOf[T] - else throw new IndexOutOfBoundsException(s"Index $index outside of range 0 - ${args.length}") - } -} -sealed trait Target[T]{ - val label: String - def evaluate(args: Args): T - val inputs: Seq[Target[_]] - - def map[V](f: T => V)(implicit path: Enclosing) = { - Target.Mapped(this, f, path.value) - } - def zip[V](other: Target[V])(implicit path: Enclosing) = { - Target.Zipped(this, other, path.value) - } - def ~[V, R](other: Target[V]) - (implicit s: Implicits.Sequencer[T, V, R]): Target[R] = { - this.zip(other).map(s.apply _ tupled) - } - -} - -object Target{ - def traverse[T](source: Seq[Target[T]])(implicit path: Enclosing) = { - Traverse(source, path.value) - } - case class Traverse[T](inputs: Seq[Target[T]], label: String) extends Target[Seq[T]]{ - def evaluate(args: Args) = { - for (i <- 0 until args.length) - yield args(i) - } - - } - case class Mapped[T, V](source: Target[T], f: T => V, - label: String) extends Target[V]{ - def evaluate(args: Args) = f(args(0)) - val inputs = List(source) - } - case class Zipped[T, V](source1: Target[T], - source2: Target[V], - label: String) extends Target[(T, V)]{ - def evaluate(args: Args) = (args(0), args(0)) - val inputs = List(source1, source1) - } - case class Path(path: jnio.Path, label: String) extends Target[jnio.Path]{ - def evaluate(args: Args) = path - val inputs = Nil - } -// case class Command(inputs: Seq[Target[jnio.Path]], -// output: Seq[Target[jnio.Path]], -// label: String) extends Target[Command.Result] -// object Command{ -// case class Result(stdout: String, -// stderr: String, -// writtenFiles: Seq[jnio.Path]) -// } -} +import Util._ object Main{ - def compileAll(sources: Target[Seq[jnio.Path]]) - (implicit path: Enclosing): Target[jnio.Path] = { - for(sources0 <- sources) yield { - val output = jnio.Paths.get(path.value) - jnio.Files.createDirectories(output) - val command = - Seq("scalac") ++ - sources0.map(_.toString) ++ - Seq("-d", path.value) - - - - new java.lang.ProcessBuilder() - .command(command: _*) - .start() - .waitFor() - - output - } - } - - def list(root: Target[jnio.Path]): Target[Seq[jnio.Path]] = { - root.map(jnio.Files.list(_).iterator().asScala.toArray[jnio.Path]) - } - def jarUp(roots: Target[jnio.Path]*)(implicit path: Enclosing): Target[jnio.Path] = { - for(rootsValue <- Target.traverse(roots)) yield { - val output = new java.util.jar.JarOutputStream(new FileOutputStream(path.value)) - for{ - root <- rootsValue - path <- jnio.Files.list(root).iterator().asScala - }{ - val relative = root.relativize(path) - output.putNextEntry(new JarEntry(relative.toString)) - output.write(jnio.Files.readAllBytes(path)) - } - jnio.Paths.get(path.value) - } - } def main(args: Array[String]): Unit = { val sourceRoot = Target.Path(jnio.Paths.get("test/src"), "sourceRoot") val resourceRoot = Target.Path(jnio.Paths.get("test/resources"), "resourceRoot") @@ -114,35 +9,4 @@ object Main{ val classFiles = compileAll(allSources) val jar = jarUp(resourceRoot, classFiles) } - - def evaluateTargetGraph[T](t: Target[T]): T = { - val targetSet = mutable.Set.empty[Target[_]] - def rec(t: Target[_]): Unit = { - if (targetSet.contains(t)) () // do nothing - else { - targetSet.add(t) - t.inputs.foreach(rec) - } - } - rec(t) - val targets = targetSet.toIndexedSeq - val targetIndices = targets.zipWithIndex.toMap - - val numberedEdges = - for(i <- targets.indices) - yield targets(i).inputs.map(targetIndices) - - val sortedClusters = Tarjans(numberedEdges) - val nonTrivialClusters = sortedClusters.filter(_.length > 1) - assert(nonTrivialClusters.isEmpty, nonTrivialClusters) - - val results = mutable.Map.empty[Target[_], Any] - for (cluster <- sortedClusters){ - val Seq(singletonIndex) = cluster - val singleton = targets(singletonIndex) - val inputResults = singleton.inputs.map(results) - results(singleton) = singleton.evaluate(new Args(inputResults.toIndexedSeq)) - } - results(t).asInstanceOf[T] - } } \ No newline at end of file diff --git a/src/main/scala/hbt/Util.scala b/src/main/scala/hbt/Util.scala new file mode 100644 index 00000000..a7456b56 --- /dev/null +++ b/src/main/scala/hbt/Util.scala @@ -0,0 +1,53 @@ +package hbt + +import java.io.FileOutputStream +import java.nio.{file => jnio} +import java.util.jar.JarEntry + +import sourcecode.Enclosing + +import scala.collection.JavaConverters._ +import scala.collection.mutable + +object Util{ + def compileAll(sources: Target[Seq[jnio.Path]]) + (implicit path: Enclosing): Target[jnio.Path] = { + for(sources0 <- sources) yield { + val output = jnio.Paths.get(path.value) + jnio.Files.createDirectories(output) + val command = + Seq("scalac") ++ + sources0.map(_.toString) ++ + Seq("-d", path.value) + + + + new java.lang.ProcessBuilder() + .command(command: _*) + .start() + .waitFor() + + output + } + } + + def list(root: Target[jnio.Path]): Target[Seq[jnio.Path]] = { + root.map(jnio.Files.list(_).iterator().asScala.toArray[jnio.Path]) + } + def jarUp(roots: Target[jnio.Path]*)(implicit path: Enclosing): Target[jnio.Path] = { + for(rootsValue <- Target.traverse(roots)) yield { + val output = new java.util.jar.JarOutputStream(new FileOutputStream(path.value)) + for{ + root <- rootsValue + path <- jnio.Files.list(root).iterator().asScala + }{ + val relative = root.relativize(path) + output.putNextEntry(new JarEntry(relative.toString)) + output.write(jnio.Files.readAllBytes(path)) + } + jnio.Paths.get(path.value) + } + } + + +} \ No newline at end of file -- cgit v1.2.3