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

Improve Intellij Idea support #351

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
105 changes: 87 additions & 18 deletions scalalib/src/mill/scalalib/GenIdeaImpl.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package mill.scalalib

import ammonite.ops._
import coursier.Repository
import ammonite.runtime.SpecialClassLoader
import coursier.{Cache, CoursierPaths, Repository}
import mill.define._
import mill.eval.{Evaluator, PathRef, Result}
import mill.{T, scalalib}
import mill.util.Ctx.{Home, Log}
import mill.util.{Loose, PrintLogger, Strict}
import mill.util.Strict.Agg
import mill.util.{Loose, Strict}
import mill.{T, scalalib}

import scala.util.Try

Expand All @@ -34,7 +35,8 @@ object GenIdeaImpl {

val jdkInfo = extractCurrentJdk(pwd / ".idea" / "misc.xml").getOrElse(("JDK_1_8", "1.8 (1)"))

rm! pwd/".idea"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this change makes the user's life more comfortable by not asking them to reset various pieces of mill-unrelated configuration

rm! pwd/".idea"/"libraries"
rm! pwd/".idea"/"scala_compiler.xml"
rm! pwd/".idea_modules"


Expand Down Expand Up @@ -81,6 +83,17 @@ object GenIdeaImpl {
res.items.toList.map(_.path)
}

val buildDepsPaths = Try(evaluator
Copy link
Contributor Author

Choose a reason for hiding this comment

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

attempts to retrieve magic imports

.rootModule
.getClass
.getClassLoader
.asInstanceOf[SpecialClassLoader]
).map {
_.allJars
.map(url => Path(url.getFile))
.filter(_.toIO.exists)
}.getOrElse(Seq())

val resolved = for((path, mod) <- modules) yield {
val scalaLibraryIvyDeps = mod match{
case x: ScalaModule => x.scalaLibraryIvyDeps
Expand Down Expand Up @@ -119,8 +132,8 @@ object GenIdeaImpl {
}
val moduleLabels = modules.map(_.swap).toMap

val allResolved = resolved.flatMap(_._2) ++ buildLibraryPaths ++ buildDepsPaths

val allResolved = resolved.flatMap(_._2) ++ buildLibraryPaths
val commonPrefix =
if (allResolved.isEmpty) 0
else {
Expand Down Expand Up @@ -148,13 +161,64 @@ object GenIdeaImpl {
}
.toMap

sealed trait ResolvedLibrary { def path : Path }
case class CoursierResolved(path : Path, pom : Path, sources : Option[Path])
extends ResolvedLibrary
case class OtherResolved(path : Path) extends ResolvedLibrary

// Tries to group jars with their poms and sources.
def toResolvedJar(path : Path) : Option[ResolvedLibrary] = {
val inCoursierCache = path.startsWith(Path(CoursierPaths.cacheDirectory()))
val isSource = path.segments.last.endsWith("sources.jar")
val isPom = path.ext == "pom"
if (inCoursierCache && (isSource || isPom)) {
// Remove sources and pom as they'll be recovered from the jar path
None
} else if (inCoursierCache && path.ext == "jar") {
val withoutExt = path.segments.last.dropRight(path.ext.length + 1)
val pom = path / up / s"$withoutExt.pom"
val sources = Some(path / up / s"$withoutExt-sources.jar")
.filter(_.toIO.exists())
Some(CoursierResolved(path, pom, sources))
} else Some(OtherResolved(path))
}

// Hack so that Intellij does not complain about unresolved magic
// imports in build.sc when in fact they are resolved
def sbtLibraryNameFromPom(pom : Path) : String = {
Copy link
Contributor Author

@Baccata Baccata May 28, 2018

Choose a reason for hiding this comment

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

I should maybe remove this, Intellij seems to be flaky as hell with this. It worked on a java library, doesn't seem to work on scala ones ...

Copy link
Contributor Author

@Baccata Baccata May 28, 2018

Choose a reason for hiding this comment

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

Changed to ed958b7. Should they want to, this allows users to avoid the magic appearing in RED by defining their artifacts with ":" rather than "::" (which implies adding _2.12 to the artifact name) .

Note that the magic imports being red does not have any consequence on whether the artifact is actually indexed by IntelliJ and the ide's ability to resolve names coming from this artifact.

val xml = scala.xml.XML.loadFile(pom.toIO)

val groupId = (xml \ "groupId").text
val artifactId = (xml \ "artifactId").text
val version = (xml \ "version").text

// The scala version here is non incidental
s"SBT: $groupId:$artifactId:$version:jar"
}

def libraryName(resolvedJar: ResolvedLibrary) : String = resolvedJar match {
case CoursierResolved(path, pom, _) if buildDepsPaths.contains(path) =>
sbtLibraryNameFromPom(pom)
case CoursierResolved(path, _, _) =>
pathToLibName(path)
case OtherResolved(path) =>
pathToLibName(path)
}

def resolvedLibraries(resolved : Seq[Path]) : Seq[ResolvedLibrary] = resolved
.map(toResolvedJar)
.collect { case Some(r) => r}

val compilerSettings = resolved
.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))
}

val allBuildLibraries : Set[ResolvedLibrary] =
resolvedLibraries(buildLibraryPaths ++ buildDepsPaths).toSet

val fixedFiles = Seq(
Tuple2(".idea"/"misc.xml", miscXmlTemplate(jdkInfo)),
Tuple2(".idea"/"scala_settings.xml", scalaSettingsTemplate()),
Expand All @@ -168,8 +232,8 @@ object GenIdeaImpl {
Tuple2(
".idea_modules"/"mill-build.iml",
rootXmlTemplate(
for(path <- buildLibraryPaths)
yield pathToLibName(path)
for(lib <- allBuildLibraries)
yield libraryName(lib)
)
),
Tuple2(
Expand All @@ -178,16 +242,15 @@ object GenIdeaImpl {
)
)

val libraries = allResolved.map{path =>
val libraries = resolvedLibraries(allResolved).map{ resolved =>
import resolved.path
val url = "jar://" + path + "!/"
val name = pathToLibName(path)
Tuple2(".idea"/'libraries/s"$name.xml", libraryXmlTemplate(name, url))
}

val buildLibraries = buildLibraryPaths.map{path =>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

buildLibraryPaths is contained by allResolved

val url = "jar://" + path + "!/"
val name = pathToLibName(path)
Tuple2(".idea"/'libraries/s"$name.xml", libraryXmlTemplate(name, url))
val name = libraryName(resolved)
val sources = resolved match {
case CoursierResolved(_, _, s) => s.map(p => "jar://" + p + "!/")
case OtherResolved(_) => None
}
Tuple2(".idea"/'libraries/s"$name.xml", libraryXmlTemplate(name, url, sources))
}

val moduleFiles = resolved.map{ case (path, resolvedDeps, mod, _, _) =>
Expand Down Expand Up @@ -231,7 +294,7 @@ object GenIdeaImpl {
Tuple2(".idea_modules"/s"${moduleName(path)}.iml", elem)
}

fixedFiles ++ libraries ++ moduleFiles ++ buildLibraries
fixedFiles ++ libraries ++ moduleFiles
}

def evalOrElse[T](evaluator: Evaluator[_], e: Task[T], default: => T): T = {
Expand Down Expand Up @@ -307,12 +370,18 @@ object GenIdeaImpl {
</component>
</module>
}
def libraryXmlTemplate(name: String, url: String) = {
def libraryXmlTemplate(name: String, url: String, sources: Option[String]) = {
<component name="libraryTable">
<library name={name} type={if(name.contains("scala-library-")) "Scala" else null}>
<CLASSES>
<root url={url}/>
</CLASSES>
{ if (sources.isDefined) {
<SOURCES>
<root url={sources.get}/>
</SOURCES>
}
}
</library>
</component>
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
<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!/"/>
</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!/"/>
</SOURCES>
</library>
</component>
2 changes: 0 additions & 2 deletions scalalib/test/src/mill/scalalib/GenIdeaTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ object GenIdeaTests extends TestSuite {
millSourcePath / "generated" / ".idea_modules" /"mill-build.iml",
"gen-idea/idea/libraries/scala-library-2.12.4.jar.xml" ->
millSourcePath / "generated" / ".idea" / "libraries" / "scala-library-2.12.4.jar.xml",
"gen-idea/idea/libraries/scala-library-2.12.4-sources.jar.xml" ->
Copy link
Contributor Author

Choose a reason for hiding this comment

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

sources are grouped in the same file as the jar

millSourcePath / "generated" / ".idea" / "libraries" / "scala-library-2.12.4-sources.jar.xml",
"gen-idea/idea/modules.xml" ->
millSourcePath / "generated" / ".idea" / "modules.xml",
"gen-idea/idea/misc.xml" ->
Expand Down