diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2018-01-13 13:00:21 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2018-01-13 14:37:24 -0800 |
commit | 57501fca3b6c2c64d32744e6d534b9de3a6674f6 (patch) | |
tree | 912a22fb405c971f4a4b75d737a35e522d6a420e /core/src | |
parent | 91102940a0bcdd7efc1d13e43510c4a0e406ead2 (diff) | |
download | mill-57501fca3b6c2c64d32744e6d534b9de3a6674f6.tar.gz mill-57501fca3b6c2c64d32744e6d534b9de3a6674f6.tar.bz2 mill-57501fca3b6c2c64d32744e6d534b9de3a6674f6.zip |
Migrate most classpath-related code onto `Loose.OSet` abstraction, to enforce deduplication
Diffstat (limited to 'core/src')
17 files changed, 131 insertions, 114 deletions
diff --git a/core/src/main/scala/mill/define/Graph.scala b/core/src/main/scala/mill/define/Graph.scala index e7844691..68fb65ed 100644 --- a/core/src/main/scala/mill/define/Graph.scala +++ b/core/src/main/scala/mill/define/Graph.scala @@ -1,7 +1,8 @@ package mill.define import mill.eval.Tarjans -import mill.util.{MultiBiMap, OSet} +import mill.util.MultiBiMap +import mill.util.Strict.OSet object Graph { class TopoSorted private[Graph](val values: OSet[Task[_]]) diff --git a/core/src/main/scala/mill/discover/Discovered.scala b/core/src/main/scala/mill/discover/Discovered.scala index c5ca4843..b7ec2140 100644 --- a/core/src/main/scala/mill/discover/Discovered.scala +++ b/core/src/main/scala/mill/discover/Discovered.scala @@ -5,7 +5,7 @@ import ammonite.main.Router import ammonite.main.Router.EntryPoint import mill.discover.Mirror.TargetPoint import mill.util.Ctx.Loader -import mill.util.OSet +import mill.util.Strict.OSet import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index efb10d36..2afaec6e 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -9,6 +9,7 @@ import mill.discover.{Discovered, Mirror} import mill.define.Segment import mill.util import mill.util._ +import mill.util.Strict.OSet import scala.collection.mutable import scala.util.control.NonFatal diff --git a/core/src/main/scala/mill/main/ReplApplyHandler.scala b/core/src/main/scala/mill/main/ReplApplyHandler.scala index d4236487..b83453ee 100644 --- a/core/src/main/scala/mill/main/ReplApplyHandler.scala +++ b/core/src/main/scala/mill/main/ReplApplyHandler.scala @@ -5,7 +5,7 @@ import mill.define.Applicative.ApplyHandler import mill.define._ import mill.discover.{Discovered, Mirror} import mill.eval.{Evaluator, Result} -import mill.util.OSet +import mill.util.Strict.OSet import scala.collection.mutable object ReplApplyHandler{ diff --git a/core/src/main/scala/mill/main/RunScript.scala b/core/src/main/scala/mill/main/RunScript.scala index b8793b40..9f73fbc8 100644 --- a/core/src/main/scala/mill/main/RunScript.scala +++ b/core/src/main/scala/mill/main/RunScript.scala @@ -11,7 +11,8 @@ import mill.define.Task import mill.define.Segment import mill.discover.Discovered import mill.eval.{Evaluator, Result} -import mill.util.{EitherOps, Logger, OSet} +import mill.util.{EitherOps, Logger} +import mill.util.Strict.OSet import upickle.Js /** diff --git a/core/src/main/scala/mill/modules/Jvm.scala b/core/src/main/scala/mill/modules/Jvm.scala index e6806923..6e3fe45f 100644 --- a/core/src/main/scala/mill/modules/Jvm.scala +++ b/core/src/main/scala/mill/modules/Jvm.scala @@ -9,14 +9,15 @@ import ammonite.ops._ import mill.define.Task import mill.eval.PathRef import mill.util.Ctx +import mill.util.Loose.OSet import scala.annotation.tailrec import scala.collection.mutable object Jvm { - def gatherClassloaderJars(): Seq[Path] = { - val allJars = collection.mutable.Buffer.empty[Path] + def gatherClassloaderJars(): OSet[Path] = { + val allJars = new OSet.Mutable[Path]() var currentClassloader = Thread.currentThread().getContextClassLoader while(currentClassloader != null){ currentClassloader match{ @@ -29,14 +30,14 @@ object Jvm { } def interactiveSubprocess(mainClass: String, - classPath: Seq[Path], + classPath: OSet[Path], options: Seq[String] = Seq.empty): Unit = { import ammonite.ops.ImplicitWd._ %("java", "-cp", classPath.mkString(":"), mainClass, options) } def subprocess(mainClass: String, - classPath: Seq[Path], + classPath: OSet[Path], jvmOptions: Seq[String] = Seq.empty, options: Seq[String] = Seq.empty, workingDir: Path = null) @@ -100,7 +101,7 @@ object Jvm { m } - def createJar(inputPaths: Seq[Path], mainClass: Option[String] = None) + def createJar(inputPaths: OSet[Path], mainClass: Option[String] = None) (implicit ctx: Ctx.DestCtx): PathRef = { val outputPath = ctx.dest rm(outputPath) @@ -134,7 +135,7 @@ object Jvm { PathRef(outputPath) } - def createAssembly(inputPaths: Seq[Path], + def createAssembly(inputPaths: OSet[Path], mainClass: Option[String] = None, prependShellScript: String = "") (implicit ctx: Ctx.DestCtx): PathRef = { diff --git a/core/src/main/scala/mill/package.scala b/core/src/main/scala/mill/package.scala index 3463b63f..0b4f4873 100644 --- a/core/src/main/scala/mill/package.scala +++ b/core/src/main/scala/mill/package.scala @@ -8,4 +8,6 @@ package object mill extends JsonFormatters{ type Module = define.Module val Module = define.Module type Cross[T] = define.Cross[T] + type OSet[T] = util.Loose.OSet[T] + val OSet = util.Loose.OSet } diff --git a/core/src/main/scala/mill/util/MultiBiMap.scala b/core/src/main/scala/mill/util/MultiBiMap.scala index ef5359bc..abbaa752 100644 --- a/core/src/main/scala/mill/util/MultiBiMap.scala +++ b/core/src/main/scala/mill/util/MultiBiMap.scala @@ -1,7 +1,7 @@ package mill.util import scala.collection.mutable - +import Strict.OSet /** * A map from keys to collections of values: you can assign multiple values * to any particular key. Also allows lookups in both directions: what values diff --git a/core/src/main/scala/mill/util/OSet.scala b/core/src/main/scala/mill/util/OSet.scala index 52b47cde..a4fcc406 100644 --- a/core/src/main/scala/mill/util/OSet.scala +++ b/core/src/main/scala/mill/util/OSet.scala @@ -3,108 +3,114 @@ package mill.util import scala.collection.mutable - -/** - * A collection with enforced uniqueness, fast contains and deterministic - * ordering. Raises an exception if a duplicate is found; call - * `toSeq.distinct` if you explicitly want to make it swallow duplicates - */ -trait OSet[V] extends TraversableOnce[V]{ - def contains(v: V): Boolean - def items: Iterator[V] - def indexed: IndexedSeq[V] - def flatMap[T](f: V => TraversableOnce[T]): OSet[T] - def map[T](f: V => T): OSet[T] - def filter(f: V => Boolean): OSet[V] - def withFilter(f: V => Boolean): OSet[V] - def collect[T](f: PartialFunction[V, T]): OSet[T] - def zipWithIndex: OSet[(V, Int)] - def reverse: OSet[V] - def zip[T](other: OSet[T]): OSet[(V, T)] -} - -object OSet{ - implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[OSet[T]] = - upickle.default.ReadWriter[OSet[T]] ( - oset => upickle.default.writeJs(oset.toList), - {case json => OSet.from(upickle.default.readJs[Seq[T]](json))} - ) - def apply[V](items: V*) = from(items) - - def from[V](items: TraversableOnce[V]): OSet[V] = { - val set = new OSet.Mutable[V]() - items.foreach(set.append) - set +object Strict extends OSetWrapper(true) +object Loose extends OSetWrapper(false) +sealed class OSetWrapper(strictUniqueness: Boolean){ + /** + * A collection with enforced uniqueness, fast contains and deterministic + * ordering. Raises an exception if a duplicate is found; call + * `toSeq.distinct` if you explicitly want to make it swallow duplicates + */ + trait OSet[V] extends TraversableOnce[V]{ + def contains(v: V): Boolean + def items: Iterator[V] + def indexed: IndexedSeq[V] + def flatMap[T](f: V => TraversableOnce[T]): OSet[T] + def map[T](f: V => T): OSet[T] + def filter(f: V => Boolean): OSet[V] + def withFilter(f: V => Boolean): OSet[V] + def collect[T](f: PartialFunction[V, T]): OSet[T] + def zipWithIndex: OSet[(V, Int)] + def reverse: OSet[V] + def zip[T](other: OSet[T]): OSet[(V, T)] + def ++[T >: V](other: TraversableOnce[T]): OSet[T] } + object OSet{ + def empty[V]: OSet[V] = new OSet.Mutable[V] + implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[OSet[T]] = + upickle.default.ReadWriter[OSet[T]] ( + oset => upickle.default.writeJs(oset.toList), + {case json => OSet.from(upickle.default.readJs[Seq[T]](json))} + ) + def apply[V](items: V*) = from(items) + + def from[V](items: TraversableOnce[V]): OSet[V] = { + val set = new OSet.Mutable[V]() + items.foreach(set.append) + set + } - class Mutable[V]() extends OSet[V]{ - private[this] val set0 = mutable.LinkedHashSet.empty[V] - def contains(v: V) = set0.contains(v) - def append(v: V) = if (!contains(v)){ - set0.add(v) + class Mutable[V]() extends OSet[V]{ - }else { - throw new Exception("Duplicated item inserted into OrderedSet: " + v) - } - def appendAll(vs: Seq[V]) = vs.foreach(append) - def items = set0.iterator - def indexed: IndexedSeq[V] = items.toIndexedSeq - def set: collection.Set[V] = set0 - - def map[T](f: V => T): OSet[T] = { - val output = new OSet.Mutable[T] - for(i <- items) output.append(f(i)) - output - } - def flatMap[T](f: V => TraversableOnce[T]): OSet[T] = { - val output = new OSet.Mutable[T] - for(i <- items) for(i0 <- f(i)) output.append(i0) - output - } - def filter(f: V => Boolean): OSet[V] = { - val output = new OSet.Mutable[V] - for(i <- items) if (f(i)) output.append(i) - output - } - def withFilter(f: V => Boolean): OSet[V] = filter(f) + private[this] val set0 = mutable.LinkedHashSet.empty[V] + def contains(v: V) = set0.contains(v) + def append(v: V) = if (!contains(v)){ + set0.add(v) - def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x)) + }else if (strictUniqueness){ + throw new Exception("Duplicated item inserted into OrderedSet: " + v) + } + def appendAll(vs: Seq[V]) = vs.foreach(append) + def items = set0.iterator + def indexed: IndexedSeq[V] = items.toIndexedSeq + def set: collection.Set[V] = set0 + + def map[T](f: V => T): OSet[T] = { + val output = new OSet.Mutable[T] + for(i <- items) output.append(f(i)) + output + } + def flatMap[T](f: V => TraversableOnce[T]): OSet[T] = { + val output = new OSet.Mutable[T] + for(i <- items) for(i0 <- f(i)) output.append(i0) + output + } + def filter(f: V => Boolean): OSet[V] = { + val output = new OSet.Mutable[V] + for(i <- items) if (f(i)) output.append(i) + output + } + def withFilter(f: V => Boolean): OSet[V] = filter(f) - def zipWithIndex = { - var i = 0 - this.map{ x => - i += 1 - (x, i-1) + def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x)) + + def zipWithIndex = { + var i = 0 + this.map{ x => + i += 1 + (x, i-1) + } } - } - def reverse = OSet.from(indexed.reverseIterator) - - def zip[T](other: OSet[T]) = OSet.from(items.zip(other.items)) - - // Members declared in scala.collection.GenTraversableOnce - def isTraversableAgain: Boolean = items.isTraversableAgain - def toIterator: Iterator[V] = items.toIterator - def toStream: Stream[V] = items.toStream - - // Members declared in scala.collection.TraversableOnce - def copyToArray[B >: V](xs: Array[B],start: Int,len: Int): Unit = items.copyToArray(xs, start, len) - def exists(p: V => Boolean): Boolean = items.exists(p) - def find(p: V => Boolean): Option[V] = items.find(p) - def forall(p: V => Boolean): Boolean = items.forall(p) - def foreach[U](f: V => U): Unit = items.foreach(f) - def hasDefiniteSize: Boolean = items.hasDefiniteSize - def isEmpty: Boolean = items.isEmpty - def seq: scala.collection.TraversableOnce[V] = items - def toTraversable: Traversable[V] = items.toTraversable - - override def hashCode() = items.hashCode() - override def equals(other: Any) = other match{ - case s: OSet[_] => items.sameElements(s.items) - case _ => super.equals(other) + def reverse = OSet.from(indexed.reverseIterator) + + def zip[T](other: OSet[T]) = OSet.from(items.zip(other.items)) + def ++[T >: V](other: TraversableOnce[T]) = OSet.from(items ++ other) + + // Members declared in scala.collection.GenTraversableOnce + def isTraversableAgain: Boolean = items.isTraversableAgain + def toIterator: Iterator[V] = items.toIterator + def toStream: Stream[V] = items.toStream + + // Members declared in scala.collection.TraversableOnce + def copyToArray[B >: V](xs: Array[B], start: Int,len: Int): Unit = items.copyToArray(xs, start, len) + def exists(p: V => Boolean): Boolean = items.exists(p) + def find(p: V => Boolean): Option[V] = items.find(p) + def forall(p: V => Boolean): Boolean = items.forall(p) + def foreach[U](f: V => U): Unit = items.foreach(f) + def hasDefiniteSize: Boolean = items.hasDefiniteSize + def isEmpty: Boolean = items.isEmpty + def seq: scala.collection.TraversableOnce[V] = items + def toTraversable: Traversable[V] = items.toTraversable + + override def hashCode() = items.map(_.hashCode()).sum + override def equals(other: Any) = other match{ + case s: OSet[_] => items.sameElements(s.items) + case _ => super.equals(other) + } + override def toString = items.mkString("OSet(", ", ", ")") } - override def toString = items.mkString("OSet(", ", ", ")") } } diff --git a/core/src/test/scala/mill/define/CacherTests.scala b/core/src/test/scala/mill/define/CacherTests.scala index faf274f2..4127a75b 100644 --- a/core/src/test/scala/mill/define/CacherTests.scala +++ b/core/src/test/scala/mill/define/CacherTests.scala @@ -2,7 +2,8 @@ package mill.define import mill.discover.Discovered import mill.eval.Evaluator -import mill.util.{DummyLogger, OSet, TestUtil} +import mill.util.{DummyLogger, TestUtil} +import mill.util.Strict.OSet import mill.T import mill.eval.Result.Success import utest._ diff --git a/core/src/test/scala/mill/define/GraphTests.scala b/core/src/test/scala/mill/define/GraphTests.scala index 718fd673..7241087a 100644 --- a/core/src/test/scala/mill/define/GraphTests.scala +++ b/core/src/test/scala/mill/define/GraphTests.scala @@ -4,9 +4,9 @@ package mill.define import mill.discover.Discovered import Discovered.mapping import mill.eval.Evaluator -import mill.util.{OSet, TestGraphs, TestUtil} +import mill.util.{TestGraphs, TestUtil} import utest._ - +import mill.util.Strict.OSet object GraphTests extends TestSuite{ val tests = Tests{ diff --git a/core/src/test/scala/mill/discover/ConsistencyTests.scala b/core/src/test/scala/mill/discover/ConsistencyTests.scala index 190b2cee..4a9ae843 100644 --- a/core/src/test/scala/mill/discover/ConsistencyTests.scala +++ b/core/src/test/scala/mill/discover/ConsistencyTests.scala @@ -3,7 +3,8 @@ package mill.discover import mill.define.Segment.Label import mill.define.Segments -import mill.util.{OSet, TestGraphs} +import mill.util.{TestGraphs} +import mill.util.Strict.OSet import utest._ object ConsistencyTests extends TestSuite{ diff --git a/core/src/test/scala/mill/eval/EvaluationTests.scala b/core/src/test/scala/mill/eval/EvaluationTests.scala index 54e184b5..2b9dd102 100644 --- a/core/src/test/scala/mill/eval/EvaluationTests.scala +++ b/core/src/test/scala/mill/eval/EvaluationTests.scala @@ -6,7 +6,8 @@ import mill.define.{Graph, Target, Task} import mill.{Module, T} import mill.discover.Discovered import mill.discover.Discovered.mapping -import mill.util.{DummyLogger, OSet, TestGraphs, TestUtil} +import mill.util.{DummyLogger, TestGraphs, TestUtil} +import mill.util.Strict.OSet import utest._ import utest.framework.TestPath diff --git a/core/src/test/scala/mill/eval/FailureTests.scala b/core/src/test/scala/mill/eval/FailureTests.scala index c2057cd1..ef206740 100644 --- a/core/src/test/scala/mill/eval/FailureTests.scala +++ b/core/src/test/scala/mill/eval/FailureTests.scala @@ -3,7 +3,8 @@ package mill.eval import mill.define.Target import mill.discover.Discovered import mill.discover.Discovered.mapping -import mill.util.{DummyLogger, OSet} +import mill.util.DummyLogger +import mill.util.Strict.OSet import utest._ import utest.framework.TestPath diff --git a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala index c8320fcd..8105f2fa 100644 --- a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala +++ b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala @@ -7,7 +7,8 @@ import mill.discover.Discovered import mill.modules.Jvm import mill.util.Ctx.DestCtx import mill.{Module, T} -import mill.util.{DummyLogger, OSet, TestUtil} +import mill.util.{DummyLogger, Loose, TestUtil} +import mill.util.Strict.OSet import utest._ import mill._ @@ -40,7 +41,7 @@ object JavaCompileJarTests extends TestSuite{ def resourceRoot = T.source{ resourceRootPath } def allSources = T{ ls.rec(sourceRoot().path).map(PathRef(_)) } def classFiles = T{ compileAll(allSources()) } - def jar = T{ Jvm.createJar(Seq(resourceRoot().path, classFiles().path)) } + def jar = T{ Jvm.createJar(Loose.OSet(resourceRoot().path, classFiles().path)) } def run(mainClsName: String) = T.command{ %%('java, "-cp", classFiles().path, mainClsName) diff --git a/core/src/test/scala/mill/util/TestEvaluator.scala b/core/src/test/scala/mill/util/TestEvaluator.scala index 646ca418..3f6086ba 100644 --- a/core/src/test/scala/mill/util/TestEvaluator.scala +++ b/core/src/test/scala/mill/util/TestEvaluator.scala @@ -4,7 +4,7 @@ import ammonite.ops.Path import mill.define.{Input, Target, Task} import mill.discover.{Discovered, Mirror} import mill.eval.{Evaluator, Result} - +import mill.util.Strict.OSet class TestEvaluator(mapping: Discovered.Mapping[_], workspacePath: Path, basePath: Path){ diff --git a/core/src/test/scala/mill/util/TestUtil.scala b/core/src/test/scala/mill/util/TestUtil.scala index ae985665..3cc945db 100644 --- a/core/src/test/scala/mill/util/TestUtil.scala +++ b/core/src/test/scala/mill/util/TestUtil.scala @@ -4,7 +4,7 @@ import ammonite.main.Router.Overrides import mill.define._ import mill.eval.Result import utest.assert - +import mill.util.Strict.OSet import scala.collection.mutable object TestUtil { |