summaryrefslogtreecommitdiff
path: root/scalalib
diff options
context:
space:
mode:
Diffstat (limited to 'scalalib')
-rw-r--r--scalalib/src/mill/scalalib/Dep.scala66
-rw-r--r--scalalib/src/mill/scalalib/GenIdeaImpl.scala (renamed from scalalib/src/mill/scalalib/GenIdea.scala)69
-rw-r--r--scalalib/src/mill/scalalib/JavaModule.scala284
-rw-r--r--scalalib/src/mill/scalalib/Lib.scala86
-rw-r--r--scalalib/src/mill/scalalib/PublishModule.scala8
-rw-r--r--scalalib/src/mill/scalalib/ScalaModule.scala245
-rw-r--r--scalalib/src/mill/scalalib/ScalaWorkerApi.scala5
-rw-r--r--scalalib/src/mill/scalalib/publish/Ivy.scala6
-rw-r--r--scalalib/src/mill/scalalib/publish/Pom.scala2
-rw-r--r--scalalib/src/mill/scalalib/publish/settings.scala20
-rw-r--r--scalalib/test/resources/hello-java/core/src/hello/Core.java8
-rw-r--r--scalalib/test/resources/hello-java/main/src/hello/Main.java7
-rw-r--r--scalalib/test/resources/hello-world-macros/core/src/Main.scala5
-rw-r--r--scalalib/test/src/mill/scalalib/GenIdeaTests.scala2
-rw-r--r--scalalib/test/src/mill/scalalib/HelloJavaTests.scala60
-rw-r--r--scalalib/test/src/mill/scalalib/HelloWorldTests.scala71
-rw-r--r--scalalib/test/src/mill/scalalib/ResolveDepsTests.scala14
-rw-r--r--scalalib/test/src/mill/scalalib/publish/IvyTests.scala14
18 files changed, 666 insertions, 306 deletions
diff --git a/scalalib/src/mill/scalalib/Dep.scala b/scalalib/src/mill/scalalib/Dep.scala
index f20480b7..9719bd2d 100644
--- a/scalalib/src/mill/scalalib/Dep.scala
+++ b/scalalib/src/mill/scalalib/Dep.scala
@@ -3,23 +3,29 @@ import mill.util.JsonFormatters._
import upickle.default.{macroRW, ReadWriter => RW}
sealed trait Dep {
def configure(attributes: coursier.Attributes): Dep
- def exclude(exclusions: (String, String)*): Dep =
- this match {
- case dep : Dep.Java => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
- case dep : Dep.Scala => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
- case dep : Dep.Point => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
- }
+ def force: Boolean
+ def forceVersion(): Dep = this match {
+ case dep : Dep.Java => dep.copy(force = true)
+ case dep : Dep.Scala => dep.copy(force = true)
+ case dep : Dep.Point => dep.copy(force = true)
+ }
+ def exclude(exclusions: (String, String)*): Dep = this match {
+ case dep : Dep.Java => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
+ case dep : Dep.Scala => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
+ case dep : Dep.Point => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
+ }
def excludeOrg(organizations: String*): Dep = exclude(organizations.map(_ -> "*"): _*)
def excludeName(names: String*): Dep = exclude(names.map("*" -> _): _*)
- def withConfiguration(configuration: String): Dep =
- this match {
- case dep : Dep.Java => dep.copy(dep = dep.dep.copy(configuration = configuration))
- case dep : Dep.Scala => dep.copy(dep = dep.dep.copy(configuration = configuration))
- case dep : Dep.Point => dep.copy(dep = dep.dep.copy(configuration = configuration))
- }
+ def withConfiguration(configuration: String): Dep = this match {
+ case dep : Dep.Java => dep.copy(dep = dep.dep.copy(configuration = configuration))
+ case dep : Dep.Scala => dep.copy(dep = dep.dep.copy(configuration = configuration))
+ case dep : Dep.Point => dep.copy(dep = dep.dep.copy(configuration = configuration))
+ }
}
object Dep{
+ val DefaultConfiguration = "default(compile)"
+
implicit def parse(signature: String) = {
val parts = signature.split(';')
val module = parts.head
@@ -31,45 +37,45 @@ object Dep{
}
}
(module.split(':') match {
- case Array(a, b, c) => Dep.Java(a, b, c, cross = false)
- case Array(a, b, "", c) => Dep.Java(a, b, c, cross = true)
- case Array(a, "", b, c) => Dep.Scala(a, b, c, cross = false)
- case Array(a, "", b, "", c) => Dep.Scala(a, b, c, cross = true)
- case Array(a, "", "", b, c) => Dep.Point(a, b, c, cross = false)
- case Array(a, "", "", b, "", c) => Dep.Point(a, b, c, cross = true)
+ case Array(a, b, c) => Dep.Java(a, b, c, cross = false, force = false)
+ case Array(a, b, "", c) => Dep.Java(a, b, c, cross = true, force = false)
+ case Array(a, "", b, c) => Dep.Scala(a, b, c, cross = false, force = false)
+ case Array(a, "", b, "", c) => Dep.Scala(a, b, c, cross = true, force = false)
+ case Array(a, "", "", b, c) => Dep.Point(a, b, c, cross = false, force = false)
+ case Array(a, "", "", b, "", c) => Dep.Point(a, b, c, cross = true, force = false)
case _ => throw new Exception(s"Unable to parse signature: [$signature]")
}).configure(attributes = attributes)
}
def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
- this(coursier.Dependency(coursier.Module(org, name), version), cross)
+ this(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross)
}
- case class Java(dep: coursier.Dependency, cross: Boolean) extends Dep {
+ case class Java(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
}
object Java{
implicit def rw: RW[Java] = macroRW
- def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
- Java(coursier.Dependency(coursier.Module(org, name), version), cross)
+ def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
+ Java(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
}
}
- implicit def default(dep: coursier.Dependency): Dep = new Java(dep, false)
- def apply(dep: coursier.Dependency, cross: Boolean) = Scala(dep, cross)
- case class Scala(dep: coursier.Dependency, cross: Boolean) extends Dep {
+ implicit def default(dep: coursier.Dependency): Dep = new Java(dep, false, false)
+ def apply(dep: coursier.Dependency, cross: Boolean) = Scala(dep, cross, false)
+ case class Scala(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
}
object Scala{
implicit def rw: RW[Scala] = macroRW
- def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
- Scala(coursier.Dependency(coursier.Module(org, name), version), cross)
+ def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
+ Scala(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
}
}
- case class Point(dep: coursier.Dependency, cross: Boolean) extends Dep {
+ case class Point(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
}
object Point{
implicit def rw: RW[Point] = macroRW
- def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
- Point(coursier.Dependency(coursier.Module(org, name), version), cross)
+ def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
+ Point(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
}
}
implicit def rw = RW.merge[Dep](
diff --git a/scalalib/src/mill/scalalib/GenIdea.scala b/scalalib/src/mill/scalalib/GenIdeaImpl.scala
index b118f29b..3e90f269 100644
--- a/scalalib/src/mill/scalalib/GenIdea.scala
+++ b/scalalib/src/mill/scalalib/GenIdeaImpl.scala
@@ -12,10 +12,10 @@ import mill.util.Strict.Agg
import scala.util.Try
-object GenIdeaModule extends ExternalModule {
+object GenIdea extends ExternalModule {
def idea(ev: Evaluator[Any]) = T.command{
- mill.scalalib.GenIdea(
+ mill.scalalib.GenIdeaImpl(
implicitly,
ev.rootModule,
ev.rootModule.millDiscover
@@ -25,7 +25,7 @@ object GenIdeaModule extends ExternalModule {
implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]()
lazy val millDiscover = Discover[this.type]
}
-object GenIdea {
+object GenIdeaImpl {
def apply(ctx: Log with Home,
rootModule: BaseModule,
@@ -62,27 +62,31 @@ object GenIdea {
fetchMillModules: Boolean = true): Seq[(RelPath, scala.xml.Node)] = {
val modules = rootModule.millInternal.segmentsToModules.values
- .collect{ case x: scalalib.ScalaModule => (x.millModuleSegments, x)}
+ .collect{ case x: scalalib.JavaModule => (x.millModuleSegments, x)}
.toSeq
val buildLibraryPaths =
if (!fetchMillModules) Nil
else sys.props.get("MILL_BUILD_LIBRARIES") match {
- case Some(found) => Agg.from(found.split(',').map(Path(_)).distinct)
+ case Some(found) => found.split(',').map(Path(_)).distinct.toList
case None =>
- val repos = modules.foldLeft(Set.empty[Repository]) { _ ++ _._2.scalaWorker.repositories }
+ val repos = modules.foldLeft(Set.empty[Repository]) { _ ++ _._2.repositories }
val artifactNames = Seq("moduledefs", "core", "scalalib", "scalajslib")
val Result.Success(res) = scalalib.Lib.resolveDependencies(
repos.toList,
- "2.12.4",
+ Lib.depToDependency(_, "2.12.4", ""),
for(name <- artifactNames)
yield ivy"com.lihaoyi::mill-$name:${sys.props("MILL_VERSION")}"
)
- res.items.toSeq.map(_.path)
+ res.items.toList.map(_.path)
}
val resolved = for((path, mod) <- modules) yield {
- val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ mod.scalaLibraryIvyDeps() ++ mod.compileIvyDeps()}
+ val scalaLibraryIvyDeps = mod match{
+ case x: ScalaModule => x.scalaLibraryIvyDeps
+ case _ => T.task{Nil}
+ }
+ val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ scalaLibraryIvyDeps() ++ mod.compileIvyDeps()}
val externalDependencies = T.task{
mod.resolveDeps(allIvyDeps)() ++
Task.traverse(mod.transitiveModuleDeps)(_.unmanagedClasspath)().flatten
@@ -92,8 +96,10 @@ object GenIdea {
mod.resolveDeps(allIvyDeps, sources = true)()
}
- val scalacPluginsIvyDeps = T.task{mod.scalacPluginIvyDeps()}
- val scalacOptions = T.task{mod.scalacOptions()}
+ val (scalacPluginsIvyDeps, scalacOptions) = mod match{
+ case mod: ScalaModule => T.task{mod.scalacPluginIvyDeps()} -> T.task{mod.scalacOptions()}
+ case _ => T.task(Loose.Agg[Dep]()) -> T.task(Seq())
+ }
val scalacPluginDependencies = T.task{
mod.resolveDeps(scalacPluginsIvyDeps)()
}
@@ -103,18 +109,27 @@ object GenIdea {
val resolvedSp: Loose.Agg[PathRef] = evalOrElse(evaluator, scalacPluginDependencies, Loose.Agg.empty)
val scalacOpts: Seq[String] = evalOrElse(evaluator, scalacOptions, Seq())
- (path, resolvedCp.map(_.path).filter(_.ext == "jar") ++ resolvedSrcs.map(_.path), mod,
- resolvedSp.map(_.path).filter(_.ext == "jar"), scalacOpts)
+ (
+ path,
+ resolvedCp.map(_.path).filter(_.ext == "jar") ++ resolvedSrcs.map(_.path),
+ mod,
+ resolvedSp.map(_.path).filter(_.ext == "jar"),
+ scalacOpts
+ )
}
val moduleLabels = modules.map(_.swap).toMap
val allResolved = resolved.flatMap(_._2) ++ buildLibraryPaths
- val minResolvedLength = allResolved.map(_.segments.length).min
- val commonPrefix = allResolved.map(_.segments.take(minResolvedLength))
- .transpose
- .takeWhile(_.distinct.length == 1)
- .length
+ val commonPrefix =
+ if (allResolved.isEmpty) 0
+ else {
+ val minResolvedLength = allResolved.map(_.segments.length).min
+ allResolved.map(_.segments.take(minResolvedLength))
+ .transpose
+ .takeWhile(_.distinct.length == 1)
+ .length
+ }
// only resort to full long path names if the jar name is a duplicate
val pathShortLibNameDuplicate = allResolved
@@ -134,7 +149,7 @@ object GenIdea {
.toMap
val compilerSettings = resolved
- .foldLeft(Map[(Loose.Agg[Path], Seq[String]), Vector[ScalaModule]]()) {
+ .foldLeft(Map[(Loose.Agg[Path], Seq[String]), Vector[JavaModule]]()) {
(r, q) =>
val key = (q._4, q._5)
r + (key -> (r.getOrElse(key, Vector()) :+ q._3))
@@ -190,7 +205,10 @@ object GenIdea {
evaluator.outPath,
mod.compile.ctx.segments
)
- val Seq(scalaVersion: String) = evaluator.evaluate(Agg(mod.scalaVersion)).values
+ val scalaVersionOpt = mod match {
+ case x: ScalaModule => Some(evaluator.evaluate(Agg(x.scalaVersion)).values.head.asInstanceOf[String])
+ case _ => None
+ }
val generatedSourceOutPath = Evaluator.resolveDestPaths(
evaluator.outPath,
mod.generatedSources.ctx.segments
@@ -198,7 +216,7 @@ object GenIdea {
val elem = moduleXmlTemplate(
mod.millModuleBasePath.value,
- scalaVersion,
+ scalaVersionOpt,
Strict.Agg.from(resourcesPathRefs.map(_.path)),
Strict.Agg.from(normalSourcePaths),
Strict.Agg.from(generatedSourcePaths),
@@ -293,7 +311,7 @@ object GenIdea {
</component>
}
def moduleXmlTemplate(basePath: Path,
- scalaVersion: String,
+ scalaVersionOpt: Option[String],
resourcePaths: Strict.Agg[Path],
normalSourcePaths: Strict.Agg[Path],
generatedSourcePaths: Strict.Agg[Path],
@@ -326,7 +344,10 @@ object GenIdea {
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
- <orderEntry type="library" name={s"scala-sdk-$scalaVersion"} level="application" />
+ {
+ for(scalaVersion <- scalaVersionOpt.toSeq)
+ yield <orderEntry type="library" name={s"scala-sdk-$scalaVersion"} level="application" />
+ }
{
for(name <- libNames.toSeq.sorted)
@@ -340,7 +361,7 @@ object GenIdea {
</component>
</module>
}
- def scalaCompilerTemplate(settings: Map[(Loose.Agg[Path], Seq[String]), Seq[ScalaModule]]) = {
+ def scalaCompilerTemplate(settings: Map[(Loose.Agg[Path], Seq[String]), Seq[JavaModule]]) = {
<project version="4">
<component name="ScalaCompilerConfiguration">
diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala
new file mode 100644
index 00000000..b8ae0fd4
--- /dev/null
+++ b/scalalib/src/mill/scalalib/JavaModule.scala
@@ -0,0 +1,284 @@
+package mill
+package scalalib
+
+
+import ammonite.ops._
+import coursier.Repository
+import mill.define.Task
+import mill.define.TaskModule
+import mill.eval.{PathRef, Result}
+import mill.modules.Jvm
+import mill.modules.Jvm.{createAssembly, createJar}
+import Lib._
+import mill.scalalib.publish.{Artifact, Scope}
+import mill.util.Loose.Agg
+
+/**
+ * Core configuration required to compile a single Scala compilation target
+ */
+trait JavaModule extends mill.Module with TaskModule { outer =>
+
+ def defaultCommandName() = "run"
+
+ def resolvePublishDependency: Task[Dep => publish.Dependency] = T.task{
+ Artifact.fromDepJava(_: Dep)
+ }
+ def resolveCoursierDependency: Task[Dep => coursier.Dependency] = T.task{
+ Lib.depToDependencyJava(_: Dep)
+ }
+
+ def mainClass: T[Option[String]] = None
+
+ def finalMainClassOpt: T[Either[String, String]] = T{
+ mainClass() match{
+ case Some(m) => Right(m)
+ case None => Left("No main class specified or found")
+ }
+ }
+
+ def finalMainClass: T[String] = T{
+ finalMainClassOpt() match {
+ case Right(main) => Result.Success(main)
+ case Left(msg) => Result.Failure(msg)
+ }
+ }
+
+ def ivyDeps = T{ Agg.empty[Dep] }
+ def compileIvyDeps = T{ Agg.empty[Dep] }
+ def runIvyDeps = T{ Agg.empty[Dep] }
+
+ def javacOptions = T{ Seq.empty[String] }
+
+ def moduleDeps = Seq.empty[JavaModule]
+
+
+ def transitiveModuleDeps: Seq[JavaModule] = {
+ Seq(this) ++ moduleDeps.flatMap(_.transitiveModuleDeps).distinct
+ }
+ def unmanagedClasspath = T{ Agg.empty[PathRef] }
+
+
+ def transitiveIvyDeps: T[Agg[Dep]] = T{
+ ivyDeps() ++ Task.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten
+ }
+
+ def upstreamCompileOutput = T{
+ Task.traverse(moduleDeps)(_.compile)
+ }
+
+ def transitiveLocalClasspath: T[Agg[PathRef]] = T{
+ Task.traverse(moduleDeps)(m =>
+ T.task{m.localClasspath() ++ m.transitiveLocalClasspath()}
+ )().flatten
+ }
+
+ def mapDependencies(d: coursier.Dependency) = d
+
+ def resolveDeps(deps: Task[Agg[Dep]], sources: Boolean = false) = T.task{
+ resolveDependencies(
+ repositories,
+ resolveCoursierDependency().apply(_),
+ deps(),
+ sources,
+ mapDependencies = Some(mapDependencies)
+ )
+ }
+
+
+ def repositories: Seq[Repository] = ScalaWorkerModule.repositories
+
+ def platformSuffix = T{ "" }
+
+ private val Milestone213 = raw"""2.13.(\d+)-M(\d+)""".r
+
+ def prependShellScript: T[String] = T{
+ mainClass() match{
+ case None => ""
+ case Some(cls) =>
+ val isWin = scala.util.Properties.isWin
+ mill.modules.Jvm.launcherUniversalScript(
+ cls,
+ Agg("$0"), Agg("%~dpnx0"),
+ forkArgs()
+ )
+ }
+ }
+
+ def sources = T.sources{ millSourcePath / 'src }
+ def resources = T.sources{ millSourcePath / 'resources }
+ def generatedSources = T{ Seq.empty[PathRef] }
+ def allSources = T{ sources() ++ generatedSources() }
+
+ def allSourceFiles = T{
+ for {
+ root <- allSources()
+ if exists(root.path)
+ path <- ls.rec(root.path)
+ if path.isFile && (path.ext == "scala" || path.ext == "java")
+ } yield PathRef(path)
+ }
+
+ def compile: T[CompilationResult] = T{
+ Lib.compileJava(
+ allSourceFiles().map(_.path.toIO).toArray,
+ compileClasspath().map(_.path.toIO).toArray,
+ javacOptions(),
+ upstreamCompileOutput()
+ )
+ }
+ def localClasspath = T{
+ resources() ++ Agg(compile().classes)
+ }
+ def compileClasspath = T{
+ transitiveLocalClasspath() ++
+ resources() ++
+ unmanagedClasspath() ++
+ resolveDeps(T.task{compileIvyDeps() ++ transitiveIvyDeps()})()
+ }
+
+ def upstreamAssemblyClasspath = T{
+ transitiveLocalClasspath() ++
+ unmanagedClasspath() ++
+ resolveDeps(T.task{runIvyDeps() ++ transitiveIvyDeps()})()
+ }
+
+ def runClasspath = T{
+ localClasspath() ++
+ upstreamAssemblyClasspath()
+ }
+
+ /**
+ * Build the assembly for upstream dependencies separate from the current classpath
+ *
+ * This should allow much faster assembly creation in the common case where
+ * upstream dependencies do not change
+ */
+ def upstreamAssembly = T{
+ createAssembly(upstreamAssemblyClasspath().map(_.path), mainClass())
+ }
+
+ def assembly = T{
+ createAssembly(
+ Agg.from(localClasspath().map(_.path)),
+ mainClass(),
+ prependShellScript(),
+ Some(upstreamAssembly().path)
+ )
+ }
+
+
+ def jar = T{
+ createJar(
+ localClasspath().map(_.path).filter(exists),
+ mainClass()
+ )
+ }
+
+ def docJar = T[PathRef] {
+ val outDir = T.ctx().dest
+
+ val javadocDir = outDir / 'javadoc
+ mkdir(javadocDir)
+
+ val files = for{
+ ref <- allSources()
+ if exists(ref.path)
+ p <- ls.rec(ref.path)
+ if p.isFile
+ } yield p.toNIO.toString
+
+ val options = Seq("-d", javadocDir.toNIO.toString)
+
+ if (files.nonEmpty) Jvm.baseInteractiveSubprocess(
+ commandArgs = Seq(
+ "javadoc"
+ ) ++ options ++
+ Seq(
+ "-classpath",
+ compileClasspath()
+ .map(_.path)
+ .filter(_.ext != "pom")
+ .mkString(java.io.File.pathSeparator)
+ ) ++
+ files.map(_.toString),
+ envArgs = Map(),
+ workingDir = T.ctx().dest
+ )
+
+ createJar(Agg(javadocDir))(outDir)
+ }
+
+ def sourceJar = T {
+ createJar((allSources() ++ resources()).map(_.path).filter(exists))
+ }
+
+ def forkArgs = T{ Seq.empty[String] }
+
+ def forkEnv = T{ sys.env.toMap }
+
+ def launcher = T{
+ Result.Success(
+ Jvm.createLauncher(
+ finalMainClass(),
+ runClasspath().map(_.path),
+ forkArgs()
+ )
+ )
+ }
+
+ def ivyDepsTree(inverse: Boolean = false) = T.command {
+ val (flattened, resolution) = Lib.resolveDependenciesMetadata(
+ repositories, resolveCoursierDependency().apply(_), ivyDeps(), Some(mapDependencies)
+ )
+
+ println(coursier.util.Print.dependencyTree(flattened, resolution,
+ printExclusions = false, reverse = inverse))
+
+ Result.Success()
+ }
+
+ def runLocal(args: String*) = T.command {
+ Jvm.runLocal(
+ finalMainClass(),
+ runClasspath().map(_.path),
+ args
+ )
+ }
+
+ def run(args: String*) = T.command{
+ Jvm.interactiveSubprocess(
+ finalMainClass(),
+ runClasspath().map(_.path),
+ forkArgs(),
+ forkEnv(),
+ args,
+ workingDir = ammonite.ops.pwd
+ )
+ }
+
+
+ def runMainLocal(mainClass: String, args: String*) = T.command {
+ Jvm.runLocal(
+ mainClass,
+ runClasspath().map(_.path),
+ args
+ )
+ }
+
+ def runMain(mainClass: String, args: String*) = T.command{
+ Jvm.interactiveSubprocess(
+ mainClass,
+ runClasspath().map(_.path),
+ forkArgs(),
+ forkEnv(),
+ args,
+ workingDir = ammonite.ops.pwd
+ )
+ }
+
+ // publish artifact with name "mill_2.12.4" instead of "mill_2.12"
+
+ def artifactName: T[String] = millModuleSegments.parts.mkString("-")
+
+ def artifactId: T[String] = artifactName()
+} \ No newline at end of file
diff --git a/scalalib/src/mill/scalalib/Lib.scala b/scalalib/src/mill/scalalib/Lib.scala
index e6a7a255..7b4b5bdb 100644
--- a/scalalib/src/mill/scalalib/Lib.scala
+++ b/scalalib/src/mill/scalalib/Lib.scala
@@ -1,6 +1,9 @@
package mill
package scalalib
+import java.io.File
+import javax.tools.ToolProvider
+
import ammonite.ops._
import ammonite.util.Util
import coursier.{Cache, Dependency, Fetch, Repository, Resolution}
@@ -15,6 +18,28 @@ object CompilationResult {
case class CompilationResult(analysisFile: Path, classes: PathRef)
object Lib{
+ def compileJava(sources: Array[java.io.File],
+ classpath: Array[java.io.File],
+ javaOpts: Seq[String],
+ upstreamCompileOutput: Seq[CompilationResult])
+ (implicit ctx: mill.util.Ctx) = {
+ val javac = ToolProvider.getSystemJavaCompiler()
+
+ rm(ctx.dest / 'classes)
+ mkdir(ctx.dest / 'classes)
+ val cpArgs =
+ if(classpath.isEmpty) Seq()
+ else Seq("-cp", classpath.mkString(File.pathSeparator))
+
+ val args = Seq("-d", ctx.dest / 'classes) ++ cpArgs ++ javaOpts ++ sources
+
+ javac.run(
+ ctx.log.inStream, ctx.log.outputStream, ctx.log.errorStream,
+ args.map(_.toString):_*
+ )
+ if (ls(ctx.dest / 'classes).isEmpty) mill.eval.Result.Failure("Compilation Failed")
+ else mill.eval.Result.Success(CompilationResult(ctx.dest / 'zinc, PathRef(ctx.dest / 'classes)))
+ }
private val ReleaseVersion = raw"""(\d+)\.(\d+)\.(\d+)""".r
private val MinorSnapshotVersion = raw"""(\d+)\.(\d+)\.([1-9]\d*)-SNAPSHOT""".r
@@ -34,17 +59,23 @@ object Lib{
.toIO
}
- def depToDependency(dep: Dep, scalaVersion: String, platformSuffix: String = ""): Dependency =
+
+ def depToDependencyJava(dep: Dep, platformSuffix: String = ""): Dependency = {
dep match {
- case Dep.Java(dep, cross) =>
+ case Dep.Java(dep, cross, force) =>
dep.copy(
module = dep.module.copy(
name =
dep.module.name +
- (if (!cross) "" else platformSuffix)
+ (if (!cross) "" else platformSuffix)
)
)
- case Dep.Scala(dep, cross) =>
+ }
+ }
+ def depToDependency(dep: Dep, scalaVersion: String, platformSuffix: String = ""): Dependency =
+ dep match {
+ case d: Dep.Java => depToDependencyJava(dep)
+ case Dep.Scala(dep, cross, force) =>
dep.copy(
module = dep.module.copy(
name =
@@ -53,7 +84,7 @@ object Lib{
"_" + scalaBinaryVersion(scalaVersion)
)
)
- case Dep.Point(dep, cross) =>
+ case Dep.Point(dep, cross, force) =>
dep.copy(
module = dep.module.copy(
name =
@@ -65,7 +96,29 @@ object Lib{
}
+ def resolveDependenciesMetadata(repositories: Seq[Repository],
+ depToDependency: Dep => coursier.Dependency,
+ deps: TraversableOnce[Dep],
+ mapDependencies: Option[Dependency => Dependency] = None) = {
+ val depSeq = deps.toSeq
+ val flattened = depSeq.map(depToDependency)
+
+ val forceVersions = depSeq.filter(_.force)
+ .map(depToDependency)
+ .map(mapDependencies.getOrElse(identity[Dependency](_)))
+ .map{d => d.module -> d.version}
+ .toMap
+ val start = Resolution(
+ flattened.map(mapDependencies.getOrElse(identity[Dependency](_))).toSet,
+ forceVersions = forceVersions,
+ mapDependencies = mapDependencies
+ )
+
+ val fetch = Fetch.from(repositories, Cache.fetch())
+ val resolution = start.process.run(fetch).unsafePerformSync
+ (flattened, resolution)
+ }
/**
* Resolve dependencies using Coursier.
*
@@ -74,16 +127,14 @@ object Lib{
* `import $ivy` syntax.
*/
def resolveDependencies(repositories: Seq[Repository],
- scalaVersion: String,
+ depToDependency: Dep => coursier.Dependency,
deps: TraversableOnce[Dep],
- platformSuffix: String = "",
- sources: Boolean = false): Result[Agg[PathRef]] = {
+ sources: Boolean = false,
+ mapDependencies: Option[Dependency => Dependency] = None): Result[Agg[PathRef]] = {
- val flattened = deps.map(depToDependency(_, scalaVersion, platformSuffix)).toSet
- val start = Resolution(flattened)
-
- val fetch = Fetch.from(repositories, Cache.fetch())
- val resolution = start.process.run(fetch).unsafePerformSync
+ val (_, resolution) = resolveDependenciesMetadata(
+ repositories, depToDependency, deps, mapDependencies
+ )
val errs = resolution.metadataErrors
if(errs.nonEmpty) {
val header =
@@ -130,16 +181,17 @@ object Lib{
}
}
def scalaCompilerIvyDeps(scalaVersion: String) = Agg[Dep](
- ivy"org.scala-lang:scala-compiler:$scalaVersion",
- ivy"org.scala-lang:scala-reflect:$scalaVersion"
+ ivy"org.scala-lang:scala-compiler:$scalaVersion".forceVersion(),
+ ivy"org.scala-lang:scala-reflect:$scalaVersion".forceVersion()
)
def scalaRuntimeIvyDeps(scalaVersion: String) = Agg[Dep](
- ivy"org.scala-lang:scala-library:$scalaVersion"
+ ivy"org.scala-lang:scala-library:$scalaVersion".forceVersion()
)
def compilerBridgeIvyDep(scalaVersion: String) =
Dep.Point(
coursier.Dependency(coursier.Module("com.lihaoyi", "mill-bridge"), "0.1", transitive = false),
- cross = false
+ cross = false,
+ force = false
)
}
diff --git a/scalalib/src/mill/scalalib/PublishModule.scala b/scalalib/src/mill/scalalib/PublishModule.scala
index 3cc9fd30..2ab81269 100644
--- a/scalalib/src/mill/scalalib/PublishModule.scala
+++ b/scalalib/src/mill/scalalib/PublishModule.scala
@@ -9,22 +9,20 @@ import mill.util.Loose.Agg
/**
* Configuration necessary for publishing a Scala module to Maven Central or similar
*/
-trait PublishModule extends ScalaModule { outer =>
+trait PublishModule extends JavaModule { outer =>
import mill.scalalib.publish._
override def moduleDeps = Seq.empty[PublishModule]
def pomSettings: T[PomSettings]
def publishVersion: T[String]
- def artifactId: T[String] = T { s"${artifactName()}${artifactSuffix()}" }
+
def publishSelfDependency = T{
Artifact(pomSettings().organization, artifactId(), publishVersion()),
}
def publishXmlDeps = T.task{
- val ivyPomDeps = ivyDeps().map(
- Artifact.fromDep(_, scalaVersion(), Lib.scalaBinaryVersion(scalaVersion()))
- )
+ val ivyPomDeps = ivyDeps().map(resolvePublishDependency().apply(_))
val modulePomDeps = Task.sequence(moduleDeps.map(_.publishSelfDependency))()
ivyPomDeps ++ modulePomDeps.map(Dependency(_, Scope.Compile))
}
diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala
index dc39a4a8..b98f248e 100644
--- a/scalalib/src/mill/scalalib/ScalaModule.scala
+++ b/scalalib/src/mill/scalalib/ScalaModule.scala
@@ -7,7 +7,7 @@ import mill.define.Task
import mill.define.TaskModule
import mill.eval.{PathRef, Result}
import mill.modules.Jvm
-import mill.modules.Jvm.{createAssembly, createJar, subprocess}
+import mill.modules.Jvm.{createJar, subprocess}
import Lib._
import mill.util.Loose.Agg
import mill.util.DummyInputStream
@@ -15,23 +15,29 @@ import mill.util.DummyInputStream
/**
* Core configuration required to compile a single Scala compilation target
*/
-trait ScalaModule extends mill.Module with TaskModule { outer =>
- def defaultCommandName() = "run"
+trait ScalaModule extends JavaModule { outer =>
+ def scalaWorker: ScalaWorkerModule = mill.scalalib.ScalaWorkerModule
+
trait Tests extends TestModule{
def scalaVersion = outer.scalaVersion()
override def repositories = outer.repositories
override def scalacPluginIvyDeps = outer.scalacPluginIvyDeps
override def scalacOptions = outer.scalacOptions
+ override def javacOptions = outer.javacOptions
override def scalaWorker = outer.scalaWorker
override def moduleDeps = Seq(outer)
}
def scalaVersion: T[String]
- def mainClass: T[Option[String]] = None
+ override def resolveCoursierDependency: Task[Dep => coursier.Dependency] = T.task{
+ Lib.depToDependency(_: Dep, scalaVersion(), platformSuffix())
+ }
- def scalaWorker: ScalaWorkerModule = mill.scalalib.ScalaWorkerModule
+ override def resolvePublishDependency: Task[Dep => publish.Dependency] = T.task{
+ publish.Artifact.fromDep(_: Dep, scalaVersion(), Lib.scalaBinaryVersion(scalaVersion()))
+ }
- def finalMainClassOpt: T[Either[String, String]] = T{
+ override def finalMainClassOpt: T[Either[String, String]] = T{
mainClass() match{
case Some(m) => Right(m)
case None =>
@@ -47,58 +53,12 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
}
}
- def finalMainClass: T[String] = T{
- finalMainClassOpt() match {
- case Right(main) => Result.Success(main)
- case Left(msg) => Result.Failure(msg)
- }
- }
- def ivyDeps = T{ Agg.empty[Dep] }
- def compileIvyDeps = T{ Agg.empty[Dep] }
def scalacPluginIvyDeps = T{ Agg.empty[Dep] }
- def runIvyDeps = T{ Agg.empty[Dep] }
def scalacOptions = T{ Seq.empty[String] }
- def javacOptions = T{ Seq.empty[String] }
-
- def moduleDeps = Seq.empty[ScalaModule]
-
-
- def transitiveModuleDeps: Seq[ScalaModule] = {
- Seq(this) ++ moduleDeps.flatMap(_.transitiveModuleDeps).distinct
- }
- def unmanagedClasspath = T{ Agg.empty[PathRef] }
-
-
- def transitiveIvyDeps: T[Agg[Dep]] = T{
- ivyDeps() ++ Task.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten
- }
-
- def upstreamCompileOutput = T{
- Task.traverse(moduleDeps)(_.compile)
- }
-
- def transitiveLocalClasspath: T[Agg[PathRef]] = T{
- Task.traverse(moduleDeps)(m =>
- T.task{m.localClasspath() ++ m.transitiveLocalClasspath()}
- )().flatten
- }
-
- def resolveDeps(deps: Task[Agg[Dep]], sources: Boolean = false) = T.task{
- resolveDependencies(
- repositories,
- scalaVersion(),
- deps(),
- platformSuffix(),
- sources
- )
- }
-
- def repositories: Seq[Repository] = scalaWorker.repositories
-
- def platformSuffix = T{ "" }
+ override def repositories: Seq[Repository] = scalaWorker.repositories
private val Milestone213 = raw"""2.13.(\d+)-M(\d+)""".r
@@ -110,7 +70,7 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
resolveDependencies(
repositories,
- scalaVersion0,
+ Lib.depToDependency(_, scalaVersion0, platformSuffix()),
Seq(ivy"org.scala-sbt::compiler-bridge:1.1.0"),
sources = true
).map(_.find(_.path.last == s"compiler-bridge_${scalaBinaryVersion0}-1.1.0-sources.jar").map(_.path).get)
@@ -129,37 +89,20 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
T.task{scalaCompilerIvyDeps(scalaVersion()) ++ scalaRuntimeIvyDeps(scalaVersion())}
)()
}
-
-
- def prependShellScript: T[String] = T{
- mainClass() match{
- case None => ""
- case Some(cls) =>
- val isWin = scala.util.Properties.isWin
- mill.modules.Jvm.launcherShellScript(
- isWin,
- cls,
- Agg(if (isWin) "%~dp0%~nx0" else "$0"),
- forkArgs()
- )
- }
+ override def compileClasspath = T{
+ transitiveLocalClasspath() ++
+ resources() ++
+ unmanagedClasspath() ++
+ resolveDeps(T.task{compileIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})()
}
- def sources = T.sources{ millSourcePath / 'src }
- def resources = T.sources{ millSourcePath / 'resources }
- def generatedSources = T{ Seq.empty[PathRef] }
- def allSources = T{ sources() ++ generatedSources() }
-
- def allSourceFiles = T{
- for {
- root <- allSources()
- if exists(root.path)
- path <- ls.rec(root.path)
- if path.isFile && (path.ext == "scala" || path.ext == "java")
- } yield PathRef(path)
+ override def upstreamAssemblyClasspath = T{
+ transitiveLocalClasspath() ++
+ unmanagedClasspath() ++
+ resolveDeps(T.task{runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})()
}
- def compile: T[CompilationResult] = T.persistent{
+ override def compile: T[CompilationResult] = T.persistent{
scalaWorker.worker().compileScala(
scalaVersion(),
allSourceFiles().map(_.path),
@@ -172,55 +115,8 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
upstreamCompileOutput()
)
}
- def localClasspath = T{
- resources() ++ Agg(compile().classes)
- }
- def compileClasspath = T{
- transitiveLocalClasspath() ++
- resources() ++
- unmanagedClasspath() ++
- resolveDeps(T.task{compileIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})()
- }
-
- def upstreamAssemblyClasspath = T{
- transitiveLocalClasspath() ++
- unmanagedClasspath() ++
- resolveDeps(T.task{runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})()
- }
-
- def runClasspath = T{
- localClasspath() ++
- upstreamAssemblyClasspath()
- }
-
- /**
- * Build the assembly for upstream dependencies separate from the current classpath
- *
- * This should allow much faster assembly creation in the common case where
- * upstream dependencies do not change
- */
- def upstreamAssembly = T{
- createAssembly(upstreamAssemblyClasspath().map(_.path), mainClass())
- }
-
- def assembly = T{
- createAssembly(
- Agg.from(localClasspath().map(_.path)),
- mainClass(),
- prependShellScript(),
- Some(upstreamAssembly().path)
- )
- }
-
-
- def jar = T{
- createJar(
- localClasspath().map(_.path).filter(exists),
- mainClass()
- )
- }
- def docJar = T {
+ override def docJar = T {
val outDir = T.ctx().dest
val javadocDir = outDir / 'javadoc
@@ -233,7 +129,8 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
if p.isFile
} yield p.toNIO.toString
- val options = Seq("-d", javadocDir.toNIO.toString, "-usejavacp")
+ val pluginOptions = scalacPluginClasspath().map(pluginPathRef => s"-Xplugin:${pluginPathRef.path}")
+ val options = Seq("-d", javadocDir.toNIO.toString, "-usejavacp") ++ pluginOptions
if (files.nonEmpty) subprocess(
"scala.tools.nsc.ScalaDoc",
@@ -244,77 +141,6 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
createJar(Agg(javadocDir))(outDir)
}
- def sourceJar = T {
- createJar((allSources() ++ resources()).map(_.path).filter(exists))
- }
-
- def forkArgs = T{ Seq.empty[String] }
-
- def forkEnv = T{ sys.env.toMap }
-
- def launcher = T{
- Result.Success(
- Jvm.createLauncher(
- finalMainClass(),
- runClasspath().map(_.path),
- forkArgs()
- )
- )
- }
-
- def ivyDepsTree(inverse: Boolean = false) = T.command {
- import coursier.{Cache, Fetch, Resolution}
-
- val flattened = ivyDeps().map(depToDependency(_, scalaVersion(), platformSuffix())).toSeq
- val start = Resolution(flattened.toSet)
- val fetch = Fetch.from(repositories, Cache.fetch())
- val resolution = start.process.run(fetch).unsafePerformSync
-
- println(coursier.util.Print.dependencyTree(flattened, resolution,
- printExclusions = false, reverse = inverse))
-
- Result.Success()
- }
-
- def runLocal(args: String*) = T.command {
- Jvm.runLocal(
- finalMainClass(),
- runClasspath().map(_.path),
- args
- )
- }
-
- def run(args: String*) = T.command{
- Jvm.interactiveSubprocess(
- finalMainClass(),
- runClasspath().map(_.path),
- forkArgs(),
- forkEnv(),
- args,
- workingDir = ammonite.ops.pwd
- )
- }
-
-
- def runMainLocal(mainClass: String, args: String*) = T.command {
- Jvm.runLocal(
- mainClass,
- runClasspath().map(_.path),
- args
- )
- }
-
- def runMain(mainClass: String, args: String*) = T.command{
- Jvm.interactiveSubprocess(
- mainClass,
- runClasspath().map(_.path),
- forkArgs(),
- forkEnv(),
- args,
- workingDir = ammonite.ops.pwd
- )
- }
-
def console() = T.command{
if (T.ctx().log.inStream == DummyInputStream){
Result.Failure("repl needs to be run with the -i/--interactive flag")
@@ -330,15 +156,22 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
}
def ammoniteReplClasspath = T{
- resolveDeps(T.task{Agg(ivy"com.lihaoyi:::ammonite:1.1.0-7-33b728c")})()
+ localClasspath() ++
+ transitiveLocalClasspath() ++
+ unmanagedClasspath() ++
+ resolveDeps(T.task{
+ runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps() ++
+ Agg(ivy"com.lihaoyi:::ammonite:1.1.0-12-f07633d")
+ })()
}
+
def repl() = T.command{
if (T.ctx().log.inStream == DummyInputStream){
Result.Failure("repl needs to be run with the -i/--interactive flag")
}else{
Jvm.interactiveSubprocess(
mainClass = "ammonite.Main",
- classPath = runClasspath().map(_.path) ++ ammoniteReplClasspath().map(_.path),
+ classPath = ammoniteReplClasspath().map(_.path),
mainArgs = Nil,
workingDir = pwd
)
@@ -354,9 +187,11 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
if (crossFullScalaVersion()) scalaVersion()
else Lib.scalaBinaryVersion(scalaVersion())
}
- def artifactName: T[String] = millModuleSegments.parts.mkString("-")
- def artifactSuffix: T[String] = T { s"_${artifactScalaVersion()}" }
+ def artifactSuffix: T[String] = s"_${artifactScalaVersion()}"
+
+ override def artifactId: T[String] = artifactName() + artifactSuffix()
+
}
diff --git a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala b/scalalib/src/mill/scalalib/ScalaWorkerApi.scala
index 9739089a..f6500ae8 100644
--- a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala
+++ b/scalalib/src/mill/scalalib/ScalaWorkerApi.scala
@@ -29,7 +29,7 @@ trait ScalaWorkerModule extends mill.Module{
} else {
resolveDependencies(
repositories,
- "2.12.4",
+ Lib.depToDependency(_, "2.12.4", ""),
Seq(ivy"com.lihaoyi::mill-scalaworker:${sys.props("MILL_VERSION")}")
).map(_.map(_.path))
}
@@ -48,7 +48,7 @@ trait ScalaWorkerModule extends mill.Module{
def compilerInterfaceClasspath = T{
resolveDependencies(
repositories,
- "2.12.4",
+ Lib.depToDependency(_, "2.12.4", ""),
Seq(ivy"org.scala-sbt:compiler-interface:1.1.0")
)
}
@@ -56,6 +56,7 @@ trait ScalaWorkerModule extends mill.Module{
}
trait ScalaWorkerApi {
+
def compileScala(scalaVersion: String,
sources: Agg[Path],
compilerBridgeSources: Path,
diff --git a/scalalib/src/mill/scalalib/publish/Ivy.scala b/scalalib/src/mill/scalalib/publish/Ivy.scala
index 3b271fa8..22e26ff6 100644
--- a/scalalib/src/mill/scalalib/publish/Ivy.scala
+++ b/scalalib/src/mill/scalalib/publish/Ivy.scala
@@ -42,10 +42,10 @@ object Ivy {
private def renderDependency(dep: Dependency) = {
if (dep.exclusions.isEmpty)
- <dependency org={dep.artifact.group} name={dep.artifact.id} rev={dep.artifact.version} conf={s"${dep.scope}->default(${dep.configuration.getOrElse("compile")})"} />
+ <dependency org={dep.artifact.group} name={dep.artifact.id} rev={dep.artifact.version} conf={s"${scopeToConf(dep.scope)}->${dep.configuration.getOrElse("default(compile)")}"} />
else
- <dependency org={dep.artifact.group} name={dep.artifact.id} rev={dep.artifact.version} conf={s"${dep.scope}->default(${dep.configuration.getOrElse("compile")})"}>
- {dep.exclusions.map(ex => <exclude org={ex._1} name={ex._2} matcher="exact"/>).toSeq}
+ <dependency org={dep.artifact.group} name={dep.artifact.id} rev={dep.artifact.version} conf={s"${scopeToConf(dep.scope)}->${dep.configuration.getOrElse("default(compile)")}"}>
+ {dep.exclusions.map(ex => <exclude org={ex._1} name={ex._2} matcher="exact"/>)}
</dependency>
}
diff --git a/scalalib/src/mill/scalalib/publish/Pom.scala b/scalalib/src/mill/scalalib/publish/Pom.scala
index 3c8ba4dc..84cf0632 100644
--- a/scalalib/src/mill/scalalib/publish/Pom.scala
+++ b/scalalib/src/mill/scalalib/publish/Pom.scala
@@ -108,7 +108,7 @@ object Pom {
<groupId>{ex._1}</groupId>
<artifactId>{ex._2}</artifactId>
</exclude>
- )}.toSeq
+ )}
</exclusions>
{scope}
</dependency>
diff --git a/scalalib/src/mill/scalalib/publish/settings.scala b/scalalib/src/mill/scalalib/publish/settings.scala
index 34f7e7ad..2cd92eb2 100644
--- a/scalalib/src/mill/scalalib/publish/settings.scala
+++ b/scalalib/src/mill/scalalib/publish/settings.scala
@@ -7,19 +7,23 @@ case class Artifact(group: String, id: String, version: String) {
}
object Artifact {
-
- def fromDep(dep: Dep,
- scalaFull: String,
- scalaBin: String): Dependency = {
+ def fromDepJava(dep: Dep) = {
dep match {
- case Dep.Java(dep, cross) =>
+ case Dep.Java(dep, cross, force) =>
Dependency(
Artifact(dep.module.organization, dep.module.name, dep.version),
Scope.Compile,
- if (dep.configuration == "" ) None else Some(dep.configuration),
+ if (dep.configuration == "") None else Some(dep.configuration),
dep.exclusions.toList
)
- case Dep.Scala(dep, cross) =>
+ }
+ }
+ def fromDep(dep: Dep,
+ scalaFull: String,
+ scalaBin: String): Dependency = {
+ dep match {
+ case d: Dep.Java => fromDepJava(d)
+ case Dep.Scala(dep, cross, force) =>
Dependency(
Artifact(
dep.module.organization,
@@ -30,7 +34,7 @@ object Artifact {
if (dep.configuration == "") None else Some(dep.configuration),
dep.exclusions.toList
)
- case Dep.Point(dep, cross) =>
+ case Dep.Point(dep, cross, force) =>
Dependency(
Artifact(
dep.module.organization,
diff --git a/scalalib/test/resources/hello-java/core/src/hello/Core.java b/scalalib/test/resources/hello-java/core/src/hello/Core.java
new file mode 100644
index 00000000..bef1a5a0
--- /dev/null
+++ b/scalalib/test/resources/hello-java/core/src/hello/Core.java
@@ -0,0 +1,8 @@
+package hello;
+
+public class Core{
+ public static String msg(){
+ return "Hello World";
+ }
+
+} \ No newline at end of file
diff --git a/scalalib/test/resources/hello-java/main/src/hello/Main.java b/scalalib/test/resources/hello-java/main/src/hello/Main.java
new file mode 100644
index 00000000..44b927bd
--- /dev/null
+++ b/scalalib/test/resources/hello-java/main/src/hello/Main.java
@@ -0,0 +1,7 @@
+package hello;
+
+public class Main{
+ public static void main(String[] args){
+ System.out.println(Core.msg() + " " + args[0]);
+ }
+} \ No newline at end of file
diff --git a/scalalib/test/resources/hello-world-macros/core/src/Main.scala b/scalalib/test/resources/hello-world-macros/core/src/Main.scala
new file mode 100644
index 00000000..20924a60
--- /dev/null
+++ b/scalalib/test/resources/hello-world-macros/core/src/Main.scala
@@ -0,0 +1,5 @@
+import monocle.macros._
+@Lenses case class Foo(bar: String)
+object Main extends App {
+ println(Foo.bar.get(Foo("bar")))
+}
diff --git a/scalalib/test/src/mill/scalalib/GenIdeaTests.scala b/scalalib/test/src/mill/scalalib/GenIdeaTests.scala
index 0f776802..51665867 100644
--- a/scalalib/test/src/mill/scalalib/GenIdeaTests.scala
+++ b/scalalib/test/src/mill/scalalib/GenIdeaTests.scala
@@ -23,7 +23,7 @@ object GenIdeaTests extends TestSuite {
'genIdeaTests - {
val pp = new scala.xml.PrettyPrinter(999, 4)
- val layout = GenIdea.xmlFileLayout(
+ val layout = GenIdeaImpl.xmlFileLayout(
helloWorldEvaluator.evaluator,
HelloWorld,
("JDK_1_8", "1.8 (1)"), fetchMillModules = false)
diff --git a/scalalib/test/src/mill/scalalib/HelloJavaTests.scala b/scalalib/test/src/mill/scalalib/HelloJavaTests.scala
new file mode 100644
index 00000000..7794d5a5
--- /dev/null
+++ b/scalalib/test/src/mill/scalalib/HelloJavaTests.scala
@@ -0,0 +1,60 @@
+package mill.scalalib
+
+
+import ammonite.ops.{%, %%, cp, ls, mkdir, pwd, rm, up}
+import ammonite.ops.ImplicitWd._
+import mill.util.{TestEvaluator, TestUtil}
+import utest._
+import utest.framework.TestPath
+
+
+object HelloJavaTests extends TestSuite {
+
+ object HelloJava extends TestUtil.BaseModule{
+ def millSourcePath = TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.')
+ object core extends JavaModule
+ object main extends JavaModule{
+ def moduleDeps = Seq(core)
+ }
+ }
+ val resourcePath = pwd / 'scalalib / 'test / 'resources / "hello-java"
+
+ def init()(implicit tp: TestPath) = {
+ val eval = new TestEvaluator(HelloJava)
+ rm(HelloJava.millSourcePath)
+ rm(eval.outPath)
+ mkdir(HelloJava.millSourcePath / up)
+ cp(resourcePath, HelloJava.millSourcePath)
+ eval
+ }
+ def tests: Tests = Tests {
+ 'scalaVersion - {
+ val eval = init()
+
+ val Right((res1, n1)) = eval.apply(HelloJava.core.compile)
+ val Right((res2, 0)) = eval.apply(HelloJava.core.compile)
+ val Right((res3, n2)) = eval.apply(HelloJava.main.compile)
+
+ assert(
+ res1 == res2,
+ n1 != 0,
+ n2 != 0,
+ ls.rec(res1.classes.path).exists(_.last == "Core.class"),
+ !ls.rec(res1.classes.path).exists(_.last == "Main.class"),
+ ls.rec(res3.classes.path).exists(_.last == "Main.class"),
+ !ls.rec(res3.classes.path).exists(_.last == "Core.class")
+ )
+ }
+ 'docJar - {
+ val eval = init()
+
+ val Right((ref1, _)) = eval.apply(HelloJava.core.docJar)
+ val Right((ref2, _)) = eval.apply(HelloJava.main.docJar)
+
+ assert(
+ %%("jar", "tf", ref1.path).out.lines.contains("hello/Core.html"),
+ %%("jar", "tf", ref2.path).out.lines.contains("hello/Main.html")
+ )
+ }
+ }
+}
diff --git a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala
index 74078221..10f936f0 100644
--- a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala
+++ b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala
@@ -98,6 +98,38 @@ object HelloWorldTests extends TestSuite {
override def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode:0.1.4")
}
}
+
+ object HelloWorldTypeLevel extends HelloBase{
+ object foo extends ScalaModule {
+ def scalaVersion = "2.11.8"
+ override def mapDependencies(d: coursier.Dependency) = {
+ val artifacts = Set("scala-library", "scala-compiler", "scala-reflect")
+ if (d.module.organization != "org.scala-lang" || !artifacts(d.module.name)) d
+ else d.copy(module = d.module.copy(organization = "org.typelevel"))
+ }
+
+ def ivyDeps = Agg(
+ ivy"com.github.julien-truffaut::monocle-macro::1.4.0"
+ )
+ def scalacPluginIvyDeps = super.scalacPluginIvyDeps() ++ Agg(
+ ivy"org.scalamacros:::paradise:2.1.0"
+ )
+ }
+ }
+
+ object HelloWorldMacros extends HelloBase{
+ object core extends ScalaModule {
+ def scalaVersion = "2.12.4"
+
+ def ivyDeps = Agg(
+ ivy"com.github.julien-truffaut::monocle-macro::1.4.0"
+ )
+ def scalacPluginIvyDeps = super.scalacPluginIvyDeps() ++ Agg(
+ ivy"org.scalamacros:::paradise:2.1.0"
+ )
+ }
+ }
+
val resourcePath = pwd / 'scalalib / 'test / 'resources / "hello-world"
def jarMainClass(jar: JarFile): Option[String] = {
@@ -438,7 +470,42 @@ object HelloWorldTests extends TestSuite {
!result2.exists(_.path.last == "sourcecode_2.12-0.1.3.jar")
)
}
- }
-
+ 'typeLevel - workspaceTest(HelloWorldTypeLevel){ eval =>
+ val classPathsToCheck = Seq(
+ HelloWorldTypeLevel.foo.runClasspath,
+ HelloWorldTypeLevel.foo.ammoniteReplClasspath,
+ HelloWorldTypeLevel.foo.compileClasspath
+ )
+ for(cp <- classPathsToCheck){
+ val Right((result, _)) = eval.apply(cp)
+ assert(
+ // Make sure every relevant piece org.scala-lang has been substituted for org.typelevel
+ !result.map(_.toString).exists(x =>
+ x.contains("scala-lang") &&
+ (x.contains("scala-library") || x.contains("scala-compiler") || x.contains("scala-reflect"))
+ ),
+ result.map(_.toString).exists(x => x.contains("typelevel") && x.contains("scala-library"))
+ )
+ }
+ }
+ 'macros - {
+ // make sure macros are applied when compiling/running
+ 'runMain - workspaceTest(
+ HelloWorldMacros,
+ resourcePath = pwd / 'scalalib / 'test / 'resources / "hello-world-macros"
+ ){ eval =>
+ val Right((_, evalCount)) = eval.apply(HelloWorldMacros.core.runMain("Main"))
+ assert(evalCount > 0)
+ }
+ // make sure macros are applied when compiling during scaladoc generation
+ 'docJar - workspaceTest(
+ HelloWorldMacros,
+ resourcePath = pwd / 'scalalib / 'test / 'resources / "hello-world-macros"
+ ){ eval =>
+ val Right((_, evalCount)) = eval.apply(HelloWorldMacros.core.docJar)
+ assert(evalCount > 0)
+ }
+ }
+ }
}
diff --git a/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala b/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala
index b1fcec3e..4240478c 100644
--- a/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala
+++ b/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala
@@ -10,7 +10,11 @@ import utest._
object ResolveDepsTests extends TestSuite {
val repos = Seq(Cache.ivy2Local, MavenRepository("https://repo1.maven.org/maven2"))
- def evalDeps(deps: Agg[Dep]): Result[Agg[PathRef]] = Lib.resolveDependencies(repos, "2.12.4", deps)
+ def evalDeps(deps: Agg[Dep]): Result[Agg[PathRef]] = Lib.resolveDependencies(
+ repos,
+ Lib.depToDependency(_, "2.12.4", ""),
+ deps
+ )
val tests = Tests {
'resolveValidDeps - {
@@ -26,6 +30,14 @@ object ResolveDepsTests extends TestSuite {
assert(paths.items.next.path.toString.contains("natives-macos"))
}
+ 'resolveTransitiveRuntimeDeps - {
+ val deps = Agg(ivy"org.mockito:mockito-core:2.7.22")
+ val Success(paths) = evalDeps(deps)
+ assert(paths.nonEmpty)
+ assert(paths.exists(_.path.toString.contains("objenesis")))
+ assert(paths.exists(_.path.toString.contains("byte-buddy")))
+ }
+
'excludeTransitiveDeps - {
val deps = Agg(ivy"com.lihaoyi::pprint:0.5.3".exclude("com.lihaoyi" -> "fansi_2.12"))
val Success(paths) = evalDeps(deps)
diff --git a/scalalib/test/src/mill/scalalib/publish/IvyTests.scala b/scalalib/test/src/mill/scalalib/publish/IvyTests.scala
index 0f275dd9..d187f969 100644
--- a/scalalib/test/src/mill/scalalib/publish/IvyTests.scala
+++ b/scalalib/test/src/mill/scalalib/publish/IvyTests.scala
@@ -26,9 +26,9 @@ object IvyTests extends TestSuite {
'topLevel - {
val info = singleNode(fullIvy \ "info")
assert(
- singleAttr(info, "organisation") == artifact.group
- , singleAttr(info, "module") == artifact.id
- , singleAttr(info, "revision") == artifact.version
+ singleAttr(info, "organisation") == artifact.group,
+ singleAttr(info, "module") == artifact.id,
+ singleAttr(info, "revision") == artifact.version
)
}
@@ -40,10 +40,10 @@ object IvyTests extends TestSuite {
dependencies.zipWithIndex.foreach { case (dep, index) =>
assert(
- singleAttr(dep, "org") == ivyDeps(index).artifact.group
- , singleAttr(dep, "name") == ivyDeps(index).artifact.id
- , singleAttr(dep, "rev") == ivyDeps(index).artifact.version
- , (dep \ "exclude").zipWithIndex forall { case (exclude, j) =>
+ singleAttr(dep, "org") == ivyDeps(index).artifact.group,
+ singleAttr(dep, "name") == ivyDeps(index).artifact.id,
+ singleAttr(dep, "rev") == ivyDeps(index).artifact.version,
+ (dep \ "exclude").zipWithIndex forall { case (exclude, j) =>
singleAttr(exclude, "org") == ivyDeps(index).exclusions(j)._1 &&
singleAttr(exclude, "name") == ivyDeps(index).exclusions(j)._2
}