Skip to content

Commit

Permalink
GenIdea improvements (#3153)
Browse files Browse the repository at this point in the history
- Some cleanups
- Made GenIdea testsuite more generic
- Try to make more IDEA paths relative to user home directory
- Renamed module name in test case to avoid yet another "hello world"

Pull request: #3153
  • Loading branch information
lefou authored May 16, 2024
1 parent b74608f commit 1a5b950
Show file tree
Hide file tree
Showing 18 changed files with 131 additions and 126 deletions.
2 changes: 1 addition & 1 deletion idea/src/mill/idea/GenIdea.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object GenIdea extends ExternalModule {
def idea(allBootstrapEvaluators: Evaluator.AllBootstrapEvaluators): Command[Unit] = T.command {
try {
Result.Success(GenIdeaImpl(
evaluators = Evaluator.allBootstrapEvaluators.value.value
evaluators = allBootstrapEvaluators.value
).run())
} catch {
case GenIdeaImpl.GenIdeaException(m) => Result.Failure(m)
Expand Down
85 changes: 51 additions & 34 deletions idea/src/mill/idea/GenIdeaImpl.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package mill.idea

import scala.collection.immutable
import scala.util.Try
import scala.util.{Success, Try}
import scala.xml.{Elem, MetaData, Node, NodeSeq, Null, UnprefixedAttribute}
import coursier.core.compatibility.xmlParseDom
import coursier.maven.Pom
Expand All @@ -15,16 +15,15 @@ import mill.scalalib.GenIdeaModule.{IdeaConfigFile, JavaFacet}
import mill.scalalib.internal.JavaModuleUtils
import mill.util.Classpath
import mill.{T, scalalib}
import os.{Path, SubPath}
import mill.scalalib.{GenIdeaImpl => _, _}

case class GenIdeaImpl(
private val evaluators: Seq[Evaluator]
)(implicit ctx: Ctx) {
import GenIdeaImpl._

val workDir: Path = evaluators.head.rootModule.millSourcePath
val ideaDir: Path = workDir / ".idea"
val workDir: os.Path = evaluators.head.rootModule.millSourcePath
val ideaDir: os.Path = workDir / ".idea"

val ideaConfigVersion = 4

Expand All @@ -34,7 +33,7 @@ case class GenIdeaImpl(
.getOrElse(("JDK_1_8", "1.8 (1)"))

ctx.log.info("Analyzing modules ...")
val layout: Seq[(SubPath, Node)] =
val layout: Seq[(os.SubPath, Node)] =
xmlFileLayout(evaluators, jdkInfo)

ctx.log.debug("Cleaning obsolete IDEA project files ...")
Expand Down Expand Up @@ -102,7 +101,7 @@ case class GenIdeaImpl(
// .toSeq
// .distinct

val buildLibraryPaths: immutable.Seq[Path] = {
val buildLibraryPaths: immutable.Seq[os.Path] = {
if (!fetchMillModules) Nil
else {
val moduleRepos = modulesByEvaluator.toSeq.flatMap { case (ev, modules) =>
Expand Down Expand Up @@ -197,7 +196,7 @@ case class GenIdeaImpl(
}

T.task {
val resolvedCp: Agg[Scoped[Path]] =
val resolvedCp: Agg[Scoped[os.Path]] =
externalDependencies().map(_.path).map(Scoped(_, None)) ++
extCompileIvyDeps()
.map(_.path)
Expand Down Expand Up @@ -251,14 +250,14 @@ case class GenIdeaImpl(

val moduleLabels = modules.map { case (s, m, e) => (m, s) }.toMap

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

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

val (wholeFileConfigs, configFileContributions) =
Expand All @@ -267,20 +266,20 @@ case class GenIdeaImpl(
.partition(_.asWholeFile.isDefined)

// whole file
val ideaWholeConfigFiles: Seq[(SubPath, Elem)] =
val ideaWholeConfigFiles: Seq[(os.SubPath, Elem)] =
wholeFileConfigs.flatMap(_.asWholeFile).map { wf =>
os.sub / wf._1 -> ideaConfigElementTemplate(wf._2)
}

type FileComponent = (SubPath, Option[String])
type FileComponent = (os.SubPath, Option[String])

/** Ensure, the additional configs don't collide. */
def collisionFreeExtraConfigs(
confs: Seq[IdeaConfigFile]
): Map[SubPath, Seq[IdeaConfigFile]] = {
): Map[os.SubPath, Seq[IdeaConfigFile]] = {

var seen: Map[FileComponent, Seq[GenIdeaModule.Element]] = Map()
var result: Map[SubPath, Seq[IdeaConfigFile]] = Map()
var result: Map[os.SubPath, Seq[IdeaConfigFile]] = Map()
confs.foreach { conf =>
val key = conf.subPath -> conf.component
seen.get(key) match {
Expand All @@ -307,7 +306,7 @@ case class GenIdeaImpl(
result
}

val fileComponentContributions: Seq[(SubPath, Elem)] =
val fileComponentContributions: Seq[(os.SubPath, Elem)] =
collisionFreeExtraConfigs(configFileContributions).toSeq.map {
case (file, configs) =>
val map: Map[Option[String], Seq[GenIdeaModule.Element]] =
Expand Down Expand Up @@ -340,7 +339,7 @@ case class GenIdeaImpl(
type ArtifactAndVersion = (String, String)

def guessJarArtifactNameAndVersionFromPath(
path: Path
path: os.Path
): Option[ArtifactAndVersion] =
Try {
// in a local maven repo or a local Coursier repo,
Expand Down Expand Up @@ -444,7 +443,7 @@ case class GenIdeaImpl(
r + (key -> (r.getOrElse(key, Vector()) :+ q.module))
}

val fixedFiles: Seq[(SubPath, Elem)] = Seq(
val fixedFiles: Seq[(os.SubPath, Elem)] = Seq(
Tuple2(os.sub / "misc.xml", miscXmlTemplate(jdkInfo)),
Tuple2(os.sub / "scala_settings.xml", scalaSettingsTemplate()),
Tuple2(
Expand All @@ -471,7 +470,7 @@ case class GenIdeaImpl(
name.replaceAll("""[-.:]""", "_")
}

val libraries: Seq[(SubPath, Elem)] =
val libraries: Seq[(os.SubPath, Elem)] =
resolvedLibraries(allResolved).flatMap { resolved =>
val names = libraryNames(resolved)
val sources = resolved match {
Expand All @@ -481,7 +480,7 @@ case class GenIdeaImpl(
}
for (name <- names)
yield {
val compilerCp: Agg[Path] = librariesProperties.getOrElse(resolved.path, Agg.empty)
val compilerCp: Agg[os.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.3.") => Some("Scala_3_3")
Expand Down Expand Up @@ -509,7 +508,7 @@ case class GenIdeaImpl(
}
}

val moduleFiles: Seq[(SubPath, Elem)] = resolvedModules.map {
val moduleFiles: Seq[(os.SubPath, Elem)] = resolvedModules.map {
case ResolvedModule(
path,
resolvedDeps,
Expand Down Expand Up @@ -557,7 +556,7 @@ case class GenIdeaImpl(

val sanizedDeps: Seq[ScopedOrd[String]] = {
resolvedDeps
.map((s: Scoped[Path]) => pathToLibName(s.value) -> s.scope)
.map((s: Scoped[os.Path]) => pathToLibName(s.value) -> s.scope)
.iterator
.toSeq
.groupBy(_._1)
Expand Down Expand Up @@ -727,31 +726,49 @@ case class GenIdeaImpl(
</module>
}

/** Try to make the file path a relative JAR URL (to PROJECT_DIR). */
/** Try to make the file path a relative JAR URL (to PROJECT_DIR or HOME_DIR). */
def relativeJarUrl(path: os.Path): String = {
// When coursier cache dir is on different logical drive than project dir
// we can not use a relative path. See issue: https://github.com/lihaoyi/mill/issues/905
val relPath = relForwardPath(path, "$PROJECT_DIR$/")
val relPath = relForwardPath(path)
if (path.ext == "jar") "jar://" + relPath + "!/" else "file://" + relPath
}

/** Try to make the file path a relative URL (to PROJECT_DIR). */
def relativeFileUrl(path: Path): String = {
/** Try to make the file path a relative URL (to PROJECT_DIR or HOME_DIR). */
def relativeFileUrl(path: os.Path): String = {
// When coursier cache dir is on different logical drive than project dir
// we can not use a relative path. See issue: https://github.com/lihaoyi/mill/issues/905
"file://" + relForwardPath(path, "$PROJECT_DIR$/")
"file://" + relForwardPath(path)
}

private def relForwardPath(path: os.Path, prefix: String): String = {
private val projectDir = (workDir, "$PROJECT_DIR$/")
private val homeDir = (os.home, "$USER_HOME$/")

private def relForwardPath(path: os.Path): String = {

def forward(p: os.FilePath): String = p.toString().replace("""\""", "/")
Try(prefix + forward(path.relativeTo(workDir))).getOrElse(forward(path))

val relToProjectDir = Try(projectDir._2 + forward(path.relativeTo(projectDir._1)))
val relToHomeDir = Try(homeDir._2 + forward(path.relativeTo(homeDir._1)))

(relToProjectDir, relToHomeDir) match {
// We seem to be outside of project-dir but inside home dir, so use releative path to home dir
case (Success(p1), Success(p2)) if p1.contains("..") && !p2.contains("..") => p2
// default to project-dir-relative
case (Success(p), _) => p
// if that fails, use home-dir-relative, which might fix cases on Windows
// where the home-dir is not on the same drive as the project-dir
case (_, Success(p)) => p
// Use the absolute path
case _ => forward(path)
}
}

def libraryXmlTemplate(
name: String,
path: os.Path,
sources: Option[os.Path],
scalaCompilerClassPath: Agg[Path],
scalaCompilerClassPath: Agg[os.Path],
languageLevel: Option[String]
): Elem = {
val isScalaLibrary = scalaCompilerClassPath.iterator.nonEmpty
Expand Down Expand Up @@ -990,15 +1007,15 @@ object GenIdeaImpl {

final case class ResolvedModule(
path: Segments,
classpath: Agg[Scoped[Path]],
classpath: Agg[Scoped[os.Path]],
module: JavaModule,
pluginClasspath: Agg[Path],
pluginClasspath: Agg[os.Path],
scalaOptions: Seq[String],
compilerClasspath: Agg[Path],
libraryClasspath: Agg[Path],
compilerClasspath: Agg[os.Path],
libraryClasspath: Agg[os.Path],
facets: Seq[JavaFacet],
configFileContributions: Seq[IdeaConfigFile],
compilerOutput: Path,
compilerOutput: os.Path,
evaluator: Evaluator
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<component name="libraryTable">
<library name="SBT: junit:junit_2.13:4.13.2:jar">
<CLASSES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar!/"/>
<root url="jar://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar!/"/>
</CLASSES>
<SOURCES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2-sources.jar!/"/>
<root url="jar://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2-sources.jar!/"/>
</SOURCES>
</library>
</component>
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<component name="libraryTable">
<library name="SBT: org.scalameta:munit_2.13:0.7.29:jar">
<CLASSES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scalameta/munit_2.13/0.7.29/munit_2.13-0.7.29.jar!/"/>
<root url="jar://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalameta/munit_2.13/0.7.29/munit_2.13-0.7.29.jar!/"/>
</CLASSES>
<SOURCES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scalameta/munit_2.13/0.7.29/munit_2.13-0.7.29-sources.jar!/"/>
<root url="jar://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalameta/munit_2.13/0.7.29/munit_2.13-0.7.29-sources.jar!/"/>
</SOURCES>
</library>
</component>
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
<properties>
<language-level>Scala_2_13</language-level>
<compiler-classpath>
<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"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/net/java/dev/jna/jna/5.3.1/jna-5.3.1.jar"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/jline/jline/3.19.0/jline-3.19.0.jar"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.6/scala-compiler-2.13.6.jar"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6.jar"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/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.13.6/scala-library-2.13.6.jar!/"/>
<root url="jar://$USER_HOME$/.cache/coursier/v1/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.13.6/scala-library-2.13.6-sources.jar!/"/>
<root url="jar://$USER_HOME$/.cache/coursier/v1/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 @@ -3,7 +3,7 @@ import mill.define.Target
import mill._
import mill.scalalib.{Dep, DepSyntax, TestModule}

trait HelloWorldModule extends scalalib.ScalaModule {
trait HelloIdeaModule extends scalalib.ScalaModule {
def scalaVersion = "2.12.5"
object test extends ScalaTests with TestModule.Utest {
override def compileIvyDeps: Target[Agg[Dep]] = Agg(
Expand All @@ -20,8 +20,8 @@ trait HelloWorldModule extends scalalib.ScalaModule {
}
}

object HelloWorld extends HelloWorldModule
object HelloIdea extends HelloIdeaModule

object HiddenWorld extends HelloWorldModule {
object HiddenIdea extends HelloIdeaModule {
override def skipIdea = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="libraryTable">
<library name="scala-library-2.12.5.jar" type="Scala">
<properties>
<language-level>Scala_2_12</language-level>
<compiler-classpath>
<root url="file://$USER_HOME$/.cache/coursier/v1/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://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.5/scala-compiler-2.12.5.jar"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.5/scala-library-2.12.5.jar"/>
<root url="file://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.12.5/scala-reflect-2.12.5.jar"/>
</compiler-classpath>
</properties>
<CLASSES>
<root url="jar://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.5/scala-library-2.12.5.jar!/"/>
</CLASSES>
<SOURCES>
<root url="jar://$USER_HOME$/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.5/scala-library-2.12.5-sources.jar!/"/>
</SOURCES>
</library>
</component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/../../out/HelloIdea/ideaCompileOutput.dest/classes"/>
<exclude-output/>
<content url="file://$MODULE_DIR$/../../HelloIdea">
<sourceFolder url="file://$MODULE_DIR$/../../HelloIdea/src" isTestSource="false"/>
<sourceFolder url="file://$MODULE_DIR$/../../HelloIdea/resources" type="java-resource"/>
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.12.5.jar" level="project"/>
</component>
</module>
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output-test url="file://$MODULE_DIR$/../../out/HelloWorld/test/ideaCompileOutput.dest/classes"/>
<output-test url="file://$MODULE_DIR$/../../out/HelloIdea/test/ideaCompileOutput.dest/classes"/>
<exclude-output/>
<content url="file://$MODULE_DIR$/../../HelloWorld/test">
<sourceFolder url="file://$MODULE_DIR$/../../HelloWorld/test/src" isTestSource="true"/>
<sourceFolder url="file://$MODULE_DIR$/../../HelloWorld/test/resources" type="java-test-resource"/>
<content url="file://$MODULE_DIR$/../../HelloIdea/test">
<sourceFolder url="file://$MODULE_DIR$/../../HelloIdea/test/src" isTestSource="true"/>
<sourceFolder url="file://$MODULE_DIR$/../../HelloIdea/test/resources" type="java-test-resource"/>
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
Expand All @@ -13,6 +13,6 @@
<orderEntry type="library" name="logback-core-1.2.3.jar" level="project"/>
<orderEntry type="library" name="scala-library-2.12.5.jar" level="project"/>
<orderEntry type="library" name="slf4j-api-1.7.25.jar" level="project"/>
<orderEntry type="module" module-name="helloworld" exported=""/>
<orderEntry type="module" module-name="helloidea" exported=""/>
</component>
</module>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<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.test.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.test.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloidea.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloidea.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloidea.test.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloidea.test.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/mill-build.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/mill-build.iml"/>
</modules>
</component>
Expand Down
Loading

0 comments on commit 1a5b950

Please # to comment.