From 538b5ac28b80285953dbea08651cf5c5afa7c0f9 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 18 Oct 2017 21:16:19 -0700 Subject: Basic evaluator that creates classfiles and a jar now works --- build.sbt | 5 +++- src/main/scala/hbt/Hbt.scala | 56 ++++++++++++++++++++++++-------------- src/main/scala/hbt/Main.scala | 5 ++-- src/main/scala/hbt/ReadWrite.scala | 20 ++++++++++++++ src/main/scala/hbt/Tarjans.scala | 11 +------- src/main/scala/hbt/Util.scala | 43 +++++++++++++++++------------ test/src/Foo.scala | 3 ++ 7 files changed, 92 insertions(+), 51 deletions(-) create mode 100644 src/main/scala/hbt/ReadWrite.scala diff --git a/build.sbt b/build.sbt index 7478db4f..ecfedcef 100644 --- a/build.sbt +++ b/build.sbt @@ -8,7 +8,10 @@ libraryDependencies += "com.lihaoyi" %% "utest" % "0.5.4" % "test" testFrameworks += new TestFramework("utest.runner.Framework") -libraryDependencies += "com.lihaoyi" %% "sourcecode" % "0.1.4" +libraryDependencies ++= Seq( + "com.lihaoyi" %% "sourcecode" % "0.1.4", + "com.lihaoyi" %% "pprint" % "0.5.3" +) sourceGenerators in Compile += Def.task { val dir = (sourceManaged in Compile).value diff --git a/src/main/scala/hbt/Hbt.scala b/src/main/scala/hbt/Hbt.scala index c6035e55..b321920b 100644 --- a/src/main/scala/hbt/Hbt.scala +++ b/src/main/scala/hbt/Hbt.scala @@ -1,25 +1,21 @@ 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[_]){ +class Args(val args: IndexedSeq[_], val dest: jnio.Path){ 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]{ +trait Target[T]{ val label: String - def evaluate(args: Args): T val inputs: Seq[Target[_]] + def evaluate(args: Args): T def map[V](f: T => V)(implicit path: Enclosing) = { Target.Mapped(this, f, path.value) @@ -36,12 +32,12 @@ sealed trait Target[T]{ object Target{ def traverse[T](source: Seq[Target[T]])(implicit path: Enclosing) = { - Traverse(source, path.value) + Traverse[T](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) + yield args(i).asInstanceOf[T] } } @@ -56,6 +52,8 @@ object Target{ def evaluate(args: Args) = (args(0), args(0)) val inputs = List(source1, source1) } + + def path(path: jnio.Path)(implicit label: Enclosing) = Path(path, label.value) case class Path(path: jnio.Path, label: String) extends Target[jnio.Path]{ def evaluate(args: Args) = path val inputs = Nil @@ -72,17 +70,21 @@ object Target{ 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 + def evaluateTargetGraph[T](t: Target[T])(implicit enclosing: Enclosing): T = { + val targetPaths = mutable.Map.empty[Target[_], List[String]] + def rec(t: Target[_], path: List[String]): Unit = { + if (targetPaths.contains(t)) () // do nothing else { - targetSet.add(t) - t.inputs.foreach(rec) + val currentPath = + if (!t.label.startsWith(enclosing.value)) path.reverse + else t.label.stripPrefix(enclosing.value).drop(1).split('.').toList + + targetPaths(t) = currentPath + t.inputs.zipWithIndex.foreach{case (c, i) => rec(c, i.toString :: currentPath)} } } - rec(t) - val targets = targetSet.toIndexedSeq + rec(t, Nil) + val targets = targetPaths.keys.toIndexedSeq val targetIndices = targets.zipWithIndex.toMap val numberedEdges = @@ -96,10 +98,22 @@ object Hbt{ 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)) + val target = targets(singletonIndex) + val inputResults = target.inputs.map(results) + val targetDestPath = jnio.Paths.get(targetPaths(target).mkString("/")) + import collection.JavaConverters._ + if (jnio.Files.exists(targetDestPath)){ + jnio.Files.walk(targetDestPath).iterator() + .asScala + .toArray + .reverseIterator + .map(jnio.Files.deleteIfExists) + } + + results(target) = target.evaluate( + new Args(inputResults.toIndexedSeq, targetDestPath) + ) } 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 2cc59cc9..3baadda1 100644 --- a/src/main/scala/hbt/Main.scala +++ b/src/main/scala/hbt/Main.scala @@ -3,10 +3,11 @@ import java.nio.{file => jnio} import Util._ object Main{ 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") + val sourceRoot = Target.path(jnio.Paths.get("test/src")) + val resourceRoot = Target.path(jnio.Paths.get("test/resources")) val allSources = list(sourceRoot) val classFiles = compileAll(allSources) val jar = jarUp(resourceRoot, classFiles) + Hbt.evaluateTargetGraph(jar) } } \ No newline at end of file diff --git a/src/main/scala/hbt/ReadWrite.scala b/src/main/scala/hbt/ReadWrite.scala new file mode 100644 index 00000000..962c0ea4 --- /dev/null +++ b/src/main/scala/hbt/ReadWrite.scala @@ -0,0 +1,20 @@ +package hbt +import java.nio.{file => jnio} + +trait ReadWrite[T] { + def write(t: T, p: jnio.Path): Unit + def read(p: jnio.Path): T +} + +object ReadWrite{ + implicit object String extends ReadWrite[java.lang.String]{ + def write(t: String, p: jnio.Path) = { + jnio.Files.createDirectories(p.getParent) + jnio.Files.deleteIfExists(p) + jnio.Files.write(p, t.getBytes) + } + def read(p: jnio.Path) = { + new String(jnio.Files.readAllBytes(p)) + } + } +} diff --git a/src/main/scala/hbt/Tarjans.scala b/src/main/scala/hbt/Tarjans.scala index dc95b02f..7518080c 100644 --- a/src/main/scala/hbt/Tarjans.scala +++ b/src/main/scala/hbt/Tarjans.scala @@ -4,16 +4,7 @@ import collection.mutable // Adapted from // https://github.com/indy256/codelibrary/blob/c52247216258e84aac442a23273b7d8306ef757b/java/src/SCCTarjan.java object Tarjans { - def main(args: Array[String]) = { - val components = Tarjans( - Vector( - Vector(1), - Vector(0), - Vector(0, 1) - ) - ) - println(components) - } + def apply(graph0: Seq[Seq[Int]]): Seq[Seq[Int]] = { val graph = graph0.map(_.toArray).toArray diff --git a/src/main/scala/hbt/Util.scala b/src/main/scala/hbt/Util.scala index a7456b56..fef4009b 100644 --- a/src/main/scala/hbt/Util.scala +++ b/src/main/scala/hbt/Util.scala @@ -10,43 +10,52 @@ 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) + case class compileAll(sources: Target[Seq[jnio.Path]]) + (implicit path: Enclosing) extends Target[jnio.Path]{ + val label = path.value + val inputs = Seq(sources) + def evaluate(args: Args): jnio.Path = { + + jnio.Files.createDirectories(args.dest) val command = Seq("scalac") ++ - sources0.map(_.toString) ++ - Seq("-d", path.value) - + args[Seq[jnio.Path]](0).map(_.toString) ++ + Seq("-d", args.dest.toString) - - new java.lang.ProcessBuilder() + val result = new java.lang.ProcessBuilder() .command(command: _*) .start() .waitFor() - output + args.dest } } 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)) + case class jarUp(roots: Target[jnio.Path]*)(implicit path: Enclosing) extends Target[jnio.Path]{ + val label = path.value + val inputs = roots + def evaluate(args: Args): jnio.Path = { + + val output = new java.util.jar.JarOutputStream(new FileOutputStream(args.dest.toFile)) for{ - root <- rootsValue - path <- jnio.Files.list(root).iterator().asScala + root0 <- args.args + root = root0.asInstanceOf[jnio.Path] + + path <- jnio.Files.walk(root).iterator().asScala + if jnio.Files.isRegularFile(path) }{ val relative = root.relativize(path) output.putNextEntry(new JarEntry(relative.toString)) output.write(jnio.Files.readAllBytes(path)) } - jnio.Paths.get(path.value) + output.close() + args.dest } + + } diff --git a/test/src/Foo.scala b/test/src/Foo.scala index 96b7a530..4e8e09d6 100644 --- a/test/src/Foo.scala +++ b/test/src/Foo.scala @@ -1,4 +1,7 @@ package test object Foo{ def value = 31337 + def main(args: Array[String]): Unit = { + println(value) + } } \ No newline at end of file -- cgit v1.2.3