blob: 7845d32938da56de93f37fc03bbf8c48235a1826 [file] [log] [blame]
/*
* Copyright 2000-2014 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.gant.JpsGantTool
import org.jetbrains.jps.gant.TeamCityBuildInfoPrinter
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModule
includeTool << JpsGantTool
binding.setVariable("p", {String key ->
return getProperty(key) as String
})
binding.setVariable("guessJdk", {
String javaHome = p("java.home")
if (new File(javaHome).getName() == "jre") {
javaHome = new File(javaHome).getParent()
}
return javaHome
})
binding.setVariable("includeFile", {String filePath ->
Script s = groovyShell.parse(new File(filePath))
s.setBinding(binding)
s
})
binding.setVariable("isMac", {
return System.getProperty("os.name").toLowerCase().startsWith("mac")
})
binding.setVariable("isWin", {
return System.getProperty("os.name").toLowerCase().startsWith("windows")
})
binding.setVariable("isEap", {
return "true" == p("component.version.eap")
})
binding.setVariable("mem32", "-server -Xms128m -Xmx512m -XX:MaxPermSize=250m -XX:ReservedCodeCacheSize=150m")
binding.setVariable("mem64", "-Xms128m -Xmx750m -XX:MaxPermSize=350m -XX:ReservedCodeCacheSize=225m")
binding.setVariable("common_vmoptions", "-ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true " +
"-Didea.project.structure.max.errors.to.show=0 " +
"-Djsse.enableSNIExtension=false " +
"-XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50")
binding.setVariable("vmOptions", { "$common_vmoptions ${isEap() ? '-XX:+HeapDumpOnOutOfMemoryError' : ''}".trim() })
binding.setVariable("vmOptions32", { "$mem32 ${vmOptions()}".trim() })
binding.setVariable("vmOptions64", { "$mem64 ${vmOptions()}".trim() })
binding.setVariable("yjpOptions", { String systemSelector, String platformSuffix = "" ->
"-agentlib:yjpagent$platformSuffix=probe_disable=*,disablealloc,disabletracing,onlylocal,disableexceptiontelemetry,delay=10000,sessionname=$systemSelector".trim()
})
binding.setVariable("vmOptions32yjp", { String systemSelector ->
"${vmOptions32()} ${yjpOptions(systemSelector)}".trim()
})
binding.setVariable("vmOptions64yjp", { String systemSelector ->
"${vmOptions64()} ${yjpOptions(systemSelector, "64")}".trim()
})
binding.setVariable("isDefined", {String key ->
try {
this[key]
return true
}
catch (MissingPropertyException ignored) {
return false
}
})
private String require(String key) {
try {
this[key]
}
catch (MissingPropertyException ignored) {
projectBuilder.error("Property '$key' is required")
}
}
private String require(String key, String defaultValue) {
try {
this[key]
}
catch (MissingPropertyException ignored) {
projectBuilder.info("'$key' is not defined. Defaulting to '$defaultValue'")
this[key] = defaultValue
}
}
binding.setVariable("requireProperty", {String key, String defaultValue = null ->
if (defaultValue == null) {
require(key)
}
else {
require(key, defaultValue)
}
})
binding.setVariable("guessHome", {
// current file is supposed to be at build/scripts/*.gant path
String uri = requireProperty("gant.file")
new File(new URI(uri).getSchemeSpecificPart()).getParentFile().getParentFile().getParent()
})
binding.setVariable("loadProject", {
requireProperty("jdkHome", guessJdk())
def mac = isMac()
jdk("IDEA jdk", jdkHome) {
if (!mac) {
classpath "$jdkHome/lib/tools.jar"
}
}
projectBuilder.dataStorageRoot = new File("$home/.jps-build-data")
loadProjectFromPath(home)
})
boolean hasSourceRoots(JpsModule module) {
return module.getSourceRoots(JavaSourceRootType.SOURCE).iterator().hasNext()
}
binding.setVariable("findModule", {String name ->
project.modules.find { it.name == name }
})
binding.setVariable("allModules", {
return project.modules
})
binding.setVariable("printUnusedModules", {Set<String> usedModules ->
allModules().each {JpsModule m ->
if (!usedModules.contains(m.name) && hasSourceRoots(m)) {
projectBuilder.warning("Module $m.name is not used in project layout")
}
}
})
requireProperty("home", guessHome())
String readSnapshotBuild() {
def file = new File("$home/community/build.txt")
if (!file.exists()) {
file = new File("$home/build.txt")
}
return file.readLines().get(0)
}
binding.setVariable("snapshot", readSnapshotBuild())
projectBuilder.buildInfoPrinter = new TeamCityBuildInfoPrinter()
projectBuilder.compressJars = false
binding.setVariable("notifyArtifactBuilt", { String artifactPath ->
if (!artifactPath.startsWith(home)) {
// AndroidStudio: make this to be just an info as the out folder is typically
// not in the home folder
projectBuilder.info("Artifact path $artifactPath should start with $home")
return
}
def relativePath = artifactPath.substring(home.length())
if (relativePath.startsWith("/")) {
relativePath = relativePath.substring(1)
}
def file = new File(artifactPath)
if (file.isDirectory()) {
relativePath += "=>" + file.name
}
projectBuilder.info("##teamcity[publishArtifacts '$relativePath']")
})
def suspendUntilDebuggerConnect = System.getProperty("debug.suspend") ?: "n"
def debugPort = System.getProperty("debug.port") ?: 5555
if (suspendUntilDebuggerConnect == 'y') {
println """\
------------->----------- This process is suspended until remote debugger connects to the port $debugPort ----<----
-------------------------------------------^------^------^------^------^------^------^-----------------------
"""
}
binding.setVariable("patchFiles", { List files, Map args, String marker = "__" ->
files.each { file ->
args.each { arg ->
ant.replace(file: file, token: "${marker}${arg.key}${marker}", value: arg.value)
}
}
})
binding.setVariable("copyAndPatchFile", { String file, String target, Map args, String marker = "__" ->
ant.copy(file: file, tofile: target, overwrite: "true") {
filterset(begintoken: marker, endtoken: marker) {
args.each {
filter(token: it.key, value: it.value)
}
}
}
})
binding.setVariable("copyAndPatchFiles", { Closure files, String target, Map args, String marker = "__" ->
ant.copy(todir: target, overwrite: "true") {
files()
filterset(begintoken: marker, endtoken: marker) {
args.each {
filter(token: it.key, value: it.value)
}
}
}
})
binding.setVariable("wireBuildDate", { String buildNumber, String appInfoFile ->
ant.tstamp()
patchFiles([appInfoFile], ["BUILD_NUMBER": buildNumber, "BUILD_DATE": DSTAMP,
"PACKAGE_CODE": buildNumber.substring(0, buildNumber.indexOf('-'))])
})
binding.setVariable("commonJvmArgs", {
return [
"-ea",
"-server",
"-Didea.home.path=$home",
"-Xbootclasspath/p:${projectBuilder.moduleOutput(findModule("boot"))}",
"-XX:+HeapDumpOnOutOfMemoryError",
"-Didea.system.path=${p("teamcity.build.tempDir")}/system",
"-Didea.config.path=${p("teamcity.build.tempDir")}/config"]
// We don't want this on the Jenkins build server
// "-Xdebug",
// "-Xrunjdwp:transport=dt_socket,server=y,suspend=$suspendUntilDebuggerConnect,address=$debugPort"]
})
binding.setVariable("classPathLibs", [
"bootstrap.jar",
"extensions.jar",
"util.jar",
"jdom.jar",
"log4j.jar",
"trove4j.jar",
"jna.jar"
])
binding.setVariable("platformApiModules", [
"analysis-api",
"core-api",
"dvcs-api",
"editor-ui-api",
"external-system-api",
"indexing-api",
"jps-model-api",
"lang-api",
"lvcs-api",
"projectModel-api",
"platform-api",
"structure-view-api",
"usageView",
"vcs-api",
"vcs-api-core",
"vcs-log-api",
"vcs-log-graph-api",
"xdebugger-api",
"remote-servers-api",
"remote-servers-agent-rt",
"xml-analysis-api",
"xml-openapi",
"xml-psi-api",
"xml-structure-view-api",
])
binding.setVariable("platformImplementationModules", [
"analysis-impl",
"core-impl",
"dvcs-impl",
"editor-ui-ex",
"images",
"indexing-impl",
"jps-model-impl",
"jps-model-serialization",
"lang-impl",
"lvcs-impl",
"projectModel-impl",
"platform-impl",
"structure-view-impl",
"vcs-impl",
"vcs-log-graph",
"vcs-log-impl",
"testRunner",
"smRunner",
"relaxng",
"RegExpSupport",
"spellchecker",
"xdebugger-impl",
"remote-servers-impl",
"xml",
"xml-analysis-impl",
"xml-psi-impl",
"xml-structure-view-impl",
"protocol-reader-runtime",
"script-debugger-backend",
"script-debugger-ui"
])
binding.setVariable("layoutMacApp", { String path, String ch, Map args ->
ant.copy(todir: "$path/bin") {
fileset(dir: "$ch/bin/mac")
}
ant.copy(todir: path) {
fileset(dir: "$ch/build/conf/mac/Contents")
}
ant.tstamp() {
format(property: "todayYear", pattern: "yyyy")
}
String executable = args.executable != null ? args.executable : p("component.names.product").toLowerCase()
String helpId = args.help_id != null ? args.help_id : "IJ"
String icns = "idea.icns"
String helpIcns = "$path/Resources/${helpId}.help/Contents/Resources/Shared/product.icns"
if (args.icns != null) {
ant.delete(file: "$path/Resources/idea.icns")
ant.copy(file: args.icns, todir: "$path/Resources")
ant.copy(file: args.icns, tofile: helpIcns)
icns = new File((String)args.icns).getName();
} else {
ant.copy(file: "$path/Resources/idea.icns", tofile: helpIcns)
}
String fullName = args.fullName != null ? args.fullName : p("component.names.fullname")
String vmOptions = "-Dfile.encoding=UTF-8 ${vmOptions()} -Xverify:none"
String minor = p("component.version.minor")
String version = isEap() && !minor.contains("RC") && !minor.contains("Beta") ? "EAP $args.buildNumber" : "${p("component.version.major")}.${minor}"
Map properties = readIdeaProperties(args)
def coreKeys = ["idea.platform.prefix", "idea.paths.selector"]
String coreProperties = submapToXml(properties, coreKeys);
StringBuilder effectiveProperties = new StringBuilder()
properties.each { k, v ->
if (!coreKeys.contains(k)) {
effectiveProperties.append("$k=$v\n");
}
}
new File("$path/bin/idea.properties").text = effectiveProperties.toString()
String ideaVmOptions = "$mem64 -XX:+UseCompressedOops".split(" ").join("\n")
if (isEap() && !args.mac_no_yjp) {
ideaVmOptions += " ${yjpOptions(args.system_selector)}"
}
new File("$path/bin/idea.vmoptions").text = ideaVmOptions
String classPath = classPathLibs.collect {"\$APP_PACKAGE/Contents/lib/${it}" }.join(":")
String archs = """
<key>LSArchitecturePriority</key>
<array>"""
(args.archs != null ? args.archs : ["x86_64", "i386"]).each {
archs += "<string>${it}</string>"
}
archs +="</array>\n"
String urlSchemes = ""
if (args.urlSchemes != null) {
urlSchemes += """
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>Stacktrace</string>
<key>CFBundleURLSchemes</key>
<array>
"""
args.urlSchemes.each { scheme ->
urlSchemes += " <string>${scheme}</string>"
}
urlSchemes += """
</array>
</dict>
</array>
"""
}
ant.replace(file: "$path/Info.plist") {
replacefilter(token: "@@build@@", value: args.buildNumber)
replacefilter(token: "@@doc_types@@", value: ifNull(args.doc_types, ""))
replacefilter(token: "@@executable@@", value: executable)
replacefilter(token: "@@icns@@", value: icns)
replacefilter(token: "@@bundle_name@@", value: fullName)
replacefilter(token: "@@bundle_identifier@@", value: args.bundleIdentifier)
replacefilter(token: "@@year@@", value: "$todayYear")
replacefilter(token: "@@company_name@@", value: args.companyName)
replacefilter(token: "@@min_year@@", value: "2013")
replacefilter(token: "@@max_year@@", value: "$todayYear")
replacefilter(token: "@@version@@", value: version)
replacefilter(token: "@@vmoptions@@", value: vmOptions)
replacefilter(token: "@@idea_properties@@", value: coreProperties)
replacefilter(token: "@@class_path@@", value: classPath)
replacefilter(token: "@@help_id@@", value: helpId)
replacefilter(token: "@@url_schemes@@", value: urlSchemes)
replacefilter(token: "@@archs@@", value: archs)
replacefilter(token: "@@min_osx@@", value: ifNull(args.min_osx, "10.6"))
}
if (executable != "idea") {
ant.move(file: "$path/MacOS/idea", tofile: "$path/MacOS/$executable")
}
ant.replace(file: "$path/bin/inspect.sh") {
replacefilter(token: "@@product_full@@", value: fullName)
replacefilter(token: "@@script_name@@", value: executable)
}
if (args.inspect_script != null && args.inspect_script != "inspect") {
ant.move(file: "$path/bin/inspect.sh", tofile: "$path/bin/${args.inspect_script}.sh")
}
ant.fixcrlf(srcdir: "$path/bin", includes: "*.sh", eol: "unix")
})
binding.setVariable("winScripts", { String target, String home, String name, Map args ->
String fullName = args.fullName != null ? args.fullName : p("component.names.fullname")
String product_uc = args.product_uc != null ? args.product_uc : p("component.names.product").toUpperCase().replace(" ", "_")
String vm_options = args.vm_options != null ? args.vm_options : "${p("component.names.product").toLowerCase().replace(" ", "-")}.exe"
if (vm_options.endsWith(".exe")) {
vm_options = vm_options.replace(".exe", "%BITS%.exe")
}
else {
vm_options = vm_options + "%BITS%"
}
String classPath = "SET CLASS_PATH=%IDE_HOME%\\lib\\${classPathLibs[0]}\n"
classPath += classPathLibs[1..-1].collect {"SET CLASS_PATH=%CLASS_PATH%;%IDE_HOME%\\lib\\${it}"}.join("\n")
if (args.tools_jar) classPath += "\nSET CLASS_PATH=%CLASS_PATH%;%JDK%\\lib\\tools.jar"
ant.copy(todir: "$target/bin") {
fileset(dir: "$home/bin/scripts/win")
filterset(begintoken: "@@", endtoken: "@@") {
filter(token: "product_full", value: fullName)
filter(token: "product_uc", value: product_uc)
filter(token: "vm_options", value: vm_options)
filter(token: "isEap", value: isEap())
filter(token: "system_selector", value: args.system_selector)
filter(token: "ide_jvm_args", value: ifNull(args.ide_jvm_args, ""))
filter(token: "class_path", value: classPath)
filter(token: "script_name", value: name)
}
}
if (name != "idea.bat") {
ant.move(file: "$target/bin/idea.bat", tofile: "$target/bin/$name")
}
if (args.inspect_script != null && args.inspect_script != "inspect") {
ant.move(file: "$target/bin/inspect.bat", tofile: "$target/bin/${args.inspect_script}.bat")
}
ant.fixcrlf(srcdir: "$target/bin", includes: "*.bat", eol: "dos")
})
private ifNull(v, defVal) { v != null ? v : defVal }
binding.setVariable("unixScripts", { String target, String home, String name, Map args ->
String fullName = args.fullName != null ? args.fullName : p("component.names.fullname")
String product_uc = args.product_uc != null ? args.product_uc : p("component.names.product").toUpperCase()
String vm_options = args.vm_options != null ? args.vm_options : p("component.names.product").toLowerCase()
String classPath = "CLASSPATH=\"\$IDE_HOME/lib/${classPathLibs[0]}\"\n"
classPath += classPathLibs[1..-1].collect {"CLASSPATH=\"\$CLASSPATH:\$IDE_HOME/lib/${it}\""}.join("\n")
if (args.tools_jar) classPath += "\nCLASSPATH=\"\$CLASSPATH:\$JDK/lib/tools.jar\""
ant.copy(todir: "$target/bin") {
fileset(dir: "$home/bin/scripts/unix")
filterset(begintoken: "@@", endtoken: "@@") {
filter(token: "product_full", value: fullName)
filter(token: "product_uc", value: product_uc)
filter(token: "vm_options", value: vm_options)
filter(token: "isEap", value: isEap())
filter(token: "system_selector", value: args.system_selector)
filter(token: "ide_jvm_args", value: ifNull(args.ide_jvm_args, ""))
filter(token: "class_path", value: classPath)
filter(token: "script_name", value: name)
}
}
if (name != "idea.sh") {
ant.move(file: "$target/bin/idea.sh", tofile: "$target/bin/$name")
}
if (args.inspect_script != null && args.inspect_script != "inspect") {
ant.move(file: "$target/bin/inspect.sh", tofile: "$target/bin/${args.inspect_script}.sh")
}
ant.fixcrlf(srcdir: "$target/bin", includes: "*.sh", eol: "unix")
})
binding.setVariable("winVMOptions", { String target, Map args, String name, String name64 = null ->
if (name != null) {
def options = vmOptions32()
options = options.replace(" -XX:+UseCodeCacheFlushing", "")
options += " -Didea.platform.prefix=" + args.platform_prefix
options += " -Didea.paths.selector=" + args.system_selector
ant.echo(file: "$target/bin/${name}.vmoptions", message: options.replace(' ', '\n'))
}
if (name64 != null) {
def options = vmOptions64()
options += " -Didea.platform.prefix=" + args.platform_prefix
options += " -Didea.paths.selector=" + args.system_selector
ant.echo(file: "$target/bin/${name64}.vmoptions", message: options.replace(' ', '\n'))
}
ant.fixcrlf(srcdir: "$target/bin", includes: "*.vmoptions", eol: "dos")
})
binding.setVariable("unixVMOptions", { String target, String name, String name64 = (name + "64") ->
if (name != null) {
ant.echo(file: "$target/bin/${name}.vmoptions", message: "${vmOptions32()} -Dawt.useSystemAAFontSettings=lcd".trim().replace(' ', '\n'))
}
if (name64 != null) {
ant.echo(file: "$target/bin/${name64}.vmoptions", message: "${vmOptions64()} -Dawt.useSystemAAFontSettings=lcd".trim().replace(' ', '\n'))
}
ant.fixcrlf(srcdir: "$target/bin", includes: "*.vmoptions", eol: "unix")
})
binding.setVariable("unixReadme", { String target, String home, Map args ->
String fullName = args.fullName != null ? args.fullName : p("component.names.fullname")
String settings_dir = args.system_selector.replaceFirst("\\d+", "")
copyAndPatchFile("$home/build/Install-Linux-tar.txt", "$target/Install-Linux-tar.txt",
["product_full": fullName,
"product": p("component.names.product").toLowerCase(),
"system_selector": args.system_selector,
"script_name" : args.script_name,
"settings_dir": settings_dir], "@@")
ant.fixcrlf(file: "$target/bin/Install-Linux-tar.txt", eol: "unix")
})
binding.setVariable("forceDelete", { String dirPath ->
// if wasn't deleted - retry several times
attempt = 1
while (attempt < 21 && (new File(dirPath).exists())) {
if (attempt > 1) {
ant.echo "Deleting $dirPath ... (attempt=$attempt)"
// let's wait a bit and try again - may be help
// in some cases on our windows 7 agents
sleep(2000)
}
ant.delete(failonerror: false, dir: dirPath)
attempt++
}
if (new File(dirPath).exists()) {
ant.project.log ("Cannot delete directory: $dirPath" )
System.exit (1)
}
})
binding.setVariable("patchPropertiesFile", { String target, Map args = [:] ->
String file = "$target/bin/idea.properties"
if (args.appendices != null) {
ant.concat(destfile: file, append: true) {
args.appendices.each {
fileset(file: it)
}
}
}
String product_uc = args.product_uc != null ? args.product_uc : p("component.names.product").toUpperCase()
String settings_dir = args.system_selector.replaceFirst("\\d+", "")
ant.replace(file: file) {
replacefilter(token: "@@product_uc@@", value: product_uc)
replacefilter(token: "@@settings_dir@@", value: settings_dir)
}
String message = (isEap() ? """
#-----------------------------------------------------------------------
# Change to 'disabled' if you don't want to receive instant visual notifications
# about fatal errors that happen to an IDE or plugins installed.
#-----------------------------------------------------------------------
idea.fatal.error.notification=enabled
"""
: """
#-----------------------------------------------------------------------
# Change to 'enabled' if you want to receive instant visual notifications
# about fatal errors that happen to an IDE or plugins installed.
#-----------------------------------------------------------------------
idea.fatal.error.notification=disabled
""")
ant.echo(file: file, append: true, message: message)
})
binding.setVariable("zipSources", { String home, String targetDir ->
String sources = "$targetDir/sources.zip"
projectBuilder.stage("zip sources to $sources")
ant.mkdir(dir: targetDir)
ant.delete(file: sources)
ant.zip(destfile: sources) {
fileset(dir: home) {
["java", "groovy", "ipr", "iml", "form", "xml", "properties"].each {
include(name: "**/*.$it")
}
exclude(name: "**/testData/**")
}
}
notifyArtifactBuilt(sources)
})
/**
* E.g.
*
* Load all properties from file:
* readIdeaProperties("idea.properties.path" : "$home/ruby/build/idea.properties")
*
* Load all properties except "idea.cycle.buffer.size", change "idea.max.intellisense.filesize" to 3000
* and enable "idea.is.internal" mode:
* readIdeaProperties("idea.properties.path" : "$home/ruby/build/idea.properties",
* "idea.properties" : ["idea.max.intellisense.filesize" : 3000,
* "idea.cycle.buffer.size" : null,
* "idea.is.internal" : true ])
* @param args
* @return text xml properties description in xml
*/
private Map readIdeaProperties(Map args) {
String ideaPropertiesPath = args == null ? null : args.get("idea.properties.path")
if (ideaPropertiesPath == null) {
return [:]
}
// read idea.properties file
Properties ideaProperties = new Properties();
FileInputStream ideaPropertiesFile = new FileInputStream(ideaPropertiesPath);
ideaProperties.load(ideaPropertiesFile);
ideaPropertiesFile.close();
def defaultProperties = ["CVS_PASSFILE": "~/.cvspass",
"com.apple.mrj.application.live-resize": "false",
"idea.paths.selector": args.system_selector,
"java.endorsed.dirs": "",
"idea.smooth.progress": "false",
"apple.laf.useScreenMenuBar": "true",
"apple.awt.graphics.UseQuartz": "true",
"apple.awt.fullscreencapturealldisplays": "false"]
if (args.platform_prefix != null) {
defaultProperties.put("idea.platform.prefix", args.platform_prefix)
}
Map properties = defaultProperties
def customProperties = args.get("idea.properties")
if (customProperties != null) {
properties += customProperties
}
properties.each {k, v ->
if (v == null) {
// if overridden with null - ignore property
ideaProperties.remove(k)
} else {
// if property is overridden in args map - use new value
ideaProperties.put(k, v)
}
}
return ideaProperties;
}
private String submapToXml(Map properties, List keys) {
// generate properties description for Info.plist
StringBuilder buff = new StringBuilder()
keys.each { key ->
String value = properties[key]
if (value != null) {
String string =
"""
<key>$key</key>
<string>$value</string>
"""
buff.append(string)
}
}
return buff.toString()
}
binding.setVariable("buildWinZip", { String zipRoot, String zipPath, List paths ->
projectBuilder.stage(".win.zip")
fixIdeaPropertiesEol(paths, "dos")
ant.zip(zipfile: zipPath) {
paths.each {
zipfileset(dir: it, prefix: zipRoot)
}
}
notifyArtifactBuilt(zipPath)
})
binding.setVariable("buildMacZip", { String zipRoot, String zipPath, List paths, String macPath, List extraBins = [] ->
projectBuilder.stage(".mac.zip")
allPaths = paths + [macPath]
ant.zip(zipfile: zipPath) {
allPaths.each {
zipfileset(dir: it, prefix: zipRoot) {
exclude(name: "bin/*.sh")
exclude(name: "bin/*.py")
exclude(name: "bin/fsnotifier")
exclude(name: "bin/restarter")
exclude(name: "MacOS/*")
extraBins.each {
exclude(name: it)
}
exclude(name: "bin/idea.properties")
}
}
allPaths.each {
zipfileset(dir: it, filemode: "755", prefix: zipRoot) {
include(name: "bin/*.sh")
include(name: "bin/*.py")
include(name: "bin/fsnotifier")
include(name: "bin/restarter")
include(name: "MacOS/*")
extraBins.each {
include(name: it)
}
}
}
zipfileset(file: "$macPath/bin/idea.properties", prefix: "$zipRoot/bin")
}
})
binding.setVariable("buildTarGz", { String tarRoot, String tarPath, List paths, List extraBins = [] ->
projectBuilder.stage(".tar.gz")
fixIdeaPropertiesEol(paths, "unix")
ant.tar(tarfile: tarPath, longfile: "gnu") {
paths.each {
tarfileset(dir: it, prefix: tarRoot) {
exclude(name: "bin/*.sh")
exclude(name: "bin/fsnotifier*")
extraBins.each {
exclude(name: it)
}
type(type: "file")
}
}
paths.each {
tarfileset(dir: it, filemode: "755", prefix: tarRoot) {
include(name: "bin/*.sh")
include(name: "bin/fsnotifier*")
extraBins.each {
include(name: it)
}
type(type: "file")
}
}
}
String gzPath = "${tarPath}.gz"
ant.gzip(src: tarPath, zipfile: gzPath)
ant.delete(file: tarPath)
notifyArtifactBuilt(gzPath)
})
private void fixIdeaPropertiesEol(List paths, String eol) {
paths.each {
String file = "$it/bin/idea.properties"
if (new File(file).exists()) {
ant.fixcrlf(file: file, eol: eol)
}
}
}
binding.setVariable("buildWinLauncher", { String ch, String inputPath, String outputPath, String appInfo,
String launcherProperties, String pathsSelector, List resourcePaths ->
projectBuilder.stage("winLauncher")
if (pathsSelector != null) {
def paths = getProperty("paths")
def launcherPropertiesTemp = "${paths.sandbox}/launcher.properties"
copyAndPatchFile(launcherProperties, launcherPropertiesTemp, ["PRODUCT_PATHS_SELECTOR": pathsSelector])
launcherProperties = launcherPropertiesTemp
}
ant.java(classname: "com.pme.launcher.LauncherGeneratorMain", fork: "true") {
sysproperty(key: "java.awt.headless", value: "true")
arg(value: inputPath)
arg(value: appInfo)
arg(value: "$ch/native/WinLauncher/WinLauncher/resource.h")
arg(value: launcherProperties)
arg(value: outputPath)
classpath {
pathelement(location: "$ch/build/lib/launcher-generator.jar")
fileset(dir: "$ch/lib") {
include(name: "guava*.jar")
include(name: "jdom.jar")
include(name: "sanselan*.jar")
}
resourcePaths.each {
pathelement(location: it)
}
}
}
})
binding.setVariable("layoutUpdater", { String target, String jarName = "updater.jar" ->
layout(target) {
jar(jarName) {
module("updater")
}
}
})
binding.setVariable("collectUsedJars", { List modules, List approvedJars, List forbiddenJars, List modulesToBuild ->
def usedJars = new HashSet();
modules.each {
def module = findModule(it)
if (module != null) {
projectBuilder.moduleRuntimeClasspath(module, false).each {
File file = new File(it)
if (file.exists()) {
String path = file.canonicalPath.replace('\\', '/')
if (path.endsWith(".jar") && approvedJars.any { path.startsWith(it) } && !forbiddenJars.any { path.contains(it) }) {
if (usedJars.add(path)) {
projectBuilder.info("\tADDED: $path for ${module.getName()}")
}
}
}
}
if (modulesToBuild != null) {
modulesToBuild << module
}
}
else {
projectBuilder.warning("$it is not a module")
}
}
return usedJars
})
binding.setVariable("buildModulesAndCollectUsedJars", { List modules, List approvedJars, List forbiddenJars ->
def modulesToBuild = []
def usedJars = collectUsedJars(modules, approvedJars, forbiddenJars, modulesToBuild)
projectBuilder.cleanOutput()
projectBuilder.buildModules(modulesToBuild)
return usedJars
})
binding.setVariable("buildSearchableOptions", { String target, List licenses, Closure cp, String jvmArgs = null,
def paths = getProperty("paths") ->
projectBuilder.stage("Building searchable options")
String targetFile = "${target}/searchableOptions.xml"
ant.delete(file: targetFile)
licenses.each {
ant.copy(file: it, todir: paths.ideaSystem)
}
ant.path(id: "searchable.options.classpath") { cp() }
String classpathFile = "${paths.sandbox}/classpath.txt"
ant.echo(file: classpathFile, append: false, message: "\${toString:searchable.options.classpath}")
ant.replace(file: classpathFile, token: File.pathSeparator, value: "\n")
ant.java(classname: "com.intellij.rt.execution.CommandLineWrapper", fork: true, failonerror: true) {
jvmarg(line: "-Xbootclasspath/a:${projectBuilder.moduleOutput(findModule("boot"))} -ea -Xmx500m -XX:MaxPermSize=200m")
jvmarg(line: "-Didea.home.path=$home -Didea.system.path=${paths.ideaSystem} -Didea.config.path=${paths.ideaConfig}")
if (jvmArgs != null) {
jvmarg(line: jvmArgs)
}
arg(line: "${classpathFile} com.intellij.idea.Main traverseUI ${target}/searchableOptions.xml")
classpath() {
pathelement(location: "${projectBuilder.moduleOutput(findModule("java-runtime"))}")
}
}
ant.available(file: targetFile, property: "searchable.options.exists");
ant.fail(unless: "searchable.options.exists", message: "Searchable options were not built.")
})
binding.setVariable("reassignAltClickToMultipleCarets", {String communityHome ->
String defaultKeymapContent = new File("$communityHome/platform/platform-resources/src/idea/Keymap_Default.xml").text
defaultKeymapContent = defaultKeymapContent.replace("<mouse-shortcut keystroke=\"alt button1\"/>", "")
defaultKeymapContent = defaultKeymapContent.replace("<mouse-shortcut keystroke=\"alt shift button1\"/>",
"<mouse-shortcut keystroke=\"alt button1\"/>")
patchedKeymapFile = new File("${paths.sandbox}/classes/production/platform-resources/idea/Keymap_Default.xml")
patchedKeymapFile.write(defaultKeymapContent)
})
// modules used in Upsource and in Kotlin as an API to IDEA
binding.setVariable("analysisApiModules", [
"analysis-api",
"boot",
"core-api",
"duplicates-analysis",
"editor-ui-api",
"editor-ui-ex",
"extensions",
"indexing-api",
"java-analysis-api",
"java-indexing-api",
"java-psi-api",
"java-structure-view",
"jps-model-api",
"jps-model-serialization",
"projectModel-api",
"structure-view-api",
"util",
"util-rt",
"xml-analysis-api",
"xml-psi-api",
"xml-structure-view-api",
])
binding.setVariable("analysisImplModules", [
"analysis-impl",
"core-impl",
"indexing-impl",
"java-analysis-impl",
"java-indexing-impl",
"java-psi-impl",
"projectModel-impl",
"structure-view-impl",
"xml-analysis-impl",
"xml-psi-impl",
"xml-structure-view-impl",
])