Skip to content

Commit 1fcfdd8

Browse files
committed
Merge pull request scala#5054 from lrytz/intellij-2.11
Update IntelliJ build for use with sbt
2 parents 4ef1429 + 2b3696e commit 1fcfdd8

27 files changed

+507
-236
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
/jenkins.properties
3131

3232
# target directories for ant build
33+
/build
3334
/build/
3435
/dists/
3536

@@ -55,5 +56,6 @@
5556
# Sbt's target directories
5657
/target/
5758
/project/target/
58-
/project/project/target
59+
/project/project/target/
60+
/project/project/project/target/
5961
/build-sbt/

build.sbt

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,6 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
463463
x.name.endsWith(".class") || x.name.endsWith(".properties") || x.name.startsWith("META-INF/native") || x.name.startsWith("META-INF/maven")
464464
)
465465
}
466-
//println(inputs.map(_.name).mkString("\n"))
467466
import JarJar.JarJarConfig._
468467
val config: Seq[JarJar.JarJarConfig] = Seq(
469468
Rule("org.fusesource.**", "scala.tools.fusesource_embedded.@1"),
@@ -851,3 +850,158 @@ commands ++= {
851850
}
852851

853852
addCommandAlias("scalap", "scalap/compile:runMain scala.tools.scalap.Main -usejavacp")
853+
854+
lazy val intellij = taskKey[Unit]("Update the library classpaths in the IntelliJ project files.")
855+
856+
def moduleDeps(p: Project) = (externalDependencyClasspath in Compile in p).map(a => (p.id, a.map(_.data)))
857+
858+
// aliases to projects to prevent name clashes
859+
def compilerP = compiler
860+
def testP = test
861+
862+
intellij := {
863+
import xml._
864+
import xml.transform._
865+
866+
val s = streams.value
867+
868+
val modules: List[(String, Seq[File])] = {
869+
// for the sbt build module, the dependencies are fetched from the project's build using sbt-buildinfo
870+
val buildModule = ("scala-build", scalabuild.BuildInfo.buildClasspath.split(":").toSeq.map(new File(_)))
871+
// `sbt projects` lists all modules in the build
872+
buildModule :: List(
873+
moduleDeps(actors).value,
874+
moduleDeps(compilerP).value,
875+
// moduleDeps(dist).value, // No sources, therefore no module in IntelliJ
876+
moduleDeps(forkjoin).value,
877+
moduleDeps(interactive).value,
878+
moduleDeps(junit).value,
879+
moduleDeps(library).value,
880+
// moduleDeps(libraryAll).value, // No sources
881+
moduleDeps(manual).value,
882+
moduleDeps(partestExtras).value,
883+
moduleDeps(partestJavaAgent).value,
884+
moduleDeps(reflect).value,
885+
moduleDeps(repl).value,
886+
moduleDeps(replJline).value,
887+
// moduleDeps(replJlineEmbedded).value, // No sources
888+
// moduleDeps(root).value, // No sources
889+
// moduleDeps(scalaDist).value, // No sources
890+
moduleDeps(scaladoc).value,
891+
moduleDeps(scalap).value,
892+
moduleDeps(testP).value)
893+
}
894+
895+
def moduleDep(name: String, jars: Seq[File]) = {
896+
val entries = jars.map(f => s""" <root url="jar://${f.toURI.getRawPath}!/" />""").mkString("\n")
897+
s"""| <library name="${name}-deps">
898+
| <CLASSES>
899+
|$entries
900+
| </CLASSES>
901+
| <JAVADOC />
902+
| <SOURCES />
903+
| </library>""".stripMargin
904+
}
905+
906+
def starrDep(jars: Seq[File]) = {
907+
val entries = jars.map(f => s""" <root url="file://${f.toURI.getRawPath}" />""").mkString("\n")
908+
s"""| <library name="starr" type="Scala">
909+
| <properties>
910+
| <option name="languageLevel" value="Scala_2_12" />
911+
| <compiler-classpath>
912+
|$entries
913+
| </compiler-classpath>
914+
| </properties>
915+
| <CLASSES />
916+
| <JAVADOC />
917+
| <SOURCES />
918+
| </library>""".stripMargin
919+
}
920+
921+
def replaceLibrary(data: Node, libName: String, libType: Option[String], newContent: String) = {
922+
object rule extends RewriteRule {
923+
var transformed = false
924+
def checkAttrs(attrs: MetaData) = {
925+
def check(key: String, expected: String) = {
926+
val a = attrs(key)
927+
a != null && a.text == expected
928+
}
929+
check("name", libName) && libType.forall(tp => check("type", tp))
930+
}
931+
932+
override def transform(n: Node): Seq[Node] = n match {
933+
case e @ Elem(_, "library", attrs, _, _, _*) if checkAttrs(attrs) =>
934+
transformed = true
935+
XML.loadString(newContent)
936+
case other =>
937+
other
938+
}
939+
}
940+
object trans extends RuleTransformer(rule)
941+
val r = trans(data)
942+
if (!rule.transformed) sys.error(s"Replacing library classpath for $libName failed, no existing library found.")
943+
r
944+
}
945+
946+
val ipr = (baseDirectory in ThisBuild).value / "src/intellij/scala.ipr"
947+
948+
var continue = false
949+
if (!ipr.exists) {
950+
scala.Console.print(s"Could not find src/intellij/scala.ipr. Create new project files from src/intellij/*.SAMPLE (y/N)? ")
951+
if (scala.Console.readLine() == "y") {
952+
intellijCreateFromSample((baseDirectory in ThisBuild).value)
953+
continue = true
954+
}
955+
} else {
956+
scala.Console.print("Update library classpaths in the current src/intellij/scala.ipr (y/N)? ")
957+
continue = scala.Console.readLine() == "y"
958+
}
959+
if (continue) {
960+
s.log.info("Updating library classpaths in src/intellij/scala.ipr.")
961+
val content = XML.loadFile(ipr)
962+
963+
val newStarr = replaceLibrary(content, "starr", Some("Scala"), starrDep((scalaInstance in LocalProject("compiler")).value.jars))
964+
val newModules = modules.foldLeft(newStarr)({
965+
case (res, (modName, jars)) =>
966+
if (jars.isEmpty) res // modules without dependencies
967+
else replaceLibrary(res, s"$modName-deps", None, moduleDep(modName, jars))
968+
})
969+
970+
XML.save(ipr.getAbsolutePath, newModules)
971+
} else {
972+
s.log.info("Aborting.")
973+
}
974+
}
975+
976+
lazy val intellijFromSample = taskKey[Unit]("Create fresh IntelliJ project files from src/intellij/*.SAMPLE.")
977+
978+
intellijFromSample := {
979+
val s = streams.value
980+
scala.Console.print(s"Create new project files from src/intellij/*.SAMPLE (y/N)? ")
981+
if (scala.Console.readLine() == "y")
982+
intellijCreateFromSample((baseDirectory in ThisBuild).value)
983+
else
984+
s.log.info("Aborting.")
985+
}
986+
987+
def intellijCreateFromSample(basedir: File): Unit = {
988+
val files = basedir / "src/intellij" * "*.SAMPLE"
989+
val copies = files.get.map(f => (f, new File(f.getAbsolutePath.stripSuffix(".SAMPLE"))))
990+
IO.copy(copies, overwrite = true)
991+
}
992+
993+
lazy val intellijToSample = taskKey[Unit]("Update src/intellij/*.SAMPLE using the current IntelliJ project files.")
994+
995+
intellijToSample := {
996+
val s = streams.value
997+
scala.Console.print(s"Update src/intellij/*.SAMPLE using the current IntelliJ project files (y/N)? ")
998+
if (scala.Console.readLine() == "y") {
999+
val basedir = (baseDirectory in ThisBuild).value
1000+
val existing = basedir / "src/intellij" * "*.SAMPLE"
1001+
IO.delete(existing.get)
1002+
val current = basedir / "src/intellij" * ("*.iml" || "*.ipr")
1003+
val copies = current.get.map(f => (f, new File(f.getAbsolutePath + ".SAMPLE")))
1004+
IO.copy(copies)
1005+
} else
1006+
s.log.info("Aborting.")
1007+
}

project/plugins.sbt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,15 @@ libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.3.2"
33
libraryDependencies += "org.pantsbuild" % "jarjar" % "1.6.0"
44

55
libraryDependencies += "biz.aQute" % "bndlib" % "1.50.0"
6+
7+
enablePlugins(BuildInfoPlugin)
8+
9+
// configure sbt-buildinfo to send the externalDependencyClasspath to the main build, which allows using it for the IntelliJ project config
10+
11+
lazy val buildClasspath = taskKey[String]("Colon-separated list of entries on the sbt build classpath.")
12+
13+
buildClasspath := (externalDependencyClasspath in Compile).value.map(_.data).mkString(":")
14+
15+
buildInfoKeys := Seq[BuildInfoKey](buildClasspath)
16+
17+
buildInfoPackage := "scalabuild"

project/project/plugins.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1")

src/intellij/README.md

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
1-
Use the latest IntelliJ IDEA release and install the Scala plugin from within the IDE.
1+
# Building Scala in IntelliJ IDEA
22

3-
Compilation withing IDEA is performed in "-Dlocker.skip=1" mode: the sources are built
4-
directly using the STARR compiler.
3+
## Requirements
54

6-
The following steps are required to use IntelliJ IDEA on Scala trunk
7-
- Run `ant init`. This will download some JARs to `./build/deps`, which are included in IntelliJ's classpath.
8-
- Run `./src/intellij/setup.sh`.
9-
- Open `./src/intellij/scala.ipr` in IntelliJ.
10-
- `File``Project Structure``Project``Project SDK`. Create an SDK entry named "1.6" containing the Java 1.6 SDK. (Or other SDK version; see "Requirements" in the repo's main README.)
5+
Use the latest IntelliJ release and install the Scala plugin from within the IDE.
116

12-
Compilation within IDEA is performed in `-Dlocker.skip=1` mode: the sources are built
13-
directly using the STARR compiler (which is downloaded from [the Central Repository](http://central.sonatype.org/), according to `starr.version` in `versions.properties`).
7+
## Initial setup
8+
9+
To create the IntelliJ project files:
10+
11+
- Run `sbt intellij`
12+
- Open `src/intellij/scala.ipr` in IntelliJ
13+
- In `File``Project Structure``Project``Project SDK`, create an SDK entry named "1.6" containing the Java 1.6 SDK
14+
15+
The project files are created by as copies of the `.SAMPLE` files, which are under version control.
16+
The actual IntelliJ project files are in `.gitignore` so that local changes are ignored.
17+
18+
## Dependencies
19+
20+
For every module in the IntelliJ project there is a corresponding `-deps` library, for exmaple `compiler-deps` provides `ant.jar` for the compiler codebase.
21+
The `.jar` files in these `-deps` libraries can be easily kept up-to-date by running `sbt intellij` again.
22+
This is necessary whenever the dependencies in the sbt build change, for example when the STARR version is updated.
23+
24+
Note that this command only patches the dependency lists, all other settings in the IntelliJ project definition are unchanged.
25+
To overwrite the project definition files by copying the `.SAMPLE` files again run `sbt intellijFromSample`.
26+
27+
## Usage
28+
29+
Compiling, running, JUnit tests and debugging should all work.
30+
You can work on the compiler, the standard library, and other components as well.
31+
32+
Note that compilation within IntelliJ is performed in a single pass.
33+
The code is compiled using the "STARR" (stable reference) compiler, as specified by `starr.version` in `versions.properties`.
34+
This is consistent with the sbt build.
35+
36+
Note that the output directory when compiling in IntelliJ is the same as for the sbt build.
37+
This allows building incrementally in IntelliJ and directly use the changes using the command-line scripts in `build/quick/bin/`.
38+
39+
## Updating the `.SAMPLE` files
40+
41+
The command `intellijToSample` overwrites the `.SAMPLE` files using the current project definition files.

src/intellij/actors.iml.SAMPLE

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<module type="JAVA_MODULE" version="4">
3-
<component name="NewModuleRootManager" inherit-compiler-output="true">
3+
<component name="NewModuleRootManager" inherit-compiler-output="false">
4+
<output url="file://$MODULE_DIR$/../../build/quick/classes/actors" />
5+
<output-test url="file://$MODULE_DIR$/../../out/test/actors" />
46
<exclude-output />
57
<content url="file://$MODULE_DIR$/../actors">
68
<sourceFolder url="file://$MODULE_DIR$/../actors" isTestSource="false" />

src/intellij/asm.iml.SAMPLE

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/intellij/compiler.iml.SAMPLE

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<module type="JAVA_MODULE" version="4">
3-
<component name="NewModuleRootManager" inherit-compiler-output="true">
3+
<component name="NewModuleRootManager" inherit-compiler-output="false">
4+
<output url="file://$MODULE_DIR$/../../build/quick/classes/compiler" />
5+
<output-test url="file://$MODULE_DIR$/../../out/test/compiler" />
46
<exclude-output />
57
<content url="file://$MODULE_DIR$/../compiler">
6-
<sourceFolder url="file://$MODULE_DIR$/../compiler/src" isTestSource="false" />
78
<sourceFolder url="file://$MODULE_DIR$/../compiler" isTestSource="false" />
89
</content>
910
<orderEntry type="inheritedJdk" />
1011
<orderEntry type="sourceFolder" forTests="false" />
1112
<orderEntry type="module" module-name="library" />
1213
<orderEntry type="module" module-name="reflect" />
14+
<orderEntry type="library" name="compiler-deps" level="project" />
1315
<orderEntry type="library" name="starr" level="project" />
14-
<orderEntry type="library" name="ant" level="project" />
15-
<orderEntry type="library" name="asm" level="project" />
1616
</component>
1717
</module>

src/intellij/diff.sh

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/intellij/forkjoin.iml.SAMPLE

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<module type="JAVA_MODULE" version="4">
3-
<component name="NewModuleRootManager" inherit-compiler-output="true">
3+
<component name="NewModuleRootManager" inherit-compiler-output="false">
4+
<output url="file://$MODULE_DIR$/../../build/quick/classes/forkjoin" />
5+
<output-test url="file://$MODULE_DIR$/../../out/test/forkjoin" />
46
<exclude-output />
57
<content url="file://$MODULE_DIR$/../forkjoin">
68
<sourceFolder url="file://$MODULE_DIR$/../forkjoin" isTestSource="false" />

0 commit comments

Comments
 (0)