diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
index af2a19460731..2ea7c9bc8117 100644
--- a/.idea/codeStyleSettings.xml
+++ b/.idea/codeStyleSettings.xml
@@ -90,11 +90,6 @@
-
-
-
-
-
@@ -185,6 +180,13 @@
+
+
+
+
+
+
+
diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant
index 55c5cf77e6a6..11de4164c82b 100644
--- a/build/scripts/layouts.gant
+++ b/build/scripts/layouts.gant
@@ -157,7 +157,10 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir
module("jps-model")
}
- fileset(dir: "$home/jps/lib", includes: "optimizedFileManager.jar")
+ fileset(dir: "$home/jps/lib") {
+ include(name: "optimizedFileManager.jar")
+ include(name: "ecj-*.jar")
+ }
fileset(dir: "$home/lib", includesfile: "${home}/lib/required_for_dist.txt")
diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant
index 9d98c0ac7105..753c6ad8b8ff 100644
--- a/build/scripts/libLicenses.gant
+++ b/build/scripts/libLicenses.gant
@@ -1,245 +1,246 @@
-/*
- * Copyright 2000-2012 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.jetbrains.jps.ClasspathKind
-import org.jetbrains.jps.Library
-import org.jetbrains.jps.Module
-
-class LibraryLicense {
- String name, url, version
- List libraryNames
- String license, licenseUrl
- String attachedTo
-}
-
-List licensesList = []
-List jetbrainsLibraries = []
-Map predefinedLicenseUrls = ["Apache 2.0": "http://www.apache.org/licenses/LICENSE-2.0"]
-
-binding.setVariable("libraryLicense", {Map args ->
- if (args.libraryNames == null) {
- args.libraryNames = [args.libraryName?:args.name]
- args.remove("libraryName")
- }
- if (args.licenseUrl == null) {
- args.licenseUrl = predefinedLicenseUrls[args.license]
- }
- licensesList << new LibraryLicense(args)
-})
-
-binding.setVariable("jetbrainsLibrary", {String name ->
- jetbrainsLibraries << name
-})
-
-def String getLibraryName(Library lib) {
- def name = lib.name
- if (name.startsWith("moduleLibrary#")) {
- if (lib.classpath.size() != 1) {
- project.warning("Non-single entry module library $name: $lib.classpath");
- }
- String filePath = lib.classpath[0]
- return filePath.substring(filePath.lastIndexOf('/')+1)
- }
- return name
-}
-
-binding.setVariable("checkLibLicenses", {
- def libraries = new HashSet()
- def lib2Module = new HashMap();
- project.modules.values().each {Module module ->
- module.getClasspath(ClasspathKind.PRODUCTION_RUNTIME).each {
- if (it instanceof Library) {
- lib2Module[it] = module
- libraries << it
- }
- }
- }
-
- def libWithLicenses = licensesList.collectAll {it.libraryNames}.flatten() as Set
- libWithLicenses.addAll(jetbrainsLibraries)
-
- List withoutLicenses = []
- libraries.each {Library lib ->
- def name = getLibraryName(lib)
- if (!libWithLicenses.contains(name)) {
- withoutLicenses << "$name (used in module ${lib2Module[lib].name})".toString()
- }
- }
-
- if (!withoutLicenses.isEmpty()) {
- def errorMessage = []
- errorMessage << "Licenses aren't specified for ${withoutLicenses.size()} libraries:"
- withoutLicenses.sort(String.CASE_INSENSITIVE_ORDER)
- withoutLicenses.each { errorMessage << it}
- errorMessage << "If a library is packaged into IDEA installation information about its license must be added to libLicenses.gant file"
- errorMessage << "If a library is used in tests only change its scope to 'Test'"
- errorMessage << "If a library is used for compilation only change its scope to 'Provided'"
- project.error(errorMessage.join("\n"))
- }
-});
-
-binding.setVariable("generateLicensesTable", {String filePath, Set usedModulesNames ->
- project.info("Generating licenses table")
- project.info("Used modules: $usedModulesNames")
- Set usedModules = project.modules.values().findAll {usedModulesNames.contains(it.name)}
- Map usedLibraries = [:]
- usedModules.each {Module module ->
- module.getClasspath(ClasspathKind.PRODUCTION_RUNTIME).each {item ->
- if (item instanceof Library) {
- usedLibraries[getLibraryName(item)] = module.name
- }
- }
- }
-
- Map licenses = [:]
- licensesList.each {LibraryLicense lib ->
- if (usedModulesNames.contains(lib.attachedTo)) {
- licenses[lib] = lib.attachedTo
- }
- else {
- lib.libraryNames.each {
- String module = usedLibraries[it]
- if (module != null) {
- licenses[lib] = module
- }
- }
- }
- }
-
- project.info("Used libraries:")
- List lines = []
- licenses.entrySet().each {
- LibraryLicense lib = it.key
- String moduleName = it.value
- def name = lib.url != null ? "[$lib.name|$lib.url]" : lib.name
- def license = lib.licenseUrl != null ? "[$lib.license|$lib.licenseUrl]" : lib.license
- project.info(" $lib.name (in module $moduleName)")
- lines << "|$name| ${lib.version?:""}|$license|".toString()
- }
- //project.info("Unused libraries:")
- //licensesList.findAll {!licenses.containsKey(it)}.each {LibraryLicense lib ->
- // project.info(" $lib.name")
- //}
-
- lines.sort(String.CASE_INSENSITIVE_ORDER)
- File file = new File(filePath)
- file.parentFile.mkdirs()
- FileWriter out = new FileWriter(file)
- try {
- out.println("|| Software || Version || License ||")
- lines.each {
- out.println(it)
- }
- }
- finally {
- out.close()
- }
- notifyArtifactBuilt(filePath)
-})
-
-libraryLicense(name: "Alloy L&F", libraryName: "alloy.jar", version: "1.4.4", license: "link (company license)", url: "http://www.incors.com/lookandfeel/", licenseUrl: "http://lookandfeel.incors.com/display_licence.php?back=purchase.php&selMenu=Purchase")
-libraryLicense(name: "Ant", version: "1.7", license: "Apache 2.0", url: "http://ant.apache.org/", licenseUrl: "http://ant.apache.org/license.html")
-libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm", version: "3.3", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html")
-libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm4", version: "4.0", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html")
-libraryLicense(name: "Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/axis-1.4.0/axis.LICENSE")
-libraryLicense(name: "CGLib", libraryName: "CGLIB", version: "2.2.2", license: "Apache", url: "http://cglib.sourceforge.net/", licenseUrl: "http://www.apache.org/foundation/licence-FAQ.html")
-libraryLicense(name: "classworlds", libraryName: "classworlds-1.1.jar", version: "1.1", license: "codehaus", url: "http://classworlds.codehaus.org/", licenseUrl: "http://classworlds.codehaus.org/license.html")
-libraryLicense(name: "Android SDK Tools", libraryName: "android-sdk-tools", license: "Apache 2.0", url: "http://source.android.com/")
-libraryLicense(name: "Android SDK Tools JPS", libraryName: "android-sdk-tools-jps", license: "Apache 2.0", url: "http://source.android.com/")
-libraryLicense(name: "Apache Commons BeanUtils", libraryName: "commons-beanutils.jar", version: "1.6", license: "Apache 2.0", url: "http://commons.apache.org/beanutils/")
-libraryLicense(name: "Apache Commons Codec", libraryName: "commons-codec", version: "1.3", license: "Apache 2.0", url: "http://commons.apache.org/codec/", licenseUrl: "http://commons.apache.org/license.html")
-libraryLicense(name: "Apache Commons Collections", libraryName: "commons-collections", version: "3.1", license: "Apache 2.0", url: "http://commons.apache.org/collections/", licenseUrl: "http://commons.apache.org/license.html")
-libraryLicense(name: "Apache Commons Discovery", libraryName: "commons-discovery-0.4.jar", version: "0.4", license: "Apache 2.0", url: "http://jakarta.apache.org/commons/discovery/", licenseUrl: "http://commons.apache.org/license.html")
-libraryLicense(name: "Apache Commons HTTPClient", libraryName: "http-client-3.1", version: "3.1 (with patch by JetBrains)", license: "Apache 2.0", url: "http://hc.apache.org/httpclient-3.x")
-libraryLicense(name: "Apache Commons Net", libraryName: "commons-net", version: "2.0", license: "Apache 2.0", url: "http://commons.apache.org/net/")
-libraryLicense(name: "Apache Commons Lang", libraryName: "commons-lang", version: "2.4", license: "Apache 2.0", url: "http://commons.apache.org/lang/", licenseUrl: "http://commons.apache.org/lang/license.html")
-libraryLicense(name: "Apache Commons Logging", libraryName: "commons-logging", version: "1.1.1", license: "Apache 2.0", url: "http://commons.apache.org/logging/")
-libraryLicense(name: "Apache Lucene", libraryName: "lucene-core-2.4.1.jar", version: "2.4.1", license: "Apache 2.0", url: "http://lucene.apache.org/java")
-libraryLicense(name: "Apache Sanselan", libraryName: "Sanselan", version: "0.98", license: "Apache 2.0", url: "http://commons.apache.org/sanselan/")
-libraryLicense(name: "Automaton", libraryName: "automaton.jar", version: "1.11", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
-libraryLicense(name: "DTDParser", version: "1.13", license: "LGPL", url: "http://sourceforge.net/projects/dtdparser/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1")
-libraryLicense(name: "Ganymed", version: "bundled with SVNKit", libraryName: "svnkit.jar", license: "BSD", url: "http://www.ganymed.ethz.ch/ssh2/", licenseUrl: "http://www.ganymed.ethz.ch/ssh2/LICENSE.txt")
-libraryLicense(name: "sqljet", version: "bundled with SVNKit", libraryName: "sqljet.jar", license: "GPLv2", url: "http://sqljet.com", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1")
-libraryLicense(name: "svnkit-javahl", version: "bundled with SVNKit", libraryName: "svnkit-javahl.jar", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html")
-libraryLicense(name: "javahl", version: "1.7.2", libraryName: "javahl.jar", license: "Apache", url: "http://subversion.apache.org", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
-libraryLicense(name: "Apache Commons HTTPClient", libraryName: "httpclient-4.1.1.jar", version:"4.1.1", license: "Apache 2.0",
- url: "http://hc.apache.org/httpcomponents-client-ga/index.html", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
-libraryLicense(name: "Apache Commons HTTPCore", libraryName: "httpcore-4.1.jar", version: "4.1", license: "Apache 2.0",
- url: "http://hc.apache.org/httpcomponents-core-ga/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
-libraryLicense(name: "Antlr", libraryName: "antlr.jar", version: "3.1.3", license: "BSD", url: "http://www.antlr.org",
- licenseUrl: "http://www.antlr.org/license.html")
-libraryLicense(name: "Guava", version: "12.0", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/", licenseUrl: "http://ant.apache.org/license.html")
-libraryLicense(name: "Groovy", version: "1.7.3", license: "Apache 2.0", url: "http://groovy.codehaus.org/")
-libraryLicense(name: "Gson", libraryName: "gson", license: "Apache 2.0", url: "http://code.google.com/p/google-gson/")
-libraryLicense(name: "ini4j", libraryName: "ini4j-0.5.2-patched", version: "0.5.2 (with a patch by JetBrains)", license: "Apache 2.0", url: "http://ini4j.sourceforge.net/", attachedTo: "git4idea")
-libraryLicense(name: "ISO RELAX", libraryName: "isorelax.jar", license: "MIT License", url: "http://sourceforge.net/projects/iso-relax/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
-libraryLicense(name: "JavaCVS", attachedTo: "javacvs-src", version: "no version number available (with patches by JetBrains)", license: "Sun Public License", url: "http://javacvs.netbeans.org/library/", licenseUrl: "http://www.netbeans.org/about/legal/spl.html")
-libraryLicense(name: "JAXB", libraryName: "JAXB", version: "2.2.4-1", license: "CDDL 1.1", url: "http://jaxb.java.net/", licenseUrl: "http://glassfish.java.net/public/CDDL+GPL_1_1.html")
-libraryLicense(name: "Jaxen", version: "", license: "modified Apache", url: "http://www.jaxen.org/", licenseUrl: "http://www.jaxen.org/license.html")
-libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as license/javahelp_license.html in IntelliJ IDEA distribution", url: "http://java.sun.com/products/javahelp/")
-libraryLicense(name: "JCIP Annotations", libraryName: "jcip", license: "Creative Commons Attribution License", url: "http://www.jcip.net", licenseUrl: "http://creativecommons.org/licenses/by/2.5")
-libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030")
-libraryLicense(name: "jgit-1.1.0", version: "1.1.0.201109151100", license: "EDL/BSD", url: "http://www.eclipse.org/jgit/", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", attachedTo: "git4idea")
-libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
-libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
-libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
-libraryLicense(name: "JNA", libraryName: "jna", version: "3.4.0", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php")
-libraryLicense(name: "JSch", libraryName: "JSch", version: "0.1.44", license: "BSD", url: "http://www.jcraft.com/jsch/", licenseUrl: "http://www.jcraft.com/jsch/LICENSE.txt")
-libraryLicense(name: "JUnit", libraryName: "JUnit3", version: "3.8.1", license: "CPL 1.0", url: "http://junit.org/")
-libraryLicense(name: "JUnit", libraryName: "JUnit4", version: "4.8", license: "CPL 1.0", url: "http://junit.org/")
-libraryLicense(name: "Log4j", libraryName: "Log4J", version: "1.2", license: "Apache 2.0", url: "http://logging.apache.org/log4j/1.2/index.html", licenseUrl: "http://logging.apache.org/license.html")
-libraryLicense(name: "Maven", version: "2.2.1", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html")
-libraryLicense(name: "Maven3", libraryNames: ["Maven3", "maven-dependency-tree-1.2.jar"], version: "3.0.3", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html")
-libraryLicense(name: "markdownj", attachedTo: "tasks-core", version: "", license: "BSD", url: "http://markdownj.org/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
-libraryLicense(name: "mercurial_prompthooks", attachedTo: "hg4idea", version: "", license: "GPLv2 (used as hg extension called from hg executable)", url: "https://github.com/willemv/mercurial_prompthooks", licenseUrl: "https://github.com/willemv/mercurial_prompthooks/blob/master/LICENSE.txt")
-libraryLicense(name: "Microba", libraryName: "microba", version: "0.4.2", license: "BSD", url: "http://microba.sourceforge.net/", licenseUrl: "http://microba.sourceforge.net/license.txt")
-libraryLicense(name: "MigLayout", libraryName: "miglayout-swing", version: "3.7.1", license: "BSD", url: "http://www.miglayout.com/", licenseUrl: "http://www.miglayout.com/mavensite/license.html")
-libraryLicense(name: "NanoXML", version: "2.2.3", license: "zlib/libpng", url: "http://nanoxml.cyberelf.be/", licenseUrl: "http://devkix.com/nanoxml.php")
-libraryLicense(name: "nekohtml", libraryName: "nekohtml", version: "1.9.14", license: "Apache 2.0", url: "http://nekohtml.sourceforge.net/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0.txt")
-libraryLicense(name: "Eclipse JDT Core", libraryName: "Eclipse", version: "3.3", license: "CPL 1.0", url: "http://www.eclipse.org/jdt/core/index.php")
-libraryLicense(name: "Jakarta ORO", libraryName: "OroMatcher", version: "2.0.8", license: "Apache", url: "http://jakarta.apache.org/oro/", licenseUrl: "http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE")
-libraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "http://www.picocontainer.org/", licenseUrl: "http://docs.codehaus.org/display/PICO/License")
-libraryLicense(name: "Plexus Utils", libraryName: "plexus-utils-1.5.5.jar", version: "1.5.5", license: "Apache 2.0", url: "http://plexus.codehaus.org/plexus-utils")
-libraryLicense(name: "Quaqua L&F", attachedTo: "platform-impl", version: "6.2", license: "BSD", url: "http://www.randelshofer.ch/quaqua/", licenseUrl: "http://www.randelshofer.ch/quaqua/license.html")
-libraryLicense(name: "Relax NG Object Model", libraryName: "rngom-20051226-patched.jar", license: "MIT", url: "http://java.net/projects/rngom/", licenseUrl: "http://www.opensource.org/licenses/mit-license.php")
-libraryLicense(name: "RMI Stubs", attachedTo: "xslt-debugger-engine", license: "Apache 2.0", url: "http://confluence.jetbrains.net/display/CONTEST/XSLT-Debugger", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
-libraryLicense(name: "Saxon-9HE", version: "9", license: "Mozilla Public License", url: "http://saxon.sourceforge.net/", licenseUrl: "http://www.mozilla.org/MPL/")
-libraryLicense(name: "Saxon-6.5.5", version: "6.5.5", license: "Mozilla Public License", url: "http://saxon.sourceforge.net/", licenseUrl: "http://www.mozilla.org/MPL/")
-libraryLicense(name: "Sonatype Nexus: Indexer", libraryName: "nexus-indexer-1.2.3.jar", version: "1.2.3", license: "Eclipse Public License v1.0", url: "http://nexus.sonatype.org/", licenseUrl: "http://www.eclipse.org/org/documents/epl-v10.html")
-libraryLicense(name: "Sonatype Nexus: Indexer", libraryName: "nexus-indexer-3.0.4.jar", version: "3.0.4", license: "Eclipse Public License v1.0", url: "http://nexus.sonatype.org/", licenseUrl: "http://www.eclipse.org/org/documents/epl-v10.html")
-libraryLicense(name: "SVNKit", libraryName: "svnkit.jar", version: "SVN version, 1.1 branch as of 1 Oct 2007", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html")
-libraryLicense(name: "Sequence", libraryName: "sequence-library.jar", version: "bundled with SVNKit", license: "", url:"http://www.syntevo.com", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/svn4idea/lib/SEQUENCE-LICENSE")
-libraryLicense(name: "swingx", libraryName: "swingx", version: "1.6.2", license: "LGPL 2.1", url: "http://java.net/downloads/swingx/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php")
-libraryLicense(name: "TestNG", version: "5.7 snapshot", license: "Apache 2.0", url: "http://testng.org/doc/", licenseUrl: "http://code.google.com/p/testng/")
-libraryLicense(name: "Trilead SSH", libraryName: "trilead-ssh2", version: "build 213", license: "BSD style (see LICENSE.txt in trilead.jar)", url: "http://www.trilead.com/SSH_Library/")
-libraryLicense(name: "Trove4j", version: "1.1 (with patches by JetBrains)", license: "LGPL", url: "http://trove4j.sourceforge.net/", licenseUrl: "http://trove4j.sourceforge.net/html/license.html")
-libraryLicense(name: "Velocity", version: "1.7", license: "Apache 2.0", url: "http://velocity.apache.org/", licenseUrl: "http://velocity.apache.org/index.html")
-libraryLicense(name: "winp", version: "1.16 (patched)", license: "MIT", url: "http://winp.dev.java.net/", licenseUrl: "https://winp.dev.java.net/license.html")
-libraryLicense(name: "Xalan", libraryName:"Xalan-2.7.1", version: "2.7.1", license: "Apache 2.0", url: "http://xml.apache.org/xalan-j/", licenseUrl: "http://xml.apache.org/xalan-j/")
-libraryLicense(name: "Xerces", version: "2.9.1", license: "Apache 2.0", url: "http://xerces.apache.org/xerces2-j/", licenseUrl: "http://xerces.apache.org/xerces2-j/")
-libraryLicense(name: "XML Commons (xml-apis.jar, resolver.jar)", version: "", license: "Apache 2.0, W3C Software License , public domain", url: "http://xml.apache.org/commons/", licenseUrl: "http://xml.apache.org/commons/licenses.html")
-libraryLicense(name: "XMLBeans", libraryName: "XmlBeans", version: "2.3.0", license: "Apache 2.0", url: "http://xmlbeans.apache.org/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/xmlbeans-2.3.0/xmlbeans.LICENSE")
-libraryLicense(name: "XML-RPC", libraryName: "XmlRPC", version: "2.0", license: "Apache 2.0", url: "http://ws.apache.org/xmlrpc/xmlrpc2/", licenseUrl: "http://ws.apache.org/xmlrpc/xmlrpc2/license.html")
-libraryLicense(name: "XStream", version: "1.2.1", license: "BSD", url: "http://xstream.codehaus.org/", licenseUrl: "http://xstream.codehaus.org/license.html")
-libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "8.0.x", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html")
-libraryLicense(name: "protobuf", version: "2.3.0", license: "New BSD", url: "http://code.google.com/p/protobuf/", licenseUrl: "http://code.google.com/p/protobuf/source/browse/trunk/COPYING.txt?r=367")
-libraryLicense(name: "Netty", libraryName: "Netty", version: "3.3.1", license: "Apache 2.0", url: "http://netty.io", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
-libraryLicense(name: "Kryo", libraryName: "Kryo", version: "1.04", license: "New BSD License", url: "http://code.google.com/p/kryo/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
-libraryLicense(name: "Snappy-Java", libraryName: "Snappy-Java", version: "1.0.4.1", license: "Apache 2.0", url: "http://code.google.com/p/snappy-java/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
-jetbrainsLibrary("JPS")
-jetbrainsLibrary("Maven Embedder")
-jetbrainsLibrary("tcServiceMessages")
-jetbrainsLibrary("optimizedFileManager.jar")
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.jetbrains.jps.ClasspathKind
+import org.jetbrains.jps.Library
+import org.jetbrains.jps.Module
+
+class LibraryLicense {
+ String name, url, version
+ List libraryNames
+ String license, licenseUrl
+ String attachedTo
+}
+
+List licensesList = []
+List jetbrainsLibraries = []
+Map predefinedLicenseUrls = ["Apache 2.0": "http://www.apache.org/licenses/LICENSE-2.0"]
+
+binding.setVariable("libraryLicense", {Map args ->
+ if (args.libraryNames == null) {
+ args.libraryNames = [args.libraryName?:args.name]
+ args.remove("libraryName")
+ }
+ if (args.licenseUrl == null) {
+ args.licenseUrl = predefinedLicenseUrls[args.license]
+ }
+ licensesList << new LibraryLicense(args)
+})
+
+binding.setVariable("jetbrainsLibrary", {String name ->
+ jetbrainsLibraries << name
+})
+
+def String getLibraryName(Library lib) {
+ def name = lib.name
+ if (name.startsWith("moduleLibrary#")) {
+ if (lib.classpath.size() != 1) {
+ project.warning("Non-single entry module library $name: $lib.classpath");
+ }
+ String filePath = lib.classpath[0]
+ return filePath.substring(filePath.lastIndexOf('/')+1)
+ }
+ return name
+}
+
+binding.setVariable("checkLibLicenses", {
+ def libraries = new HashSet()
+ def lib2Module = new HashMap();
+ project.modules.values().each {Module module ->
+ module.getClasspath(ClasspathKind.PRODUCTION_RUNTIME).each {
+ if (it instanceof Library) {
+ lib2Module[it] = module
+ libraries << it
+ }
+ }
+ }
+
+ def libWithLicenses = licensesList.collectAll {it.libraryNames}.flatten() as Set
+ libWithLicenses.addAll(jetbrainsLibraries)
+
+ List withoutLicenses = []
+ libraries.each {Library lib ->
+ def name = getLibraryName(lib)
+ if (!libWithLicenses.contains(name)) {
+ withoutLicenses << "$name (used in module ${lib2Module[lib].name})".toString()
+ }
+ }
+
+ if (!withoutLicenses.isEmpty()) {
+ def errorMessage = []
+ errorMessage << "Licenses aren't specified for ${withoutLicenses.size()} libraries:"
+ withoutLicenses.sort(String.CASE_INSENSITIVE_ORDER)
+ withoutLicenses.each { errorMessage << it}
+ errorMessage << "If a library is packaged into IDEA installation information about its license must be added to libLicenses.gant file"
+ errorMessage << "If a library is used in tests only change its scope to 'Test'"
+ errorMessage << "If a library is used for compilation only change its scope to 'Provided'"
+ project.error(errorMessage.join("\n"))
+ }
+});
+
+binding.setVariable("generateLicensesTable", {String filePath, Set usedModulesNames ->
+ project.info("Generating licenses table")
+ project.info("Used modules: $usedModulesNames")
+ Set usedModules = project.modules.values().findAll {usedModulesNames.contains(it.name)}
+ Map usedLibraries = [:]
+ usedModules.each {Module module ->
+ module.getClasspath(ClasspathKind.PRODUCTION_RUNTIME).each {item ->
+ if (item instanceof Library) {
+ usedLibraries[getLibraryName(item)] = module.name
+ }
+ }
+ }
+
+ Map licenses = [:]
+ licensesList.each {LibraryLicense lib ->
+ if (usedModulesNames.contains(lib.attachedTo)) {
+ licenses[lib] = lib.attachedTo
+ }
+ else {
+ lib.libraryNames.each {
+ String module = usedLibraries[it]
+ if (module != null) {
+ licenses[lib] = module
+ }
+ }
+ }
+ }
+
+ project.info("Used libraries:")
+ List lines = []
+ licenses.entrySet().each {
+ LibraryLicense lib = it.key
+ String moduleName = it.value
+ def name = lib.url != null ? "[$lib.name|$lib.url]" : lib.name
+ def license = lib.licenseUrl != null ? "[$lib.license|$lib.licenseUrl]" : lib.license
+ project.info(" $lib.name (in module $moduleName)")
+ lines << "|$name| ${lib.version?:""}|$license|".toString()
+ }
+ //project.info("Unused libraries:")
+ //licensesList.findAll {!licenses.containsKey(it)}.each {LibraryLicense lib ->
+ // project.info(" $lib.name")
+ //}
+
+ lines.sort(String.CASE_INSENSITIVE_ORDER)
+ File file = new File(filePath)
+ file.parentFile.mkdirs()
+ FileWriter out = new FileWriter(file)
+ try {
+ out.println("|| Software || Version || License ||")
+ lines.each {
+ out.println(it)
+ }
+ }
+ finally {
+ out.close()
+ }
+ notifyArtifactBuilt(filePath)
+})
+
+libraryLicense(name: "Alloy L&F", libraryName: "alloy.jar", version: "1.4.4", license: "link (company license)", url: "http://www.incors.com/lookandfeel/", licenseUrl: "http://lookandfeel.incors.com/display_licence.php?back=purchase.php&selMenu=Purchase")
+libraryLicense(name: "Ant", version: "1.7", license: "Apache 2.0", url: "http://ant.apache.org/", licenseUrl: "http://ant.apache.org/license.html")
+libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm", version: "3.3", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html")
+libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm4", version: "4.0", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html")
+libraryLicense(name: "Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/axis-1.4.0/axis.LICENSE")
+libraryLicense(name: "CGLib", libraryName: "CGLIB", version: "2.2.2", license: "Apache", url: "http://cglib.sourceforge.net/", licenseUrl: "http://www.apache.org/foundation/licence-FAQ.html")
+libraryLicense(name: "classworlds", libraryName: "classworlds-1.1.jar", version: "1.1", license: "codehaus", url: "http://classworlds.codehaus.org/", licenseUrl: "http://classworlds.codehaus.org/license.html")
+libraryLicense(name: "Android SDK Tools", libraryName: "android-sdk-tools", license: "Apache 2.0", url: "http://source.android.com/")
+libraryLicense(name: "Android SDK Tools JPS", libraryName: "android-sdk-tools-jps", license: "Apache 2.0", url: "http://source.android.com/")
+libraryLicense(name: "Apache Commons BeanUtils", libraryName: "commons-beanutils.jar", version: "1.6", license: "Apache 2.0", url: "http://commons.apache.org/beanutils/")
+libraryLicense(name: "Apache Commons Codec", libraryName: "commons-codec", version: "1.3", license: "Apache 2.0", url: "http://commons.apache.org/codec/", licenseUrl: "http://commons.apache.org/license.html")
+libraryLicense(name: "Apache Commons Collections", libraryName: "commons-collections", version: "3.1", license: "Apache 2.0", url: "http://commons.apache.org/collections/", licenseUrl: "http://commons.apache.org/license.html")
+libraryLicense(name: "Apache Commons Discovery", libraryName: "commons-discovery-0.4.jar", version: "0.4", license: "Apache 2.0", url: "http://jakarta.apache.org/commons/discovery/", licenseUrl: "http://commons.apache.org/license.html")
+libraryLicense(name: "Apache Commons HTTPClient", libraryName: "http-client-3.1", version: "3.1 (with patch by JetBrains)", license: "Apache 2.0", url: "http://hc.apache.org/httpclient-3.x")
+libraryLicense(name: "Apache Commons Net", libraryName: "commons-net", version: "2.0", license: "Apache 2.0", url: "http://commons.apache.org/net/")
+libraryLicense(name: "Apache Commons Lang", libraryName: "commons-lang", version: "2.4", license: "Apache 2.0", url: "http://commons.apache.org/lang/", licenseUrl: "http://commons.apache.org/lang/license.html")
+libraryLicense(name: "Apache Commons Logging", libraryName: "commons-logging", version: "1.1.1", license: "Apache 2.0", url: "http://commons.apache.org/logging/")
+libraryLicense(name: "Apache Lucene", libraryName: "lucene-core-2.4.1.jar", version: "2.4.1", license: "Apache 2.0", url: "http://lucene.apache.org/java")
+libraryLicense(name: "Apache Sanselan", libraryName: "Sanselan", version: "0.98", license: "Apache 2.0", url: "http://commons.apache.org/sanselan/")
+libraryLicense(name: "Automaton", libraryName: "automaton.jar", version: "1.11", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
+libraryLicense(name: "DTDParser", version: "1.13", license: "LGPL", url: "http://sourceforge.net/projects/dtdparser/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1")
+libraryLicense(name: "Ganymed", version: "bundled with SVNKit", libraryName: "svnkit.jar", license: "BSD", url: "http://www.ganymed.ethz.ch/ssh2/", licenseUrl: "http://www.ganymed.ethz.ch/ssh2/LICENSE.txt")
+libraryLicense(name: "sqljet", version: "bundled with SVNKit", libraryName: "sqljet.jar", license: "GPLv2", url: "http://sqljet.com", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1")
+libraryLicense(name: "svnkit-javahl", version: "bundled with SVNKit", libraryName: "svnkit-javahl.jar", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html")
+libraryLicense(name: "javahl", version: "1.7.2", libraryName: "javahl.jar", license: "Apache", url: "http://subversion.apache.org", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "Apache Commons HTTPClient", libraryName: "httpclient-4.1.1.jar", version:"4.1.1", license: "Apache 2.0",
+ url: "http://hc.apache.org/httpcomponents-client-ga/index.html", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "Apache Commons HTTPCore", libraryName: "httpcore-4.1.jar", version: "4.1", license: "Apache 2.0",
+ url: "http://hc.apache.org/httpcomponents-core-ga/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "Antlr", libraryName: "antlr.jar", version: "3.1.3", license: "BSD", url: "http://www.antlr.org",
+ licenseUrl: "http://www.antlr.org/license.html")
+libraryLicense(name: "Guava", version: "12.0", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/", licenseUrl: "http://ant.apache.org/license.html")
+libraryLicense(name: "Groovy", version: "1.7.3", license: "Apache 2.0", url: "http://groovy.codehaus.org/")
+libraryLicense(name: "Gson", libraryName: "gson", license: "Apache 2.0", url: "http://code.google.com/p/google-gson/")
+libraryLicense(name: "ini4j", libraryName: "ini4j-0.5.2-patched", version: "0.5.2 (with a patch by JetBrains)", license: "Apache 2.0", url: "http://ini4j.sourceforge.net/", attachedTo: "git4idea")
+libraryLicense(name: "ISO RELAX", libraryName: "isorelax.jar", license: "MIT License", url: "http://sourceforge.net/projects/iso-relax/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
+libraryLicense(name: "JavaCVS", attachedTo: "javacvs-src", version: "no version number available (with patches by JetBrains)", license: "Sun Public License", url: "http://javacvs.netbeans.org/library/", licenseUrl: "http://www.netbeans.org/about/legal/spl.html")
+libraryLicense(name: "JAXB", libraryName: "JAXB", version: "2.2.4-1", license: "CDDL 1.1", url: "http://jaxb.java.net/", licenseUrl: "http://glassfish.java.net/public/CDDL+GPL_1_1.html")
+libraryLicense(name: "Jaxen", version: "", license: "modified Apache", url: "http://www.jaxen.org/", licenseUrl: "http://www.jaxen.org/license.html")
+libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as license/javahelp_license.html in IntelliJ IDEA distribution", url: "http://java.sun.com/products/javahelp/")
+libraryLicense(name: "JCIP Annotations", libraryName: "jcip", license: "Creative Commons Attribution License", url: "http://www.jcip.net", licenseUrl: "http://creativecommons.org/licenses/by/2.5")
+libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030")
+libraryLicense(name: "jgit-1.1.0", version: "1.1.0.201109151100", license: "EDL/BSD", url: "http://www.eclipse.org/jgit/", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", attachedTo: "git4idea")
+libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
+libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
+libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
+libraryLicense(name: "JNA", libraryName: "jna", version: "3.4.0", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php")
+libraryLicense(name: "JSch", libraryName: "JSch", version: "0.1.44", license: "BSD", url: "http://www.jcraft.com/jsch/", licenseUrl: "http://www.jcraft.com/jsch/LICENSE.txt")
+libraryLicense(name: "JUnit", libraryName: "JUnit3", version: "3.8.1", license: "CPL 1.0", url: "http://junit.org/")
+libraryLicense(name: "JUnit", libraryName: "JUnit4", version: "4.8", license: "CPL 1.0", url: "http://junit.org/")
+libraryLicense(name: "Log4j", libraryName: "Log4J", version: "1.2", license: "Apache 2.0", url: "http://logging.apache.org/log4j/1.2/index.html", licenseUrl: "http://logging.apache.org/license.html")
+libraryLicense(name: "Maven", version: "2.2.1", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html")
+libraryLicense(name: "Maven3", libraryNames: ["Maven3", "maven-dependency-tree-1.2.jar"], version: "3.0.3", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html")
+libraryLicense(name: "markdownj", attachedTo: "tasks-core", version: "", license: "BSD", url: "http://markdownj.org/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
+libraryLicense(name: "mercurial_prompthooks", attachedTo: "hg4idea", version: "", license: "GPLv2 (used as hg extension called from hg executable)", url: "https://github.com/willemv/mercurial_prompthooks", licenseUrl: "https://github.com/willemv/mercurial_prompthooks/blob/master/LICENSE.txt")
+libraryLicense(name: "Microba", libraryName: "microba", version: "0.4.2", license: "BSD", url: "http://microba.sourceforge.net/", licenseUrl: "http://microba.sourceforge.net/license.txt")
+libraryLicense(name: "MigLayout", libraryName: "miglayout-swing", version: "3.7.1", license: "BSD", url: "http://www.miglayout.com/", licenseUrl: "http://www.miglayout.com/mavensite/license.html")
+libraryLicense(name: "NanoXML", version: "2.2.3", license: "zlib/libpng", url: "http://nanoxml.cyberelf.be/", licenseUrl: "http://devkix.com/nanoxml.php")
+libraryLicense(name: "nekohtml", libraryName: "nekohtml", version: "1.9.14", license: "Apache 2.0", url: "http://nekohtml.sourceforge.net/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0.txt")
+libraryLicense(name: "Eclipse JDT Core", libraryName: "Eclipse", version: "3.3", license: "CPL 1.0", url: "http://www.eclipse.org/jdt/core/index.php")
+libraryLicense(name: "Jakarta ORO", libraryName: "OroMatcher", version: "2.0.8", license: "Apache", url: "http://jakarta.apache.org/oro/", licenseUrl: "http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE")
+libraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "http://www.picocontainer.org/", licenseUrl: "http://docs.codehaus.org/display/PICO/License")
+libraryLicense(name: "Plexus Utils", libraryName: "plexus-utils-1.5.5.jar", version: "1.5.5", license: "Apache 2.0", url: "http://plexus.codehaus.org/plexus-utils")
+libraryLicense(name: "Quaqua L&F", attachedTo: "platform-impl", version: "6.2", license: "BSD", url: "http://www.randelshofer.ch/quaqua/", licenseUrl: "http://www.randelshofer.ch/quaqua/license.html")
+libraryLicense(name: "Relax NG Object Model", libraryName: "rngom-20051226-patched.jar", license: "MIT", url: "http://java.net/projects/rngom/", licenseUrl: "http://www.opensource.org/licenses/mit-license.php")
+libraryLicense(name: "RMI Stubs", attachedTo: "xslt-debugger-engine", license: "Apache 2.0", url: "http://confluence.jetbrains.net/display/CONTEST/XSLT-Debugger", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "Saxon-9HE", version: "9", license: "Mozilla Public License", url: "http://saxon.sourceforge.net/", licenseUrl: "http://www.mozilla.org/MPL/")
+libraryLicense(name: "Saxon-6.5.5", version: "6.5.5", license: "Mozilla Public License", url: "http://saxon.sourceforge.net/", licenseUrl: "http://www.mozilla.org/MPL/")
+libraryLicense(name: "Sonatype Nexus: Indexer", libraryName: "nexus-indexer-1.2.3.jar", version: "1.2.3", license: "Eclipse Public License v1.0", url: "http://nexus.sonatype.org/", licenseUrl: "http://www.eclipse.org/org/documents/epl-v10.html")
+libraryLicense(name: "Sonatype Nexus: Indexer", libraryName: "nexus-indexer-3.0.4.jar", version: "3.0.4", license: "Eclipse Public License v1.0", url: "http://nexus.sonatype.org/", licenseUrl: "http://www.eclipse.org/org/documents/epl-v10.html")
+libraryLicense(name: "SVNKit", libraryName: "svnkit.jar", version: "SVN version, 1.1 branch as of 1 Oct 2007", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html")
+libraryLicense(name: "Sequence", libraryName: "sequence-library.jar", version: "bundled with SVNKit", license: "", url:"http://www.syntevo.com", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/svn4idea/lib/SEQUENCE-LICENSE")
+libraryLicense(name: "swingx", libraryName: "swingx", version: "1.6.2", license: "LGPL 2.1", url: "http://java.net/downloads/swingx/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php")
+libraryLicense(name: "TestNG", version: "5.7 snapshot", license: "Apache 2.0", url: "http://testng.org/doc/", licenseUrl: "http://code.google.com/p/testng/")
+libraryLicense(name: "Trilead SSH", libraryName: "trilead-ssh2", version: "build 213", license: "BSD style (see LICENSE.txt in trilead.jar)", url: "http://www.trilead.com/SSH_Library/")
+libraryLicense(name: "Trove4j", version: "1.1 (with patches by JetBrains)", license: "LGPL", url: "http://trove4j.sourceforge.net/", licenseUrl: "http://trove4j.sourceforge.net/html/license.html")
+libraryLicense(name: "Velocity", version: "1.7", license: "Apache 2.0", url: "http://velocity.apache.org/", licenseUrl: "http://velocity.apache.org/index.html")
+libraryLicense(name: "winp", version: "1.16 (patched)", license: "MIT", url: "http://winp.dev.java.net/", licenseUrl: "https://winp.dev.java.net/license.html")
+libraryLicense(name: "Xalan", libraryName:"Xalan-2.7.1", version: "2.7.1", license: "Apache 2.0", url: "http://xml.apache.org/xalan-j/", licenseUrl: "http://xml.apache.org/xalan-j/")
+libraryLicense(name: "Xerces", version: "2.9.1", license: "Apache 2.0", url: "http://xerces.apache.org/xerces2-j/", licenseUrl: "http://xerces.apache.org/xerces2-j/")
+libraryLicense(name: "XML Commons (xml-apis.jar, resolver.jar)", version: "", license: "Apache 2.0, W3C Software License , public domain", url: "http://xml.apache.org/commons/", licenseUrl: "http://xml.apache.org/commons/licenses.html")
+libraryLicense(name: "XMLBeans", libraryName: "XmlBeans", version: "2.3.0", license: "Apache 2.0", url: "http://xmlbeans.apache.org/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/xmlbeans-2.3.0/xmlbeans.LICENSE")
+libraryLicense(name: "XML-RPC", libraryName: "XmlRPC", version: "2.0", license: "Apache 2.0", url: "http://ws.apache.org/xmlrpc/xmlrpc2/", licenseUrl: "http://ws.apache.org/xmlrpc/xmlrpc2/license.html")
+libraryLicense(name: "XStream", version: "1.2.1", license: "BSD", url: "http://xstream.codehaus.org/", licenseUrl: "http://xstream.codehaus.org/license.html")
+libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "8.0.x", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html")
+libraryLicense(name: "protobuf", version: "2.3.0", license: "New BSD", url: "http://code.google.com/p/protobuf/", licenseUrl: "http://code.google.com/p/protobuf/source/browse/trunk/COPYING.txt?r=367")
+libraryLicense(name: "Netty", libraryName: "Netty", version: "3.3.1", license: "Apache 2.0", url: "http://netty.io", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "Kryo", libraryName: "Kryo", version: "1.04", license: "New BSD License", url: "http://code.google.com/p/kryo/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php")
+libraryLicense(name: "Snappy-Java", libraryName: "Snappy-Java", version: "1.0.4.1", license: "Apache 2.0", url: "http://code.google.com/p/snappy-java/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "ecj-4.2.jar", libraryName: "ecj-4.2.jar", version: "4.2", license: "CPL 1.0", url: "http://www.eclipse.org/jdt/core/index.php")
+jetbrainsLibrary("JPS")
+jetbrainsLibrary("Maven Embedder")
+jetbrainsLibrary("tcServiceMessages")
+jetbrainsLibrary("optimizedFileManager.jar")
diff --git a/images/src/org/intellij/images/index/ImageInfoIndex.java b/images/src/org/intellij/images/index/ImageInfoIndex.java
index 4b990f0114b3..10a008eae8dd 100644
--- a/images/src/org/intellij/images/index/ImageInfoIndex.java
+++ b/images/src/org/intellij/images/index/ImageInfoIndex.java
@@ -1,149 +1,146 @@
-/*
- * Copyright 2000-2009 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.intellij.images.index;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.util.indexing.*;
-import com.intellij.util.io.DataExternalizer;
-import com.intellij.util.io.DataInputOutputUtil;
-import org.intellij.images.fileTypes.ImageFileTypeManager;
-import org.intellij.images.util.ImageInfoReader;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-
-/**
- * @author spleaner
- */
-public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension {
- public static final ID INDEX_ID = ID.create("ImageFileInfoIndex");
-
- private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() {
- @Override
- public boolean acceptInput(final VirtualFile file) {
- return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) &&
- file.getFileType() == ImageFileTypeManager.getInstance().getImageFileType();
- }
- };
-
- private final DataExternalizer myValueExternalizer = new DataExternalizer() {
- @Override
- public void save(final DataOutput out, final ImageInfo info) throws IOException {
- DataInputOutputUtil.writeINT(out, info.width);
- DataInputOutputUtil.writeINT(out, info.height);
- DataInputOutputUtil.writeINT(out, info.bpp);
- }
-
- @Override
- public ImageInfo read(final DataInput in) throws IOException {
- return new ImageInfo(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in));
- }
- };
-
- private final SingleEntryIndexer myDataIndexer = new SingleEntryIndexer(false) {
- @Override
- protected ImageInfo computeValue(@NotNull FileContent inputData) {
- VirtualFile file = inputData.getFile();
- final ImageInfoReader.Info info;
- if (file.getFileSystem() == TempFileSystem.getInstance()) { // for tests load content directly as we are now not requiring content index
- try {
- info = ImageInfoReader.getInfo(file.contentsToByteArray());
- } catch (IOException ex) { return null; }
- }
- else {
- info = ImageInfoReader.getInfo(file.getPath());
- }
- return info != null? new ImageInfo(info.width, info.height, info.bpp) : null;
- }
- };
-
- @Override
- @NotNull
- public ID getName() {
- return INDEX_ID;
- }
-
- @Override
- @NotNull
- public SingleEntryIndexer getIndexer() {
- return myDataIndexer;
- }
-
- public static void processValues(VirtualFile virtualFile, FileBasedIndex.ValueProcessor processor, Project project) {
- FileBasedIndex.getInstance().processValues(INDEX_ID, Math.abs(FileBasedIndex.getFileId(virtualFile)), virtualFile, processor, GlobalSearchScope
- .fileScope(project, virtualFile));
- }
-
- @Override
- public DataExternalizer getValueExternalizer() {
- return myValueExternalizer;
- }
-
- @Override
- public FileBasedIndex.InputFilter getInputFilter() {
- return myInputFilter;
- }
-
- @Override
- public boolean dependsOnFileContent() {
- return false;
- }
-
- @Override
- public int getVersion() {
- return 4;
- }
-
- public static class ImageInfo {
- public int width;
- public int height;
- public int bpp;
-
- public ImageInfo(int width, int height, int bpp) {
- this.width = width;
- this.height = height;
- this.bpp = bpp;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- ImageInfo imageInfo = (ImageInfo)o;
-
- if (bpp != imageInfo.bpp) return false;
- if (height != imageInfo.height) return false;
- if (width != imageInfo.width) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = width;
- result = 31 * result + height;
- result = 31 * result + bpp;
- return result;
- }
- }
-}
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.intellij.images.index;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.indexing.*;
+import com.intellij.util.io.DataExternalizer;
+import com.intellij.util.io.DataInputOutputUtil;
+import org.intellij.images.fileTypes.ImageFileTypeManager;
+import org.intellij.images.util.ImageInfoReader;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * @author spleaner
+ */
+public class ImageInfoIndex extends SingleEntryFileBasedIndexExtension {
+ private static final int ourMaxImageSize;
+ static {
+ int maxImageSize = 200;
+ try {
+ maxImageSize = Integer.parseInt(System.getProperty("idea.max.image.filesize", Integer.toString(maxImageSize)), 10);
+ } catch (NumberFormatException ex) {}
+ ourMaxImageSize = maxImageSize;
+ }
+
+ public static final ID INDEX_ID = ID.create("ImageFileInfoIndex");
+
+ private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() {
+ @Override
+ public boolean acceptInput(final VirtualFile file) {
+ return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) &&
+ file.getFileType() == ImageFileTypeManager.getInstance().getImageFileType() &&
+ (file.getLength() / 1024) < ourMaxImageSize
+ ;
+ }
+ };
+
+ private final DataExternalizer myValueExternalizer = new DataExternalizer() {
+ @Override
+ public void save(final DataOutput out, final ImageInfo info) throws IOException {
+ DataInputOutputUtil.writeINT(out, info.width);
+ DataInputOutputUtil.writeINT(out, info.height);
+ DataInputOutputUtil.writeINT(out, info.bpp);
+ }
+
+ @Override
+ public ImageInfo read(final DataInput in) throws IOException {
+ return new ImageInfo(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in));
+ }
+ };
+
+ private final SingleEntryIndexer myDataIndexer = new SingleEntryIndexer(false) {
+ @Override
+ protected ImageInfo computeValue(@NotNull FileContent inputData) {
+ final ImageInfoReader.Info info = ImageInfoReader.getInfo(inputData.getContent());
+ return info != null? new ImageInfo(info.width, info.height, info.bpp) : null;
+ }
+ };
+
+ @Override
+ @NotNull
+ public ID getName() {
+ return INDEX_ID;
+ }
+
+ @Override
+ @NotNull
+ public SingleEntryIndexer getIndexer() {
+ return myDataIndexer;
+ }
+
+ public static void processValues(VirtualFile virtualFile, FileBasedIndex.ValueProcessor processor, Project project) {
+ FileBasedIndex.getInstance().processValues(INDEX_ID, Math.abs(FileBasedIndex.getFileId(virtualFile)), virtualFile, processor, GlobalSearchScope
+ .fileScope(project, virtualFile));
+ }
+
+ @Override
+ public DataExternalizer getValueExternalizer() {
+ return myValueExternalizer;
+ }
+
+ @Override
+ public FileBasedIndex.InputFilter getInputFilter() {
+ return myInputFilter;
+ }
+
+ @Override
+ public int getVersion() {
+ return 5;
+ }
+
+ public static class ImageInfo {
+ public int width;
+ public int height;
+ public int bpp;
+
+ public ImageInfo(int width, int height, int bpp) {
+ this.width = width;
+ this.height = height;
+ this.bpp = bpp;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ImageInfo imageInfo = (ImageInfo)o;
+
+ if (bpp != imageInfo.bpp) return false;
+ if (height != imageInfo.height) return false;
+ if (width != imageInfo.width) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = width;
+ result = 31 * result + height;
+ result = 31 * result + bpp;
+ return result;
+ }
+ }
+}
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java
index e043fbe9423c..b17c463f2813 100644
--- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java
+++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java
@@ -50,9 +50,20 @@ public class EclipseCompiler extends ExternalCompiler {
private final Project myProject;
private final List myTempFiles = new ArrayList();
+ private static final String COMPILER_CLASS_NAME = "org.eclipse.jdt.core.compiler.batch.BatchCompiler";
@NonNls private static final String PATH_TO_COMPILER_JAR = findJarPah();
private static String findJarPah() {
+ try {
+ final Class> aClass = Class.forName(COMPILER_CLASS_NAME);
+ final String path = PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class");
+ if (path != null) {
+ return path;
+ }
+ }
+ catch (ClassNotFoundException ignored) {
+ }
+
File dir = new File(PathManager.getLibPath());
File[] jars = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
index bc2aecdad71d..8ba5b70a2d71 100644
--- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
+++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
@@ -1,989 +1,990 @@
-/*
- * Copyright 2000-2012 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.compiler.server;
-
-import com.intellij.ProjectTopics;
-import com.intellij.application.options.PathMacrosImpl;
-import com.intellij.compiler.CompilerWorkspaceConfiguration;
-import com.intellij.compiler.server.impl.CompileServerClasspathManager;
-import com.intellij.execution.ExecutionAdapter;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.ExecutionManager;
-import com.intellij.execution.configurations.GeneralCommandLine;
-import com.intellij.execution.configurations.RunProfile;
-import com.intellij.execution.process.*;
-import com.intellij.execution.ui.RunContentDescriptor;
-import com.intellij.execution.ui.RunContentManager;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.PathMacros;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.components.ApplicationComponent;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileTypes.FileTypeManager;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.project.ProjectManagerAdapter;
-import com.intellij.openapi.projectRoots.*;
-import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
-import com.intellij.openapi.roots.ModuleRootAdapter;
-import com.intellij.openapi.roots.ModuleRootEvent;
-import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.openapi.roots.OrderRootType;
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.roots.libraries.LibraryTable;
-import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
-import com.intellij.openapi.util.JDOMUtil;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.ShutDownTracker;
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.registry.Registry;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.*;
-import com.intellij.openapi.vfs.encoding.EncodingManager;
-import com.intellij.openapi.vfs.newvfs.BulkFileListener;
-import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
-import com.intellij.util.Alarm;
-import com.intellij.util.messages.MessageBusConnection;
-import com.intellij.util.net.NetUtils;
-import gnu.trove.THashSet;
-import gnu.trove.TObjectHashingStrategy;
-import org.jboss.netty.bootstrap.ServerBootstrap;
-import org.jboss.netty.channel.*;
-import org.jboss.netty.channel.group.ChannelGroup;
-import org.jboss.netty.channel.group.ChannelGroupFuture;
-import org.jboss.netty.channel.group.DefaultChannelGroup;
-import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
-import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder;
-import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
-import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
-import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
-import org.jdom.Element;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.api.*;
-import org.jetbrains.jps.cmdline.BuildMain;
-import org.jetbrains.jps.server.ClasspathBootstrap;
-import org.jetbrains.jps.server.Server;
-
-import javax.tools.JavaCompiler;
-import javax.tools.ToolProvider;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.*;
-import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 9/6/11
- */
-public class BuildManager implements ApplicationComponent{
- private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.server.BuildManager");
- private static final String SYSTEM_ROOT = "compile-server";
- private static final String LOGGER_CONFIG = "log.xml";
- private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
- private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
-
- private final File mySystemDirectory;
- private final ProjectManager myProjectManager;
-
- private final Map myAutomakeFutures = new HashMap();
- private final Map myBuildsInProgress = Collections.synchronizedMap(new HashMap());
- private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager();
- private final Executor myPooledThreadExecutor = new Executor() {
- @Override
- public void execute(Runnable command) {
- ApplicationManager.getApplication().executeOnPooledThread(command);
- }
- };
- private final SequentialTaskExecutor myEventsProcessor = new SequentialTaskExecutor(myPooledThreadExecutor);
- private final Map myProjectDataMap = Collections.synchronizedMap(new HashMap());
-
- private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
- private final AtomicBoolean myAutoMakeInProgress = new AtomicBoolean(false);
-
- private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("build-manager");
- private final BuildMessageDispatcher myMessageDispatcher = new BuildMessageDispatcher();
- private int myListenPort = -1;
- private volatile CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings myGlobals;
-
- public BuildManager(final ProjectManager projectManager) {
- myProjectManager = projectManager;
- final String systemPath = PathManager.getSystemPath();
- File system = new File(systemPath);
- try {
- system = system.getCanonicalFile();
- }
- catch (IOException e) {
- LOG.info(e);
- }
- mySystemDirectory = system;
-
- projectManager.addProjectManagerListener(new ProjectWatcher());
- final MessageBusConnection conn = ApplicationManager.getApplication().getMessageBus().connect();
- conn.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
- @Override
- public void before(@NotNull List extends VFileEvent> events) {
- }
-
- @Override
- public void after(@NotNull List extends VFileEvent> events) {
- if (shouldTriggerMake(events)) {
- scheduleAutoMake();
- }
- }
-
- private boolean shouldTriggerMake(List extends VFileEvent> events) {
- for (VFileEvent event : events) {
- if (event.isFromRefresh() || event.getRequestor() instanceof SavingRequestor) {
- return true;
- }
- }
- return false;
- }
- });
-
- ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
- @Override
- public void run() {
- stopListening();
- }
- });
- }
-
- public static BuildManager getInstance() {
- return ApplicationManager.getApplication().getComponent(BuildManager.class);
- }
-
- public void notifyFilesChanged(final Collection paths) {
- doNotify(paths, false);
- }
-
- public void notifyFilesDeleted(Collection paths) {
- doNotify(paths, true);
- }
-
- private void doNotify(final Collection paths, final boolean notifyDeletion) {
- // ensure events processed in the order they arrived
- myEventsProcessor.submit(new Runnable() {
- @Override
- public void run() {
- synchronized (myProjectDataMap) {
- for (Map.Entry entry : myProjectDataMap.entrySet()) {
- final ProjectData data = entry.getValue();
- if (notifyDeletion) {
- data.addDeleted(paths);
- }
- else {
- data.addChanged(paths);
- }
- final RequestFuture future = myBuildsInProgress.get(entry.getKey());
- if (future != null && !future.isCancelled() && !future.isDone()) {
- final UUID sessionId = future.getRequestID();
- final Channel channel = myMessageDispatcher.getConnectedChannel(sessionId);
- if (channel != null) {
- final CmdlineRemoteProto.Message.ControllerMessage message =
- CmdlineRemoteProto.Message.ControllerMessage.newBuilder().setType(
- CmdlineRemoteProto.Message.ControllerMessage.Type.FS_EVENT).setFsEvent(data.createNextEvent()).build();
- Channels.write(channel, CmdlineProtoUtil.toMessage(sessionId, message));
- }
- }
- }
- }
- }
- });
- }
-
- public void clearState(Project project) {
- myGlobals = null;
- final String projectPath = getProjectPath(project);
- synchronized (myProjectDataMap) {
- final ProjectData data = myProjectDataMap.get(projectPath);
- if (data != null) {
- data.dropChanges();
- }
- }
- }
-
- public boolean rescanRequired(Project project) {
- final String projectPath = getProjectPath(project);
- synchronized (myProjectDataMap) {
- final ProjectData data = myProjectDataMap.get(projectPath);
- return data == null || data.myNeedRescan;
- }
- }
-
- @Nullable
- private static String getProjectPath(final Project project) {
- final String path = project.getPresentableUrl();
- if (path == null) {
- return null;
- }
- final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(path);
- return vFile != null ? vFile.getPath() : null;
- }
-
- private void scheduleAutoMake() {
- if (ApplicationManager.getApplication().isUnitTestMode()) {
- return;
- }
- if (CompilerWorkspaceConfiguration.useServerlessOutOfProcessBuild()) {
- addMakeRequest(new Runnable() {
- @Override
- public void run() {
- if (!myAutoMakeInProgress.getAndSet(true)) {
- try {
- ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
- @Override
- public void run() {
- try {
- runAutoMake();
- }
- finally {
- myAutoMakeInProgress.set(false);
- }
- }
- });
- }
- catch (RejectedExecutionException ignored) {
- // we were shut down
- }
- }
- else {
- addMakeRequest(this);
- }
- }
- });
- }
- }
-
- private void addMakeRequest(Runnable runnable) {
- myAlarm.cancelAllRequests();
- myAlarm.addRequest(runnable, MAKE_TRIGGER_DELAY);
- }
-
- private void runAutoMake() {
- final Project[] openProjects = myProjectManager.getOpenProjects();
- if (openProjects.length > 0) {
- final List futures = new ArrayList();
- for (final Project project : openProjects) {
- if (project.isDefault() || project.isDisposed()) {
- continue;
- }
- final CompilerWorkspaceConfiguration config = CompilerWorkspaceConfiguration.getInstance(project);
- if (!config.useOutOfProcessBuild() || !config.MAKE_PROJECT_ON_SAVE) {
- continue;
- }
- if (!config.allowAutoMakeWhileRunningApplication()) {
- final RunContentManager contentManager = ExecutionManager.getInstance(project).getContentManager();
- boolean hasRunningProcesses = false;
- for (RunContentDescriptor descriptor : contentManager.getAllDescriptors()) {
- final ProcessHandler handler = descriptor.getProcessHandler();
- if (handler != null && !handler.isProcessTerminated()) { // active process
- hasRunningProcesses = true;
- break;
- }
- }
- if (hasRunningProcesses) {
- continue;
- }
- }
-
- final List emptyList = Collections.emptyList();
- final RequestFuture future = scheduleBuild(
- project, false, true, emptyList, emptyList, emptyList, Collections.emptyMap(), new AutoMakeMessageHandler(project)
- );
- if (future != null) {
- futures.add(future);
- synchronized (myAutomakeFutures) {
- myAutomakeFutures.put(future, project);
- }
- }
- }
- try {
- for (RequestFuture future : futures) {
- future.waitFor();
- }
- }
- finally {
- synchronized (myAutomakeFutures) {
- myAutomakeFutures.keySet().removeAll(futures);
- }
- }
- }
- }
-
- public Collection cancelAutoMakeTasks(Project project) {
- final Collection futures = new ArrayList();
- synchronized (myAutomakeFutures) {
- for (Map.Entry entry : myAutomakeFutures.entrySet()) {
- if (entry.getValue().equals(project)) {
- final RequestFuture future = entry.getKey();
- future.cancel(false);
- futures.add(future);
- }
- }
- }
- return futures;
- }
-
- @Nullable
- public RequestFuture scheduleBuild(
- final Project project, final boolean isRebuild,
- final boolean isMake,
- final Collection modules,
- final Collection artifacts,
- final Collection paths,
- final Map userData, DefaultMessageHandler handler) {
-
- final String projectPath = getProjectPath(project);
- final UUID sessionId = UUID.randomUUID();
- final CmdlineRemoteProto.Message.ControllerMessage params;
- CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = myGlobals;
- if (globals == null) {
- globals = buildGlobalSettings();
- myGlobals = globals;
- }
-
- CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges = null;
- final SequentialTaskExecutor projectTaskQueue;
- synchronized (myProjectDataMap) {
- ProjectData data = myProjectDataMap.get(projectPath);
- if (data == null) {
- data = new ProjectData(new SequentialTaskExecutor(myPooledThreadExecutor));
- myProjectDataMap.put(projectPath, data);
- }
- if (isRebuild) {
- data.dropChanges();
- }
- currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent();
- projectTaskQueue = data.taskQueue;
- }
-
- if (isRebuild) {
- params = CmdlineProtoUtil.createRebuildRequest(projectPath, userData, globals);
- }
- else {
- params = isMake ?
- CmdlineProtoUtil.createMakeRequest(projectPath, modules, artifacts, userData, globals, currentFSChanges) :
- CmdlineProtoUtil.createForceCompileRequest(projectPath, modules, artifacts, paths, userData, globals, currentFSChanges);
- }
-
- myMessageDispatcher.registerBuildMessageHandler(sessionId, handler, params);
-
- // ensure server is listening
- if (myListenPort < 0) {
- try {
- myListenPort = startListening();
- }
- catch (Exception e) {
- myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
- handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), null));
- handler.sessionTerminated();
- return null;
- }
- }
-
- final RequestFuture future = new RequestFuture(handler, sessionId, new RequestFuture.CancelAction() {
- @Override
- public void cancel(RequestFuture future) throws Exception {
- myMessageDispatcher.cancelSession(future.getRequestID());
- }
- });
-
- projectTaskQueue.submit(new Runnable() {
- @Override
- public void run() {
- try {
- if (project.isDisposed()) {
- future.cancel(false);
- return;
- }
- myBuildsInProgress.put(projectPath, future);
- final Process process = launchBuildProcess(project, myListenPort, sessionId);
- final OSProcessHandler processHandler = new OSProcessHandler(process, null) {
- @Override
- protected boolean shouldDestroyProcessRecursively() {
- return true;
- }
- };
- final StringBuilder stdErrOutput = new StringBuilder();
- processHandler.addProcessListener(new ProcessAdapter() {
- @Override
- public void processTerminated(ProcessEvent event) {
- final BuilderMessageHandler handler = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
- if (handler != null) {
- handler.sessionTerminated();
- }
- }
-
- @Override
- public void onTextAvailable(ProcessEvent event, Key outputType) {
- // re-translate builder's output to idea.log
- final String text = event.getText();
- if (!StringUtil.isEmptyOrSpaces(text)) {
- LOG.info("BUILDER_PROCESS [" + outputType.toString() + "]: " + text.trim());
- if (stdErrOutput.length() < 1024 && ProcessOutputTypes.STDERR.equals(outputType)) {
- stdErrOutput.append(text);
- }
- }
- }
- });
- processHandler.startNotify();
- final boolean terminated = processHandler.waitFor();
- if (terminated) {
- final int exitValue = processHandler.getProcess().exitValue();
- if (exitValue != 0) {
- final StringBuilder msg = new StringBuilder();
- msg.append("Abnormal build process termination: ");
- if (stdErrOutput.length() > 0) {
- msg.append("\n").append(stdErrOutput);
- }
- else {
- msg.append("unknown error");
- }
- future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null));
- }
- }
- else {
- future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null));
- }
- }
- catch (ExecutionException e) {
- myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
- future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
- future.getMessageHandler().sessionTerminated();
- }
- finally {
- myBuildsInProgress.remove(projectPath);
- future.setDone();
- }
- }
- });
-
- return future;
- }
-
- @Override
- public void initComponent() {
- }
-
- @Override
- public void disposeComponent() {
- stopListening();
- }
-
- @NotNull
- @Override
- public String getComponentName() {
- return "com.intellij.compiler.server.BuildManager";
- }
-
- private static CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings buildGlobalSettings() {
- final Map data = new HashMap();
-
- for (Map.Entry entry : PathMacrosImpl.getGlobalSystemMacros().entrySet()) {
- data.put(entry.getKey(), FileUtil.toSystemIndependentName(entry.getValue()));
- }
-
- final PathMacros pathVars = PathMacros.getInstance();
- for (String name : pathVars.getAllMacroNames()) {
- final String path = pathVars.getValue(name);
- if (path != null) {
- data.put(name, FileUtil.toSystemIndependentName(path));
- }
- }
-
- final List globals = new ArrayList();
-
- fillSdks(globals);
- fillGlobalLibraries(globals);
-
- final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.Builder cmdBuilder =
- CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder();
-
- if (!data.isEmpty()) {
- for (Map.Entry entry : data.entrySet()) {
- final String var = entry.getKey();
- final String value = entry.getValue();
- if (var != null && value != null) {
- cmdBuilder.addPathVariable(CmdlineProtoUtil.createPair(var, value));
- }
- }
- }
-
- if (!globals.isEmpty()) {
- for (GlobalLibrary lib : globals) {
- final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary.Builder libBuilder =
- CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary.newBuilder();
- libBuilder.setName(lib.getName()).addAllPath(lib.getPaths());
- if (lib instanceof SdkLibrary) {
- final SdkLibrary sdk = (SdkLibrary)lib;
- libBuilder.setHomePath(sdk.getHomePath());
- libBuilder.setTypeName(sdk.getTypeName());
- final String additional = sdk.getAdditionalDataXml();
- if (additional != null) {
- libBuilder.setAdditionalDataXml(additional);
- }
- final String version = sdk.getVersion();
- if (version != null) {
- libBuilder.setVersion(version);
- }
- }
- cmdBuilder.addGlobalLibrary(libBuilder.build());
- }
- }
-
- final String defaultCharset = EncodingManager.getInstance().getDefaultCharsetName();
- if (!StringUtil.isEmpty(defaultCharset)) {
- cmdBuilder.setGlobalEncoding(defaultCharset);
- }
-
- final String ignoredFilesList = FileTypeManager.getInstance().getIgnoredFilesList();
- cmdBuilder.setIgnoredFilesPatterns(ignoredFilesList);
- return cmdBuilder.build();
- }
-
- private static void fillSdks(List globals) {
- for (Sdk sdk : ProjectJdkTable.getInstance().getAllJdks()) {
- final String name = sdk.getName();
- final String homePath = sdk.getHomePath();
- if (homePath == null) {
- continue;
- }
- final SdkAdditionalData data = sdk.getSdkAdditionalData();
- final String additionalDataXml;
- final SdkType sdkType = (SdkType) sdk.getSdkType();
- if (data == null) {
- additionalDataXml = null;
- }
- else {
- final Element element = new Element("additional");
- sdkType.saveAdditionalData(data, element);
- additionalDataXml = JDOMUtil.writeElement(element, "\n");
- }
- final List paths = convertToLocalPaths(sdk.getRootProvider().getFiles(OrderRootType.CLASSES));
- String versionString = sdk.getVersionString();
- if (versionString != null && sdkType instanceof JavaSdk) {
- final JavaSdkVersion version = ((JavaSdk)sdkType).getVersion(versionString);
- if (version != null) {
- versionString = version.getDescription();
- }
- }
- globals.add(new SdkLibrary(name, sdkType.getName(), versionString, homePath, paths, additionalDataXml));
- }
- }
-
- private static void fillGlobalLibraries(List globals) {
- final LibraryTablesRegistrar tableRegistrar = LibraryTablesRegistrar.getInstance();
- List tables = new ArrayList();
- tables.add(tableRegistrar.getLibraryTable());
-
- tables.addAll(tableRegistrar.getCustomLibraryTables());
- for (LibraryTable libraryTable : tables) {
- final Iterator iterator = libraryTable.getLibraryIterator();
- while (iterator.hasNext()) {
- Library library = iterator.next();
- final String name = library.getName();
-
- if (name != null) {
- final List paths = convertToLocalPaths(library.getFiles(OrderRootType.CLASSES));
- globals.add(new GlobalLibrary(name, paths));
- }
- }
- }
- }
-
- private static List convertToLocalPaths(VirtualFile[] files) {
- final List paths = new ArrayList();
- for (VirtualFile file : files) {
- if (file.isValid()) {
- paths.add(StringUtil.trimEnd(FileUtil.toSystemIndependentName(file.getPath()), JarFileSystem.JAR_SEPARATOR));
- }
- }
- return paths;
- }
-
- private Process launchBuildProcess(Project project, final int port, final UUID sessionId) throws ExecutionException {
- // choosing sdk with which the build process should be run
- final Sdk internalJdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
- Sdk projectJdk = internalJdk;
- final String versionString = projectJdk.getVersionString();
- JavaSdkVersion sdkVersion = versionString != null? ((JavaSdk)projectJdk.getSdkType()).getVersion(versionString) : null;
- int sdkMinorVersion = getMinorVersion(versionString);
- if (sdkVersion != null) {
- final Set candidates = new HashSet();
- for (Module module : ModuleManager.getInstance(project).getModules()) {
- final Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
- if (sdk != null && sdk.getSdkType() instanceof JavaSdk) {
- candidates.add(sdk);
- }
- }
- // now select the latest version from the sdks that are used in the project, but not older than the internal sdk version
- for (Sdk candidate : candidates) {
- final String vs = candidate.getVersionString();
- if (vs != null) {
- final JavaSdkVersion candidateVersion = ((JavaSdk)candidate.getSdkType()).getVersion(vs);
- if (candidateVersion != null) {
- final int candidateMinorVersion = getMinorVersion(vs);
- final int result = candidateVersion.compareTo(sdkVersion);
- if (result > 0 || (result == 0 && candidateMinorVersion > sdkMinorVersion)) {
- sdkVersion = candidateVersion;
- sdkMinorVersion = candidateMinorVersion;
- projectJdk = candidate;
- }
- }
- }
- }
- }
-
- // validate tools.jar presence
- final File compilerPath;
- if (projectJdk.equals(internalJdk)) {
- final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
- if (systemCompiler == null) {
- throw new ExecutionException("No system java compiler is provided by the JRE. Make sure tools.jar is present in IntelliJ IDEA classpath.");
- }
- compilerPath = ClasspathBootstrap.getResourcePath(systemCompiler.getClass());
- }
- else {
- final String path = ((JavaSdk)projectJdk.getSdkType()).getToolsPath(projectJdk);
- if (path == null) {
- throw new ExecutionException("Cannot determine path to 'tools.jar' library for " + projectJdk.getName() + " (" + projectJdk.getHomePath() + ")");
- }
- compilerPath = new File(path);
- }
-
- final GeneralCommandLine cmdLine = new GeneralCommandLine();
- final String vmExecutablePath = ((JavaSdkType)projectJdk.getSdkType()).getVMExecutablePath(projectJdk);
- cmdLine.setExePath(vmExecutablePath);
- cmdLine.addParameter("-XX:MaxPermSize=150m");
- cmdLine.addParameter("-XX:ReservedCodeCacheSize=64m");
- final int heapSize = Registry.intValue("compiler.process.heap.size");
- final int xms = heapSize / 2;
- if (xms > 32) {
- cmdLine.addParameter("-Xms" + xms + "m");
- }
- cmdLine.addParameter("-Xmx" + heapSize + "m");
-
- if (SystemInfo.isMac && sdkVersion != null && JavaSdkVersion.JDK_1_6.equals(sdkVersion) && Registry.is("compiler.process.32bit.vm.on.mac")) {
- // unfortunately -d32 is supported on jdk 1.6 only
- cmdLine.addParameter("-d32");
- }
-
- cmdLine.addParameter("-Djava.awt.headless=true");
- if (ApplicationManager.getApplication().isUnitTestMode()) {
- cmdLine.addParameter("-Dtest.mode=true");
- }
-
- final String shouldGenerateIndex = System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION);
- if (shouldGenerateIndex != null) {
- cmdLine.addParameter("-D"+ GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION +"=" + shouldGenerateIndex);
- }
-
- final String additionalOptions = Registry.stringValue("compiler.process.vm.options");
- if (!StringUtil.isEmpty(additionalOptions)) {
- final StringTokenizer tokenizer = new StringTokenizer(additionalOptions, " ", false);
- while (tokenizer.hasMoreTokens()) {
- cmdLine.addParameter(tokenizer.nextToken());
- }
- }
-
- // debugging
- final int debugPort = Registry.intValue("compiler.process.debug.port");
- if (debugPort > 0) {
- cmdLine.addParameter("-XX:+HeapDumpOnOutOfMemoryError");
- cmdLine.addParameter("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + debugPort);
- }
-
- if (Registry.is("compiler.process.use.memory.temp.cache")) {
- cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION);
- }
- if (Registry.is("compiler.process.use.external.javac")) {
- cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION);
- }
- final String host = NetUtils.getLocalHostString();
- cmdLine.addParameter("-D"+ GlobalOptions.HOSTNAME_OPTION + "=" + host);
-
- // javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
- final String lang = System.getProperty("user.language");
- if (lang != null) {
- //noinspection HardCodedStringLiteral
- cmdLine.addParameter("-Duser.language=" + lang);
- }
- final String country = System.getProperty("user.country");
- if (country != null) {
- //noinspection HardCodedStringLiteral
- cmdLine.addParameter("-Duser.country=" + country);
- }
- //noinspection HardCodedStringLiteral
- final String region = System.getProperty("user.region");
- if (region != null) {
- //noinspection HardCodedStringLiteral
- cmdLine.addParameter("-Duser.region=" + region);
- }
-
- cmdLine.addParameter("-classpath");
-
- final List cp = ClasspathBootstrap.getBuildProcessApplicationClasspath();
- cp.add(compilerPath);
- cp.addAll(myClasspathManager.getCompileServerPluginsClasspath());
-
- cmdLine.addParameter(classpathToString(cp));
-
- cmdLine.addParameter(BuildMain.class.getName());
- cmdLine.addParameter(host);
- cmdLine.addParameter(Integer.toString(port));
- cmdLine.addParameter(sessionId.toString());
-
- final File workDirectory = getBuildSystemDirectory();
- workDirectory.mkdirs();
- ensureLogConfigExists(workDirectory);
-
- cmdLine.addParameter(FileUtil.toSystemIndependentName(workDirectory.getPath()));
-
- cmdLine.setWorkDirectory(workDirectory);
-
- return cmdLine.createProcess();
- }
-
- public File getBuildSystemDirectory() {
- return new File(mySystemDirectory, SYSTEM_ROOT);
- }
-
- private static int getMinorVersion(String vs) {
- final int dashIndex = vs.lastIndexOf('_');
- if (dashIndex >= 0) {
- StringBuilder builder = new StringBuilder();
- for (int idx = dashIndex + 1; idx < vs.length(); idx++) {
- final char ch = vs.charAt(idx);
- if (Character.isDigit(ch)) {
- builder.append(ch);
- }
- else {
- break;
- }
- }
- if (builder.length() > 0) {
- try {
- return Integer.parseInt(builder.toString());
- }
- catch (NumberFormatException ignored) {
- }
- }
- }
- return 0;
- }
-
- private static void ensureLogConfigExists(File workDirectory) {
- final File logConfig = new File(workDirectory, LOGGER_CONFIG);
- if (!logConfig.exists()) {
- FileUtil.createIfDoesntExist(logConfig);
- try {
- final InputStream in = Server.class.getResourceAsStream("/" + DEFAULT_LOGGER_CONFIG);
- if (in != null) {
- try {
- final FileOutputStream out = new FileOutputStream(logConfig);
- try {
- FileUtil.copy(in, out);
- }
- finally {
- out.close();
- }
- }
- finally {
- in.close();
- }
- }
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- }
-
- public void stopListening() {
- final ChannelGroupFuture closeFuture = myAllOpenChannels.close();
- closeFuture.awaitUninterruptibly();
- }
-
- private int startListening() throws Exception {
- final ChannelFactory channelFactory = new NioServerSocketChannelFactory(myPooledThreadExecutor, myPooledThreadExecutor);
- final SimpleChannelUpstreamHandler channelRegistrar = new SimpleChannelUpstreamHandler() {
- public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
- myAllOpenChannels.add(e.getChannel());
- super.channelOpen(ctx, e);
- }
-
- @Override
- public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
- myAllOpenChannels.remove(e.getChannel());
- super.channelClosed(ctx, e);
- }
- };
- ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {
- public ChannelPipeline getPipeline() throws Exception {
- return Channels.pipeline(
- channelRegistrar,
- new ProtobufVarint32FrameDecoder(),
- new ProtobufDecoder(CmdlineRemoteProto.Message.getDefaultInstance()),
- new ProtobufVarint32LengthFieldPrepender(),
- new ProtobufEncoder(),
- myMessageDispatcher
- );
- }
- };
- final ServerBootstrap bootstrap = new ServerBootstrap(channelFactory);
- bootstrap.setPipelineFactory(pipelineFactory);
- bootstrap.setOption("child.tcpNoDelay", true);
- bootstrap.setOption("child.keepAlive", true);
- final int listenPort = NetUtils.findAvailableSocketPort();
- final Channel serverChannel = bootstrap.bind(new InetSocketAddress(listenPort));
- myAllOpenChannels.add(serverChannel);
- return listenPort;
- }
-
- private static String classpathToString(List cp) {
- StringBuilder builder = new StringBuilder();
- for (File file : cp) {
- if (builder.length() > 0) {
- builder.append(File.pathSeparator);
- }
- builder.append(FileUtil.toCanonicalPath(file.getPath()));
- }
- return builder.toString();
- }
-
- private class ProjectWatcher extends ProjectManagerAdapter {
- private final Map myConnections = new HashMap();
-
- @Override
- public void projectOpened(final Project project) {
- final MessageBusConnection conn = project.getMessageBus().connect();
- myConnections.put(project, conn);
- conn.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
- @Override
- public void rootsChanged(final ModuleRootEvent event) {
- final Object source = event.getSource();
- if (source instanceof Project) {
- clearState((Project)source);
- }
- }
- });
- conn.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionAdapter() {
- @Override
- public void processTerminated(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) {
- scheduleAutoMake();
- }
- });
- }
-
- @Override
- public boolean canCloseProject(Project project) {
- cancelAutoMakeTasks(project);
- return super.canCloseProject(project);
- }
-
- @Override
- public void projectClosing(Project project) {
- for (RequestFuture future : cancelAutoMakeTasks(project)) {
- future.waitFor(500, TimeUnit.MILLISECONDS);
- }
- }
-
- @Override
- public void projectClosed(Project project) {
- myProjectDataMap.remove(getProjectPath(project));
- final MessageBusConnection conn = myConnections.remove(project);
- if (conn != null) {
- conn.disconnect();
- }
- }
- }
-
- private static class ProjectData {
- final SequentialTaskExecutor taskQueue;
- private final Set myChanged = new THashSet(PathHashingStrategy.INSTANCE);
- private final Set myDeleted = new THashSet(PathHashingStrategy.INSTANCE);
- private long myNextEventOrdinal = 0L;
- private boolean myNeedRescan = true;
-
- private ProjectData(SequentialTaskExecutor taskQueue) {
- this.taskQueue = taskQueue;
- }
-
- public void addChanged(Collection paths) {
- if (!myNeedRescan) {
- myDeleted.removeAll(paths);
- myChanged.addAll(paths);
- }
- }
-
- public void addDeleted(Collection paths) {
- if (!myNeedRescan) {
- myChanged.removeAll(paths);
- myDeleted.addAll(paths);
- }
- }
-
- public CmdlineRemoteProto.Message.ControllerMessage.FSEvent createNextEvent() {
- final CmdlineRemoteProto.Message.ControllerMessage.FSEvent.Builder builder =
- CmdlineRemoteProto.Message.ControllerMessage.FSEvent.newBuilder();
- builder.setOrdinal(++myNextEventOrdinal);
- builder.addAllChangedPaths(myChanged);
- myChanged.clear();
- builder.addAllDeletedPaths(myDeleted);
- myDeleted.clear();
- return builder.build();
- }
-
- public boolean getAndResetRescanFlag() {
- final boolean rescan = myNeedRescan;
- myNeedRescan = false;
- return rescan;
- }
-
- public void dropChanges() {
- myNeedRescan = true;
- myNextEventOrdinal = 0L;
- myChanged.clear();
- myDeleted.clear();
- }
-
- static class PathHashingStrategy implements TObjectHashingStrategy {
- static final PathHashingStrategy INSTANCE = new PathHashingStrategy();
-
- @Override
- public int computeHashCode(String path) {
- return FileUtil.pathHashCode(path);
- }
-
- @Override
- public boolean equals(String path1, String path2) {
- return FileUtil.pathsEqual(path1, path2);
- }
- }
- }
-
-}
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.compiler.server;
+
+import com.intellij.ProjectTopics;
+import com.intellij.application.options.PathMacrosImpl;
+import com.intellij.compiler.CompilerWorkspaceConfiguration;
+import com.intellij.compiler.server.impl.CompileServerClasspathManager;
+import com.intellij.execution.ExecutionAdapter;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionManager;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.process.*;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.execution.ui.RunContentManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathMacros;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.project.ProjectManagerAdapter;
+import com.intellij.openapi.projectRoots.*;
+import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
+import com.intellij.openapi.roots.ModuleRootAdapter;
+import com.intellij.openapi.roots.ModuleRootEvent;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.ShutDownTracker;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.*;
+import com.intellij.openapi.vfs.encoding.EncodingManager;
+import com.intellij.openapi.vfs.newvfs.BulkFileListener;
+import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
+import com.intellij.util.Alarm;
+import com.intellij.util.messages.MessageBusConnection;
+import com.intellij.util.net.NetUtils;
+import gnu.trove.THashSet;
+import gnu.trove.TObjectHashingStrategy;
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.*;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.jboss.netty.channel.group.ChannelGroupFuture;
+import org.jboss.netty.channel.group.DefaultChannelGroup;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder;
+import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
+import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
+import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.api.*;
+import org.jetbrains.jps.cmdline.BuildMain;
+import org.jetbrains.jps.server.ClasspathBootstrap;
+import org.jetbrains.jps.server.Server;
+
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.*;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: 9/6/11
+ */
+public class BuildManager implements ApplicationComponent{
+ private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.server.BuildManager");
+ private static final String SYSTEM_ROOT = "compile-server";
+ private static final String LOGGER_CONFIG = "log.xml";
+ private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
+ private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
+
+ private final File mySystemDirectory;
+ private final ProjectManager myProjectManager;
+
+ private final Map myAutomakeFutures = new HashMap();
+ private final Map myBuildsInProgress = Collections.synchronizedMap(new HashMap());
+ private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager();
+ private final Executor myPooledThreadExecutor = new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ ApplicationManager.getApplication().executeOnPooledThread(command);
+ }
+ };
+ private final SequentialTaskExecutor myEventsProcessor = new SequentialTaskExecutor(myPooledThreadExecutor);
+ private final Map myProjectDataMap = Collections.synchronizedMap(new HashMap());
+
+ private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
+ private final AtomicBoolean myAutoMakeInProgress = new AtomicBoolean(false);
+
+ private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("build-manager");
+ private final BuildMessageDispatcher myMessageDispatcher = new BuildMessageDispatcher();
+ private int myListenPort = -1;
+ private volatile CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings myGlobals;
+
+ public BuildManager(final ProjectManager projectManager) {
+ myProjectManager = projectManager;
+ final String systemPath = PathManager.getSystemPath();
+ File system = new File(systemPath);
+ try {
+ system = system.getCanonicalFile();
+ }
+ catch (IOException e) {
+ LOG.info(e);
+ }
+ mySystemDirectory = system;
+
+ projectManager.addProjectManagerListener(new ProjectWatcher());
+ final MessageBusConnection conn = ApplicationManager.getApplication().getMessageBus().connect();
+ conn.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
+ @Override
+ public void before(@NotNull List extends VFileEvent> events) {
+ }
+
+ @Override
+ public void after(@NotNull List extends VFileEvent> events) {
+ if (shouldTriggerMake(events)) {
+ scheduleAutoMake();
+ }
+ }
+
+ private boolean shouldTriggerMake(List extends VFileEvent> events) {
+ for (VFileEvent event : events) {
+ if (event.isFromRefresh() || event.getRequestor() instanceof SavingRequestor) {
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+
+ ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
+ @Override
+ public void run() {
+ stopListening();
+ }
+ });
+ }
+
+ public static BuildManager getInstance() {
+ return ApplicationManager.getApplication().getComponent(BuildManager.class);
+ }
+
+ public void notifyFilesChanged(final Collection paths) {
+ doNotify(paths, false);
+ }
+
+ public void notifyFilesDeleted(Collection paths) {
+ doNotify(paths, true);
+ }
+
+ private void doNotify(final Collection paths, final boolean notifyDeletion) {
+ // ensure events processed in the order they arrived
+ myEventsProcessor.submit(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (myProjectDataMap) {
+ for (Map.Entry entry : myProjectDataMap.entrySet()) {
+ final ProjectData data = entry.getValue();
+ if (notifyDeletion) {
+ data.addDeleted(paths);
+ }
+ else {
+ data.addChanged(paths);
+ }
+ final RequestFuture future = myBuildsInProgress.get(entry.getKey());
+ if (future != null && !future.isCancelled() && !future.isDone()) {
+ final UUID sessionId = future.getRequestID();
+ final Channel channel = myMessageDispatcher.getConnectedChannel(sessionId);
+ if (channel != null) {
+ final CmdlineRemoteProto.Message.ControllerMessage message =
+ CmdlineRemoteProto.Message.ControllerMessage.newBuilder().setType(
+ CmdlineRemoteProto.Message.ControllerMessage.Type.FS_EVENT).setFsEvent(data.createNextEvent()).build();
+ Channels.write(channel, CmdlineProtoUtil.toMessage(sessionId, message));
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public void clearState(Project project) {
+ myGlobals = null;
+ final String projectPath = getProjectPath(project);
+ synchronized (myProjectDataMap) {
+ final ProjectData data = myProjectDataMap.get(projectPath);
+ if (data != null) {
+ data.dropChanges();
+ }
+ }
+ }
+
+ public boolean rescanRequired(Project project) {
+ final String projectPath = getProjectPath(project);
+ synchronized (myProjectDataMap) {
+ final ProjectData data = myProjectDataMap.get(projectPath);
+ return data == null || data.myNeedRescan;
+ }
+ }
+
+ @Nullable
+ private static String getProjectPath(final Project project) {
+ final String path = project.getPresentableUrl();
+ if (path == null) {
+ return null;
+ }
+ final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(path);
+ return vFile != null ? vFile.getPath() : null;
+ }
+
+ private void scheduleAutoMake() {
+ if (ApplicationManager.getApplication().isUnitTestMode()) {
+ return;
+ }
+ if (CompilerWorkspaceConfiguration.useServerlessOutOfProcessBuild()) {
+ addMakeRequest(new Runnable() {
+ @Override
+ public void run() {
+ if (!myAutoMakeInProgress.getAndSet(true)) {
+ try {
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runAutoMake();
+ }
+ finally {
+ myAutoMakeInProgress.set(false);
+ }
+ }
+ });
+ }
+ catch (RejectedExecutionException ignored) {
+ // we were shut down
+ }
+ }
+ else {
+ addMakeRequest(this);
+ }
+ }
+ });
+ }
+ }
+
+ private void addMakeRequest(Runnable runnable) {
+ myAlarm.cancelAllRequests();
+ myAlarm.addRequest(runnable, MAKE_TRIGGER_DELAY);
+ }
+
+ private void runAutoMake() {
+ final Project[] openProjects = myProjectManager.getOpenProjects();
+ if (openProjects.length > 0) {
+ final List futures = new ArrayList();
+ for (final Project project : openProjects) {
+ if (project.isDefault() || project.isDisposed()) {
+ continue;
+ }
+ final CompilerWorkspaceConfiguration config = CompilerWorkspaceConfiguration.getInstance(project);
+ if (!config.useOutOfProcessBuild() || !config.MAKE_PROJECT_ON_SAVE) {
+ continue;
+ }
+ if (!config.allowAutoMakeWhileRunningApplication()) {
+ final RunContentManager contentManager = ExecutionManager.getInstance(project).getContentManager();
+ boolean hasRunningProcesses = false;
+ for (RunContentDescriptor descriptor : contentManager.getAllDescriptors()) {
+ final ProcessHandler handler = descriptor.getProcessHandler();
+ if (handler != null && !handler.isProcessTerminated()) { // active process
+ hasRunningProcesses = true;
+ break;
+ }
+ }
+ if (hasRunningProcesses) {
+ continue;
+ }
+ }
+
+ final List emptyList = Collections.emptyList();
+ final RequestFuture future = scheduleBuild(
+ project, false, true, emptyList, emptyList, emptyList, Collections.emptyMap(), new AutoMakeMessageHandler(project)
+ );
+ if (future != null) {
+ futures.add(future);
+ synchronized (myAutomakeFutures) {
+ myAutomakeFutures.put(future, project);
+ }
+ }
+ }
+ try {
+ for (RequestFuture future : futures) {
+ future.waitFor();
+ }
+ }
+ finally {
+ synchronized (myAutomakeFutures) {
+ myAutomakeFutures.keySet().removeAll(futures);
+ }
+ }
+ }
+ }
+
+ public Collection cancelAutoMakeTasks(Project project) {
+ final Collection futures = new ArrayList();
+ synchronized (myAutomakeFutures) {
+ for (Map.Entry entry : myAutomakeFutures.entrySet()) {
+ if (entry.getValue().equals(project)) {
+ final RequestFuture future = entry.getKey();
+ future.cancel(false);
+ futures.add(future);
+ }
+ }
+ }
+ return futures;
+ }
+
+ @Nullable
+ public RequestFuture scheduleBuild(
+ final Project project, final boolean isRebuild,
+ final boolean isMake,
+ final Collection modules,
+ final Collection artifacts,
+ final Collection paths,
+ final Map userData, DefaultMessageHandler handler) {
+
+ final String projectPath = getProjectPath(project);
+ final UUID sessionId = UUID.randomUUID();
+ final CmdlineRemoteProto.Message.ControllerMessage params;
+ CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = myGlobals;
+ if (globals == null) {
+ globals = buildGlobalSettings();
+ myGlobals = globals;
+ }
+
+ CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges = null;
+ final SequentialTaskExecutor projectTaskQueue;
+ synchronized (myProjectDataMap) {
+ ProjectData data = myProjectDataMap.get(projectPath);
+ if (data == null) {
+ data = new ProjectData(new SequentialTaskExecutor(myPooledThreadExecutor));
+ myProjectDataMap.put(projectPath, data);
+ }
+ if (isRebuild) {
+ data.dropChanges();
+ }
+ currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent();
+ projectTaskQueue = data.taskQueue;
+ }
+
+ if (isRebuild) {
+ params = CmdlineProtoUtil.createRebuildRequest(projectPath, userData, globals);
+ }
+ else {
+ params = isMake ?
+ CmdlineProtoUtil.createMakeRequest(projectPath, modules, artifacts, userData, globals, currentFSChanges) :
+ CmdlineProtoUtil.createForceCompileRequest(projectPath, modules, artifacts, paths, userData, globals, currentFSChanges);
+ }
+
+ myMessageDispatcher.registerBuildMessageHandler(sessionId, handler, params);
+
+ // ensure server is listening
+ if (myListenPort < 0) {
+ try {
+ myListenPort = startListening();
+ }
+ catch (Exception e) {
+ myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
+ handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), null));
+ handler.sessionTerminated();
+ return null;
+ }
+ }
+
+ final RequestFuture future = new RequestFuture(handler, sessionId, new RequestFuture.CancelAction() {
+ @Override
+ public void cancel(RequestFuture future) throws Exception {
+ myMessageDispatcher.cancelSession(future.getRequestID());
+ }
+ });
+
+ projectTaskQueue.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (project.isDisposed()) {
+ future.cancel(false);
+ return;
+ }
+ myBuildsInProgress.put(projectPath, future);
+ final Process process = launchBuildProcess(project, myListenPort, sessionId);
+ final OSProcessHandler processHandler = new OSProcessHandler(process, null) {
+ @Override
+ protected boolean shouldDestroyProcessRecursively() {
+ return true;
+ }
+ };
+ final StringBuilder stdErrOutput = new StringBuilder();
+ processHandler.addProcessListener(new ProcessAdapter() {
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ final BuilderMessageHandler handler = myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
+ if (handler != null) {
+ handler.sessionTerminated();
+ }
+ }
+
+ @Override
+ public void onTextAvailable(ProcessEvent event, Key outputType) {
+ // re-translate builder's output to idea.log
+ final String text = event.getText();
+ if (!StringUtil.isEmptyOrSpaces(text)) {
+ LOG.info("BUILDER_PROCESS [" + outputType.toString() + "]: " + text.trim());
+ if (stdErrOutput.length() < 1024 && ProcessOutputTypes.STDERR.equals(outputType)) {
+ stdErrOutput.append(text);
+ }
+ }
+ }
+ });
+ processHandler.startNotify();
+ final boolean terminated = processHandler.waitFor();
+ if (terminated) {
+ final int exitValue = processHandler.getProcess().exitValue();
+ if (exitValue != 0) {
+ final StringBuilder msg = new StringBuilder();
+ msg.append("Abnormal build process termination: ");
+ if (stdErrOutput.length() > 0) {
+ msg.append("\n").append(stdErrOutput);
+ }
+ else {
+ msg.append("unknown error");
+ }
+ future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null));
+ }
+ }
+ else {
+ future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null));
+ }
+ }
+ catch (ExecutionException e) {
+ myMessageDispatcher.unregisterBuildMessageHandler(sessionId);
+ future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
+ future.getMessageHandler().sessionTerminated();
+ }
+ finally {
+ myBuildsInProgress.remove(projectPath);
+ future.setDone();
+ }
+ }
+ });
+
+ return future;
+ }
+
+ @Override
+ public void initComponent() {
+ }
+
+ @Override
+ public void disposeComponent() {
+ stopListening();
+ }
+
+ @NotNull
+ @Override
+ public String getComponentName() {
+ return "com.intellij.compiler.server.BuildManager";
+ }
+
+ private static CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings buildGlobalSettings() {
+ final Map data = new HashMap();
+
+ for (Map.Entry entry : PathMacrosImpl.getGlobalSystemMacros().entrySet()) {
+ data.put(entry.getKey(), FileUtil.toSystemIndependentName(entry.getValue()));
+ }
+
+ final PathMacros pathVars = PathMacros.getInstance();
+ for (String name : pathVars.getAllMacroNames()) {
+ final String path = pathVars.getValue(name);
+ if (path != null) {
+ data.put(name, FileUtil.toSystemIndependentName(path));
+ }
+ }
+
+ final List globals = new ArrayList();
+
+ fillSdks(globals);
+ fillGlobalLibraries(globals);
+
+ final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.Builder cmdBuilder =
+ CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder();
+
+ if (!data.isEmpty()) {
+ for (Map.Entry entry : data.entrySet()) {
+ final String var = entry.getKey();
+ final String value = entry.getValue();
+ if (var != null && value != null) {
+ cmdBuilder.addPathVariable(CmdlineProtoUtil.createPair(var, value));
+ }
+ }
+ }
+
+ if (!globals.isEmpty()) {
+ for (GlobalLibrary lib : globals) {
+ final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary.Builder libBuilder =
+ CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary.newBuilder();
+ libBuilder.setName(lib.getName()).addAllPath(lib.getPaths());
+ if (lib instanceof SdkLibrary) {
+ final SdkLibrary sdk = (SdkLibrary)lib;
+ libBuilder.setHomePath(sdk.getHomePath());
+ libBuilder.setTypeName(sdk.getTypeName());
+ final String additional = sdk.getAdditionalDataXml();
+ if (additional != null) {
+ libBuilder.setAdditionalDataXml(additional);
+ }
+ final String version = sdk.getVersion();
+ if (version != null) {
+ libBuilder.setVersion(version);
+ }
+ }
+ cmdBuilder.addGlobalLibrary(libBuilder.build());
+ }
+ }
+
+ final String defaultCharset = EncodingManager.getInstance().getDefaultCharsetName();
+ if (!StringUtil.isEmpty(defaultCharset)) {
+ cmdBuilder.setGlobalEncoding(defaultCharset);
+ }
+
+ final String ignoredFilesList = FileTypeManager.getInstance().getIgnoredFilesList();
+ cmdBuilder.setIgnoredFilesPatterns(ignoredFilesList);
+ return cmdBuilder.build();
+ }
+
+ private static void fillSdks(List globals) {
+ for (Sdk sdk : ProjectJdkTable.getInstance().getAllJdks()) {
+ final String name = sdk.getName();
+ final String homePath = sdk.getHomePath();
+ if (homePath == null) {
+ continue;
+ }
+ final SdkAdditionalData data = sdk.getSdkAdditionalData();
+ final String additionalDataXml;
+ final SdkType sdkType = (SdkType) sdk.getSdkType();
+ if (data == null) {
+ additionalDataXml = null;
+ }
+ else {
+ final Element element = new Element("additional");
+ sdkType.saveAdditionalData(data, element);
+ additionalDataXml = JDOMUtil.writeElement(element, "\n");
+ }
+ final List paths = convertToLocalPaths(sdk.getRootProvider().getFiles(OrderRootType.CLASSES));
+ String versionString = sdk.getVersionString();
+ if (versionString != null && sdkType instanceof JavaSdk) {
+ final JavaSdkVersion version = ((JavaSdk)sdkType).getVersion(versionString);
+ if (version != null) {
+ versionString = version.getDescription();
+ }
+ }
+ globals.add(new SdkLibrary(name, sdkType.getName(), versionString, homePath, paths, additionalDataXml));
+ }
+ }
+
+ private static void fillGlobalLibraries(List globals) {
+ final LibraryTablesRegistrar tableRegistrar = LibraryTablesRegistrar.getInstance();
+ List tables = new ArrayList();
+ tables.add(tableRegistrar.getLibraryTable());
+
+ tables.addAll(tableRegistrar.getCustomLibraryTables());
+ for (LibraryTable libraryTable : tables) {
+ final Iterator iterator = libraryTable.getLibraryIterator();
+ while (iterator.hasNext()) {
+ Library library = iterator.next();
+ final String name = library.getName();
+
+ if (name != null) {
+ final List paths = convertToLocalPaths(library.getFiles(OrderRootType.CLASSES));
+ globals.add(new GlobalLibrary(name, paths));
+ }
+ }
+ }
+ }
+
+ private static List convertToLocalPaths(VirtualFile[] files) {
+ final List paths = new ArrayList();
+ for (VirtualFile file : files) {
+ if (file.isValid()) {
+ paths.add(StringUtil.trimEnd(FileUtil.toSystemIndependentName(file.getPath()), JarFileSystem.JAR_SEPARATOR));
+ }
+ }
+ return paths;
+ }
+
+ private Process launchBuildProcess(Project project, final int port, final UUID sessionId) throws ExecutionException {
+ // choosing sdk with which the build process should be run
+ final Sdk internalJdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ Sdk projectJdk = internalJdk;
+ final String versionString = projectJdk.getVersionString();
+ JavaSdkVersion sdkVersion = versionString != null? ((JavaSdk)projectJdk.getSdkType()).getVersion(versionString) : null;
+ int sdkMinorVersion = getMinorVersion(versionString);
+ if (sdkVersion != null) {
+ final Set candidates = new HashSet();
+ for (Module module : ModuleManager.getInstance(project).getModules()) {
+ final Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
+ if (sdk != null && sdk.getSdkType() instanceof JavaSdk) {
+ candidates.add(sdk);
+ }
+ }
+ // now select the latest version from the sdks that are used in the project, but not older than the internal sdk version
+ for (Sdk candidate : candidates) {
+ final String vs = candidate.getVersionString();
+ if (vs != null) {
+ final JavaSdkVersion candidateVersion = ((JavaSdk)candidate.getSdkType()).getVersion(vs);
+ if (candidateVersion != null) {
+ final int candidateMinorVersion = getMinorVersion(vs);
+ final int result = candidateVersion.compareTo(sdkVersion);
+ if (result > 0 || (result == 0 && candidateMinorVersion > sdkMinorVersion)) {
+ sdkVersion = candidateVersion;
+ sdkMinorVersion = candidateMinorVersion;
+ projectJdk = candidate;
+ }
+ }
+ }
+ }
+ }
+
+ // validate tools.jar presence
+ final File compilerPath;
+ if (projectJdk.equals(internalJdk)) {
+ final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
+ if (systemCompiler == null) {
+ throw new ExecutionException("No system java compiler is provided by the JRE. Make sure tools.jar is present in IntelliJ IDEA classpath.");
+ }
+ compilerPath = ClasspathBootstrap.getResourcePath(systemCompiler.getClass());
+ }
+ else {
+ final String path = ((JavaSdk)projectJdk.getSdkType()).getToolsPath(projectJdk);
+ if (path == null) {
+ throw new ExecutionException("Cannot determine path to 'tools.jar' library for " + projectJdk.getName() + " (" + projectJdk.getHomePath() + ")");
+ }
+ compilerPath = new File(path);
+ }
+
+ final GeneralCommandLine cmdLine = new GeneralCommandLine();
+ final String vmExecutablePath = ((JavaSdkType)projectJdk.getSdkType()).getVMExecutablePath(projectJdk);
+ cmdLine.setExePath(vmExecutablePath);
+ cmdLine.addParameter("-XX:MaxPermSize=150m");
+ cmdLine.addParameter("-XX:ReservedCodeCacheSize=64m");
+ final int heapSize = Registry.intValue("compiler.process.heap.size");
+ final int xms = heapSize / 2;
+ if (xms > 32) {
+ cmdLine.addParameter("-Xms" + xms + "m");
+ }
+ cmdLine.addParameter("-Xmx" + heapSize + "m");
+
+ if (SystemInfo.isMac && sdkVersion != null && JavaSdkVersion.JDK_1_6.equals(sdkVersion) && Registry.is("compiler.process.32bit.vm.on.mac")) {
+ // unfortunately -d32 is supported on jdk 1.6 only
+ cmdLine.addParameter("-d32");
+ }
+
+ cmdLine.addParameter("-Djava.awt.headless=true");
+ if (ApplicationManager.getApplication().isUnitTestMode()) {
+ cmdLine.addParameter("-Dtest.mode=true");
+ }
+ cmdLine.addParameter("-Djdt.compiler.useSingleThread=true");
+
+ final String shouldGenerateIndex = System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION);
+ if (shouldGenerateIndex != null) {
+ cmdLine.addParameter("-D"+ GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION +"=" + shouldGenerateIndex);
+ }
+
+ final String additionalOptions = Registry.stringValue("compiler.process.vm.options");
+ if (!StringUtil.isEmpty(additionalOptions)) {
+ final StringTokenizer tokenizer = new StringTokenizer(additionalOptions, " ", false);
+ while (tokenizer.hasMoreTokens()) {
+ cmdLine.addParameter(tokenizer.nextToken());
+ }
+ }
+
+ // debugging
+ final int debugPort = Registry.intValue("compiler.process.debug.port");
+ if (debugPort > 0) {
+ cmdLine.addParameter("-XX:+HeapDumpOnOutOfMemoryError");
+ cmdLine.addParameter("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + debugPort);
+ }
+
+ if (Registry.is("compiler.process.use.memory.temp.cache")) {
+ cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION);
+ }
+ if (Registry.is("compiler.process.use.external.javac")) {
+ cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION);
+ }
+ final String host = NetUtils.getLocalHostString();
+ cmdLine.addParameter("-D"+ GlobalOptions.HOSTNAME_OPTION + "=" + host);
+
+ // javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
+ final String lang = System.getProperty("user.language");
+ if (lang != null) {
+ //noinspection HardCodedStringLiteral
+ cmdLine.addParameter("-Duser.language=" + lang);
+ }
+ final String country = System.getProperty("user.country");
+ if (country != null) {
+ //noinspection HardCodedStringLiteral
+ cmdLine.addParameter("-Duser.country=" + country);
+ }
+ //noinspection HardCodedStringLiteral
+ final String region = System.getProperty("user.region");
+ if (region != null) {
+ //noinspection HardCodedStringLiteral
+ cmdLine.addParameter("-Duser.region=" + region);
+ }
+
+ cmdLine.addParameter("-classpath");
+
+ final List cp = ClasspathBootstrap.getBuildProcessApplicationClasspath();
+ cp.add(compilerPath);
+ cp.addAll(myClasspathManager.getCompileServerPluginsClasspath());
+
+ cmdLine.addParameter(classpathToString(cp));
+
+ cmdLine.addParameter(BuildMain.class.getName());
+ cmdLine.addParameter(host);
+ cmdLine.addParameter(Integer.toString(port));
+ cmdLine.addParameter(sessionId.toString());
+
+ final File workDirectory = getBuildSystemDirectory();
+ workDirectory.mkdirs();
+ ensureLogConfigExists(workDirectory);
+
+ cmdLine.addParameter(FileUtil.toSystemIndependentName(workDirectory.getPath()));
+
+ cmdLine.setWorkDirectory(workDirectory);
+
+ return cmdLine.createProcess();
+ }
+
+ public File getBuildSystemDirectory() {
+ return new File(mySystemDirectory, SYSTEM_ROOT);
+ }
+
+ private static int getMinorVersion(String vs) {
+ final int dashIndex = vs.lastIndexOf('_');
+ if (dashIndex >= 0) {
+ StringBuilder builder = new StringBuilder();
+ for (int idx = dashIndex + 1; idx < vs.length(); idx++) {
+ final char ch = vs.charAt(idx);
+ if (Character.isDigit(ch)) {
+ builder.append(ch);
+ }
+ else {
+ break;
+ }
+ }
+ if (builder.length() > 0) {
+ try {
+ return Integer.parseInt(builder.toString());
+ }
+ catch (NumberFormatException ignored) {
+ }
+ }
+ }
+ return 0;
+ }
+
+ private static void ensureLogConfigExists(File workDirectory) {
+ final File logConfig = new File(workDirectory, LOGGER_CONFIG);
+ if (!logConfig.exists()) {
+ FileUtil.createIfDoesntExist(logConfig);
+ try {
+ final InputStream in = Server.class.getResourceAsStream("/" + DEFAULT_LOGGER_CONFIG);
+ if (in != null) {
+ try {
+ final FileOutputStream out = new FileOutputStream(logConfig);
+ try {
+ FileUtil.copy(in, out);
+ }
+ finally {
+ out.close();
+ }
+ }
+ finally {
+ in.close();
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ }
+
+ public void stopListening() {
+ final ChannelGroupFuture closeFuture = myAllOpenChannels.close();
+ closeFuture.awaitUninterruptibly();
+ }
+
+ private int startListening() throws Exception {
+ final ChannelFactory channelFactory = new NioServerSocketChannelFactory(myPooledThreadExecutor, myPooledThreadExecutor);
+ final SimpleChannelUpstreamHandler channelRegistrar = new SimpleChannelUpstreamHandler() {
+ public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+ myAllOpenChannels.add(e.getChannel());
+ super.channelOpen(ctx, e);
+ }
+
+ @Override
+ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+ myAllOpenChannels.remove(e.getChannel());
+ super.channelClosed(ctx, e);
+ }
+ };
+ ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {
+ public ChannelPipeline getPipeline() throws Exception {
+ return Channels.pipeline(
+ channelRegistrar,
+ new ProtobufVarint32FrameDecoder(),
+ new ProtobufDecoder(CmdlineRemoteProto.Message.getDefaultInstance()),
+ new ProtobufVarint32LengthFieldPrepender(),
+ new ProtobufEncoder(),
+ myMessageDispatcher
+ );
+ }
+ };
+ final ServerBootstrap bootstrap = new ServerBootstrap(channelFactory);
+ bootstrap.setPipelineFactory(pipelineFactory);
+ bootstrap.setOption("child.tcpNoDelay", true);
+ bootstrap.setOption("child.keepAlive", true);
+ final int listenPort = NetUtils.findAvailableSocketPort();
+ final Channel serverChannel = bootstrap.bind(new InetSocketAddress(listenPort));
+ myAllOpenChannels.add(serverChannel);
+ return listenPort;
+ }
+
+ private static String classpathToString(List cp) {
+ StringBuilder builder = new StringBuilder();
+ for (File file : cp) {
+ if (builder.length() > 0) {
+ builder.append(File.pathSeparator);
+ }
+ builder.append(FileUtil.toCanonicalPath(file.getPath()));
+ }
+ return builder.toString();
+ }
+
+ private class ProjectWatcher extends ProjectManagerAdapter {
+ private final Map myConnections = new HashMap();
+
+ @Override
+ public void projectOpened(final Project project) {
+ final MessageBusConnection conn = project.getMessageBus().connect();
+ myConnections.put(project, conn);
+ conn.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
+ @Override
+ public void rootsChanged(final ModuleRootEvent event) {
+ final Object source = event.getSource();
+ if (source instanceof Project) {
+ clearState((Project)source);
+ }
+ }
+ });
+ conn.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionAdapter() {
+ @Override
+ public void processTerminated(@NotNull RunProfile runProfile, @NotNull ProcessHandler handler) {
+ scheduleAutoMake();
+ }
+ });
+ }
+
+ @Override
+ public boolean canCloseProject(Project project) {
+ cancelAutoMakeTasks(project);
+ return super.canCloseProject(project);
+ }
+
+ @Override
+ public void projectClosing(Project project) {
+ for (RequestFuture future : cancelAutoMakeTasks(project)) {
+ future.waitFor(500, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ @Override
+ public void projectClosed(Project project) {
+ myProjectDataMap.remove(getProjectPath(project));
+ final MessageBusConnection conn = myConnections.remove(project);
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ }
+
+ private static class ProjectData {
+ final SequentialTaskExecutor taskQueue;
+ private final Set myChanged = new THashSet(PathHashingStrategy.INSTANCE);
+ private final Set myDeleted = new THashSet(PathHashingStrategy.INSTANCE);
+ private long myNextEventOrdinal = 0L;
+ private boolean myNeedRescan = true;
+
+ private ProjectData(SequentialTaskExecutor taskQueue) {
+ this.taskQueue = taskQueue;
+ }
+
+ public void addChanged(Collection paths) {
+ if (!myNeedRescan) {
+ myDeleted.removeAll(paths);
+ myChanged.addAll(paths);
+ }
+ }
+
+ public void addDeleted(Collection paths) {
+ if (!myNeedRescan) {
+ myChanged.removeAll(paths);
+ myDeleted.addAll(paths);
+ }
+ }
+
+ public CmdlineRemoteProto.Message.ControllerMessage.FSEvent createNextEvent() {
+ final CmdlineRemoteProto.Message.ControllerMessage.FSEvent.Builder builder =
+ CmdlineRemoteProto.Message.ControllerMessage.FSEvent.newBuilder();
+ builder.setOrdinal(++myNextEventOrdinal);
+ builder.addAllChangedPaths(myChanged);
+ myChanged.clear();
+ builder.addAllDeletedPaths(myDeleted);
+ myDeleted.clear();
+ return builder.build();
+ }
+
+ public boolean getAndResetRescanFlag() {
+ final boolean rescan = myNeedRescan;
+ myNeedRescan = false;
+ return rescan;
+ }
+
+ public void dropChanges() {
+ myNeedRescan = true;
+ myNextEventOrdinal = 0L;
+ myChanged.clear();
+ myDeleted.clear();
+ }
+
+ static class PathHashingStrategy implements TObjectHashingStrategy {
+ static final PathHashingStrategy INSTANCE = new PathHashingStrategy();
+
+ @Override
+ public int computeHashCode(String path) {
+ return FileUtil.pathHashCode(path);
+ }
+
+ @Override
+ public boolean equals(String path1, String path2) {
+ return FileUtil.pathsEqual(path1, path2);
+ }
+ }
+ }
+
+}
diff --git a/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java b/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java
index fa5d43376429..aa9d214f7553 100644
--- a/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java
+++ b/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java
@@ -1,188 +1,191 @@
-/*
- * Copyright 2000-2009 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * User: anna
- * Date: 24-Dec-2008
- */
-package com.intellij.execution.actions;
-
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.Executor;
-import com.intellij.execution.RunnerRegistry;
-import com.intellij.execution.configurations.*;
-import com.intellij.execution.executors.DefaultDebugExecutor;
-import com.intellij.execution.executors.DefaultRunExecutor;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.execution.runners.ProgramRunner;
-import com.intellij.execution.testframework.*;
-import com.intellij.idea.ActionsBundle;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Getter;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMExternalizable;
-import com.intellij.openapi.util.WriteExternalException;
-import org.jdom.Element;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class AbstractRerunFailedTestsAction extends AnAction {
- private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction");
- private TestFrameworkRunningModel myModel;
- private Getter myModelProvider;
- protected TestConsoleProperties myConsoleProperties;
- protected ExecutionEnvironment myEnvironment;
-
- public void init(final TestConsoleProperties consoleProperties,
- final ExecutionEnvironment environment) {
- myEnvironment = environment;
- myConsoleProperties = consoleProperties;
- }
-
- public void setModel(TestFrameworkRunningModel model) {
- myModel = model;
- }
-
- public void setModelProvider(Getter modelProvider) {
- myModelProvider = modelProvider;
- }
-
- public void update(AnActionEvent e) {
- e.getPresentation().setEnabled(isActive(e));
- }
-
- private boolean isActive(AnActionEvent e) {
- DataContext dataContext = e.getDataContext();
- Project project = PlatformDataKeys.PROJECT.getData(dataContext);
- if (project == null) return false;
- TestFrameworkRunningModel model = getModel();
- if (model == null || model.getRoot() == null) return false;
- List failed = getFailedTests(project);
- return !failed.isEmpty();
- }
-
- @NotNull
- protected List getFailedTests(Project project) {
- final List extends AbstractTestProxy> myAllTests = getModel().getRoot().getAllTests();
- return Filter.FAILED_OR_INTERRUPTED.and(JavaAwareFilter.METHOD(project)).select(myAllTests);
- }
-
- public void actionPerformed(AnActionEvent e) {
- final DataContext dataContext = e.getDataContext();
- boolean isDebug = myConsoleProperties.isDebug();
- final MyRunProfile profile = getRunProfile();
- try {
- final Executor executor = isDebug ? DefaultDebugExecutor.getDebugExecutorInstance() : DefaultRunExecutor.getRunExecutorInstance();
- final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(executor.getId(), profile);
- assert runner != null;
- runner.execute(executor, new ExecutionEnvironment(runner, myEnvironment.getExecutionTarget(),
- myEnvironment.getRunnerAndConfigurationSettings(),
- myEnvironment.getProject()));
- }
- catch (ExecutionException e1) {
- LOG.error(e1);
- }
- finally {
- profile.clear();
- }
- }
-
- public MyRunProfile getRunProfile() {
- return null;
- }
-
- public TestFrameworkRunningModel getModel() {
- if (myModel != null) {
- return myModel;
- }
- if (myModelProvider != null) {
- return myModelProvider.get();
- }
- return null;
- }
-
- protected static abstract class MyRunProfile extends RunConfigurationBase implements ModuleRunProfile{
- private final RunConfigurationBase myConfiguration;
-
- public MyRunProfile(RunConfigurationBase configuration) {
- super(configuration.getProject(), configuration.getFactory(), ActionsBundle.message("action.RerunFailedTests.text"));
- myConfiguration = configuration;
- }
-
- public void clear() { }
-
-
- public void checkConfiguration() throws RuntimeConfigurationException {}
-
- ///////////////////////////////////Delegates
- public void readExternal(final Element element) throws InvalidDataException {
- myConfiguration.readExternal(element);
- }
-
- public void writeExternal(final Element element) throws WriteExternalException {
- myConfiguration.writeExternal(element);
- }
-
- public SettingsEditor extends RunConfiguration> getConfigurationEditor() {
- return myConfiguration.getConfigurationEditor();
- }
-
- @NotNull
- public ConfigurationType getType() {
- return myConfiguration.getType();
- }
-
- public JDOMExternalizable createRunnerSettings(final ConfigurationInfoProvider provider) {
- return myConfiguration.createRunnerSettings(provider);
- }
-
- public SettingsEditor getRunnerSettingsEditor(final ProgramRunner runner) {
- return myConfiguration.getRunnerSettingsEditor(runner);
- }
-
- public RunConfiguration clone() {
- return myConfiguration.clone();
- }
-
- public int getUniqueID() {
- return myConfiguration.getUniqueID();
- }
-
- public LogFileOptions getOptionsForPredefinedLogFile(PredefinedLogFile predefinedLogFile) {
- return myConfiguration.getOptionsForPredefinedLogFile(predefinedLogFile);
- }
-
- public ArrayList getPredefinedLogFiles() {
- return myConfiguration.getPredefinedLogFiles();
- }
-
- public ArrayList getAllLogFiles() {
- return myConfiguration.getAllLogFiles();
- }
-
- public ArrayList getLogFiles() {
- return myConfiguration.getLogFiles();
- }
- }
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * User: anna
+ * Date: 24-Dec-2008
+ */
+package com.intellij.execution.actions;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.RunnerRegistry;
+import com.intellij.execution.configurations.*;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.executors.DefaultRunExecutor;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.execution.testframework.*;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Getter;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AbstractRerunFailedTestsAction extends AnAction {
+ private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction");
+ private TestFrameworkRunningModel myModel;
+ private Getter myModelProvider;
+ protected TestConsoleProperties myConsoleProperties;
+ protected ExecutionEnvironment myEnvironment;
+
+ public void init(final TestConsoleProperties consoleProperties,
+ final ExecutionEnvironment environment) {
+ myEnvironment = environment;
+ myConsoleProperties = consoleProperties;
+ }
+
+ public void setModel(TestFrameworkRunningModel model) {
+ myModel = model;
+ }
+
+ public void setModelProvider(Getter modelProvider) {
+ myModelProvider = modelProvider;
+ }
+
+ public void update(AnActionEvent e) {
+ e.getPresentation().setEnabled(isActive(e));
+ }
+
+ private boolean isActive(AnActionEvent e) {
+ DataContext dataContext = e.getDataContext();
+ Project project = PlatformDataKeys.PROJECT.getData(dataContext);
+ if (project == null) return false;
+ TestFrameworkRunningModel model = getModel();
+ if (model == null || model.getRoot() == null) return false;
+ List failed = getFailedTests(project);
+ return !failed.isEmpty();
+ }
+
+ @NotNull
+ protected List getFailedTests(Project project) {
+ final List extends AbstractTestProxy> myAllTests = getModel().getRoot().getAllTests();
+ return Filter.FAILED_OR_INTERRUPTED.and(JavaAwareFilter.METHOD(project)).select(myAllTests);
+ }
+
+ public void actionPerformed(AnActionEvent e) {
+ final DataContext dataContext = e.getDataContext();
+ boolean isDebug = myConsoleProperties.isDebug();
+ final MyRunProfile profile = getRunProfile();
+ try {
+ final Executor executor = isDebug ? DefaultDebugExecutor.getDebugExecutorInstance() : DefaultRunExecutor.getRunExecutorInstance();
+ final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(executor.getId(), profile);
+ assert runner != null;
+ runner.execute(executor, new ExecutionEnvironment(profile,
+ myEnvironment.getExecutionTarget(),
+ profile.getProject(),
+ myEnvironment.getRunnerSettings(),
+ myEnvironment.getConfigurationSettings(),
+ null));
+ }
+ catch (ExecutionException e1) {
+ LOG.error(e1);
+ }
+ finally {
+ profile.clear();
+ }
+ }
+
+ public MyRunProfile getRunProfile() {
+ return null;
+ }
+
+ public TestFrameworkRunningModel getModel() {
+ if (myModel != null) {
+ return myModel;
+ }
+ if (myModelProvider != null) {
+ return myModelProvider.get();
+ }
+ return null;
+ }
+
+ protected static abstract class MyRunProfile extends RunConfigurationBase implements ModuleRunProfile{
+ private final RunConfigurationBase myConfiguration;
+
+ public MyRunProfile(RunConfigurationBase configuration) {
+ super(configuration.getProject(), configuration.getFactory(), ActionsBundle.message("action.RerunFailedTests.text"));
+ myConfiguration = configuration;
+ }
+
+ public void clear() { }
+
+
+ public void checkConfiguration() throws RuntimeConfigurationException {}
+
+ ///////////////////////////////////Delegates
+ public void readExternal(final Element element) throws InvalidDataException {
+ myConfiguration.readExternal(element);
+ }
+
+ public void writeExternal(final Element element) throws WriteExternalException {
+ myConfiguration.writeExternal(element);
+ }
+
+ public SettingsEditor extends RunConfiguration> getConfigurationEditor() {
+ return myConfiguration.getConfigurationEditor();
+ }
+
+ @NotNull
+ public ConfigurationType getType() {
+ return myConfiguration.getType();
+ }
+
+ public JDOMExternalizable createRunnerSettings(final ConfigurationInfoProvider provider) {
+ return myConfiguration.createRunnerSettings(provider);
+ }
+
+ public SettingsEditor getRunnerSettingsEditor(final ProgramRunner runner) {
+ return myConfiguration.getRunnerSettingsEditor(runner);
+ }
+
+ public RunConfiguration clone() {
+ return myConfiguration.clone();
+ }
+
+ public int getUniqueID() {
+ return myConfiguration.getUniqueID();
+ }
+
+ public LogFileOptions getOptionsForPredefinedLogFile(PredefinedLogFile predefinedLogFile) {
+ return myConfiguration.getOptionsForPredefinedLogFile(predefinedLogFile);
+ }
+
+ public ArrayList getPredefinedLogFiles() {
+ return myConfiguration.getPredefinedLogFiles();
+ }
+
+ public ArrayList getAllLogFiles() {
+ return myConfiguration.getAllLogFiles();
+ }
+
+ public ArrayList getLogFiles() {
+ return myConfiguration.getLogFiles();
+ }
+ }
}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java
index 052c51891c0b..5825e5aa56a5 100644
--- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java
+++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java
@@ -101,12 +101,7 @@ public class DuplicatesImpl {
private static boolean replaceMatch(final Project project, final MatchProvider provider, final Match match, @NotNull final Editor editor,
final int idx, final int size, Ref showAll, final String confirmDuplicatePrompt) {
- final ArrayList highlighters = new ArrayList();
- highlightMatch(project, editor, match, highlighters);
- final TextRange textRange = match.getTextRange();
- final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset());
- expandAllRegionsCoveringRange(project, editor, textRange);
- editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.MAKE_VISIBLE);
+ final ArrayList highlighters = previewMatch(project, match, editor);
if (!ApplicationManager.getApplication().isUnitTestMode()) {
if (size > 1 && (showAll.get() == null || !showAll.get())) {
final String prompt = provider.getConfirmDuplicatePrompt(match);
@@ -145,6 +140,16 @@ public class DuplicatesImpl {
return false;
}
+ public static ArrayList previewMatch(Project project, Match match, Editor editor) {
+ final ArrayList highlighters = new ArrayList();
+ highlightMatch(project, editor, match, highlighters);
+ final TextRange textRange = match.getTextRange();
+ final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset());
+ expandAllRegionsCoveringRange(project, editor, textRange);
+ editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.MAKE_VISIBLE);
+ return highlighters;
+ }
+
private static void expandAllRegionsCoveringRange(final Project project, Editor editor, final TextRange textRange) {
final FoldRegion[] foldRegions = CodeFoldingManager.getInstance(project).getFoldRegionsAtOffset(editor, textRange.getStartOffset());
boolean anyCollapsed = false;
@@ -177,9 +182,13 @@ public class DuplicatesImpl {
public static void processDuplicates(@NotNull MatchProvider provider, @NotNull Project project, @NotNull Editor editor) {
boolean hasDuplicates = provider.hasDuplicates();
if (hasDuplicates) {
+ List duplicates = provider.getDuplicates();
+ if (duplicates.size() == 1) {
+ previewMatch(project, duplicates.get(0), editor);
+ }
final int answer = Messages.showYesNoDialog(project,
RefactoringBundle.message("0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.method",
- ApplicationNamesInfo.getInstance().getProductName(), provider.getDuplicates().size()),
+ ApplicationNamesInfo.getInstance().getProductName(), duplicates.size()),
"Process Duplicates", Messages.getQuestionIcon());
if (answer == 0) {
invoke(project, editor, provider);
diff --git a/jps/jps-builders/jps-builders.iml b/jps/jps-builders/jps-builders.iml
index 31cc304514d6..7b79e8572ff5 100644
--- a/jps/jps-builders/jps-builders.iml
+++ b/jps/jps-builders/jps-builders.iml
@@ -41,6 +41,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java
index 36f1941ccf3d..602b94bd177c 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java
@@ -1,719 +1,719 @@
-package org.jetbrains.jps.cmdline;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.io.DataOutputStream;
-import groovy.util.Node;
-import groovy.util.XmlParser;
-import org.codehaus.groovy.runtime.MethodClosure;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.Channels;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.ether.dependencyView.Callbacks;
-import org.jetbrains.jps.Library;
-import org.jetbrains.jps.Module;
-import org.jetbrains.jps.Project;
-import org.jetbrains.jps.Sdk;
-import org.jetbrains.jps.api.*;
-import org.jetbrains.jps.artifacts.Artifact;
-import org.jetbrains.jps.idea.IdeaProjectLoader;
-import org.jetbrains.jps.idea.SystemOutErrorReporter;
-import org.jetbrains.jps.incremental.*;
-import org.jetbrains.jps.incremental.fs.BuildFSState;
-import org.jetbrains.jps.incremental.fs.RootDescriptor;
-import org.jetbrains.jps.incremental.messages.*;
-import org.jetbrains.jps.incremental.storage.BuildDataManager;
-import org.jetbrains.jps.incremental.storage.ProjectTimestamps;
-import org.jetbrains.jps.incremental.storage.Timestamps;
-import org.jetbrains.jps.server.ProjectDescriptor;
-
-import java.io.*;
-import java.util.*;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
-* @author Eugene Zhuravlev
-* Date: 4/17/12
-*/
-final class BuildSession implements Runnable, CanceledStatus {
- private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.BuildSession");
- public static final String IDEA_PROJECT_DIRNAME = ".idea";
- private static final String FS_STATE_FILE = "fs_state.dat";
- private final UUID mySessionId;
- private final Channel myChannel;
- private volatile boolean myCanceled = false;
- // globals
- private final Map myPathVars;
- private final List myGlobalLibraries;
- private final String myGlobalEncoding;
- private final String myIgnorePatterns;
- // build params
- private final BuildType myBuildType;
- private final Set myModules;
- private final List myArtifacts;
- private final List myFilePaths;
- private final Map myBuilderParams;
- private String myProjectPath;
- @Nullable
- private CmdlineRemoteProto.Message.ControllerMessage.FSEvent myInitialFSDelta;
- // state
- private EventsProcessor myEventsProcessor = new EventsProcessor();
- private volatile long myLastEventOrdinal;
- private volatile ProjectDescriptor myProjectDescriptor;
- private final Map, ConstantSearchFuture> mySearchTasks = Collections.synchronizedMap(new HashMap, ConstantSearchFuture>());
- private final ConstantSearch myConstantSearch = new ConstantSearch();
-
- BuildSession(UUID sessionId,
- Channel channel,
- CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage params,
- @Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta) {
- mySessionId = sessionId;
- myChannel = channel;
-
- // globals
- myPathVars = new HashMap();
- final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = params.getGlobalSettings();
- for (CmdlineRemoteProto.Message.KeyValuePair variable : globals.getPathVariableList()) {
- myPathVars.put(variable.getKey(), variable.getValue());
- }
- myGlobalLibraries = new ArrayList();
- for (CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary library : globals.getGlobalLibraryList()) {
- myGlobalLibraries.add(
- library.hasHomePath() ?
- new SdkLibrary(library.getName(), library.getTypeName(), library.hasVersion() ? library.getVersion() : null, library.getHomePath(), library.getPathList(), library.hasAdditionalDataXml() ? library.getAdditionalDataXml() : null) :
- new GlobalLibrary(library.getName(), library.getPathList())
- );
- }
- myGlobalEncoding = globals.hasGlobalEncoding()? globals.getGlobalEncoding() : null;
- myIgnorePatterns = globals.hasIgnoredFilesPatterns()? globals.getIgnoredFilesPatterns() : null;
-
- // session params
- myProjectPath = FileUtil.toCanonicalPath(params.getProjectId());
- myBuildType = convertCompileType(params.getBuildType());
- myModules = new HashSet(params.getModuleNameList());
- myArtifacts = params.getArtifactNameList();
- myFilePaths = params.getFilePathList();
- myBuilderParams = new HashMap();
- for (CmdlineRemoteProto.Message.KeyValuePair pair : params.getBuilderParameterList()) {
- myBuilderParams.put(pair.getKey(), pair.getValue());
- }
- myInitialFSDelta = delta;
- }
-
- public void run() {
- Throwable error = null;
- final Ref hasErrors = new Ref(false);
- final Ref markedFilesUptodate = new Ref(false);
- try {
- runBuild(myProjectPath, myBuildType, myModules, myArtifacts, myBuilderParams, myFilePaths, new MessageHandler() {
- public void processMessage(BuildMessage buildMessage) {
- final CmdlineRemoteProto.Message.BuilderMessage response;
- if (buildMessage instanceof FileGeneratedEvent) {
- final Collection> paths = ((FileGeneratedEvent)buildMessage).getPaths();
- response = !paths.isEmpty() ? CmdlineProtoUtil.createFileGeneratedEvent(paths) : null;
- }
- else if (buildMessage instanceof UptoDateFilesSavedEvent) {
- markedFilesUptodate.set(true);
- response = null;
- }
- else if (buildMessage instanceof CompilerMessage) {
- markedFilesUptodate.set(true);
- final CompilerMessage compilerMessage = (CompilerMessage)buildMessage;
- final String text = compilerMessage.getCompilerName() + ": " + compilerMessage.getMessageText();
- final BuildMessage.Kind kind = compilerMessage.getKind();
- if (kind == BuildMessage.Kind.ERROR) {
- hasErrors.set(true);
- }
- response = CmdlineProtoUtil.createCompileMessage(
- kind, text, compilerMessage.getSourcePath(),
- compilerMessage.getProblemBeginOffset(), compilerMessage.getProblemEndOffset(),
- compilerMessage.getProblemLocationOffset(), compilerMessage.getLine(), compilerMessage.getColumn(),
- -1.0f);
- }
- else {
- float done = -1.0f;
- if (buildMessage instanceof ProgressMessage) {
- done = ((ProgressMessage)buildMessage).getDone();
- }
- response = CmdlineProtoUtil.createCompileProgressMessageResponse(buildMessage.getMessageText(), done);
- }
- if (response != null) {
- Channels.write(myChannel, CmdlineProtoUtil.toMessage(mySessionId, response));
- }
- }
- }, this);
- }
- catch (Throwable e) {
- LOG.info(e);
- error = e;
- }
- finally {
- finishBuild(error, hasErrors.get(), markedFilesUptodate.get());
- }
- }
-
- private void runBuild(String projectPath, BuildType buildType, Set modules, Collection artifacts, Map builderParams, Collection paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{
- boolean forceCleanCaches = false;
-
- final File dataStorageRoot = Utils.getDataStorageRoot(projectPath);
- if (dataStorageRoot == null) {
- msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.ERROR, "Cannot determine build data storage root for project " + projectPath));
- return;
- }
- final BuildFSState fsState = new BuildFSState(false);
-
- try {
- final boolean shouldApplyEvent = loadFsState(fsState, dataStorageRoot, myInitialFSDelta);
- if (shouldApplyEvent && !containsChanges(myInitialFSDelta) && !fsState.hasWorkToDo()) {
- applyFSEvent(null, myInitialFSDelta);
- return;
- }
- if (!dataStorageRoot.exists()) {
- // invoked the very first time for this project. Force full rebuild
- buildType = BuildType.PROJECT_REBUILD;
- }
-
- final boolean inMemoryMappingsDelta = System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null;
- ProjectTimestamps projectTimestamps = null;
- BuildDataManager dataManager = null;
- try {
- projectTimestamps = new ProjectTimestamps(dataStorageRoot);
- dataManager = new BuildDataManager(dataStorageRoot, inMemoryMappingsDelta);
- if (dataManager.versionDiffers()) {
- forceCleanCaches = true;
- msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Dependency data format has changed, project rebuild required"));
- }
- }
- catch (Exception e) {
- // second try
- LOG.info(e);
- if (projectTimestamps != null) {
- projectTimestamps.close();
- }
- if (dataManager != null) {
- dataManager.close();
- }
- forceCleanCaches = true;
- FileUtil.delete(dataStorageRoot);
- projectTimestamps = new ProjectTimestamps(dataStorageRoot);
- dataManager = new BuildDataManager(dataStorageRoot, inMemoryMappingsDelta);
- // second attempt succeded
- msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage()));
- }
-
- final Project project = loadProject(projectPath);
- final ProjectDescriptor pd = new ProjectDescriptor(project, fsState, projectTimestamps, dataManager, BuildLoggingManager.DEFAULT);
- myProjectDescriptor = pd;
- if (shouldApplyEvent) {
- applyFSEvent(pd, myInitialFSDelta);
- }
-
-
- // free memory
- myInitialFSDelta = null;
- // ensure events from controller are processed after FSState initialization
- myEventsProcessor.startProcessing();
-
- for (int attempt = 0; attempt < 2; attempt++) {
- if (forceCleanCaches && modules.isEmpty() && paths.isEmpty()) {
- // if compilation scope is the whole project and cache rebuild is forced, use PROJECT_REBUILD for faster compilation
- buildType = BuildType.PROJECT_REBUILD;
- }
-
- final Timestamps timestamps = pd.timestamps.getStorage();
-
- final CompileScope compileScope = createCompilationScope(buildType, pd, timestamps, modules, artifacts, paths);
- final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), timestamps, builderParams, cs, myConstantSearch);
- builder.addMessageHandler(msgHandler);
- try {
- switch (buildType) {
- case PROJECT_REBUILD:
- builder.build(compileScope, false, true, forceCleanCaches);
- break;
-
- case FORCED_COMPILATION:
- builder.build(compileScope, false, false, forceCleanCaches);
- break;
-
- case MAKE:
- builder.build(compileScope, true, false, forceCleanCaches);
- break;
-
- case CLEAN:
- //todo[nik]
- // new ProjectBuilder(new GantBinding(), project).clean();
- break;
- }
- break; // break attempts loop
- }
- catch (RebuildRequestedException e) {
- if (attempt == 0) {
- LOG.info(e);
- forceCleanCaches = true;
- }
- else {
- throw e;
- }
- }
- }
- }
- finally {
- saveData(fsState, dataStorageRoot);
- }
- }
-
- private void saveData(final BuildFSState fsState, File dataStorageRoot) {
- final boolean wasInterrupted = Thread.interrupted();
- try {
- saveFsState(dataStorageRoot, fsState, myLastEventOrdinal);
- final ProjectDescriptor pd = myProjectDescriptor;
- if (pd != null) {
- pd.release();
- }
- }
- finally {
- if (wasInterrupted) {
- Thread.currentThread().interrupt();
- }
- }
- }
-
- public void processFSEvent(final CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) {
- myEventsProcessor.submit(new Runnable() {
- @Override
- public void run() {
- try {
- applyFSEvent(myProjectDescriptor, event);
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- });
- }
-
- public void processConstantSearchResult(CmdlineRemoteProto.Message.ControllerMessage.ConstantSearchResult result) {
- final ConstantSearchFuture future = mySearchTasks.remove(Pair.create(result.getOwnerClassName(), result.getFieldName()));
- if (future != null) {
- if (result.getIsSuccess()) {
- final List paths = result.getPathList();
- final List files = new ArrayList(paths.size());
- for (String path : paths) {
- files.add(new File(path));
- }
- future.setResult(files);
- }
- else {
- future.setDone();
- }
- }
- }
-
- private void applyFSEvent(ProjectDescriptor pd, @Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) throws IOException {
- if (event == null) {
- return;
- }
-
- if (pd != null) {
- final Timestamps timestamps = pd.timestamps.getStorage();
-
- for (String deleted : event.getDeletedPathsList()) {
- final File file = new File(deleted);
- final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
- if (rd != null) {
- if (Utils.IS_TEST_MODE) {
- LOG.info("Applying deleted path from fs event: " + file.getPath());
- }
- pd.fsState.registerDeleted(rd.module, file, rd.isTestRoot, timestamps);
- }
- else {
- if (Utils.IS_TEST_MODE) {
- LOG.info("Skipping deleted path: " + file.getPath());
- }
- }
- }
- for (String changed : event.getChangedPathsList()) {
- final File file = new File(changed);
- final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
- if (rd != null) {
- if (Utils.IS_TEST_MODE) {
- LOG.info("Applying dirty path from fs event: " + file.getPath());
- }
- pd.fsState.markDirty(file, rd, timestamps);
- }
- else {
- if (Utils.IS_TEST_MODE) {
- LOG.info("Skipping dirty path: " + file.getPath());
- }
- }
- }
- }
-
- myLastEventOrdinal += 1;
- }
-
- private static void saveFsState(File dataStorageRoot, BuildFSState state, long lastEventOrdinal) {
- final File file = new File(dataStorageRoot, FS_STATE_FILE);
- try {
- final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
- final DataOutputStream out = new DataOutputStream(bytes);
- try {
- out.writeLong(lastEventOrdinal);
- state.save(out);
- }
- finally {
- out.close();
- }
-
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file);
- }
- catch (FileNotFoundException e) {
- FileUtil.createIfDoesntExist(file);
- }
-
- if (fos == null) {
- fos = new FileOutputStream(file);
- }
- try {
- fos.write(bytes.getInternalBuffer(), 0, bytes.size());
- }
- finally {
- fos.close();
- }
-
- }
- catch (Throwable e) {
- LOG.error(e);
- FileUtil.delete(file);
- }
- }
-
- private boolean loadFsState(final BuildFSState fsState, File dataStorageRoot, CmdlineRemoteProto.Message.ControllerMessage.FSEvent initialEvent) {
- boolean shouldApplyEvent = false;
- final File file = new File(dataStorageRoot, FS_STATE_FILE);
- try {
- final InputStream fs = new FileInputStream(file);
- byte[] bytes;
- try {
- bytes = FileUtil.loadBytes(fs, (int)file.length());
- }
- finally {
- fs.close();
- }
-
- final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
- try {
- final long savedOrdinal = in.readLong();
- if (initialEvent != null && (savedOrdinal + 1L == initialEvent.getOrdinal())) {
- fsState.load(in);
- myLastEventOrdinal = savedOrdinal;
- shouldApplyEvent = true;
- //applyFSEvent(pd, initialEvent);
- }
- else {
- // either the first start or some events were lost, forcing scan
- fsState.clearAll();
- myLastEventOrdinal = initialEvent != null? initialEvent.getOrdinal() : 0L;
- }
- }
- finally {
- in.close();
- }
- return shouldApplyEvent; // successfully initialized
-
- }
- catch (FileNotFoundException ignored) {
- }
- catch (Throwable e) {
- LOG.error(e);
- }
- myLastEventOrdinal = initialEvent != null? initialEvent.getOrdinal() : 0L;
- fsState.clearAll();
- return shouldApplyEvent;
- }
-
- private static boolean containsChanges(CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) {
- return event.getChangedPathsCount() != 0 || event.getDeletedPathsCount() != 0;
- }
-
- private void finishBuild(Throwable error, boolean hadBuildErrors, boolean markedUptodateFiles) {
- CmdlineRemoteProto.Message lastMessage = null;
- try {
- if (error != null) {
- Throwable cause = error.getCause();
- if (cause == null) {
- cause = error;
- }
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- cause.printStackTrace(new PrintStream(out));
-
- final StringBuilder messageText = new StringBuilder();
- messageText.append("Internal error: (").append(cause.getClass().getName()).append(") ").append(cause.getMessage());
- final String trace = out.toString();
- if (!trace.isEmpty()) {
- messageText.append("\n").append(trace);
- }
- lastMessage = CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createFailure(messageText.toString(), cause));
- }
- else {
- CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.SUCCESS;
- if (myCanceled) {
- status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.CANCELED;
- }
- else if (hadBuildErrors) {
- status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.ERRORS;
- }
- else if (!markedUptodateFiles){
- status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.UP_TO_DATE;
- }
- lastMessage = CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createBuildCompletedEvent("build completed", status));
- }
- }
- catch (Throwable e) {
- lastMessage = CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
- }
- finally {
- try {
- Channels.write(myChannel, lastMessage).await();
- }
- catch (InterruptedException e) {
- LOG.info(e);
- }
- }
- }
-
- public void cancel() {
- myCanceled = true;
- }
-
- @Override
- public boolean isCanceled() {
- return myCanceled;
- }
-
-
- private Project loadProject(String projectPath) {
- final long start = System.currentTimeMillis();
- try {
- final Project project = new Project();
-
- initSdksAndGlobalLibraries(project);
-
- final File projectFile = new File(projectPath);
-
- //String root = dirBased ? projectPath : projectFile.getParent();
-
- final String loadPath = isDirectoryBased(projectFile) ? new File(projectFile, IDEA_PROJECT_DIRNAME).getPath() : projectPath;
- IdeaProjectLoader.loadFromPath(project, loadPath, myPathVars, null, new SystemOutErrorReporter(false));
- final String globalEncoding = myGlobalEncoding;
- if (!StringUtil.isEmpty(globalEncoding) && project.getProjectCharset() == null) {
- project.setProjectCharset(globalEncoding);
- }
- project.getIgnoredFilePatterns().loadFromString(myIgnorePatterns);
- return project;
- }
- finally {
- final long loadTime = System.currentTimeMillis() - start;
- LOG.info("Project " + projectPath + " loaded in " + loadTime + " ms");
- }
- }
-
- private void initSdksAndGlobalLibraries(Project project) {
- final MethodClosure fakeClosure = new MethodClosure(new Object(), "hashCode");
- for (GlobalLibrary library : myGlobalLibraries) {
- if (library instanceof SdkLibrary) {
- final SdkLibrary sdk = (SdkLibrary)library;
- Node additionalData = null;
- final String additionalXml = sdk.getAdditionalDataXml();
- if (additionalXml != null) {
- try {
- additionalData = new XmlParser(false, false).parseText(additionalXml);
- }
- catch (Exception e) {
- LOG.info(e);
- }
- }
- final Sdk jdk = project.createSdk(sdk.getTypeName(), sdk.getName(), sdk.getVersion(), sdk.getHomePath(), additionalData);
- if (jdk != null) {
- jdk.setClasspath(sdk.getPaths());
- }
- else {
- LOG.info("Failed to load SDK " + sdk.getName() + ", type: " + sdk.getTypeName());
- }
- }
- else {
- final Library lib = project.createGlobalLibrary(library.getName(), fakeClosure);
- if (lib != null) {
- lib.setClasspath(library.getPaths());
- }
- else {
- LOG.info("Failed to load global library " + library.getName());
- }
- }
- }
- }
-
- private static boolean isDirectoryBased(File projectFile) {
- return !(projectFile.isFile() && projectFile.getName().endsWith(".ipr"));
- }
-
- private static CompileScope createCompilationScope(BuildType buildType,
- ProjectDescriptor pd,
- final Timestamps timestamps, Set modules,
- Collection artifactNames,
- Collection paths) throws Exception {
- Set artifacts = new HashSet();
- if (artifactNames.isEmpty() && buildType == BuildType.PROJECT_REBUILD) {
- artifacts.addAll(pd.project.getArtifacts().values());
- }
- else {
- final Map artifactMap = pd.project.getArtifacts();
- for (String name : artifactNames) {
- final Artifact artifact = artifactMap.get(name);
- if (artifact != null && !StringUtil.isEmpty(artifact.getOutputPath())) {
- artifacts.add(artifact);
- }
- }
- }
-
- final CompileScope compileScope;
- if (buildType == BuildType.PROJECT_REBUILD || (modules.isEmpty() && paths.isEmpty())) {
- compileScope = new AllProjectScope(pd.project, artifacts, buildType != BuildType.MAKE);
- }
- else {
- final Set forcedModules;
- if (!modules.isEmpty()) {
- forcedModules = new HashSet();
- for (Module m : pd.project.getModules().values()) {
- if (modules.contains(m.getName())) {
- forcedModules.add(m);
- }
- }
- }
- else {
- forcedModules = Collections.emptySet();
- }
-
- final Map> filesToCompile;
- if (!paths.isEmpty()) {
- filesToCompile = new HashMap>();
- for (String path : paths) {
- final File file = new File(path);
- final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
- if (rd != null) {
- Set files = filesToCompile.get(rd.module);
- if (files == null) {
- files = new HashSet();
- filesToCompile.put(rd.module, files);
- }
- files.add(file);
- if (buildType == BuildType.FORCED_COMPILATION) {
- pd.fsState.markDirty(file, rd, timestamps);
- }
- }
- }
- }
- else {
- filesToCompile = Collections.emptyMap();
- }
-
- if (filesToCompile.isEmpty()) {
- compileScope = new ModulesScope(pd.project, forcedModules, artifacts, buildType != BuildType.MAKE);
- }
- else {
- compileScope = new ModulesAndFilesScope(pd.project, forcedModules, filesToCompile, artifacts, buildType != BuildType.MAKE);
- }
- }
- return compileScope;
- }
-
-
- private static BuildType convertCompileType(CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type compileType) {
- switch (compileType) {
- case CLEAN: return BuildType.CLEAN;
- case MAKE: return BuildType.MAKE;
- case REBUILD: return BuildType.PROJECT_REBUILD;
- case FORCED_COMPILATION: return BuildType.FORCED_COMPILATION;
- }
- return BuildType.MAKE; // use make by default
- }
-
- private static class EventsProcessor extends SequentialTaskExecutor {
- private final AtomicBoolean myProcessingEnabled = new AtomicBoolean(false);
-
- EventsProcessor() {
- super(SharedThreadPool.INSTANCE);
- }
-
- public void startProcessing() {
- if (!myProcessingEnabled.getAndSet(true)) {
- super.processQueue();
- }
- }
-
- @Override
- protected void processQueue() {
- if (myProcessingEnabled.get()) {
- super.processQueue();
- }
- }
- }
-
- private class ConstantSearch implements Callbacks.ConstantAffectionResolver {
- @Nullable @Override
- public Future request(String ownerClassName, String fieldName, int accessFlags, boolean fieldRemoved, boolean accessChanged) {
- final CmdlineRemoteProto.Message.BuilderMessage.ConstantSearchTask.Builder task =
- CmdlineRemoteProto.Message.BuilderMessage.ConstantSearchTask.newBuilder();
- task.setOwnerClassName(ownerClassName);
- task.setFieldName(fieldName);
- task.setAccessFlags(accessFlags);
- task.setIsAccessChanged(accessChanged);
- task.setIsFieldRemoved(fieldRemoved);
- final ConstantSearchFuture future = new ConstantSearchFuture();
- final ConstantSearchFuture prev = mySearchTasks.put(new Pair(ownerClassName, fieldName), future);
- if (prev != null) {
- prev.setDone();
- }
- Channels.write(myChannel,
- CmdlineProtoUtil.toMessage(
- mySessionId, CmdlineRemoteProto.Message.BuilderMessage.newBuilder().setType(CmdlineRemoteProto.Message.BuilderMessage.Type.CONSTANT_SEARCH_TASK).setConstantSearchTask(task.build()).build()
- )
- );
- return future;
- }
- }
-
- private static class ConstantSearchFuture extends BasicFuture {
- private volatile Callbacks.ConstantAffection myResult = Callbacks.ConstantAffection.EMPTY;
-
- private ConstantSearchFuture() {
- }
-
- public void setResult(final Collection affectedFiles) {
- myResult = new Callbacks.ConstantAffection(affectedFiles);
- setDone();
- }
-
- @Override
- public Callbacks.ConstantAffection get() throws InterruptedException, ExecutionException {
- super.get();
- return myResult;
- }
-
- @Override
- public Callbacks.ConstantAffection get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- super.get(timeout, unit);
- return myResult;
- }
- }
-}
+package org.jetbrains.jps.cmdline;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.io.DataOutputStream;
+import groovy.util.Node;
+import groovy.util.XmlParser;
+import org.codehaus.groovy.runtime.MethodClosure;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.Channels;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.ether.dependencyView.Callbacks;
+import org.jetbrains.jps.Library;
+import org.jetbrains.jps.Module;
+import org.jetbrains.jps.Project;
+import org.jetbrains.jps.Sdk;
+import org.jetbrains.jps.api.*;
+import org.jetbrains.jps.artifacts.Artifact;
+import org.jetbrains.jps.idea.IdeaProjectLoader;
+import org.jetbrains.jps.idea.SystemOutErrorReporter;
+import org.jetbrains.jps.incremental.*;
+import org.jetbrains.jps.incremental.fs.BuildFSState;
+import org.jetbrains.jps.incremental.fs.RootDescriptor;
+import org.jetbrains.jps.incremental.messages.*;
+import org.jetbrains.jps.incremental.storage.BuildDataManager;
+import org.jetbrains.jps.incremental.storage.ProjectTimestamps;
+import org.jetbrains.jps.incremental.storage.Timestamps;
+import org.jetbrains.jps.server.ProjectDescriptor;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+* @author Eugene Zhuravlev
+* Date: 4/17/12
+*/
+final class BuildSession implements Runnable, CanceledStatus {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.BuildSession");
+ public static final String IDEA_PROJECT_DIRNAME = ".idea";
+ private static final String FS_STATE_FILE = "fs_state.dat";
+ private final UUID mySessionId;
+ private final Channel myChannel;
+ private volatile boolean myCanceled = false;
+ // globals
+ private final Map myPathVars;
+ private final List myGlobalLibraries;
+ private final String myGlobalEncoding;
+ private final String myIgnorePatterns;
+ // build params
+ private final BuildType myBuildType;
+ private final Set myModules;
+ private final List myArtifacts;
+ private final List myFilePaths;
+ private final Map myBuilderParams;
+ private String myProjectPath;
+ @Nullable
+ private CmdlineRemoteProto.Message.ControllerMessage.FSEvent myInitialFSDelta;
+ // state
+ private EventsProcessor myEventsProcessor = new EventsProcessor();
+ private volatile long myLastEventOrdinal;
+ private volatile ProjectDescriptor myProjectDescriptor;
+ private final Map, ConstantSearchFuture> mySearchTasks = Collections.synchronizedMap(new HashMap, ConstantSearchFuture>());
+ private final ConstantSearch myConstantSearch = new ConstantSearch();
+
+ BuildSession(UUID sessionId,
+ Channel channel,
+ CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage params,
+ @Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta) {
+ mySessionId = sessionId;
+ myChannel = channel;
+
+ // globals
+ myPathVars = new HashMap();
+ final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = params.getGlobalSettings();
+ for (CmdlineRemoteProto.Message.KeyValuePair variable : globals.getPathVariableList()) {
+ myPathVars.put(variable.getKey(), variable.getValue());
+ }
+ myGlobalLibraries = new ArrayList();
+ for (CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary library : globals.getGlobalLibraryList()) {
+ myGlobalLibraries.add(
+ library.hasHomePath() ?
+ new SdkLibrary(library.getName(), library.getTypeName(), library.hasVersion() ? library.getVersion() : null, library.getHomePath(), library.getPathList(), library.hasAdditionalDataXml() ? library.getAdditionalDataXml() : null) :
+ new GlobalLibrary(library.getName(), library.getPathList())
+ );
+ }
+ myGlobalEncoding = globals.hasGlobalEncoding()? globals.getGlobalEncoding() : null;
+ myIgnorePatterns = globals.hasIgnoredFilesPatterns()? globals.getIgnoredFilesPatterns() : null;
+
+ // session params
+ myProjectPath = FileUtil.toCanonicalPath(params.getProjectId());
+ myBuildType = convertCompileType(params.getBuildType());
+ myModules = new HashSet(params.getModuleNameList());
+ myArtifacts = params.getArtifactNameList();
+ myFilePaths = params.getFilePathList();
+ myBuilderParams = new HashMap();
+ for (CmdlineRemoteProto.Message.KeyValuePair pair : params.getBuilderParameterList()) {
+ myBuilderParams.put(pair.getKey(), pair.getValue());
+ }
+ myInitialFSDelta = delta;
+ }
+
+ public void run() {
+ Throwable error = null;
+ final Ref hasErrors = new Ref(false);
+ final Ref markedFilesUptodate = new Ref(false);
+ try {
+ runBuild(myProjectPath, myBuildType, myModules, myArtifacts, myBuilderParams, myFilePaths, new MessageHandler() {
+ public void processMessage(BuildMessage buildMessage) {
+ final CmdlineRemoteProto.Message.BuilderMessage response;
+ if (buildMessage instanceof FileGeneratedEvent) {
+ final Collection> paths = ((FileGeneratedEvent)buildMessage).getPaths();
+ response = !paths.isEmpty() ? CmdlineProtoUtil.createFileGeneratedEvent(paths) : null;
+ }
+ else if (buildMessage instanceof UptoDateFilesSavedEvent) {
+ markedFilesUptodate.set(true);
+ response = null;
+ }
+ else if (buildMessage instanceof CompilerMessage) {
+ markedFilesUptodate.set(true);
+ final CompilerMessage compilerMessage = (CompilerMessage)buildMessage;
+ final String text = compilerMessage.getCompilerName() + ": " + compilerMessage.getMessageText();
+ final BuildMessage.Kind kind = compilerMessage.getKind();
+ if (kind == BuildMessage.Kind.ERROR) {
+ hasErrors.set(true);
+ }
+ response = CmdlineProtoUtil.createCompileMessage(
+ kind, text, compilerMessage.getSourcePath(),
+ compilerMessage.getProblemBeginOffset(), compilerMessage.getProblemEndOffset(),
+ compilerMessage.getProblemLocationOffset(), compilerMessage.getLine(), compilerMessage.getColumn(),
+ -1.0f);
+ }
+ else {
+ float done = -1.0f;
+ if (buildMessage instanceof ProgressMessage) {
+ done = ((ProgressMessage)buildMessage).getDone();
+ }
+ response = CmdlineProtoUtil.createCompileProgressMessageResponse(buildMessage.getMessageText(), done);
+ }
+ if (response != null) {
+ Channels.write(myChannel, CmdlineProtoUtil.toMessage(mySessionId, response));
+ }
+ }
+ }, this);
+ }
+ catch (Throwable e) {
+ LOG.info(e);
+ error = e;
+ }
+ finally {
+ finishBuild(error, hasErrors.get(), markedFilesUptodate.get());
+ }
+ }
+
+ private void runBuild(String projectPath, BuildType buildType, Set modules, Collection artifacts, Map builderParams, Collection paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{
+ boolean forceCleanCaches = false;
+
+ final File dataStorageRoot = Utils.getDataStorageRoot(projectPath);
+ if (dataStorageRoot == null) {
+ msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.ERROR, "Cannot determine build data storage root for project " + projectPath));
+ return;
+ }
+ final BuildFSState fsState = new BuildFSState(false);
+
+ try {
+ final boolean shouldApplyEvent = loadFsState(fsState, dataStorageRoot, myInitialFSDelta);
+ if (shouldApplyEvent && buildType == BuildType.MAKE && !containsChanges(myInitialFSDelta) && !fsState.hasWorkToDo()) {
+ applyFSEvent(null, myInitialFSDelta);
+ return;
+ }
+ if (!dataStorageRoot.exists()) {
+ // invoked the very first time for this project. Force full rebuild
+ buildType = BuildType.PROJECT_REBUILD;
+ }
+
+ final boolean inMemoryMappingsDelta = System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null;
+ ProjectTimestamps projectTimestamps = null;
+ BuildDataManager dataManager = null;
+ try {
+ projectTimestamps = new ProjectTimestamps(dataStorageRoot);
+ dataManager = new BuildDataManager(dataStorageRoot, inMemoryMappingsDelta);
+ if (dataManager.versionDiffers()) {
+ forceCleanCaches = true;
+ msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Dependency data format has changed, project rebuild required"));
+ }
+ }
+ catch (Exception e) {
+ // second try
+ LOG.info(e);
+ if (projectTimestamps != null) {
+ projectTimestamps.close();
+ }
+ if (dataManager != null) {
+ dataManager.close();
+ }
+ forceCleanCaches = true;
+ FileUtil.delete(dataStorageRoot);
+ projectTimestamps = new ProjectTimestamps(dataStorageRoot);
+ dataManager = new BuildDataManager(dataStorageRoot, inMemoryMappingsDelta);
+ // second attempt succeded
+ msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage()));
+ }
+
+ final Project project = loadProject(projectPath);
+ final ProjectDescriptor pd = new ProjectDescriptor(project, fsState, projectTimestamps, dataManager, BuildLoggingManager.DEFAULT);
+ myProjectDescriptor = pd;
+ if (shouldApplyEvent) {
+ applyFSEvent(pd, myInitialFSDelta);
+ }
+
+
+ // free memory
+ myInitialFSDelta = null;
+ // ensure events from controller are processed after FSState initialization
+ myEventsProcessor.startProcessing();
+
+ for (int attempt = 0; attempt < 2; attempt++) {
+ if (forceCleanCaches && modules.isEmpty() && paths.isEmpty()) {
+ // if compilation scope is the whole project and cache rebuild is forced, use PROJECT_REBUILD for faster compilation
+ buildType = BuildType.PROJECT_REBUILD;
+ }
+
+ final Timestamps timestamps = pd.timestamps.getStorage();
+
+ final CompileScope compileScope = createCompilationScope(buildType, pd, timestamps, modules, artifacts, paths);
+ final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), timestamps, builderParams, cs, myConstantSearch);
+ builder.addMessageHandler(msgHandler);
+ try {
+ switch (buildType) {
+ case PROJECT_REBUILD:
+ builder.build(compileScope, false, true, forceCleanCaches);
+ break;
+
+ case FORCED_COMPILATION:
+ builder.build(compileScope, false, false, forceCleanCaches);
+ break;
+
+ case MAKE:
+ builder.build(compileScope, true, false, forceCleanCaches);
+ break;
+
+ case CLEAN:
+ //todo[nik]
+ // new ProjectBuilder(new GantBinding(), project).clean();
+ break;
+ }
+ break; // break attempts loop
+ }
+ catch (RebuildRequestedException e) {
+ if (attempt == 0) {
+ LOG.info(e);
+ forceCleanCaches = true;
+ }
+ else {
+ throw e;
+ }
+ }
+ }
+ }
+ finally {
+ saveData(fsState, dataStorageRoot);
+ }
+ }
+
+ private void saveData(final BuildFSState fsState, File dataStorageRoot) {
+ final boolean wasInterrupted = Thread.interrupted();
+ try {
+ saveFsState(dataStorageRoot, fsState, myLastEventOrdinal);
+ final ProjectDescriptor pd = myProjectDescriptor;
+ if (pd != null) {
+ pd.release();
+ }
+ }
+ finally {
+ if (wasInterrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void processFSEvent(final CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) {
+ myEventsProcessor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ applyFSEvent(myProjectDescriptor, event);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ });
+ }
+
+ public void processConstantSearchResult(CmdlineRemoteProto.Message.ControllerMessage.ConstantSearchResult result) {
+ final ConstantSearchFuture future = mySearchTasks.remove(Pair.create(result.getOwnerClassName(), result.getFieldName()));
+ if (future != null) {
+ if (result.getIsSuccess()) {
+ final List paths = result.getPathList();
+ final List files = new ArrayList(paths.size());
+ for (String path : paths) {
+ files.add(new File(path));
+ }
+ future.setResult(files);
+ }
+ else {
+ future.setDone();
+ }
+ }
+ }
+
+ private void applyFSEvent(ProjectDescriptor pd, @Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) throws IOException {
+ if (event == null) {
+ return;
+ }
+
+ if (pd != null) {
+ final Timestamps timestamps = pd.timestamps.getStorage();
+
+ for (String deleted : event.getDeletedPathsList()) {
+ final File file = new File(deleted);
+ final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
+ if (rd != null) {
+ if (Utils.IS_TEST_MODE) {
+ LOG.info("Applying deleted path from fs event: " + file.getPath());
+ }
+ pd.fsState.registerDeleted(rd.module, file, rd.isTestRoot, timestamps);
+ }
+ else {
+ if (Utils.IS_TEST_MODE) {
+ LOG.info("Skipping deleted path: " + file.getPath());
+ }
+ }
+ }
+ for (String changed : event.getChangedPathsList()) {
+ final File file = new File(changed);
+ final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
+ if (rd != null) {
+ if (Utils.IS_TEST_MODE) {
+ LOG.info("Applying dirty path from fs event: " + file.getPath());
+ }
+ pd.fsState.markDirty(file, rd, timestamps);
+ }
+ else {
+ if (Utils.IS_TEST_MODE) {
+ LOG.info("Skipping dirty path: " + file.getPath());
+ }
+ }
+ }
+ }
+
+ myLastEventOrdinal += 1;
+ }
+
+ private static void saveFsState(File dataStorageRoot, BuildFSState state, long lastEventOrdinal) {
+ final File file = new File(dataStorageRoot, FS_STATE_FILE);
+ try {
+ final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
+ final DataOutputStream out = new DataOutputStream(bytes);
+ try {
+ out.writeLong(lastEventOrdinal);
+ state.save(out);
+ }
+ finally {
+ out.close();
+ }
+
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file);
+ }
+ catch (FileNotFoundException e) {
+ FileUtil.createIfDoesntExist(file);
+ }
+
+ if (fos == null) {
+ fos = new FileOutputStream(file);
+ }
+ try {
+ fos.write(bytes.getInternalBuffer(), 0, bytes.size());
+ }
+ finally {
+ fos.close();
+ }
+
+ }
+ catch (Throwable e) {
+ LOG.error(e);
+ FileUtil.delete(file);
+ }
+ }
+
+ private boolean loadFsState(final BuildFSState fsState, File dataStorageRoot, CmdlineRemoteProto.Message.ControllerMessage.FSEvent initialEvent) {
+ boolean shouldApplyEvent = false;
+ final File file = new File(dataStorageRoot, FS_STATE_FILE);
+ try {
+ final InputStream fs = new FileInputStream(file);
+ byte[] bytes;
+ try {
+ bytes = FileUtil.loadBytes(fs, (int)file.length());
+ }
+ finally {
+ fs.close();
+ }
+
+ final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
+ try {
+ final long savedOrdinal = in.readLong();
+ if (initialEvent != null && (savedOrdinal + 1L == initialEvent.getOrdinal())) {
+ fsState.load(in);
+ myLastEventOrdinal = savedOrdinal;
+ shouldApplyEvent = true;
+ //applyFSEvent(pd, initialEvent);
+ }
+ else {
+ // either the first start or some events were lost, forcing scan
+ fsState.clearAll();
+ myLastEventOrdinal = initialEvent != null? initialEvent.getOrdinal() : 0L;
+ }
+ }
+ finally {
+ in.close();
+ }
+ return shouldApplyEvent; // successfully initialized
+
+ }
+ catch (FileNotFoundException ignored) {
+ }
+ catch (Throwable e) {
+ LOG.error(e);
+ }
+ myLastEventOrdinal = initialEvent != null? initialEvent.getOrdinal() : 0L;
+ fsState.clearAll();
+ return shouldApplyEvent;
+ }
+
+ private static boolean containsChanges(CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) {
+ return event.getChangedPathsCount() != 0 || event.getDeletedPathsCount() != 0;
+ }
+
+ private void finishBuild(Throwable error, boolean hadBuildErrors, boolean markedUptodateFiles) {
+ CmdlineRemoteProto.Message lastMessage = null;
+ try {
+ if (error != null) {
+ Throwable cause = error.getCause();
+ if (cause == null) {
+ cause = error;
+ }
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ cause.printStackTrace(new PrintStream(out));
+
+ final StringBuilder messageText = new StringBuilder();
+ messageText.append("Internal error: (").append(cause.getClass().getName()).append(") ").append(cause.getMessage());
+ final String trace = out.toString();
+ if (!trace.isEmpty()) {
+ messageText.append("\n").append(trace);
+ }
+ lastMessage = CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createFailure(messageText.toString(), cause));
+ }
+ else {
+ CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.SUCCESS;
+ if (myCanceled) {
+ status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.CANCELED;
+ }
+ else if (hadBuildErrors) {
+ status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.ERRORS;
+ }
+ else if (!markedUptodateFiles){
+ status = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.UP_TO_DATE;
+ }
+ lastMessage = CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createBuildCompletedEvent("build completed", status));
+ }
+ }
+ catch (Throwable e) {
+ lastMessage = CmdlineProtoUtil.toMessage(mySessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e));
+ }
+ finally {
+ try {
+ Channels.write(myChannel, lastMessage).await();
+ }
+ catch (InterruptedException e) {
+ LOG.info(e);
+ }
+ }
+ }
+
+ public void cancel() {
+ myCanceled = true;
+ }
+
+ @Override
+ public boolean isCanceled() {
+ return myCanceled;
+ }
+
+
+ private Project loadProject(String projectPath) {
+ final long start = System.currentTimeMillis();
+ try {
+ final Project project = new Project();
+
+ initSdksAndGlobalLibraries(project);
+
+ final File projectFile = new File(projectPath);
+
+ //String root = dirBased ? projectPath : projectFile.getParent();
+
+ final String loadPath = isDirectoryBased(projectFile) ? new File(projectFile, IDEA_PROJECT_DIRNAME).getPath() : projectPath;
+ IdeaProjectLoader.loadFromPath(project, loadPath, myPathVars, null, new SystemOutErrorReporter(false));
+ final String globalEncoding = myGlobalEncoding;
+ if (!StringUtil.isEmpty(globalEncoding) && project.getProjectCharset() == null) {
+ project.setProjectCharset(globalEncoding);
+ }
+ project.getIgnoredFilePatterns().loadFromString(myIgnorePatterns);
+ return project;
+ }
+ finally {
+ final long loadTime = System.currentTimeMillis() - start;
+ LOG.info("Project " + projectPath + " loaded in " + loadTime + " ms");
+ }
+ }
+
+ private void initSdksAndGlobalLibraries(Project project) {
+ final MethodClosure fakeClosure = new MethodClosure(new Object(), "hashCode");
+ for (GlobalLibrary library : myGlobalLibraries) {
+ if (library instanceof SdkLibrary) {
+ final SdkLibrary sdk = (SdkLibrary)library;
+ Node additionalData = null;
+ final String additionalXml = sdk.getAdditionalDataXml();
+ if (additionalXml != null) {
+ try {
+ additionalData = new XmlParser(false, false).parseText(additionalXml);
+ }
+ catch (Exception e) {
+ LOG.info(e);
+ }
+ }
+ final Sdk jdk = project.createSdk(sdk.getTypeName(), sdk.getName(), sdk.getVersion(), sdk.getHomePath(), additionalData);
+ if (jdk != null) {
+ jdk.setClasspath(sdk.getPaths());
+ }
+ else {
+ LOG.info("Failed to load SDK " + sdk.getName() + ", type: " + sdk.getTypeName());
+ }
+ }
+ else {
+ final Library lib = project.createGlobalLibrary(library.getName(), fakeClosure);
+ if (lib != null) {
+ lib.setClasspath(library.getPaths());
+ }
+ else {
+ LOG.info("Failed to load global library " + library.getName());
+ }
+ }
+ }
+ }
+
+ private static boolean isDirectoryBased(File projectFile) {
+ return !(projectFile.isFile() && projectFile.getName().endsWith(".ipr"));
+ }
+
+ private static CompileScope createCompilationScope(BuildType buildType,
+ ProjectDescriptor pd,
+ final Timestamps timestamps, Set modules,
+ Collection artifactNames,
+ Collection paths) throws Exception {
+ Set artifacts = new HashSet();
+ if (artifactNames.isEmpty() && buildType == BuildType.PROJECT_REBUILD) {
+ artifacts.addAll(pd.project.getArtifacts().values());
+ }
+ else {
+ final Map artifactMap = pd.project.getArtifacts();
+ for (String name : artifactNames) {
+ final Artifact artifact = artifactMap.get(name);
+ if (artifact != null && !StringUtil.isEmpty(artifact.getOutputPath())) {
+ artifacts.add(artifact);
+ }
+ }
+ }
+
+ final CompileScope compileScope;
+ if (buildType == BuildType.PROJECT_REBUILD || (modules.isEmpty() && paths.isEmpty())) {
+ compileScope = new AllProjectScope(pd.project, artifacts, buildType != BuildType.MAKE);
+ }
+ else {
+ final Set forcedModules;
+ if (!modules.isEmpty()) {
+ forcedModules = new HashSet();
+ for (Module m : pd.project.getModules().values()) {
+ if (modules.contains(m.getName())) {
+ forcedModules.add(m);
+ }
+ }
+ }
+ else {
+ forcedModules = Collections.emptySet();
+ }
+
+ final Map> filesToCompile;
+ if (!paths.isEmpty()) {
+ filesToCompile = new HashMap>();
+ for (String path : paths) {
+ final File file = new File(path);
+ final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(file);
+ if (rd != null) {
+ Set files = filesToCompile.get(rd.module);
+ if (files == null) {
+ files = new HashSet();
+ filesToCompile.put(rd.module, files);
+ }
+ files.add(file);
+ if (buildType == BuildType.FORCED_COMPILATION) {
+ pd.fsState.markDirty(file, rd, timestamps);
+ }
+ }
+ }
+ }
+ else {
+ filesToCompile = Collections.emptyMap();
+ }
+
+ if (filesToCompile.isEmpty()) {
+ compileScope = new ModulesScope(pd.project, forcedModules, artifacts, buildType != BuildType.MAKE);
+ }
+ else {
+ compileScope = new ModulesAndFilesScope(pd.project, forcedModules, filesToCompile, artifacts, buildType != BuildType.MAKE);
+ }
+ }
+ return compileScope;
+ }
+
+
+ private static BuildType convertCompileType(CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.Type compileType) {
+ switch (compileType) {
+ case CLEAN: return BuildType.CLEAN;
+ case MAKE: return BuildType.MAKE;
+ case REBUILD: return BuildType.PROJECT_REBUILD;
+ case FORCED_COMPILATION: return BuildType.FORCED_COMPILATION;
+ }
+ return BuildType.MAKE; // use make by default
+ }
+
+ private static class EventsProcessor extends SequentialTaskExecutor {
+ private final AtomicBoolean myProcessingEnabled = new AtomicBoolean(false);
+
+ EventsProcessor() {
+ super(SharedThreadPool.INSTANCE);
+ }
+
+ public void startProcessing() {
+ if (!myProcessingEnabled.getAndSet(true)) {
+ super.processQueue();
+ }
+ }
+
+ @Override
+ protected void processQueue() {
+ if (myProcessingEnabled.get()) {
+ super.processQueue();
+ }
+ }
+ }
+
+ private class ConstantSearch implements Callbacks.ConstantAffectionResolver {
+ @Nullable @Override
+ public Future request(String ownerClassName, String fieldName, int accessFlags, boolean fieldRemoved, boolean accessChanged) {
+ final CmdlineRemoteProto.Message.BuilderMessage.ConstantSearchTask.Builder task =
+ CmdlineRemoteProto.Message.BuilderMessage.ConstantSearchTask.newBuilder();
+ task.setOwnerClassName(ownerClassName);
+ task.setFieldName(fieldName);
+ task.setAccessFlags(accessFlags);
+ task.setIsAccessChanged(accessChanged);
+ task.setIsFieldRemoved(fieldRemoved);
+ final ConstantSearchFuture future = new ConstantSearchFuture();
+ final ConstantSearchFuture prev = mySearchTasks.put(new Pair(ownerClassName, fieldName), future);
+ if (prev != null) {
+ prev.setDone();
+ }
+ Channels.write(myChannel,
+ CmdlineProtoUtil.toMessage(
+ mySessionId, CmdlineRemoteProto.Message.BuilderMessage.newBuilder().setType(CmdlineRemoteProto.Message.BuilderMessage.Type.CONSTANT_SEARCH_TASK).setConstantSearchTask(task.build()).build()
+ )
+ );
+ return future;
+ }
+ }
+
+ private static class ConstantSearchFuture extends BasicFuture {
+ private volatile Callbacks.ConstantAffection myResult = Callbacks.ConstantAffection.EMPTY;
+
+ private ConstantSearchFuture() {
+ }
+
+ public void setResult(final Collection affectedFiles) {
+ myResult = new Callbacks.ConstantAffection(affectedFiles);
+ setDone();
+ }
+
+ @Override
+ public Callbacks.ConstantAffection get() throws InterruptedException, ExecutionException {
+ super.get();
+ return myResult;
+ }
+
+ @Override
+ public Callbacks.ConstantAffection get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ super.get(timeout, unit);
+ return myResult;
+ }
+ }
+}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java
index ac5615cc6d9d..046b30f3413c 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java
@@ -1,754 +1,758 @@
-package org.jetbrains.jps.incremental;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.LowMemoryWatcher;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.io.MappingFailedException;
-import com.intellij.util.io.PersistentEnumerator;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.ether.dependencyView.Callbacks;
-import org.jetbrains.jps.*;
-import org.jetbrains.jps.api.CanceledStatus;
-import org.jetbrains.jps.api.GlobalOptions;
-import org.jetbrains.jps.api.RequestFuture;
-import org.jetbrains.jps.api.SharedThreadPool;
-import org.jetbrains.jps.incremental.fs.RootDescriptor;
-import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
-import org.jetbrains.jps.incremental.java.JavaBuilder;
-import org.jetbrains.jps.incremental.java.JavaBuilderLogger;
-import org.jetbrains.jps.incremental.messages.BuildMessage;
-import org.jetbrains.jps.incremental.messages.CompilerMessage;
-import org.jetbrains.jps.incremental.messages.ProgressMessage;
-import org.jetbrains.jps.incremental.storage.BuildDataManager;
-import org.jetbrains.jps.incremental.storage.SourceToFormMapping;
-import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
-import org.jetbrains.jps.incremental.storage.Timestamps;
-import org.jetbrains.jps.server.ProjectDescriptor;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.*;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 9/17/11
- */
-public class IncProjectBuilder {
- private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder");
-
- public static final String COMPILE_SERVER_NAME = "COMPILE SERVER";
- private static final String CLASSPATH_INDEX_FINE_NAME = "classpath.index";
- private static final boolean GENERATE_CLASSPATH_INDEX = "true".equals(System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION));
-
- private final ProjectDescriptor myProjectDescriptor;
- private final BuilderRegistry myBuilderRegistry;
- private final Map myBuilderParams;
- private final CanceledStatus myCancelStatus;
- @Nullable private final Callbacks.ConstantAffectionResolver myConstantSearch;
- private ProjectChunks myProductionChunks;
- private ProjectChunks myTestChunks;
- private final List myMessageHandlers = new ArrayList();
- private final MessageHandler myMessageDispatcher = new MessageHandler() {
- public void processMessage(BuildMessage msg) {
- for (MessageHandler h : myMessageHandlers) {
- h.processMessage(msg);
- }
- }
- };
-
- private float myModulesProcessed = 0.0f;
- private final float myTotalModulesWork;
- private final int myTotalModuleLevelBuilderCount;
- private final List myAsyncTasks = new ArrayList();
- private final Timestamps myTimestamps;
-
- public IncProjectBuilder(ProjectDescriptor pd,
- BuilderRegistry builderRegistry,
- final Timestamps timestamps,
- Map builderParams,
- CanceledStatus cs, @Nullable Callbacks.ConstantAffectionResolver constantSearch) {
- myProjectDescriptor = pd;
- myBuilderRegistry = builderRegistry;
- myBuilderParams = builderParams;
- myCancelStatus = cs;
- myConstantSearch = constantSearch;
- myProductionChunks = new ProjectChunks(pd.project, ClasspathKind.PRODUCTION_COMPILE);
- myTestChunks = new ProjectChunks(pd.project, ClasspathKind.TEST_COMPILE);
- myTotalModulesWork = (float)pd.rootsIndex.getTotalModuleCount() * 2; /* multiply by 2 to reflect production and test sources */
- myTotalModuleLevelBuilderCount = builderRegistry.getModuleLevelBuilderCount();
- myTimestamps = timestamps;
- }
-
- public void addMessageHandler(MessageHandler handler) {
- myMessageHandlers.add(handler);
- }
-
- public void build(CompileScope scope, final boolean isMake, final boolean isProjectRebuild, boolean forceCleanCaches)
- throws RebuildRequestedException {
- final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Runnable() {
- @Override
- public void run() {
- myProjectDescriptor.dataManager.flush(false);
- myTimestamps.force();
- }
- });
- CompileContext context = null;
- try {
- context = createContext(scope, isMake, isProjectRebuild);
- runBuild(context, forceCleanCaches);
- myProjectDescriptor.dataManager.saveVersion();
- }
- catch (ProjectBuildException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof PersistentEnumerator.CorruptedException ||
- cause instanceof MappingFailedException ||
- cause instanceof IOException) {
- myMessageDispatcher.processMessage(new CompilerMessage(
- COMPILE_SERVER_NAME, BuildMessage.Kind.INFO,
- "Internal caches are corrupted or have outdated format, forcing project rebuild: " +
- e.getMessage())
- );
- throw new RebuildRequestedException(cause);
- }
- else {
- if (cause == null) {
- final String msg = e.getMessage();
- if (!StringUtil.isEmpty(msg)) {
- myMessageDispatcher.processMessage(new ProgressMessage(msg));
- }
- }
- else {
- myMessageDispatcher.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, cause));
- }
- }
- }
- finally {
- memWatcher.stop();
- flushContext(context);
- // wait for the async tasks
- for (Future task : myAsyncTasks) {
- try {
- task.get();
- }
- catch (Throwable th) {
- LOG.info(th);
- }
- }
- }
- }
-
- private static void flushContext(CompileContext context) {
- if (context != null) {
- context.getTimestamps().force();
- context.getDataManager().flush(false);
- }
- final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
- if (descriptor != null) {
- try {
- final RequestFuture future = descriptor.client.sendShutdownRequest();
- future.waitFor(500L, TimeUnit.MILLISECONDS);
- }
- finally {
- // ensure process is not running
- descriptor.process.destroyProcess();
- }
- ExternalJavacDescriptor.KEY.set(context, null);
- }
- //cleanupJavacNameTable();
- }
-
- private static boolean ourClenupFailed = false;
-
- private static void cleanupJavacNameTable() {
- try {
- if (JavaBuilder.USE_EMBEDDED_JAVAC && !ourClenupFailed) {
- final Field freelistField = Class.forName("com.sun.tools.javac.util.Name$Table").getDeclaredField("freelist");
- freelistField.setAccessible(true);
- freelistField.set(null, com.sun.tools.javac.util.List.nil());
- }
- }
- catch (Throwable e) {
- ourClenupFailed = true;
- //LOG.info(e);
- }
- }
-
- private float updateFractionBuilderFinished(final float delta) {
- myModulesProcessed += delta;
- return myModulesProcessed / myTotalModulesWork;
- }
-
- private void runBuild(CompileContext context, boolean forceCleanCaches) throws ProjectBuildException {
- context.setDone(0.0f);
-
- LOG.info("Building project '" + context.getProject().getProjectName() + "'; isRebuild:" + context.isProjectRebuild() + "; isMake:" + context.isMake());
-
- for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
- builder.buildStarted(context);
- }
- for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) {
- builder.buildStarted(context);
- }
-
- try {
- if (context.isProjectRebuild() || forceCleanCaches) {
- cleanOutputRoots(context);
- }
-
- context.processMessage(new ProgressMessage("Running 'before' tasks"));
- runTasks(context, myBuilderRegistry.getBeforeTasks());
-
- context.setCompilingTests(false);
- context.processMessage(new ProgressMessage("Checking production sources"));
- buildChunks(context, myProductionChunks);
-
- context.setCompilingTests(true);
- context.processMessage(new ProgressMessage("Checking test sources"));
- buildChunks(context, myTestChunks);
-
- context.processMessage(new ProgressMessage("Building project"));
- runProjectLevelBuilders(context);
-
- context.processMessage(new ProgressMessage("Running 'after' tasks"));
- runTasks(context, myBuilderRegistry.getAfterTasks());
-
- // cleanup output roots layout, commented for efficiency
- //final ModuleOutputRootsLayout outputRootsLayout = context.getDataManager().getOutputRootsLayout();
- //try {
- // final Iterator keysIterator = outputRootsLayout.getKeysIterator();
- // final Map modules = myProjectDescriptor.project.getModules();
- // while (keysIterator.hasNext()) {
- // final String moduleName = keysIterator.next();
- // if (modules.containsKey(moduleName)) {
- // outputRootsLayout.remove(moduleName);
- // }
- // }
- //}
- //catch (IOException e) {
- // throw new ProjectBuildException(e);
- //}
- }
- finally {
- for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
- builder.buildFinished(context);
- }
- for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) {
- builder.buildFinished(context);
- }
- context.processMessage(new ProgressMessage("Finished, saving caches..."));
- }
-
- }
-
- private CompileContext createContext(CompileScope scope, boolean isMake, final boolean isProjectRebuild) throws ProjectBuildException {
- final CompileContext context = new CompileContext(
- scope, myProjectDescriptor, isMake, isProjectRebuild, myProductionChunks, myTestChunks, myMessageDispatcher,
- myBuilderParams, myTimestamps, myCancelStatus
- );
- ModuleLevelBuilder.CONSTANT_SEARCH_SERVICE.set(context, myConstantSearch);
- return context;
- }
-
- private void cleanOutputRoots(CompileContext context) throws ProjectBuildException {
- // whole project is affected
- final boolean shouldClear = context.getProject().getCompilerConfiguration().isClearOutputDirectoryOnRebuild();
- try {
- if (shouldClear) {
- clearOutputs(context);
- }
- else {
- for (Module module : context.getProject().getModules().values()) {
- final String moduleName = module.getName();
- clearOutputFiles(context, moduleName, true);
- clearOutputFiles(context, moduleName, false);
- }
- }
- }
- catch (IOException e) {
- throw new ProjectBuildException("Error cleaning output files", e);
- }
-
- try {
- context.getTimestamps().clean();
- }
- catch (IOException e) {
- throw new ProjectBuildException("Error cleaning timestamps storage", e);
- }
- try {
- context.getDataManager().clean();
- }
- catch (IOException e) {
- throw new ProjectBuildException("Error cleaning compiler storages", e);
- }
- myProjectDescriptor.fsState.clearAll();
- }
-
- private static void clearOutputFiles(CompileContext context, final String moduleName, boolean forTests) throws IOException {
- final SourceToOutputMapping map = context.getDataManager().getSourceToOutputMap(moduleName, forTests);
- for (String srcPath : map.getKeys()) {
- final Collection outs = map.getState(srcPath);
- if (outs != null) {
- for (String out : outs) {
- new File(out).delete();
- }
- }
- }
- }
-
- private static void clearOutputs(CompileContext context) throws ProjectBuildException, IOException {
- final Collection modulesToClean = context.getProject().getModules().values();
- final Map>> rootsToDelete = new HashMap>>(); // map: outputRoot-> setOfPairs([module, isTest])
- final Set annotationOutputs = new HashSet(); // separate collection because no root intersection checks needed for annotation generated sources
- final Set allSourceRoots = new HashSet();
-
- final ProjectPaths paths = context.getProjectPaths();
-
- for (Module module : modulesToClean) {
- final File out = paths.getModuleOutputDir(module, false);
- if (out != null) {
- appendRootInfo(rootsToDelete, out, module, false);
- }
- final File testOut = paths.getModuleOutputDir(module, true);
- if (testOut != null) {
- appendRootInfo(rootsToDelete, testOut, module, true);
- }
-
- final AnnotationProcessingProfile profile = context.getAnnotationProcessingProfile(module);
- if (profile.isEnabled()) {
- File annotationOut =
- paths.getAnnotationProcessorGeneratedSourcesOutputDir(module, false, profile.getGeneratedSourcesDirName());
- if (annotationOut != null) {
- annotationOutputs.add(annotationOut);
- }
- annotationOut =
- paths.getAnnotationProcessorGeneratedSourcesOutputDir(module, true, profile.getGeneratedSourcesDirName());
- if (annotationOut != null) {
- annotationOutputs.add(annotationOut);
- }
- }
-
- final List moduleRoots = context.getModuleRoots(module);
- for (RootDescriptor d : moduleRoots) {
- allSourceRoots.add(d.root);
- }
- }
-
- // check that output and source roots are not overlapping
- final List filesToDelete = new ArrayList();
- for (Map.Entry>> entry : rootsToDelete.entrySet()) {
- context.checkCanceled();
- boolean okToDelete = true;
- final File outputRoot = entry.getKey();
- if (PathUtil.isUnder(allSourceRoots, outputRoot)) {
- okToDelete = false;
- }
- else {
- final Set _outRoot = Collections.singleton(outputRoot);
- for (File srcRoot : allSourceRoots) {
- if (PathUtil.isUnder(_outRoot, srcRoot)) {
- okToDelete = false;
- break;
- }
- }
- }
- if (okToDelete) {
- // do not delete output root itself to avoid lots of unnecessary "roots_changed" events in IDEA
- final File[] children = outputRoot.listFiles();
- if (children != null) {
- filesToDelete.addAll(Arrays.asList(children));
- }
- }
- else {
- context.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, BuildMessage.Kind.WARNING, "Output path " +
- outputRoot.getPath() +
- " intersects with a source root. The output cannot be cleaned."));
- // clean only those files we are aware of
- for (Pair info : entry.getValue()) {
- clearOutputFiles(context, info.first, info.second);
- }
- }
- }
-
- for (File annotationOutput : annotationOutputs) {
- // do not delete output root itself to avoid lots of unnecessary "roots_changed" events in IDEA
- final File[] children = annotationOutput.listFiles();
- if (children != null) {
- filesToDelete.addAll(Arrays.asList(children));
- }
- }
-
- context.processMessage(new ProgressMessage("Cleaning output directories..."));
- FileUtil.asyncDelete(filesToDelete);
- }
-
- private static void appendRootInfo(Map>> rootsToDelete, File out, Module module, boolean isTest) {
- Set> infos = rootsToDelete.get(out);
- if (infos == null) {
- infos = new HashSet>();
- rootsToDelete.put(out, infos);
- }
- infos.add(Pair.create(module.getName(), isTest));
- }
-
- private static void runTasks(CompileContext context, final List tasks) throws ProjectBuildException {
- for (BuildTask task : tasks) {
- task.build(context);
- }
- }
-
- private void buildChunks(CompileContext context, ProjectChunks chunks) throws ProjectBuildException {
- final CompileScope scope = context.getScope();
- for (ModuleChunk chunk : chunks.getChunkList()) {
- if (scope.isAffected(chunk)) {
- buildChunk(context, chunk);
- }
- else {
- final float fraction = updateFractionBuilderFinished(chunk.getModules().size());
- context.setDone(fraction);
- }
- }
- }
-
- private void buildChunk(CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
- boolean doneSomething = false;
- try {
- context.ensureFSStateInitialized(chunk);
- if (context.isMake()) {
- processDeletedPaths(context, chunk);
- doneSomething |= context.hasRemovedSources();
- }
-
- context.onChunkBuildStart(chunk);
-
- doneSomething = runModuleLevelBuilders(context, chunk);
- }
- catch (ProjectBuildException e) {
- throw e;
- }
- catch (Exception e) {
- throw new ProjectBuildException(e);
- }
- finally {
- try {
- for (BuilderCategory category : BuilderCategory.values()) {
- for (ModuleLevelBuilder builder : myBuilderRegistry.getBuilders(category)) {
- builder.cleanupResources(context, chunk);
- }
- }
- }
- finally {
- try {
- context.onChunkBuildComplete(chunk);
- }
- catch (Exception e) {
- throw new ProjectBuildException(e);
- }
- finally {
- final Collection tempRoots = context.getRootsIndex().clearTempRoots();
- if (!tempRoots.isEmpty()) {
- final Set rootFiles = new HashSet();
- for (RootDescriptor rd : tempRoots) {
- rootFiles.add(rd.root);
- context.getProjectDescriptor().fsState.clearRecompile(rd);
- }
- FileUtil.asyncDelete(rootFiles);
- }
-
- try {
- // restore deleted paths that were not procesesd by 'integrate'
- final Map> map = Utils.REMOVED_SOURCES_KEY.get(context);
- if (map != null) {
- final boolean forTests = context.isCompilingTests();
- for (Map.Entry> entry : map.entrySet()) {
- final String moduleName = entry.getKey();
- final Collection paths = entry.getValue();
- if (paths != null) {
- for (String path : paths) {
- myProjectDescriptor.fsState.registerDeleted(moduleName, new File(path), forTests, null);
- }
- }
- }
- }
- }
- catch (IOException e) {
- throw new ProjectBuildException(e);
- }
-
- Utils.REMOVED_SOURCES_KEY.set(context, null);
-
- if (doneSomething && GENERATE_CLASSPATH_INDEX) {
- final boolean forTests = context.isCompilingTests();
- final Future> future = SharedThreadPool.INSTANCE.submit(new Runnable() {
- @Override
- public void run() {
- createClasspathIndex(chunk, forTests);
- }
- });
- myAsyncTasks.add(future);
- }
- }
- }
- }
- }
-
- private static void createClasspathIndex(final ModuleChunk chunk, boolean forTests) {
- final Set outputPaths = new LinkedHashSet();
- for (Module module : chunk.getModules()) {
- final String out = forTests ? module.getTestOutputPath() : module.getOutputPath();
- if (out != null) {
- outputPaths.add(new File(out));
- }
- }
- for (File outputRoot : outputPaths) {
- try {
- BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outputRoot, CLASSPATH_INDEX_FINE_NAME)));
- try {
- writeIndex(writer, outputRoot, "");
- }
- finally {
- writer.close();
- }
- }
- catch (IOException e) {
- // Ignore. Failed to create optional classpath index
- }
- }
- }
-
- private static void writeIndex(final BufferedWriter writer, final File file, final String path) throws IOException {
- writer.write(path);
- writer.write('\n');
- final File[] files = file.listFiles();
- if (files != null) {
- for (File child : files) {
- final String _path = path.isEmpty() ? child.getName() : path + "/" + child.getName();
- writeIndex(writer, child, _path);
- }
- }
- }
-
-
- private void processDeletedPaths(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
- try {
- // cleanup outputs
- final Map> removedSources = new HashMap>();
-
- for (Module module : chunk.getModules()) {
- final Collection deletedPaths = myProjectDescriptor.fsState.getAndClearDeletedPaths(module.getName(),
- context.isCompilingTests());
- if (deletedPaths.isEmpty()) {
- continue;
- }
- removedSources.put(module.getName(), deletedPaths);
-
- final SourceToOutputMapping sourceToOutputStorage = context.getDataManager().getSourceToOutputMap(module.getName(), context.isCompilingTests());
- // actually delete outputs associated with removed paths
- for (String deletedSource : deletedPaths) {
- // deleting outputs corresponding to non-existing source
- final Collection outputs = sourceToOutputStorage.getState(deletedSource);
-
- if (outputs != null) {
- final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
- if (logger.isEnabled()) {
- if (outputs.size() > 0) {
- final String[] buffer = new String[outputs.size()];
- int i = 0;
- for (final String o : outputs) {
- buffer[i++] = o;
- }
- Arrays.sort(buffer);
- logger.log("Cleaning output files:");
- for (final String o : buffer) {
- logger.log(o);
- }
- logger.log("End of files");
- }
- }
-
- for (String output : outputs) {
- new File(output).delete();
- }
- }
-
- // check if deleted source was associated with a form
- final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap();
- final String formPath = sourceToFormMap.getState(deletedSource);
- if (formPath != null) {
- final File formFile = new File(formPath);
- if (formFile.exists()) {
- context.markDirty(formFile);
- }
- sourceToFormMap.remove(deletedSource);
- }
- }
- }
- if (!removedSources.isEmpty()) {
- final Map> existing = Utils.REMOVED_SOURCES_KEY.get(context);
- if (existing != null) {
- for (Map.Entry> entry : existing.entrySet()) {
- final Collection paths = removedSources.get(entry.getKey());
- if (paths != null) {
- paths.addAll(entry.getValue());
- }
- else {
- removedSources.put(entry.getKey(), entry.getValue());
- }
- }
- }
- Utils.REMOVED_SOURCES_KEY.set(context, removedSources);
- }
- }
- catch (IOException e) {
- throw new ProjectBuildException(e);
- }
- }
-
- // return true if changed something, false otherwise
- private boolean runModuleLevelBuilders(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
- boolean doneSomething = false;
- boolean rebuildFromScratchRequested = false;
- float stageCount = myTotalModuleLevelBuilderCount;
- final int modulesInChunk = chunk.getModules().size();
- int buildersPassed = 0;
- boolean nextPassRequired;
- do {
- nextPassRequired = false;
- context.beforeCompileRound(chunk);
-
- if (!context.isProjectRebuild()) {
- syncOutputFiles(context, chunk);
- }
-
- BUILDER_CATEGORY_LOOP:
- for (BuilderCategory category : BuilderCategory.values()) {
- final List builders = myBuilderRegistry.getBuilders(category);
- if (builders.isEmpty()) {
- continue;
- }
-
- for (ModuleLevelBuilder builder : builders) {
- if (context.isMake()) {
- processDeletedPaths(context, chunk);
- }
- final ModuleLevelBuilder.ExitCode buildResult = builder.build(context, chunk);
-
- doneSomething |= (buildResult != ModuleLevelBuilder.ExitCode.NOTHING_DONE);
-
- if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
- throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
- }
- context.checkCanceled();
- if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
- if (!nextPassRequired) {
- // recalculate basis
- myModulesProcessed -= (buildersPassed * modulesInChunk) / stageCount;
- stageCount += myTotalModuleLevelBuilderCount;
- myModulesProcessed += (buildersPassed * modulesInChunk) / stageCount;
- }
- nextPassRequired = true;
- }
- else if (buildResult == ModuleLevelBuilder.ExitCode.CHUNK_REBUILD_REQUIRED) {
- if (!rebuildFromScratchRequested && !context.isProjectRebuild()) {
- LOG.info("Builder " + builder.getDescription() + " requested rebuild of module chunk " + chunk.getName());
- // allow rebuild from scratch only once per chunk
- rebuildFromScratchRequested = true;
- try {
- // forcibly mark all files in the chunk dirty
- context.markDirty(chunk);
- // reverting to the beginning
- myModulesProcessed -= (buildersPassed * modulesInChunk) / stageCount;
- stageCount = myTotalModuleLevelBuilderCount;
- buildersPassed = 0;
- nextPassRequired = true;
- break BUILDER_CATEGORY_LOOP;
- }
- catch (Exception e) {
- throw new ProjectBuildException(e);
- }
- }
- else {
- context.getLoggingManager().getJavaBuilderLogger().log(
- "Builder " + builder.getDescription() + " requested second chunk rebuild");
- }
- }
-
- buildersPassed++;
- final float fraction = updateFractionBuilderFinished(modulesInChunk / (stageCount));
- context.setDone(fraction);
- }
- }
- }
- while (nextPassRequired);
-
- return doneSomething;
- }
-
- private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException {
- for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
- builder.build(context);
- context.checkCanceled();
- }
- }
-
- private static void syncOutputFiles(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
- final BuildDataManager dataManager = context.getDataManager();
- final boolean compilingTests = context.isCompilingTests();
- try {
- final Collection allOutputs = new LinkedList();
-
- context.processFilesToRecompile(chunk, new FileProcessor() {
- private final Map storageMap = new HashMap();
-
- @Override
- public boolean apply(Module module, File file, String sourceRoot) throws IOException {
- SourceToOutputMapping srcToOut = storageMap.get(module);
- if (srcToOut == null) {
- srcToOut = dataManager.getSourceToOutputMap(module.getName(), compilingTests);
- storageMap.put(module, srcToOut);
- }
- final String srcPath = FileUtil.toSystemIndependentName(file.getPath());
- final Collection outputs = srcToOut.getState(srcPath);
-
- if (outputs != null) {
- final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
- for (String output : outputs) {
- if (logger.isEnabled()) {
- allOutputs.add(output);
- }
- new File(output).delete();
- }
- srcToOut.remove(srcPath);
- }
- return true;
- }
- });
-
- final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
- if (logger.isEnabled()) {
- if (context.isMake() && allOutputs.size() > 0) {
- logger.log("Cleaning output files:");
- final String[] buffer = new String[allOutputs.size()];
- int i = 0;
- for (String output : allOutputs) {
- buffer[i++] = output;
- }
- Arrays.sort(buffer);
- for (String output : buffer) {
- logger.log(output);
- }
- logger.log("End of files");
- }
- }
- }
- catch (Exception e) {
- throw new ProjectBuildException(e);
- }
- }
-}
+package org.jetbrains.jps.incremental;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.LowMemoryWatcher;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.io.MappingFailedException;
+import com.intellij.util.io.PersistentEnumerator;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.ether.dependencyView.Callbacks;
+import org.jetbrains.jps.*;
+import org.jetbrains.jps.api.CanceledStatus;
+import org.jetbrains.jps.api.GlobalOptions;
+import org.jetbrains.jps.api.RequestFuture;
+import org.jetbrains.jps.api.SharedThreadPool;
+import org.jetbrains.jps.incremental.fs.RootDescriptor;
+import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
+import org.jetbrains.jps.incremental.java.JavaBuilder;
+import org.jetbrains.jps.incremental.java.JavaBuilderLogger;
+import org.jetbrains.jps.incremental.messages.BuildMessage;
+import org.jetbrains.jps.incremental.messages.CompilerMessage;
+import org.jetbrains.jps.incremental.messages.ProgressMessage;
+import org.jetbrains.jps.incremental.storage.BuildDataManager;
+import org.jetbrains.jps.incremental.storage.SourceToFormMapping;
+import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
+import org.jetbrains.jps.incremental.storage.Timestamps;
+import org.jetbrains.jps.server.ProjectDescriptor;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: 9/17/11
+ */
+public class IncProjectBuilder {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder");
+
+ public static final String BUILD_NAME = "EXTERNAL BUILD";
+ private static final String CLASSPATH_INDEX_FINE_NAME = "classpath.index";
+ private static final boolean GENERATE_CLASSPATH_INDEX = "true".equals(System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION));
+
+ private final ProjectDescriptor myProjectDescriptor;
+ private final BuilderRegistry myBuilderRegistry;
+ private final Map myBuilderParams;
+ private final CanceledStatus myCancelStatus;
+ @Nullable private final Callbacks.ConstantAffectionResolver myConstantSearch;
+ private ProjectChunks myProductionChunks;
+ private ProjectChunks myTestChunks;
+ private final List myMessageHandlers = new ArrayList();
+ private final MessageHandler myMessageDispatcher = new MessageHandler() {
+ public void processMessage(BuildMessage msg) {
+ for (MessageHandler h : myMessageHandlers) {
+ h.processMessage(msg);
+ }
+ }
+ };
+
+ private float myModulesProcessed = 0.0f;
+ private final float myTotalModulesWork;
+ private final int myTotalModuleLevelBuilderCount;
+ private final List myAsyncTasks = new ArrayList();
+ private final Timestamps myTimestamps;
+
+ public IncProjectBuilder(ProjectDescriptor pd,
+ BuilderRegistry builderRegistry,
+ final Timestamps timestamps,
+ Map builderParams,
+ CanceledStatus cs, @Nullable Callbacks.ConstantAffectionResolver constantSearch) {
+ myProjectDescriptor = pd;
+ myBuilderRegistry = builderRegistry;
+ myBuilderParams = builderParams;
+ myCancelStatus = cs;
+ myConstantSearch = constantSearch;
+ myProductionChunks = new ProjectChunks(pd.project, ClasspathKind.PRODUCTION_COMPILE);
+ myTestChunks = new ProjectChunks(pd.project, ClasspathKind.TEST_COMPILE);
+ myTotalModulesWork = (float)pd.rootsIndex.getTotalModuleCount() * 2; /* multiply by 2 to reflect production and test sources */
+ myTotalModuleLevelBuilderCount = builderRegistry.getModuleLevelBuilderCount();
+ myTimestamps = timestamps;
+ }
+
+ public void addMessageHandler(MessageHandler handler) {
+ myMessageHandlers.add(handler);
+ }
+
+ public void build(CompileScope scope, final boolean isMake, final boolean isProjectRebuild, boolean forceCleanCaches)
+ throws RebuildRequestedException {
+ final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Runnable() {
+ @Override
+ public void run() {
+ myProjectDescriptor.dataManager.flush(false);
+ myTimestamps.force();
+ }
+ });
+ CompileContext context = null;
+ try {
+ context = createContext(scope, isMake, isProjectRebuild);
+ runBuild(context, forceCleanCaches);
+ myProjectDescriptor.dataManager.saveVersion();
+ }
+ catch (ProjectBuildException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof PersistentEnumerator.CorruptedException ||
+ cause instanceof MappingFailedException ||
+ cause instanceof IOException) {
+ myMessageDispatcher.processMessage(new CompilerMessage(
+ BUILD_NAME, BuildMessage.Kind.INFO,
+ "Internal caches are corrupted or have outdated format, forcing project rebuild: " +
+ e.getMessage())
+ );
+ throw new RebuildRequestedException(cause);
+ }
+ else {
+ if (cause == null) {
+ final String msg = e.getMessage();
+ if (!StringUtil.isEmpty(msg)) {
+ myMessageDispatcher.processMessage(new ProgressMessage(msg));
+ }
+ }
+ else {
+ myMessageDispatcher.processMessage(new CompilerMessage(BUILD_NAME, cause));
+ }
+ }
+ }
+ finally {
+ memWatcher.stop();
+ flushContext(context);
+ // wait for the async tasks
+ for (Future task : myAsyncTasks) {
+ try {
+ task.get();
+ }
+ catch (Throwable th) {
+ LOG.info(th);
+ }
+ }
+ }
+ }
+
+ private static void flushContext(CompileContext context) {
+ if (context != null) {
+ context.getTimestamps().force();
+ context.getDataManager().flush(false);
+ }
+ final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
+ if (descriptor != null) {
+ try {
+ final RequestFuture future = descriptor.client.sendShutdownRequest();
+ future.waitFor(500L, TimeUnit.MILLISECONDS);
+ }
+ finally {
+ // ensure process is not running
+ descriptor.process.destroyProcess();
+ }
+ ExternalJavacDescriptor.KEY.set(context, null);
+ }
+ //cleanupJavacNameTable();
+ }
+
+ private static boolean ourClenupFailed = false;
+
+ private static void cleanupJavacNameTable() {
+ try {
+ if (JavaBuilder.USE_EMBEDDED_JAVAC && !ourClenupFailed) {
+ final Field freelistField = Class.forName("com.sun.tools.javac.util.Name$Table").getDeclaredField("freelist");
+ freelistField.setAccessible(true);
+ freelistField.set(null, com.sun.tools.javac.util.List.nil());
+ }
+ }
+ catch (Throwable e) {
+ ourClenupFailed = true;
+ //LOG.info(e);
+ }
+ }
+
+ private float updateFractionBuilderFinished(final float delta) {
+ myModulesProcessed += delta;
+ return myModulesProcessed / myTotalModulesWork;
+ }
+
+ private void runBuild(CompileContext context, boolean forceCleanCaches) throws ProjectBuildException {
+ context.setDone(0.0f);
+
+ LOG.info("Building project '" + context.getProject().getProjectName() + "'; isRebuild:" + context.isProjectRebuild() + "; isMake:" + context.isMake());
+
+ for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
+ builder.buildStarted(context);
+ }
+ for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) {
+ builder.buildStarted(context);
+ }
+
+ try {
+ if (context.isProjectRebuild() || forceCleanCaches) {
+ cleanOutputRoots(context);
+ }
+
+ context.processMessage(new ProgressMessage("Running 'before' tasks"));
+ runTasks(context, myBuilderRegistry.getBeforeTasks());
+
+ context.setCompilingTests(false);
+ context.processMessage(new ProgressMessage("Checking production sources"));
+ buildChunks(context, myProductionChunks);
+
+ context.setCompilingTests(true);
+ context.processMessage(new ProgressMessage("Checking test sources"));
+ buildChunks(context, myTestChunks);
+
+ context.processMessage(new ProgressMessage("Building project"));
+ runProjectLevelBuilders(context);
+
+ context.processMessage(new ProgressMessage("Running 'after' tasks"));
+ runTasks(context, myBuilderRegistry.getAfterTasks());
+
+ // cleanup output roots layout, commented for efficiency
+ //final ModuleOutputRootsLayout outputRootsLayout = context.getDataManager().getOutputRootsLayout();
+ //try {
+ // final Iterator keysIterator = outputRootsLayout.getKeysIterator();
+ // final Map modules = myProjectDescriptor.project.getModules();
+ // while (keysIterator.hasNext()) {
+ // final String moduleName = keysIterator.next();
+ // if (modules.containsKey(moduleName)) {
+ // outputRootsLayout.remove(moduleName);
+ // }
+ // }
+ //}
+ //catch (IOException e) {
+ // throw new ProjectBuildException(e);
+ //}
+ }
+ finally {
+ for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
+ builder.buildFinished(context);
+ }
+ for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) {
+ builder.buildFinished(context);
+ }
+ context.processMessage(new ProgressMessage("Finished, saving caches..."));
+ }
+
+ }
+
+ private CompileContext createContext(CompileScope scope, boolean isMake, final boolean isProjectRebuild) throws ProjectBuildException {
+ final CompileContext context = new CompileContext(
+ scope, myProjectDescriptor, isMake, isProjectRebuild, myProductionChunks, myTestChunks, myMessageDispatcher,
+ myBuilderParams, myTimestamps, myCancelStatus
+ );
+ ModuleLevelBuilder.CONSTANT_SEARCH_SERVICE.set(context, myConstantSearch);
+ return context;
+ }
+
+ private void cleanOutputRoots(CompileContext context) throws ProjectBuildException {
+ // whole project is affected
+ final boolean shouldClear = context.getProject().getCompilerConfiguration().isClearOutputDirectoryOnRebuild();
+ try {
+ if (shouldClear) {
+ clearOutputs(context);
+ }
+ else {
+ for (Module module : context.getProject().getModules().values()) {
+ final String moduleName = module.getName();
+ clearOutputFiles(context, moduleName, true);
+ clearOutputFiles(context, moduleName, false);
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new ProjectBuildException("Error cleaning output files", e);
+ }
+
+ try {
+ context.getTimestamps().clean();
+ }
+ catch (IOException e) {
+ throw new ProjectBuildException("Error cleaning timestamps storage", e);
+ }
+ try {
+ context.getDataManager().clean();
+ }
+ catch (IOException e) {
+ throw new ProjectBuildException("Error cleaning compiler storages", e);
+ }
+ myProjectDescriptor.fsState.clearAll();
+ }
+
+ private static void clearOutputFiles(CompileContext context, final String moduleName, boolean forTests) throws IOException {
+ final SourceToOutputMapping map = context.getDataManager().getSourceToOutputMap(moduleName, forTests);
+ for (String srcPath : map.getKeys()) {
+ final Collection outs = map.getState(srcPath);
+ if (outs != null) {
+ for (String out : outs) {
+ new File(out).delete();
+ }
+ }
+ }
+ }
+
+ private void clearOutputs(CompileContext context) throws ProjectBuildException, IOException {
+ final Collection modulesToClean = context.getProject().getModules().values();
+ final Map>> rootsToDelete = new HashMap>>(); // map: outputRoot-> setOfPairs([module, isTest])
+ final Set annotationOutputs = new HashSet(); // separate collection because no root intersection checks needed for annotation generated sources
+ final Set allSourceRoots = new HashSet();
+
+ final ProjectPaths paths = context.getProjectPaths();
+
+ for (Module module : modulesToClean) {
+ final File out = paths.getModuleOutputDir(module, false);
+ if (out != null) {
+ appendRootInfo(rootsToDelete, out, module, false);
+ }
+ final File testOut = paths.getModuleOutputDir(module, true);
+ if (testOut != null) {
+ appendRootInfo(rootsToDelete, testOut, module, true);
+ }
+
+ final AnnotationProcessingProfile profile = context.getAnnotationProcessingProfile(module);
+ if (profile.isEnabled()) {
+ File annotationOut =
+ paths.getAnnotationProcessorGeneratedSourcesOutputDir(module, false, profile.getGeneratedSourcesDirName());
+ if (annotationOut != null) {
+ annotationOutputs.add(annotationOut);
+ }
+ annotationOut =
+ paths.getAnnotationProcessorGeneratedSourcesOutputDir(module, true, profile.getGeneratedSourcesDirName());
+ if (annotationOut != null) {
+ annotationOutputs.add(annotationOut);
+ }
+ }
+
+ final List moduleRoots = context.getModuleRoots(module);
+ for (RootDescriptor d : moduleRoots) {
+ allSourceRoots.add(d.root);
+ }
+ }
+
+ // check that output and source roots are not overlapping
+ final List filesToDelete = new ArrayList();
+ for (Map.Entry>> entry : rootsToDelete.entrySet()) {
+ context.checkCanceled();
+ boolean okToDelete = true;
+ final File outputRoot = entry.getKey();
+ if (PathUtil.isUnder(allSourceRoots, outputRoot)) {
+ okToDelete = false;
+ }
+ else {
+ final Set _outRoot = Collections.singleton(outputRoot);
+ for (File srcRoot : allSourceRoots) {
+ if (PathUtil.isUnder(_outRoot, srcRoot)) {
+ okToDelete = false;
+ break;
+ }
+ }
+ }
+ if (okToDelete) {
+ // do not delete output root itself to avoid lots of unnecessary "roots_changed" events in IDEA
+ final File[] children = outputRoot.listFiles();
+ if (children != null) {
+ filesToDelete.addAll(Arrays.asList(children));
+ }
+ }
+ else {
+ context.processMessage(new CompilerMessage(BUILD_NAME, BuildMessage.Kind.WARNING, "Output path " +
+ outputRoot.getPath() +
+ " intersects with a source root. The output cannot be cleaned."));
+ // clean only those files we are aware of
+ for (Pair info : entry.getValue()) {
+ clearOutputFiles(context, info.first, info.second);
+ }
+ }
+ }
+
+ for (File annotationOutput : annotationOutputs) {
+ // do not delete output root itself to avoid lots of unnecessary "roots_changed" events in IDEA
+ final File[] children = annotationOutput.listFiles();
+ if (children != null) {
+ filesToDelete.addAll(Arrays.asList(children));
+ }
+ }
+
+ context.processMessage(new ProgressMessage("Cleaning output directories..."));
+ myAsyncTasks.add(
+ FileUtil.asyncDelete(filesToDelete)
+ );
+ }
+
+ private static void appendRootInfo(Map>> rootsToDelete, File out, Module module, boolean isTest) {
+ Set> infos = rootsToDelete.get(out);
+ if (infos == null) {
+ infos = new HashSet>();
+ rootsToDelete.put(out, infos);
+ }
+ infos.add(Pair.create(module.getName(), isTest));
+ }
+
+ private static void runTasks(CompileContext context, final List tasks) throws ProjectBuildException {
+ for (BuildTask task : tasks) {
+ task.build(context);
+ }
+ }
+
+ private void buildChunks(CompileContext context, ProjectChunks chunks) throws ProjectBuildException {
+ final CompileScope scope = context.getScope();
+ for (ModuleChunk chunk : chunks.getChunkList()) {
+ if (scope.isAffected(chunk)) {
+ buildChunk(context, chunk);
+ }
+ else {
+ final float fraction = updateFractionBuilderFinished(chunk.getModules().size());
+ context.setDone(fraction);
+ }
+ }
+ }
+
+ private void buildChunk(CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
+ boolean doneSomething = false;
+ try {
+ context.ensureFSStateInitialized(chunk);
+ if (context.isMake()) {
+ processDeletedPaths(context, chunk);
+ doneSomething |= context.hasRemovedSources();
+ }
+
+ context.onChunkBuildStart(chunk);
+
+ doneSomething = runModuleLevelBuilders(context, chunk);
+ }
+ catch (ProjectBuildException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new ProjectBuildException(e);
+ }
+ finally {
+ try {
+ for (BuilderCategory category : BuilderCategory.values()) {
+ for (ModuleLevelBuilder builder : myBuilderRegistry.getBuilders(category)) {
+ builder.cleanupResources(context, chunk);
+ }
+ }
+ }
+ finally {
+ try {
+ context.onChunkBuildComplete(chunk);
+ }
+ catch (Exception e) {
+ throw new ProjectBuildException(e);
+ }
+ finally {
+ final Collection tempRoots = context.getRootsIndex().clearTempRoots();
+ if (!tempRoots.isEmpty()) {
+ final Set rootFiles = new HashSet();
+ for (RootDescriptor rd : tempRoots) {
+ rootFiles.add(rd.root);
+ context.getProjectDescriptor().fsState.clearRecompile(rd);
+ }
+ myAsyncTasks.add(
+ FileUtil.asyncDelete(rootFiles)
+ );
+ }
+
+ try {
+ // restore deleted paths that were not procesesd by 'integrate'
+ final Map> map = Utils.REMOVED_SOURCES_KEY.get(context);
+ if (map != null) {
+ final boolean forTests = context.isCompilingTests();
+ for (Map.Entry> entry : map.entrySet()) {
+ final String moduleName = entry.getKey();
+ final Collection paths = entry.getValue();
+ if (paths != null) {
+ for (String path : paths) {
+ myProjectDescriptor.fsState.registerDeleted(moduleName, new File(path), forTests, null);
+ }
+ }
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new ProjectBuildException(e);
+ }
+
+ Utils.REMOVED_SOURCES_KEY.set(context, null);
+
+ if (doneSomething && GENERATE_CLASSPATH_INDEX) {
+ final boolean forTests = context.isCompilingTests();
+ final Future> future = SharedThreadPool.INSTANCE.submit(new Runnable() {
+ @Override
+ public void run() {
+ createClasspathIndex(chunk, forTests);
+ }
+ });
+ myAsyncTasks.add(future);
+ }
+ }
+ }
+ }
+ }
+
+ private static void createClasspathIndex(final ModuleChunk chunk, boolean forTests) {
+ final Set outputPaths = new LinkedHashSet();
+ for (Module module : chunk.getModules()) {
+ final String out = forTests ? module.getTestOutputPath() : module.getOutputPath();
+ if (out != null) {
+ outputPaths.add(new File(out));
+ }
+ }
+ for (File outputRoot : outputPaths) {
+ try {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outputRoot, CLASSPATH_INDEX_FINE_NAME)));
+ try {
+ writeIndex(writer, outputRoot, "");
+ }
+ finally {
+ writer.close();
+ }
+ }
+ catch (IOException e) {
+ // Ignore. Failed to create optional classpath index
+ }
+ }
+ }
+
+ private static void writeIndex(final BufferedWriter writer, final File file, final String path) throws IOException {
+ writer.write(path);
+ writer.write('\n');
+ final File[] files = file.listFiles();
+ if (files != null) {
+ for (File child : files) {
+ final String _path = path.isEmpty() ? child.getName() : path + "/" + child.getName();
+ writeIndex(writer, child, _path);
+ }
+ }
+ }
+
+
+ private void processDeletedPaths(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
+ try {
+ // cleanup outputs
+ final Map> removedSources = new HashMap>();
+
+ for (Module module : chunk.getModules()) {
+ final Collection deletedPaths = myProjectDescriptor.fsState.getAndClearDeletedPaths(module.getName(),
+ context.isCompilingTests());
+ if (deletedPaths.isEmpty()) {
+ continue;
+ }
+ removedSources.put(module.getName(), deletedPaths);
+
+ final SourceToOutputMapping sourceToOutputStorage = context.getDataManager().getSourceToOutputMap(module.getName(), context.isCompilingTests());
+ // actually delete outputs associated with removed paths
+ for (String deletedSource : deletedPaths) {
+ // deleting outputs corresponding to non-existing source
+ final Collection outputs = sourceToOutputStorage.getState(deletedSource);
+
+ if (outputs != null) {
+ final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
+ if (logger.isEnabled()) {
+ if (outputs.size() > 0) {
+ final String[] buffer = new String[outputs.size()];
+ int i = 0;
+ for (final String o : outputs) {
+ buffer[i++] = o;
+ }
+ Arrays.sort(buffer);
+ logger.log("Cleaning output files:");
+ for (final String o : buffer) {
+ logger.log(o);
+ }
+ logger.log("End of files");
+ }
+ }
+
+ for (String output : outputs) {
+ new File(output).delete();
+ }
+ }
+
+ // check if deleted source was associated with a form
+ final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap();
+ final String formPath = sourceToFormMap.getState(deletedSource);
+ if (formPath != null) {
+ final File formFile = new File(formPath);
+ if (formFile.exists()) {
+ context.markDirty(formFile);
+ }
+ sourceToFormMap.remove(deletedSource);
+ }
+ }
+ }
+ if (!removedSources.isEmpty()) {
+ final Map> existing = Utils.REMOVED_SOURCES_KEY.get(context);
+ if (existing != null) {
+ for (Map.Entry> entry : existing.entrySet()) {
+ final Collection paths = removedSources.get(entry.getKey());
+ if (paths != null) {
+ paths.addAll(entry.getValue());
+ }
+ else {
+ removedSources.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ Utils.REMOVED_SOURCES_KEY.set(context, removedSources);
+ }
+ }
+ catch (IOException e) {
+ throw new ProjectBuildException(e);
+ }
+ }
+
+ // return true if changed something, false otherwise
+ private boolean runModuleLevelBuilders(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
+ boolean doneSomething = false;
+ boolean rebuildFromScratchRequested = false;
+ float stageCount = myTotalModuleLevelBuilderCount;
+ final int modulesInChunk = chunk.getModules().size();
+ int buildersPassed = 0;
+ boolean nextPassRequired;
+ do {
+ nextPassRequired = false;
+ context.beforeCompileRound(chunk);
+
+ if (!context.isProjectRebuild()) {
+ syncOutputFiles(context, chunk);
+ }
+
+ BUILDER_CATEGORY_LOOP:
+ for (BuilderCategory category : BuilderCategory.values()) {
+ final List builders = myBuilderRegistry.getBuilders(category);
+ if (builders.isEmpty()) {
+ continue;
+ }
+
+ for (ModuleLevelBuilder builder : builders) {
+ if (context.isMake()) {
+ processDeletedPaths(context, chunk);
+ }
+ final ModuleLevelBuilder.ExitCode buildResult = builder.build(context, chunk);
+
+ doneSomething |= (buildResult != ModuleLevelBuilder.ExitCode.NOTHING_DONE);
+
+ if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
+ throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
+ }
+ context.checkCanceled();
+ if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
+ if (!nextPassRequired) {
+ // recalculate basis
+ myModulesProcessed -= (buildersPassed * modulesInChunk) / stageCount;
+ stageCount += myTotalModuleLevelBuilderCount;
+ myModulesProcessed += (buildersPassed * modulesInChunk) / stageCount;
+ }
+ nextPassRequired = true;
+ }
+ else if (buildResult == ModuleLevelBuilder.ExitCode.CHUNK_REBUILD_REQUIRED) {
+ if (!rebuildFromScratchRequested && !context.isProjectRebuild()) {
+ LOG.info("Builder " + builder.getDescription() + " requested rebuild of module chunk " + chunk.getName());
+ // allow rebuild from scratch only once per chunk
+ rebuildFromScratchRequested = true;
+ try {
+ // forcibly mark all files in the chunk dirty
+ context.markDirty(chunk);
+ // reverting to the beginning
+ myModulesProcessed -= (buildersPassed * modulesInChunk) / stageCount;
+ stageCount = myTotalModuleLevelBuilderCount;
+ buildersPassed = 0;
+ nextPassRequired = true;
+ break BUILDER_CATEGORY_LOOP;
+ }
+ catch (Exception e) {
+ throw new ProjectBuildException(e);
+ }
+ }
+ else {
+ context.getLoggingManager().getJavaBuilderLogger().log(
+ "Builder " + builder.getDescription() + " requested second chunk rebuild");
+ }
+ }
+
+ buildersPassed++;
+ final float fraction = updateFractionBuilderFinished(modulesInChunk / (stageCount));
+ context.setDone(fraction);
+ }
+ }
+ }
+ while (nextPassRequired);
+
+ return doneSomething;
+ }
+
+ private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException {
+ for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
+ builder.build(context);
+ context.checkCanceled();
+ }
+ }
+
+ private static void syncOutputFiles(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
+ final BuildDataManager dataManager = context.getDataManager();
+ final boolean compilingTests = context.isCompilingTests();
+ try {
+ final Collection allOutputs = new LinkedList();
+
+ context.processFilesToRecompile(chunk, new FileProcessor() {
+ private final Map storageMap = new HashMap();
+
+ @Override
+ public boolean apply(Module module, File file, String sourceRoot) throws IOException {
+ SourceToOutputMapping srcToOut = storageMap.get(module);
+ if (srcToOut == null) {
+ srcToOut = dataManager.getSourceToOutputMap(module.getName(), compilingTests);
+ storageMap.put(module, srcToOut);
+ }
+ final String srcPath = FileUtil.toSystemIndependentName(file.getPath());
+ final Collection outputs = srcToOut.getState(srcPath);
+
+ if (outputs != null) {
+ final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
+ for (String output : outputs) {
+ if (logger.isEnabled()) {
+ allOutputs.add(output);
+ }
+ new File(output).delete();
+ }
+ srcToOut.remove(srcPath);
+ }
+ return true;
+ }
+ });
+
+ final JavaBuilderLogger logger = context.getLoggingManager().getJavaBuilderLogger();
+ if (logger.isEnabled()) {
+ if (context.isMake() && allOutputs.size() > 0) {
+ logger.log("Cleaning output files:");
+ final String[] buffer = new String[allOutputs.size()];
+ int i = 0;
+ for (String output : allOutputs) {
+ buffer[i++] = output;
+ }
+ Arrays.sort(buffer);
+ for (String output : buffer) {
+ logger.log(output);
+ }
+ logger.log("End of files");
+ }
+ }
+ }
+ catch (Exception e) {
+ throw new ProjectBuildException(e);
+ }
+ }
+}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
index 49a7dce25c80..807a16612f15 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
@@ -419,8 +419,9 @@ public class JavaBuilder extends ModuleLevelBuilder {
try {
final boolean rc;
if (USE_EMBEDDED_JAVAC) {
+ final boolean useEclipse = useEclipseCompiler(context);
rc = JavacMain.compile(
- options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus()
+ options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus(), useEclipse
);
}
else {
@@ -442,6 +443,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
}
+ private static boolean useEclipseCompiler(CompileContext context) {
+ return USE_EMBEDDED_JAVAC && "Eclipse".equalsIgnoreCase(context.getProject().getCompilerConfiguration().getOptions().get("DEFAULT_COMPILER"));
+ }
+
private void ensurePendingTasksCompleted() {
synchronized (myCounterLock) {
while (myTasksInProgress > 0) {
@@ -563,8 +568,9 @@ public class JavaBuilder extends ModuleLevelBuilder {
private static int getJavacServerHeapSize(CompileContext context) {
int heapSize = 512;
final Project project = context.getProject();
- final Map javacOpts = project.getCompilerConfiguration().getJavacOptions();
- final String hSize = javacOpts.get("MAXIMUM_HEAP_SIZE");
+ final CompilerConfiguration config = project.getCompilerConfiguration();
+ final Map opts = useEclipseCompiler(context)? config.getEclipseOptions() : config.getJavacOptions();
+ final String hSize = opts.get("MAXIMUM_HEAP_SIZE");
if (hSize != null) {
try {
heapSize = Integer.parseInt(hSize);
@@ -765,10 +771,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
//options.add("-verbose");
final Project project = context.getProject();
final CompilerConfiguration compilerConfig = project.getCompilerConfiguration();
- final Map javacOpts = compilerConfig.getJavacOptions();
- final boolean debugInfo = !"false".equals(javacOpts.get("DEBUGGING_INFO"));
- final boolean nowarn = "true".equals(javacOpts.get("GENERATE_NO_WARNINGS"));
- final boolean deprecation = !"false".equals(javacOpts.get("DEPRECATION"));
+ final Map opts = useEclipseCompiler(context)? compilerConfig.getEclipseOptions() : compilerConfig.getJavacOptions();
+ final boolean debugInfo = !"false".equals(opts.get("DEBUGGING_INFO"));
+ final boolean nowarn = "true".equals(opts.get("GENERATE_NO_WARNINGS"));
+ final boolean deprecation = !"false".equals(opts.get("DEPRECATION"));
if (debugInfo) {
options.add("-g");
}
@@ -779,7 +785,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
options.add("-nowarn");
}
- final String customArgs = javacOpts.get("ADDITIONAL_OPTIONS_STRING");
+ final String customArgs = opts.get("ADDITIONAL_OPTIONS_STRING");
if (customArgs != null) {
final StringTokenizer customOptsTokenizer = new StringTokenizer(customArgs, " \t\r\n");
boolean skip = false;
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java
index e59807f3f4da..3e2fd8867159 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java
@@ -1,310 +1,311 @@
-package org.jetbrains.jps.incremental.storage;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.io.FileUtil;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.ether.dependencyView.Mappings;
-import org.jetbrains.jps.Module;
-import org.jetbrains.jps.ModuleChunk;
-import org.jetbrains.jps.incremental.artifacts.ArtifactsBuildData;
-
-import java.io.*;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 10/7/11
- */
-public class BuildDataManager implements StorageOwner {
- private static final int VERSION = 7;
- private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.storage.BuildDataManager");
- private static final String SRC_TO_OUTPUTS_STORAGE = "src-out";
- private static final String SRC_TO_FORM_STORAGE = "src-form";
- private static final String MAPPINGS_STORAGE = "mappings";
-
- private final Object mySourceToOutputLock = new Object();
- private final Map myProductionSourceToOutputs = new HashMap();
- private final Map myTestSourceToOutputs = new HashMap();
-
- private final SourceToFormMapping mySrcToFormMap;
- private final ArtifactsBuildData myArtifactsBuildData;
- private final ModuleOutputRootsLayout myOutputRootsLayout;
- private final Mappings myMappings;
- private final File myDataStorageRoot;
- private final File myVersionFile;
-
- public BuildDataManager(final File dataStorageRoot, final boolean useMemoryTempCaches) throws IOException {
- myDataStorageRoot = dataStorageRoot;
- mySrcToFormMap = new SourceToFormMapping(new File(getSourceToFormsRoot(), "data"));
- myOutputRootsLayout = new ModuleOutputRootsLayout(new File(getOutputsLayoutRoot(), "data"));
- myMappings = new Mappings(getMappingsRoot(), useMemoryTempCaches);
- myArtifactsBuildData = new ArtifactsBuildData(new File(dataStorageRoot, "artifacts"));
- myVersionFile = new File(myDataStorageRoot, "version.dat");
- }
-
- private File getOutputsLayoutRoot() {
- return new File(myDataStorageRoot, "output-roots");
- }
-
- public SourceToOutputMapping getSourceToOutputMap(final String moduleName, final boolean testSources) throws IOException {
- String lowerCaseModuleName = moduleName.toLowerCase(Locale.US);
- final Map storageMap = testSources ? myTestSourceToOutputs : myProductionSourceToOutputs;
- SourceToOutputMapping mapping;
- synchronized (mySourceToOutputLock) {
- mapping = storageMap.get(lowerCaseModuleName);
- if (mapping == null) {
- mapping = new SourceToOutputMapping(new File(getSourceToOutputRoot(lowerCaseModuleName, testSources), "data"));
- storageMap.put(lowerCaseModuleName, mapping);
- }
- }
- return mapping;
- }
-
- public ArtifactsBuildData getArtifactsBuildData() {
- return myArtifactsBuildData;
- }
-
- public SourceToFormMapping getSourceToFormMap() {
- return mySrcToFormMap;
- }
-
- public ModuleOutputRootsLayout getOutputRootsLayout() {
- return myOutputRootsLayout;
- }
-
- public Mappings getMappings() {
- return myMappings;
- }
-
- public void clean() throws IOException {
- try {
- myArtifactsBuildData.clean();
- }
- finally {
- try {
- synchronized (mySourceToOutputLock) {
- try {
- closeSourceToOutputStorages();
- }
- finally {
- FileUtil.delete(getSourceToOutputsRoot());
- }
- }
- }
- finally {
- try {
- wipeStorage(getSourceToFormsRoot(), mySrcToFormMap);
- }
- finally {
- try {
- wipeStorage(getOutputsLayoutRoot(), myOutputRootsLayout);
- }
- finally {
- final Mappings mappings = myMappings;
- if (mappings != null) {
- synchronized (mappings) {
- mappings.clean();
- }
- }
- else {
- FileUtil.delete(getMappingsRoot());
- }
- }
- }
- }
- }
- }
-
- public void flush(boolean memoryCachesOnly) {
- myArtifactsBuildData.flush(memoryCachesOnly);
- synchronized (mySourceToOutputLock) {
- for (Map.Entry entry : myProductionSourceToOutputs.entrySet()) {
- final SourceToOutputMapping mapping = entry.getValue();
- mapping.flush(memoryCachesOnly);
- }
- for (Map.Entry entry : myTestSourceToOutputs.entrySet()) {
- final SourceToOutputMapping mapping = entry.getValue();
- mapping.flush(memoryCachesOnly);
- }
- }
- mySrcToFormMap.flush(memoryCachesOnly);
- myOutputRootsLayout.flush(memoryCachesOnly);
- final Mappings mappings = myMappings;
- if (mappings != null) {
- synchronized (mappings) {
- mappings.flush(memoryCachesOnly);
- }
- }
- }
-
- public void close() throws IOException {
- try {
- myArtifactsBuildData.close();
- }
- finally {
- try {
- synchronized (mySourceToOutputLock) {
- closeSourceToOutputStorages();
- }
- }
- finally {
- try {
- closeStorage(mySrcToFormMap);
- }
- finally {
- try {
- closeStorage(myOutputRootsLayout);
- }
- finally {
- final Mappings mappings = myMappings;
- if (mappings != null) {
- try {
- mappings.close();
- }
- catch (RuntimeException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof IOException) {
- throw ((IOException)cause);
- }
- throw e;
- }
- }
- }
- }
- }
- }
- }
-
- public void closeSourceToOutputStorages(ModuleChunk chunk, boolean testSources) throws IOException {
- final Map storageMap = testSources? myTestSourceToOutputs : myProductionSourceToOutputs;
- synchronized (mySourceToOutputLock) {
- for (Module module : chunk.getModules()) {
- final String moduleName = module.getName().toLowerCase(Locale.US);
- final SourceToOutputMapping mapping = storageMap.remove(moduleName);
- if (mapping != null) {
- mapping.close();
- }
- }
- }
- }
-
- private void closeSourceToOutputStorages() throws IOException {
- IOException ex = null;
- try {
- for (Map.Entry entry : myProductionSourceToOutputs.entrySet()) {
- try {
- entry.getValue().close();
- }
- catch (IOException e) {
- if (e != null) {
- ex = e;
- }
- }
- }
- for (Map.Entry entry : myTestSourceToOutputs.entrySet()) {
- try {
- entry.getValue().close();
- }
- catch (IOException e) {
- if (e != null) {
- ex = e;
- }
- }
- }
- }
- finally {
- myProductionSourceToOutputs.clear();
- myTestSourceToOutputs.clear();
- }
- if (ex != null) {
- throw ex;
- }
- }
-
- public File getSourceToFormsRoot() {
- return new File(myDataStorageRoot, SRC_TO_FORM_STORAGE);
- }
-
- public File getSourceToOutputRoot(String moduleName, boolean forTests) {
- return new File(getSourceToOutputsRoot(), (forTests? "tests" : "production") + "/" + moduleName);
- }
-
- private File getSourceToOutputsRoot() {
- return new File(myDataStorageRoot, SRC_TO_OUTPUTS_STORAGE);
- }
-
- public File getMappingsRoot() {
- return new File(myDataStorageRoot, MAPPINGS_STORAGE);
- }
-
- public File getDataStorageRoot() {
- return myDataStorageRoot;
- }
-
- private static void wipeStorage(File root, @Nullable AbstractStateStorage, ?> storage) {
- if (storage != null) {
- synchronized (storage) {
- storage.wipe();
- }
- }
- else {
- FileUtil.delete(root);
- }
- }
-
- private static void closeStorage(@Nullable AbstractStateStorage, ?> storage) throws IOException {
- if (storage != null) {
- synchronized (storage) {
- storage.close();
- }
- }
- }
-
- private Boolean myVersionDiffers = null;
-
- public boolean versionDiffers() {
- final Boolean cached = myVersionDiffers;
- if (cached != null) {
- return cached;
- }
- try {
- final DataInputStream is = new DataInputStream(new FileInputStream(myVersionFile));
- try {
- final boolean diff = is.readInt() != VERSION;
- myVersionDiffers = diff;
- return diff;
- }
- finally {
- is.close();
- }
- }
- catch (FileNotFoundException ignored) {
- return false; // treat it as a new dir
- }
- catch (IOException ex) {
- LOG.info(ex);
- }
- return true;
- }
-
- public void saveVersion() {
- final Boolean differs = myVersionDiffers;
- if (differs == null || differs) {
- try {
- FileUtil.createIfDoesntExist(myVersionFile);
- final DataOutputStream os = new DataOutputStream(new FileOutputStream(myVersionFile));
- try {
- os.writeInt(VERSION);
- myVersionDiffers = Boolean.FALSE;
- }
- finally {
- os.close();
- }
- }
- catch (IOException ignored) {
- }
- }
- }
-}
+package org.jetbrains.jps.incremental.storage;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.io.FileUtil;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.ether.dependencyView.Mappings;
+import org.jetbrains.jps.Module;
+import org.jetbrains.jps.ModuleChunk;
+import org.jetbrains.jps.incremental.artifacts.ArtifactsBuildData;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: 10/7/11
+ */
+public class BuildDataManager implements StorageOwner {
+ private static final int VERSION = 7;
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.storage.BuildDataManager");
+ private static final String SRC_TO_OUTPUTS_STORAGE = "src-out";
+ private static final String SRC_TO_FORM_STORAGE = "src-form";
+ private static final String MAPPINGS_STORAGE = "mappings";
+
+ private final Object mySourceToOutputLock = new Object();
+ private final Map myProductionSourceToOutputs = new HashMap();
+ private final Map myTestSourceToOutputs = new HashMap();
+
+ private final SourceToFormMapping mySrcToFormMap;
+ private final ArtifactsBuildData myArtifactsBuildData;
+ private final ModuleOutputRootsLayout myOutputRootsLayout;
+ private final Mappings myMappings;
+ private final File myDataStorageRoot;
+ private final File myVersionFile;
+
+ public BuildDataManager(final File dataStorageRoot, final boolean useMemoryTempCaches) throws IOException {
+ myDataStorageRoot = dataStorageRoot;
+ mySrcToFormMap = new SourceToFormMapping(new File(getSourceToFormsRoot(), "data"));
+ myOutputRootsLayout = new ModuleOutputRootsLayout(new File(getOutputsLayoutRoot(), "data"));
+ myMappings = new Mappings(getMappingsRoot(), useMemoryTempCaches);
+ myArtifactsBuildData = new ArtifactsBuildData(new File(dataStorageRoot, "artifacts"));
+ myVersionFile = new File(myDataStorageRoot, "version.dat");
+ }
+
+ private File getOutputsLayoutRoot() {
+ return new File(myDataStorageRoot, "output-roots");
+ }
+
+ public SourceToOutputMapping getSourceToOutputMap(final String moduleName, final boolean testSources) throws IOException {
+ String lowerCaseModuleName = moduleName.toLowerCase(Locale.US);
+ final Map storageMap = testSources ? myTestSourceToOutputs : myProductionSourceToOutputs;
+ SourceToOutputMapping mapping;
+ synchronized (mySourceToOutputLock) {
+ mapping = storageMap.get(lowerCaseModuleName);
+ if (mapping == null) {
+ mapping = new SourceToOutputMapping(new File(getSourceToOutputRoot(lowerCaseModuleName, testSources), "data"));
+ storageMap.put(lowerCaseModuleName, mapping);
+ }
+ }
+ return mapping;
+ }
+
+ public ArtifactsBuildData getArtifactsBuildData() {
+ return myArtifactsBuildData;
+ }
+
+ public SourceToFormMapping getSourceToFormMap() {
+ return mySrcToFormMap;
+ }
+
+ public ModuleOutputRootsLayout getOutputRootsLayout() {
+ return myOutputRootsLayout;
+ }
+
+ public Mappings getMappings() {
+ return myMappings;
+ }
+
+ public void clean() throws IOException {
+ try {
+ myArtifactsBuildData.clean();
+ }
+ finally {
+ try {
+ synchronized (mySourceToOutputLock) {
+ try {
+ closeSourceToOutputStorages();
+ }
+ finally {
+ FileUtil.delete(getSourceToOutputsRoot());
+ }
+ }
+ }
+ finally {
+ try {
+ wipeStorage(getSourceToFormsRoot(), mySrcToFormMap);
+ }
+ finally {
+ try {
+ wipeStorage(getOutputsLayoutRoot(), myOutputRootsLayout);
+ }
+ finally {
+ final Mappings mappings = myMappings;
+ if (mappings != null) {
+ synchronized (mappings) {
+ mappings.clean();
+ }
+ }
+ else {
+ FileUtil.delete(getMappingsRoot());
+ }
+ }
+ }
+ }
+ }
+ saveVersion();
+ }
+
+ public void flush(boolean memoryCachesOnly) {
+ myArtifactsBuildData.flush(memoryCachesOnly);
+ synchronized (mySourceToOutputLock) {
+ for (Map.Entry entry : myProductionSourceToOutputs.entrySet()) {
+ final SourceToOutputMapping mapping = entry.getValue();
+ mapping.flush(memoryCachesOnly);
+ }
+ for (Map.Entry entry : myTestSourceToOutputs.entrySet()) {
+ final SourceToOutputMapping mapping = entry.getValue();
+ mapping.flush(memoryCachesOnly);
+ }
+ }
+ mySrcToFormMap.flush(memoryCachesOnly);
+ myOutputRootsLayout.flush(memoryCachesOnly);
+ final Mappings mappings = myMappings;
+ if (mappings != null) {
+ synchronized (mappings) {
+ mappings.flush(memoryCachesOnly);
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ try {
+ myArtifactsBuildData.close();
+ }
+ finally {
+ try {
+ synchronized (mySourceToOutputLock) {
+ closeSourceToOutputStorages();
+ }
+ }
+ finally {
+ try {
+ closeStorage(mySrcToFormMap);
+ }
+ finally {
+ try {
+ closeStorage(myOutputRootsLayout);
+ }
+ finally {
+ final Mappings mappings = myMappings;
+ if (mappings != null) {
+ try {
+ mappings.close();
+ }
+ catch (RuntimeException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof IOException) {
+ throw ((IOException)cause);
+ }
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void closeSourceToOutputStorages(ModuleChunk chunk, boolean testSources) throws IOException {
+ final Map storageMap = testSources? myTestSourceToOutputs : myProductionSourceToOutputs;
+ synchronized (mySourceToOutputLock) {
+ for (Module module : chunk.getModules()) {
+ final String moduleName = module.getName().toLowerCase(Locale.US);
+ final SourceToOutputMapping mapping = storageMap.remove(moduleName);
+ if (mapping != null) {
+ mapping.close();
+ }
+ }
+ }
+ }
+
+ private void closeSourceToOutputStorages() throws IOException {
+ IOException ex = null;
+ try {
+ for (Map.Entry entry : myProductionSourceToOutputs.entrySet()) {
+ try {
+ entry.getValue().close();
+ }
+ catch (IOException e) {
+ if (e != null) {
+ ex = e;
+ }
+ }
+ }
+ for (Map.Entry entry : myTestSourceToOutputs.entrySet()) {
+ try {
+ entry.getValue().close();
+ }
+ catch (IOException e) {
+ if (e != null) {
+ ex = e;
+ }
+ }
+ }
+ }
+ finally {
+ myProductionSourceToOutputs.clear();
+ myTestSourceToOutputs.clear();
+ }
+ if (ex != null) {
+ throw ex;
+ }
+ }
+
+ public File getSourceToFormsRoot() {
+ return new File(myDataStorageRoot, SRC_TO_FORM_STORAGE);
+ }
+
+ public File getSourceToOutputRoot(String moduleName, boolean forTests) {
+ return new File(getSourceToOutputsRoot(), (forTests? "tests" : "production") + "/" + moduleName);
+ }
+
+ private File getSourceToOutputsRoot() {
+ return new File(myDataStorageRoot, SRC_TO_OUTPUTS_STORAGE);
+ }
+
+ public File getMappingsRoot() {
+ return new File(myDataStorageRoot, MAPPINGS_STORAGE);
+ }
+
+ public File getDataStorageRoot() {
+ return myDataStorageRoot;
+ }
+
+ private static void wipeStorage(File root, @Nullable AbstractStateStorage, ?> storage) {
+ if (storage != null) {
+ synchronized (storage) {
+ storage.wipe();
+ }
+ }
+ else {
+ FileUtil.delete(root);
+ }
+ }
+
+ private static void closeStorage(@Nullable AbstractStateStorage, ?> storage) throws IOException {
+ if (storage != null) {
+ synchronized (storage) {
+ storage.close();
+ }
+ }
+ }
+
+ private Boolean myVersionDiffers = null;
+
+ public boolean versionDiffers() {
+ final Boolean cached = myVersionDiffers;
+ if (cached != null) {
+ return cached;
+ }
+ try {
+ final DataInputStream is = new DataInputStream(new FileInputStream(myVersionFile));
+ try {
+ final boolean diff = is.readInt() != VERSION;
+ myVersionDiffers = diff;
+ return diff;
+ }
+ finally {
+ is.close();
+ }
+ }
+ catch (FileNotFoundException ignored) {
+ return false; // treat it as a new dir
+ }
+ catch (IOException ex) {
+ LOG.info(ex);
+ }
+ return true;
+ }
+
+ public void saveVersion() {
+ final Boolean differs = myVersionDiffers;
+ if (differs == null || differs) {
+ try {
+ FileUtil.createIfDoesntExist(myVersionFile);
+ final DataOutputStream os = new DataOutputStream(new FileOutputStream(myVersionFile));
+ try {
+ os.writeInt(VERSION);
+ myVersionDiffers = Boolean.FALSE;
+ }
+ finally {
+ os.close();
+ }
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java
index 05ab4cb55372..fd322576c447 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java
@@ -1,188 +1,216 @@
-package org.jetbrains.jps.javac;
-
-import com.intellij.openapi.util.SystemInfo;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.jps.api.CanceledStatus;
-import org.jetbrains.jps.server.ClasspathBootstrap;
-
-import javax.tools.*;
-import java.io.File;
-import java.io.IOException;
-import java.util.*;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 1/21/12
- */
-public class JavacMain {
- private static final boolean IS_VM_6_VERSION = System.getProperty("java.version", "1.6").contains("1.6");
- private static final Set FILTERED_OPTIONS = new HashSet(Arrays.asList(
- "-d", "-classpath", "-cp", "-bootclasspath"
- ));
- private static final Set FILTERED_SINGLE_OPTIONS = new HashSet(Arrays.asList(
- "-verbose", "-proc:only", "-implicit:class", "-implicit:none"
- ));
-
- public static boolean compile(Collection options,
- final Collection sources,
- Collection classpath,
- Collection platformClasspath,
- Collection sourcePath,
- Map> outputDirToRoots,
- final DiagnosticOutputConsumer outConsumer,
- final OutputFileConsumer outputSink,
- CanceledStatus canceledStatus) {
- final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-
- for (File outputDir : outputDirToRoots.keySet()) {
- outputDir.mkdirs();
- }
- final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus));
-
- fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff
- fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff
-
- try {
- fileManager.setOutputDirectories(outputDirToRoots);
- }
- catch (IOException e) {
- fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
- return false;
- }
-
- if (!classpath.isEmpty()) {
- try {
- fileManager.setLocation(StandardLocation.CLASS_PATH, classpath);
- }
- catch (IOException e) {
- fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
- return false;
- }
- }
- if (!platformClasspath.isEmpty()) {
- try {
- fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, platformClasspath);
- }
- catch (IOException e) {
- fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
- return false;
- }
- }
- if (!sourcePath.isEmpty()) {
- try {
- fileManager.setLocation(StandardLocation.SOURCE_PATH, sourcePath);
- }
- catch (IOException e) {
- fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
- return false;
- }
- }
-
- //noinspection IOResourceOpenedButNotSafelyClosed
- final LineOutputWriter out = new LineOutputWriter() {
- protected void lineAvailable(String line) {
- outConsumer.outputLineAvailable(line);
- }
- };
-
- try {
- final Collection _options = prepareOptions(options);
- final JavaCompiler.CompilationTask task = compiler.getTask(
- out, fileManager, outConsumer, _options, null, fileManager.toJavaFileObjects(sources)
- );
-
- //if (!IS_VM_6_VERSION) { //todo!
- // // Do not add the processor for JDK 1.6 because of the bugs in javac
- // // The processor's presence may lead to NPE and resolve bugs in compiler
- // final JavacASTAnalyser analyzer = new JavacASTAnalyser(outConsumer, !annotationProcessingEnabled);
- // task.setProcessors(Collections.singleton(analyzer));
- //}
- return task.call();
- }
- catch(IllegalArgumentException e) {
- outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
- }
- finally {
- fileManager.close();
- }
- return false;
- }
-
- private static boolean isAnnotationProcessingEnabled(final Collection options) {
- for (String option : options) {
- if ("-proc:none".equals(option)) {
- return false;
- }
- }
- return true;
- }
-
- private static Collection prepareOptions(final Collection options) {
- final List result = new ArrayList();
- result.add("-implicit:class");
- boolean skip = false;
- for (String option : options) {
- if (FILTERED_OPTIONS.contains(option)) {
- skip = true;
- continue;
- }
- if (!skip) {
- if (!FILTERED_SINGLE_OPTIONS.contains(option)) {
- result.add(option);
- }
- }
- skip = false;
- }
- return result;
- }
-
- private static class ContextImpl implements JavacFileManager.Context {
- private final StandardJavaFileManager myStdManager;
- private final DiagnosticOutputConsumer myOutConsumer;
- private final OutputFileConsumer myOutputFileSink;
- private final CanceledStatus myCanceledStatus;
-
- public ContextImpl(@NotNull JavaCompiler compiler,
- @NotNull DiagnosticOutputConsumer outConsumer,
- @NotNull OutputFileConsumer sink,
- CanceledStatus canceledStatus) {
- myOutConsumer = outConsumer;
- myOutputFileSink = sink;
- myCanceledStatus = canceledStatus;
- StandardJavaFileManager stdManager = null;
- final Class optimizedManagerClass = ClasspathBootstrap.getOptimizedFileManagerClass();
- if (optimizedManagerClass != null) {
- try {
- stdManager = optimizedManagerClass.newInstance();
- }
- catch (Throwable e) {
- if (SystemInfo.isWindows) {
- System.err.println("Failed to load JPS optimized file manager for javac: " + e.getMessage());
- }
- }
- }
- if (stdManager != null) {
- myStdManager = stdManager;
- }
- else {
- myStdManager = compiler.getStandardFileManager(outConsumer, Locale.US, null);
- }
- }
-
- public boolean isCanceled() {
- return myCanceledStatus.isCanceled();
- }
-
- public StandardJavaFileManager getStandardFileManager() {
- return myStdManager;
- }
-
- public void reportMessage(final Diagnostic.Kind kind, String message) {
- myOutConsumer.report(new PlainMessageDiagnostic(kind, message));
- }
-
- public void consumeOutputFile(@NotNull final OutputFileObject cls) {
- myOutputFileSink.save(cls);
- }
- }
-}
+package org.jetbrains.jps.javac;
+
+import com.intellij.openapi.util.SystemInfo;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.api.CanceledStatus;
+import org.jetbrains.jps.server.ClasspathBootstrap;
+
+import javax.tools.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: 1/21/12
+ */
+public class JavacMain {
+ private static final boolean IS_VM_6_VERSION = System.getProperty("java.version", "1.6").contains("1.6");
+ private static final Set FILTERED_OPTIONS = new HashSet(Arrays.asList(
+ "-d", "-classpath", "-cp", "-bootclasspath"
+ ));
+ private static final Set FILTERED_SINGLE_OPTIONS = new HashSet(Arrays.asList(
+ "-verbose", "-proc:only", "-implicit:class", "-implicit:none"
+ ));
+ private static final JavaCompiler SYSTEM_JAVA_COMPILER = ToolProvider.getSystemJavaCompiler();
+
+ public static boolean compile(Collection options,
+ final Collection sources,
+ Collection classpath,
+ Collection platformClasspath,
+ Collection sourcePath,
+ Map> outputDirToRoots,
+ final DiagnosticOutputConsumer outConsumer,
+ final OutputFileConsumer outputSink,
+ CanceledStatus canceledStatus, boolean useEclipseCompiler) {
+ JavaCompiler compiler = null;
+ if (useEclipseCompiler) {
+ for (JavaCompiler javaCompiler : ServiceLoader.load(JavaCompiler.class)) {
+ compiler = javaCompiler;
+ break;
+ }
+ if (compiler == null) {
+ compiler = SYSTEM_JAVA_COMPILER;
+ }
+ }
+ else {
+ compiler = SYSTEM_JAVA_COMPILER;
+ }
+
+ final boolean nowUsingJavac = compiler == SYSTEM_JAVA_COMPILER;
+
+ if (nowUsingJavac && useEclipseCompiler) {
+ final String message = "Eclipse Batch Compiler was not found in classpath";
+ outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message));
+ return false;
+ }
+
+ for (File outputDir : outputDirToRoots.keySet()) {
+ outputDir.mkdirs();
+ }
+ final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus));
+
+ fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff
+ fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff
+
+ try {
+ fileManager.setOutputDirectories(outputDirToRoots);
+ }
+ catch (IOException e) {
+ fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
+ return false;
+ }
+
+ if (!classpath.isEmpty()) {
+ try {
+ fileManager.setLocation(StandardLocation.CLASS_PATH, classpath);
+ }
+ catch (IOException e) {
+ fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
+ return false;
+ }
+ }
+ if (!platformClasspath.isEmpty()) {
+ try {
+ fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, platformClasspath);
+ }
+ catch (IOException e) {
+ fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
+ return false;
+ }
+ }
+ if (!sourcePath.isEmpty()) {
+ try {
+ fileManager.setLocation(StandardLocation.SOURCE_PATH, sourcePath);
+ }
+ catch (IOException e) {
+ fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
+ return false;
+ }
+ }
+
+ //noinspection IOResourceOpenedButNotSafelyClosed
+ final LineOutputWriter out = new LineOutputWriter() {
+ protected void lineAvailable(String line) {
+ if (nowUsingJavac) {
+ outConsumer.outputLineAvailable(line);
+ }
+ else {
+ // todo: filter too verbose eclipse output?
+ }
+ }
+ };
+
+ try {
+ final Collection _options = prepareOptions(options, compiler);
+ final JavaCompiler.CompilationTask task = compiler.getTask(
+ out, fileManager, outConsumer, _options, null, fileManager.toJavaFileObjects(sources)
+ );
+
+ //if (!IS_VM_6_VERSION) { //todo!
+ // // Do not add the processor for JDK 1.6 because of the bugs in javac
+ // // The processor's presence may lead to NPE and resolve bugs in compiler
+ // final JavacASTAnalyser analyzer = new JavacASTAnalyser(outConsumer, !annotationProcessingEnabled);
+ // task.setProcessors(Collections.singleton(analyzer));
+ //}
+ return task.call();
+ }
+ catch(IllegalArgumentException e) {
+ outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
+ }
+ finally {
+ fileManager.close();
+ }
+ return false;
+ }
+
+ private static boolean isAnnotationProcessingEnabled(final Collection options) {
+ for (String option : options) {
+ if ("-proc:none".equals(option)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static Collection prepareOptions(final Collection options, JavaCompiler compiler) {
+ final List