diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-14 21:40:49 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-14 21:40:49 -0800 |
commit | d2598aa69c866236c9b5eddac2e03161b2456848 (patch) | |
tree | 5f002510d8bc02cf9de61c9368954eac908cefc7 /scalaplugin | |
parent | ec4486c3700c421311d190c36e01faf2fd011e4e (diff) | |
download | mill-d2598aa69c866236c9b5eddac2e03161b2456848.tar.gz mill-d2598aa69c866236c9b5eddac2e03161b2456848.tar.bz2 mill-d2598aa69c866236c9b5eddac2e03161b2456848.zip |
First pass at IntelliJ project generation for a Mill build. Run using `sbt scalaplugin/assembly && amm build.sc idea`
Diffstat (limited to 'scalaplugin')
-rw-r--r-- | scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala | 135 | ||||
-rw-r--r-- | scalaplugin/src/main/scala/mill/scalaplugin/Module.scala | 79 |
2 files changed, 184 insertions, 30 deletions
diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala b/scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala new file mode 100644 index 00000000..b756d227 --- /dev/null +++ b/scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala @@ -0,0 +1,135 @@ +package mill.scalaplugin + +import ammonite.ops.{Path, pwd, rm, write} +import mill.discover.{Discovered, Hierarchy} +import mill.eval.{Evaluator, PathRef} +import mill.util.OSet + +object GenIdea { + def apply[T: Discovered](obj: T) = { + val pp = new scala.xml.PrettyPrinter(999, 4) + val discovered = implicitly[Discovered[T]] + def rec(x: Hierarchy[T]): Seq[(Seq[String], Module)] = { + val node = x.node(obj) + val self = node match{ + case m: Module => Seq(x.path -> m) + case _ => Nil + } + + self ++ x.children.flatMap(rec) + } + val mapping = Discovered.mapping(obj)(discovered) + val workspacePath = pwd / 'out + val evaluator = new Evaluator(workspacePath, mapping) + + val modules = rec(discovered.hierarchy) + println(modules) + + rm! pwd/".idea" + rm! pwd/".idea_modules" + val moduleDir = pwd/".idea_modules" + write( + pwd/".idea"/"misc.xml", + pp.format( + <project version="4"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8 (1)" project-jdk-type="JavaSDK"> + <output url="file://$PROJECT_DIR$/target/idea_output" /> + </component> + </project> + ) + ) + val allModulesFile = + <project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea_modules/root.iml" filepath="$PROJECT_DIR$/.idea_modules/root.iml" /> + { + for((path, mod) <- modules) + yield { + val selector = path.mkString(".") + val filepath = "$PROJECT_DIR$/.idea_modules/" + selector.toLowerCase() + ".iml" + val fileurl = "file://" + filepath + <module fileurl={fileurl} filepath={filepath} /> + } + } + </modules> + </component> + </project> + + write(pwd/".idea"/"modules.xml", pp.format(allModulesFile)) + val resolved = for((path, mod) <- modules) yield { + val Seq(resolvedCp: Seq[PathRef], resolvedSrcs: Seq[PathRef]) = + evaluator.evaluate(OSet(mod.externalCompileDepClasspath, mod.externalCompileDepSources)) + .values + + + (path, resolvedCp.map(_.path).filter(_.ext == "jar") ++ resolvedSrcs.map(_.path), mod) + } + val allResolved = resolved.flatMap(_._2).distinct + val minResolvedLength = allResolved.map(_.segments.length).min + val commonPrefix = allResolved.map(_.segments.take(minResolvedLength)) + .transpose + .takeWhile(_.distinct.length == 1) + .length + + val libraryFiles = for(path <- allResolved) yield { + val url = "jar://" + path + "!/" + val name = path.segments.drop(commonPrefix).mkString("_") + val elem = <component name="libraryTable"> + <library name={name}> + <CLASSES> + <root url={url}/> + </CLASSES> + </library> + </component> + write(pwd/".idea"/'libraries/s"$name.xml", pp.format(elem)) + } + + def relify(p: Path) = { + val r = p.relativeTo(moduleDir) + (Seq.fill(r.ups)("..") ++ r.segments).mkString("/") + } + val moduleFiles = for((path, resolvedDeps, mod) <- resolved) yield { + val sourcePath = evaluator.evaluate(OSet(mod.sources)).values.head.asInstanceOf[PathRef].path + val outputPath = evaluator.evaluate(OSet(mod.compile)).values.head.asInstanceOf[PathRef].path + val base = mod.getClass.getName.stripSuffix("$").split('.').last.split('$').last.toLowerCase + val elem = <module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager"> + <output url={"file://$MODULE_DIR$/" + relify(outputPath)} /> + <exclude-output /> + <content url={"file://$MODULE_DIR$/" + relify(sourcePath)}> + <sourceFolder url={"file://$MODULE_DIR$/" + relify(sourcePath)} isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + + { + for(r <- resolvedDeps) yield { + <orderEntry type="library" name={r.segments.drop(commonPrefix).mkString("_")} level="project" /> + } + } + { + for(m <- mod.projectDeps) yield { + val depName = resolved.find(_._3 eq m).get._1.mkString(".").toLowerCase + <orderEntry type="module" module-name={depName} exported="" /> + } + } + </component> + </module> + write(pwd/".idea_modules"/s"${path.mkString(".").toLowerCase}.iml", pp.format(elem)) + } + val rootModule = + <module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager"> + <output url="file://$MODULE_DIR$/../out"/> + <content url="file://$MODULE_DIR$/.." /> + <exclude-output/> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> + </module> + write(pwd/".idea_modules"/"root.iml", pp.format(rootModule)) + + } + +} diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/Module.scala b/scalaplugin/src/main/scala/mill/scalaplugin/Module.scala index 1a7cbdbe..04d3e04b 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/Module.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/Module.scala @@ -2,19 +2,16 @@ package mill package scalaplugin import java.io.File -import java.lang.annotation.Annotation -import java.net.URLClassLoader -import ammonite.ops.{Path, ls, mkdir, pwd, up} -import coursier.{Cache, Dependency, Fetch, MavenRepository, Module, Repository, Resolution} +import ammonite.ops._ +import coursier.{Cache, Fetch, MavenRepository, Repository, Resolution} import mill.define.Task import mill.define.Task.Cacher -import mill.eval.PathRef -import mill.util.Args -import play.api.libs.json._ +import mill.discover.{Discovered, Hierarchy} +import mill.eval.{Evaluator, PathRef} +import mill.util.OSet import sbt.internal.inc.{FreshCompilerCache, ScalaInstance, ZincUtil} import sbt.internal.util.{ConsoleOut, MainAppender} -import sbt.testing.{AnnotatedFingerprint, SubclassFingerprint} import sbt.util.LogExchange import xsbti.api.{ClassLike, DependencyContext} import xsbti.compile.DependencyChanges @@ -22,7 +19,6 @@ import xsbti.compile.DependencyChanges object Module{ - def compileScala(scalaVersion: String, sources: PathRef, compileClasspath: Seq[PathRef], @@ -92,7 +88,8 @@ object Module{ def resolveDependencies(repositories: Seq[Repository], scalaVersion: String, scalaBinaryVersion: String, - deps: Seq[Dep]): Seq[PathRef] = { + deps: Seq[Dep], + sources: Boolean = false): Seq[PathRef] = { val flattened = deps.map{ case Dep.Java(dep) => dep case Dep.Scala(dep) => dep.copy(module = dep.module.copy(name = dep.module.name + "_" + scalaBinaryVersion)) @@ -102,8 +99,11 @@ object Module{ val fetch = Fetch.from(repositories, Cache.fetch()) val resolution = start.process.run(fetch).unsafePerformSync + val sourceOrJar = + if (sources) resolution.classifiersArtifacts(Seq("sources")) + else resolution.artifacts val localArtifacts: Seq[File] = scalaz.concurrent.Task - .gatherUnordered(resolution.artifacts.map(Cache.file(_).run)) + .gatherUnordered(sourceOrJar.map(Cache.file(_).run)) .unsafePerformSync .flatMap(_.toOption) @@ -140,35 +140,54 @@ trait Module extends Cacher{ def upstreamRunClasspath = T{ Task.traverse( for (p <- projectDeps) - yield T.task(p.runDepClasspath() ++ Seq(p.compile())) + yield T.task(p.runDepClasspath() ++ Seq(p.compile())) ) } - def upstreamCompileClasspath = T{ - Task.traverse( - for (p <- projectDeps) - yield T.task(p.compileDepClasspath() ++ Seq(p.compile())) - ) + def upstreamCompileDepClasspath = T{ + Task.traverse(projectDeps.map(_.compileDepClasspath)) + } + def upstreamCompileDepSources = T{ + Task.traverse(projectDeps.map(_.externalCompileDepSources)) + } + def upstreamCompileOutputClasspath = T{ + Task.traverse(projectDeps.map(_.compile)) } + def externalCompileDepClasspath = T{ + upstreamCompileDepClasspath().flatten ++ + resolveDependencies( + repositories, + scalaVersion(), + scalaBinaryVersion(), + ivyDeps() ++ compileIvyDeps() ++ scalaCompilerIvyDeps(scalaVersion()) + ) + } + def externalCompileDepSources: T[Seq[PathRef]] = T{ + upstreamCompileDepSources().flatten ++ + resolveDependencies( + repositories, + scalaVersion(), + scalaBinaryVersion(), + ivyDeps() ++ compileIvyDeps() ++ scalaCompilerIvyDeps(scalaVersion()), + sources = true + ) + } def compileDepClasspath: T[Seq[PathRef]] = T{ - upstreamCompileClasspath().flatten ++ depClasspath() ++ resolveDependencies( - repositories, - scalaVersion(), - scalaBinaryVersion(), - ivyDeps() ++ compileIvyDeps() ++ scalaCompilerIvyDeps(scalaVersion()) - ) + upstreamCompileOutputClasspath() ++ + depClasspath() ++ + externalCompileDepClasspath() } def runDepClasspath: T[Seq[PathRef]] = T{ upstreamRunClasspath().flatten ++ - depClasspath() ++ - resolveDependencies( - repositories, - scalaVersion(), - scalaBinaryVersion(), - ivyDeps() ++ runIvyDeps() ++ scalaRuntimeIvyDeps(scalaVersion()) - ) + depClasspath() ++ + resolveDependencies( + repositories, + scalaVersion(), + scalaBinaryVersion(), + ivyDeps() ++ runIvyDeps() ++ scalaRuntimeIvyDeps(scalaVersion()) + ) } def sources = T.source{ basePath / 'src } |