Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GenIdea: Improved Scala 3 Support #1486

Merged
merged 9 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions main/core/src/eval/Evaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -664,10 +664,10 @@ object Evaluator {
rawValues: Seq[Result[Any]],
evaluated: Agg[Task[_]],
transitive: Agg[Task[_]],
failing: MultiBiMap[Either[Task[_], Labelled[_]], Result.Failing[_]],
failing: MultiBiMap[Either[Task[_], Labelled[_]], mill.api.Result.Failing[_]],
results: collection.Map[Task[_], Result[Any]]
) {
def values = rawValues.collect { case Result.Success(v) => v }
def values = rawValues.collect { case mill.api.Result.Success(v) => v }
}

def plan(rootModule: BaseModule, goals: Agg[Task[_]]) = {
Expand Down
111 changes: 68 additions & 43 deletions scalalib/src/GenIdeaImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import ammonite.runtime.SpecialClassLoader
import coursier.core.compatibility.xmlParseDom
import coursier.maven.Pom
import coursier.{LocalRepositories, Repositories, Repository}
import mill.Agg
import mill.api.Ctx.{Home, Log}
import mill.api.Strict.Agg
import mill.api.{Loose, PathRef, Result, Strict}
import mill.api.{PathRef, Result, Strict}
import mill.define._
import mill.eval.Evaluator
import mill.modules.Util
Expand Down Expand Up @@ -149,7 +149,7 @@ case class GenIdeaImpl(
case x: ScalaModule => x.scalaCompilerClasspath
case _ =>
T.task {
Loose.Agg.empty[PathRef]
Agg.empty[PathRef]
}
}

Expand All @@ -169,14 +169,13 @@ case class GenIdeaImpl(
}

val (scalacPluginsIvyDeps, allScalacOptions) = mod match {
case mod: ScalaModule =>
T.task {
mod.scalacPluginIvyDeps()
} -> T.task {
mod.allScalacOptions()
}
case _ => T.task(Loose.Agg[Dep]()) -> T.task(Seq())
case mod: ScalaModule => (
T.task(mod.scalacPluginIvyDeps()),
T.task(mod.allScalacOptions())
)
case _ => (T.task { Agg[Dep]() }, T.task { Seq() })
}

val scalacPluginDependencies = T.task {
mod.resolveDeps(scalacPluginsIvyDeps)()
}
Expand All @@ -194,19 +193,19 @@ case class GenIdeaImpl(
}

T.task {
val resolvedCp: Loose.Agg[Scoped[Path]] =
val resolvedCp: Agg[Scoped[Path]] =
externalDependencies().map(_.path).map(Scoped(_, None)) ++
extCompileIvyDeps()
.map(_.path)
.map(Scoped(_, Some("PROVIDED"))) ++
extRunIvyDeps().map(_.path).map(Scoped(_, Some("RUNTIME")))
// unused, but we want to trigger sources, to have them available (automatically)
// TODO: make this a separate eval to handle resolve errors
val resolvedSrcs: Loose.Agg[PathRef] = externalSources()
val resolvedSp: Loose.Agg[PathRef] = scalacPluginDependencies()
val resolvedCompilerCp: Loose.Agg[PathRef] =
val resolvedSrcs: Agg[PathRef] = externalSources()
val resolvedSp: Agg[PathRef] = scalacPluginDependencies()
val resolvedCompilerCp: Agg[PathRef] =
scalaCompilerClasspath()
val resolvedLibraryCp: Loose.Agg[PathRef] =
val resolvedLibraryCp: Agg[PathRef] =
externalLibraryDependencies()
val scalacOpts: Seq[String] = allScalacOptions()
val resolvedFacets: Seq[JavaFacet] = facets()
Expand All @@ -232,22 +231,23 @@ case class GenIdeaImpl(
}
}

val resolved: Seq[ResolvedModule] =
val resolvedModules: Seq[ResolvedModule] =
evalOrElse(evaluator, T.sequence(resolveTasks), Seq())

val moduleLabels = modules.map(_.swap).toMap

val allResolved: Seq[Path] =
(resolved.flatMap(_.classpath).map(_.value) ++ buildLibraryPaths ++ buildDepsPaths)
(resolvedModules.flatMap(_.classpath).map(_.value) ++ buildLibraryPaths ++ buildDepsPaths)
.distinct
.sorted

val librariesProperties = resolved
.flatMap(x => x.libraryClasspath.map(_ -> x.compilerClasspath))
.toMap
val librariesProperties: Map[Path, Agg[Path]] =
resolvedModules
.flatMap(x => x.libraryClasspath.map(_ -> x.compilerClasspath))
.toMap

val (wholeFileConfigs, configFileContributions) =
resolved
resolvedModules
.flatMap(_.configFileContributions)
.partition(_.asWholeFile.isDefined)

Expand Down Expand Up @@ -308,8 +308,14 @@ case class GenIdeaImpl(
.groupBy(_.last)
.filter(_._2.size > 1)
.view
.mapValues(_.sorted)
.mapValues(_.zipWithIndex)
.flatMap(y => y._2.map(x => x._1 -> s"${y._1} (${x._2})"))
.flatMap(y =>
y._2.map {
case (path, 0) => path -> y._1
case (path, idx) => path -> s"${y._1} (${idx})"
}
)
Comment on lines +313 to +318
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving out the index for the first element fixed failing tests on WIndows, where for unknown reasons we always ended up with a scala-library-2.13.6.jar (0).

.toMap

val pathToLibName = allResolved
Expand Down Expand Up @@ -408,8 +414,8 @@ case class GenIdeaImpl(
.map(toResolvedJar)
.collect { case Some(r) => r }

val compilerSettings = resolved
.foldLeft(Map[(Loose.Agg[os.Path], Seq[String]), Vector[JavaModule]]()) {
val compilerSettings = resolvedModules
.foldLeft(Map[(Agg[os.Path], Seq[String]), Vector[JavaModule]]()) {
(r, q) =>
val key = (q.pluginClasspath, q.scalaOptions)
r + (key -> (r.getOrElse(key, Vector()) :+ q.module))
Expand Down Expand Up @@ -443,27 +449,40 @@ case class GenIdeaImpl(

val libraries: Seq[(SubPath, Elem)] =
resolvedLibraries(allResolved).flatMap { resolved =>
import resolved.path
val names = libraryNames(resolved)
val sources = resolved match {
case CoursierResolved(_, _, s) => s
case WithSourcesResolved(_, s) => s
case OtherResolved(_) => None
}
for (name <- names)
yield Tuple2(
os.sub / "libraries" / s"${ideaifyLibraryName(name)}.xml",
libraryXmlTemplate(
name = name,
path = path,
sources = sources,
scalaCompilerClassPath =
librariesProperties.getOrElse(path, Loose.Agg.empty)
yield {
val compilerCp: Agg[Path] = librariesProperties.getOrElse(resolved.path, Agg.empty)
val languageLevel = name match {
case _ if compilerCp.iterator.isEmpty => None
case _ if name.startsWith("scala3-library_3-3.0.") => Some("Scala_3_0")
case _ if name.startsWith("scala-library-2.13.") => Some("Scala_2_13")
case _ if name.startsWith("scala-library-2.12.") => Some("Scala_2_12")
case _ if name.startsWith("scala-library-2.11.") => Some("Scala_2_11")
case _ if name.startsWith("scala-library-2.10.") => Some("Scala_2_10")
case _ if name.startsWith("scala-library-2.9.") => Some("Scala_2_9")
case _ if name.startsWith("dotty-version-0.27") => Some("Scala_0_27")
case _ => None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to hardcode the mapping, as Scala 3 support in IJ is still in development and it's a bit unclear if we settle with the current mapping or not.

}
Tuple2(
os.sub / "libraries" / s"${ideaifyLibraryName(name)}.xml",
libraryXmlTemplate(
name = name,
path = resolved.path,
sources = sources,
scalaCompilerClassPath = compilerCp,
languageLevel = languageLevel
)
)
)
}
}

val moduleFiles: Seq[(SubPath, Elem)] = resolved.map {
val moduleFiles: Seq[(SubPath, Elem)] = resolvedModules.map {
case ResolvedModule(
path,
resolvedDeps,
Expand Down Expand Up @@ -704,17 +723,23 @@ case class GenIdeaImpl(
name: String,
path: os.Path,
sources: Option[os.Path],
scalaCompilerClassPath: Loose.Agg[Path]
scalaCompilerClassPath: Agg[Path],
languageLevel: Option[String]
): Elem = {
val isScalaLibrary = scalaCompilerClassPath.iterator.nonEmpty
<component name="libraryTable">
<library name={name} type={if (isScalaLibrary) "Scala" else null}>
{
if (isScalaLibrary) {
<properties>
<compiler-classpath>
{
if (languageLevel.isDefined) <language-level>{languageLevel.get}</language-level>
}
<compiler-classpath>
{
scalaCompilerClassPath.toList.sortBy(_.wrapped).map(p => <root url={relativeFileUrl(p)}/>)
scalaCompilerClassPath.iterator.toSeq.sortBy(_.wrapped).map(p =>
<root url={relativeFileUrl(p)}/>
)
}
</compiler-classpath>
</properties>
Expand Down Expand Up @@ -820,7 +845,7 @@ case class GenIdeaImpl(
</module>
}
def scalaCompilerTemplate(
settings: Map[(Loose.Agg[os.Path], Seq[String]), Seq[JavaModule]]
settings: Map[(Agg[os.Path], Seq[String]), Seq[JavaModule]]
) = {

<project version={"" + ideaConfigVersion}>
Expand Down Expand Up @@ -904,12 +929,12 @@ object GenIdeaImpl {

final case class ResolvedModule(
path: Segments,
classpath: Loose.Agg[Scoped[Path]],
classpath: Agg[Scoped[Path]],
module: JavaModule,
pluginClasspath: Loose.Agg[Path],
pluginClasspath: Agg[Path],
scalaOptions: Seq[String],
compilerClasspath: Loose.Agg[Path],
libraryClasspath: Loose.Agg[Path],
compilerClasspath: Agg[Path],
libraryClasspath: Agg[Path],
facets: Seq[JavaFacet],
configFileContributions: Seq[IdeaConfigFile],
compilerOutput: Path
Expand Down
10 changes: 7 additions & 3 deletions scalalib/test/resources/gen-idea-extended-hello-world/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import mill.scalalib.GenIdeaModule._
import mill.scalalib.TestModule

trait HelloWorldModule extends scalalib.ScalaModule {
def scalaVersion = "2.12.4"
override def scalaVersion = "2.13.6"
object test extends super.Tests with TestModule.Utest

def generatedSources = T {
Seq(PathRef(T.ctx().dest / "classes"))
override def generatedSources = T {
Seq(PathRef(T.dest / "classes"))
}

object subScala3 extends scalalib.ScalaModule {
override def scalaVersion = "3.0.2"
}

def ideaJavaModuleFacets(ideaConfigVersion: Int): Command[Seq[JavaFacet]] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
<component name="libraryTable">
<library name="scala-library-2.12.4.jar" type="Scala">
<library name="scala-library-2.13.6.jar" type="Scala">
<properties>
<language-level>Scala_2_13</language-level>
<compiler-classpath>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.0.6/scala-xml_2.12-1.0.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.4/scala-compiler-2.12.4.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.4/scala-library-2.12.4.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.12.4/scala-reflect-2.12.4.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/net/java/dev/jna/jna/5.3.1/jna-5.3.1.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/jline/jline/3.19.0/jline-3.19.0.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.6/scala-compiler-2.13.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.13.6/scala-reflect-2.13.6.jar"/>
</compiler-classpath>
</properties>
<CLASSES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.4/scala-library-2.12.4.jar!/"/>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6.jar!/"/>
</CLASSES>
<SOURCES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.4/scala-library-2.12.4-sources.jar!/"/>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6-sources.jar!/"/>
</SOURCES>
</library>
</component>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.12.4.jar" level="project"/>
<orderEntry type="library" name="scala-library-2.13.6.jar" level="project"/>
</component>
<component name="FacetManager">
<facet type="AspectJ" name="AspectJ">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/../../out/HelloWorld/subScala3/ideaCompileOutput/dest/classes"/>
<exclude-output/>
<content url="file://$MODULE_DIR$/../../HelloWorld/subScala3/src">
<sourceFolder url="file://$MODULE_DIR$/../../HelloWorld/subScala3/src" isTestSource="false"/>
</content>
<content url="file://$MODULE_DIR$/../../HelloWorld/subScala3/resources">
<sourceFolder url="file://$MODULE_DIR$/../../HelloWorld/subScala3/resources" type="java-resource"/>
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.13.6.jar" level="project"/>
<orderEntry type="library" name="scala3-library_3-3.0.2.jar" level="project"/>
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.12.4.jar" level="project"/>
<orderEntry type="library" name="scala-library-2.13.6.jar" level="project"/>
<orderEntry type="module" module-name="helloworld" exported=""/>
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/mill-build.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/mill-build.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloworld.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloworld.subscala3.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.subscala3.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloworld.test.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.test.iml"/>
</modules>
</component>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<component name="libraryTable">
<library name="scala-library-2.12.4.jar" type="Scala">
<properties>
<language-level>Scala_2_12</language-level>
<compiler-classpath>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.0.6/scala-xml_2.12-1.0.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.4/scala-compiler-2.12.4.jar"/>
Expand Down
24 changes: 14 additions & 10 deletions scalalib/test/src/GenIdeaExtendedTests.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package mill.scalalib

import scala.util.Try

import mill.util.ScriptTestSuite
import os.Path
import utest._
Expand All @@ -16,24 +18,26 @@ object GenIdeaExtendedTests extends ScriptTestSuite(false) {
val workspacePath = initWorkspace()
eval("mill.scalalib.GenIdea/idea")

Seq(
val checks = Seq(
os.sub / "mill_modules" / "helloworld.iml",
os.sub / "mill_modules" / "helloworld.test.iml",
os.sub / "mill_modules" / "helloworld.subscala3.iml",
os.sub / "mill_modules" / "mill-build.iml",
os.sub / "libraries" / "scala_library_2_12_4_jar.xml",
os.sub / "libraries" / "scala_library_2_13_6_jar.xml",
os.sub / "modules.xml",
os.sub / "misc.xml",
os.sub / "compiler.xml"
).foreach { resource =>
GenIdeaTests.assertIdeaXmlResourceMatchesFile(
workspaceSlug,
workspacePath,
resource
)
).map { resource =>
Try {
GenIdeaTests.assertIdeaXmlResourceMatchesFile(
workspaceSlug,
workspacePath,
resource
)
}
}
assert(checks.forall(_.isSuccess))
}
}



}
Loading