diff --git a/build.xml b/build.xml index dd8c90d39069..bafc55b124a3 100644 --- a/build.xml +++ b/build.xml @@ -33,7 +33,16 @@ - + + + + + + + + + + diff --git a/build/download_kotlin.xml b/build/download_kotlin.xml index 47259dcbc870..3a47354116c8 100644 --- a/build/download_kotlin.xml +++ b/build/download_kotlin.xml @@ -8,6 +8,8 @@ + + diff --git a/build/scripts/download_kotlin.gant b/build/scripts/download_kotlin.gant new file mode 100644 index 000000000000..f8b7184fbbff --- /dev/null +++ b/build/scripts/download_kotlin.gant @@ -0,0 +1,168 @@ +import com.intellij.util.text.VersionComparatorUtil + +import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome +/* + * Copyright 2000-2015 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. + */ +includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant") + +String kotlinBuildConfigurationOnPublicTeamCity = "Kotlin_M15_2_Idea142branch150versionNoTests" + +target('default': 'Ensures that build/kotlinc directory contains JARs from Kotlin plugin compatible with current IDEA sources. These JARs are used by build scripts.') { + def communityHome = guessHome(this) + def reasonToUpdate = getReasonToUpdate(communityHome, new File(communityHome, "build/kotlinc")) + if (reasonToUpdate == null) { + projectBuilder.info("Compatible Kotlin plugin already installed, no update is required") + return + } + + projectBuilder.info("Kotlin plugin will be updated: $reasonToUpdate") + + if (isDefined("workIdeaHome")) { + if (updatePluginFromWorkIdeaInstallation(communityHome, workIdeaHome)) { + return + } + } + + if (isDefined("kotlin.teamcity.host")) { + if (downloadAndExtract(new TeamCityBuildLocator(p("kotlin.teamcity.host"), p("kotlin.build.type.id"), p("kotlin.build.selector")), communityHome)) { + return + } + } + if (!downloadAndExtract(new TeamCityBuildLocator("https://teamcity.jetbrains.com", kotlinBuildConfigurationOnPublicTeamCity, "status:SUCCESS"), communityHome)) { + projectBuilder.error("Failed to install Kotlin plugin") + } +} + +private boolean updatePluginFromWorkIdeaInstallation(String communityHome, String workIdeaHome) { + def kotlinPluginFromWorkIdea = new File(workIdeaHome, "plugins/Kotlin") + if (!kotlinPluginFromWorkIdea.exists()) { + projectBuilder.info("Cannot use Kotlin from $workIdeaHome: the plugin directory doesn't exist") + return false + } + + def reasonToUpdate = getReasonToUpdate(communityHome, new File(kotlinPluginFromWorkIdea, "kotlinc")) + if (reasonToUpdate != null) { + projectBuilder.info("Cannot use Kotlin from $workIdeaHome: $reasonToUpdate") + return false + } + + ant.delete(dir: "$communityHome/build/kotlinc") + ant.copy(todir: "$communityHome/build/kotlinc/plugin/Kotlin") { + ant.fileset(dir: kotlinPluginFromWorkIdea) + } + ant.copy(todir: "$communityHome/build/kotlinc") { + ant.fileset(dir: "$kotlinPluginFromWorkIdea/kotlinc") + } + ant.copy(todir: "$communityHome/build/kotlinc/jps") { + ant.fileset(dir: "$kotlinPluginFromWorkIdea/lib/jps") + } + projectBuilder.info("Kotlin plugin updated from $workIdeaHome installation") + return true +} + +private String getReasonToUpdate(String communityHome, File kotlincHome) { + def buildTxt = new File(kotlincHome, "build.txt") + if (!buildTxt.exists()) { + return "Kotlin binaries aren't found at $kotlincHome" + } + + String currentKotlinVersion + try { + currentKotlinVersion = buildTxt.text + } + catch (IOException e) { + return "cannot read Kotlin version from $buildTxt.absolutePath: $e" + } + + def externalDependenciesXml = new File(communityHome, ".idea/externalDependencies.xml") + if (!externalDependenciesXml.exists()) { + return "cannot read required Kotlin version from $externalDependenciesXml.absolutePath: the file doesn't exist" + } + + def root = new XmlParser().parse(externalDependenciesXml) + def pluginTag = root.component?.find { it.@name == "ExternalDependencies" }?.plugin?.find { it.@id == "org.jetbrains.kotlin" } + if (pluginTag == null) return "cannot find Kotlin plugin in $externalDependenciesXml.absolutePath" + + String minVersion = pluginTag['@min-version'] + if (minVersion == null) return "minimum required version for Kotlin plugin isn't specified in $externalDependenciesXml.absolutePath" + String maxVersion = pluginTag['@max-version'] + if (maxVersion == null) return "maximum required version for Kotlin plugin isn't specified in $externalDependenciesXml.absolutePath" + + if (VersionComparatorUtil.compare(currentKotlinVersion, minVersion) < 0) { + return "current Kotlin version is $currentKotlinVersion, but at least $minVersion is required"; + } + if (VersionComparatorUtil.compare(currentKotlinVersion, maxVersion) > 0) { + return "current Kotlin version is $currentKotlinVersion, but at most $maxVersion is required"; + } + return null +} + +private boolean downloadAndExtract(TeamCityBuildLocator buildLocator, String communityHome) { + String buildNumber; + try { + buildNumber = new URL(buildLocator.buildNumberUrl).text + } + catch (Exception e) { + projectBuilder.info("Cannot get Kotlin build number from $buildLocator.buildNumberUrl: $e") + return false + } + + + def pluginZip = new File(communityHome, "build/kotlin-plugin-${buildNumber}.zip") + def pluginZipPath = pluginZip.absolutePath + if (!pluginZip.exists()) { + ant.delete(dir: "$communityHome/build", includes: "kotlin-plugin-*.zip") + projectBuilder.info("Downloading Kotlin build $buildNumber") + ant.get(src: buildLocator.getDownloadUrl(buildNumber), dest: pluginZipPath) + } + else { + projectBuilder.info("Extracting Kotlin build $buildNumber") + } + + def kotlincDir = "$communityHome/build/kotlinc" + ant.delete(dir: kotlincDir) + ant.unzip(src: pluginZipPath, dest: "$kotlincDir/plugin") + ant.unzip(src: pluginZipPath, dest: "$kotlincDir") { + ant.patternset(includes: "Kotlin/kotlinc/**") + ant.globmapper(from: "Kotlin/kotlinc/*", to: "*") + } + ant.unzip(src: pluginZipPath, dest: "$kotlincDir/jps") { + ant.patternset(includes: "Kotlin/lib/jps/**") + ant.globmapper(from: "Kotlin/lib/jps/*", to: "*") + } + return true +} + +class TeamCityBuildLocator { + String host; + String buildTypeId; + String buildSelector; + + TeamCityBuildLocator(String host, String buildTypeId, String buildSelector) { + this.host = host + this.buildTypeId = buildTypeId + this.buildSelector = buildSelector + } + + String getBuildNumberUrl() { + return "$host/guestAuth/app/rest/buildTypes/id:$buildTypeId/builds/$buildSelector,count:1/number" + } + + String getDownloadUrl(String buildNumber) { + String encodedBuildNumber = URLEncoder.encode(buildNumber, "UTF-8") + return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-${encodedBuildNumber}.zip" + } +} diff --git a/build/update.cmd b/build/update.cmd index 558db879aecc..1fe5808b31d9 100644 --- a/build/update.cmd +++ b/build/update.cmd @@ -30,7 +30,7 @@ CD "%DEV_IDEA_HOME%" SET ANT_HOME=%DEV_IDEA_HOME%\lib\ant SET EXEC_ANT="%JAVA_HOME%\bin\java.exe" -Dant.home="%ANT_HOME%" -classpath "%ANT_HOME%\lib\ant-launcher.jar" org.apache.tools.ant.launch.Launcher -%EXEC_ANT% -f build/update.xml +%EXEC_ANT% -f build/update.xml -Dwork.idea.home="%WORK_IDEA_HOME%" IF NOT ERRORLEVEL 0 GOTO failed IF NOT EXIST "%DEV_IDEA_HOME%\out\deploy" GOTO failed diff --git a/build/update.sh b/build/update.sh index 22351f649b60..f1cfe923f16a 100755 --- a/build/update.sh +++ b/build/update.sh @@ -27,7 +27,7 @@ echo "Updating $WORK_IDEA_HOME from compiled classes in $DEV_IDEA_HOME" ANT_HOME="$DEV_IDEA_HOME/lib/ant" ANT_CLASSPATH="$DEV_IDEA_HOME/build/lib/gant/lib/jps.jar" java -Xms64m -Xmx512m -Dant.home="$ANT_HOME" -classpath "$ANT_HOME/lib/ant-launcher.jar" org.apache.tools.ant.launch.Launcher \ - -lib "$ANT_CLASSPATH" -f "$DEV_IDEA_HOME/build/update.xml" $TARGET + -lib "$ANT_CLASSPATH" -f "$DEV_IDEA_HOME/build/update.xml" -Dwork.idea.home="$WORK_IDEA_HOME" $TARGET if [ "$?" != "0" ]; then echo "Update failed; work IDEA build not modified." diff --git a/build/update.xml b/build/update.xml index adbc5c5faa0b..84f918f3fa0a 100644 --- a/build/update.xml +++ b/build/update.xml @@ -25,6 +25,17 @@ + + + + + + + + + + +