diff --git a/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy b/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy index e21919f150b8..9e0bdb540a4d 100644 --- a/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy +++ b/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy @@ -17,6 +17,7 @@ package org.jetbrains.intellij.build import org.codehaus.gant.GantBuilder import org.jetbrains.intellij.build.impl.BuildContextImpl +import org.jetbrains.intellij.build.impl.BundledJreManager import org.jetbrains.jps.gant.JpsGantProjectBuilder import org.jetbrains.jps.model.JpsGlobal import org.jetbrains.jps.model.JpsProject @@ -39,6 +40,7 @@ abstract class BuildContext { MacHostProperties macHostProperties BuildOptions options SignTool signTool + BundledJreManager bundledJreManager /** * Build number without product code (e.g. '162.500.10') @@ -116,22 +118,6 @@ abstract class BuildPaths { * Path to a directory containing JDK (currently Java 8) which is used to compile the project */ String jdkHome - - /** - * Path to a directory containing distribution of JRE for Windows which will be bundled with the product - */ - String winJre - - String oracleWinJre - /** - * Path to a directory containing distribution of JRE for Linux which will be bundled with the product - */ - String linuxJre - - /** - * Path to a .tar.gz archive containing distribution of JRE for Mac OS which will be bundled with the product - */ - String macJreTarGz } interface BuildMessages { diff --git a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy index 0b825d0f5d5a..28e9e367aa81 100644 --- a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy +++ b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy @@ -15,6 +15,8 @@ */ package org.jetbrains.intellij.build +import org.jetbrains.intellij.build.impl.JvmArchitecture + /** * @author nik */ @@ -29,7 +31,10 @@ abstract class WindowsDistributionCustomizer { */ boolean includeBatchLaunchers = true - boolean bundleJre = true + /** + * Specify bitness of bundled JRE. If {@code null} no JRE will be bundled + */ + JvmArchitecture bundledJreArchitecture = JvmArchitecture.x32 boolean buildZipWithBundledOracleJre = false /** diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy index eb46f2aa6f9d..ec92f520d85a 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy @@ -53,6 +53,7 @@ class BuildContextImpl extends BuildContext { underTeamCity = System.getProperty("teamcity.buildType.id") != null messages = new BuildMessagesImpl(projectBuilder, ant.project, underTeamCity) + bundledJreManager = new BundledJreManager(this, buildOutputRoot) def jdk8Home = JdkUtils.computeJdkHome(messages, "jdk8Home", "$projectHome/build/jdk/1.8", "JDK_18_x64") paths = new BuildPathsImpl(communityHome, projectHome, buildOutputRoot, jdk8Home) @@ -60,7 +61,7 @@ class BuildContextImpl extends BuildContext { loadProject() } else { - //todo[nik] currently we need this to build IDEA CE from IDEA UI build scripts. It would be better to create a separate JpsProject instance + //todo[nik] currently we need this to build IDEA CE from IDEA UI build scripts. It would be better to create a separate JpsProject instance instead messages.info("Skipping loading project because it's already loaded") } def appInfoFile = findApplicationInfoInSources() @@ -220,8 +221,5 @@ class BuildPathsImpl extends BuildPaths { artifacts = "${this.buildOutputRoot}/artifacts" distAll = "$buildOutputRoot/dist.all" temp = "$buildOutputRoot/temp" - oracleWinJre = "$buildOutputRoot/jdk.oracle.win" - winJre = "$buildOutputRoot/jdk.win" - linuxJre = "$buildOutputRoot/jdk.linux" } } diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy new file mode 100644 index 000000000000..a4494eded28e --- /dev/null +++ b/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2016 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.jetbrains.intellij.build.impl + +import com.intellij.openapi.util.SystemInfo +import org.jetbrains.intellij.build.BuildContext +/** + * @author nik + */ +class BundledJreManager { + private final BuildContext buildContext + private final String baseDirectoryForJre + + BundledJreManager(BuildContext buildContext, String baseDirectoryForJre) { + this.buildContext = buildContext + this.baseDirectoryForJre = baseDirectoryForJre + } + + /** + * Extract JRE for Linux distribution of the product + * @return path to the directory containing 'jre' subdirectory with extracted JRE + */ + public String extractLinuxJre() { + return extractJre("linux") + } + + /** + * Extract JRE for Windows distribution of the product + * @return path to the directory containing 'jre' subdirectory with extracted JRE + */ + public String extractWinJre(JvmArchitecture arch) { + return extractJre("win", arch) + } + + /** + * Extract Oracle JRE for Windows distribution of the product + * @return path to the directory containing 'jre' subdirectory with extracted JRE + */ + public String extractOracleWinJre(JvmArchitecture arch) { + return extractJre("win", arch, JreVendor.Oracle) + } + + /** + * Return path to a .tar.gz archive containing distribution of JRE for Mac OS which will be bundled with the product + */ + public String findMacJreArchive() { + return findJreArchive("mac")?.absolutePath + } + + private String extractJre(String osDirName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) { + String vendorSuffix = vendor == JreVendor.Oracle ? ".oracle" : "" + String targetDir = "$baseDirectoryForJre/jre.$osDirName$arch.fileSuffix$vendorSuffix" + if (new File(targetDir).exists()) { + buildContext.messages.info("JRE is already extracted to $targetDir") + return targetDir + } + + File archive = findJreArchive(osDirName, arch, vendor) + if (archive == null) { + return null + } + buildContext.messages.block("Extracting $archive.name JRE") { + String destination = "$targetDir/jre" + if (SystemInfo.isWindows) { + buildContext.ant.untar(src: archive.absolutePath, dest: destination, compression: 'gzip') + } + else { + //'tar' command is used instead of Ant task to ensure that executable flags will be preserved + buildContext.ant.mkdir(dir: destination) + buildContext.ant.exec(executable: "tar", dir: archive.parent) { + arg(value: "-xf") + arg(value: archive.name) + arg(value: "--directory") + arg(value: destination) + } + } + } + return targetDir + } + + private File findJreArchive(String osDirName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) { + def jdkDir = new File(buildContext.paths.projectHome, "build/jdk/$osDirName") + String suffix = arch == JvmArchitecture.x32 ? "_x86" : "_x64" + String prefix = buildContext.productProperties.toolsJarRequired ? vendor.jreWithToolsJarNamePrefix : vendor.jreNamePrefix + def jdkFiles = jdkDir.listFiles().findAll { it.name.startsWith(prefix) && it.name.endsWith("${suffix}.tar.gz") } + if (jdkFiles.size() > 1) { + buildContext.messages.warning("Cannot extract $osDirName JRE: several matching files are found ($jdkFiles)") + return null + } + if (jdkFiles.isEmpty()) { + buildContext.messages.warning("Cannot extract $osDirName JRE: no '${prefix}...${suffix}.tar.gz' files found in $jdkDir") + return null + } + return jdkFiles.first() + } + + private enum JreVendor { + Oracle("jre8", "jdk8"), JetBrains("jbre8", "jbrex8") + + final String jreNamePrefix + final String jreWithToolsJarNamePrefix + + JreVendor(String jreNamePrefix, String jreWithToolsJarNamePrefix) { + this.jreNamePrefix = jreNamePrefix + this.jreWithToolsJarNamePrefix = jreWithToolsJarNamePrefix + } + } +} \ No newline at end of file diff --git a/build/groovy/org/jetbrains/intellij/build/impl/JvmArchitecture.groovy b/build/groovy/org/jetbrains/intellij/build/impl/JvmArchitecture.groovy index 5f95ba68e425..6b5543501f96 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/JvmArchitecture.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/JvmArchitecture.groovy @@ -18,6 +18,7 @@ package org.jetbrains.intellij.build.impl /** * @author nik */ +//tode[nik] rename and move out of 'impl'? enum JvmArchitecture { x32(""), x64("64") diff --git a/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy index 228a39ab207b..a6cbe97fbf95 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy @@ -49,12 +49,13 @@ class LinuxDistributionBuilder { unixVMOptions() unixReadme() buildContext.linuxDistributionCustomizer.copyAdditionalFiles(buildContext, unixDistPath) - buildTarGz(false) - if (new File(buildContext.paths.linuxJre).exists()) { - buildTarGz(true) + buildTarGz(null) + def jreDirectoryPath = buildContext.bundledJreManager.extractLinuxJre() + if (jreDirectoryPath != null) { + buildTarGz(jreDirectoryPath) } else { - buildContext.messages.info("Skipping building Linux distribution with bundled JRE because JRE directory doesn't exist: $buildContext.paths.linuxJre") + buildContext.messages.info("Skipping building Linux distribution with bundled JRE because JRE archive is missing") } } @@ -116,17 +117,17 @@ class LinuxDistributionBuilder { buildContext.ant.fixcrlf(file: "$unixDistPath/bin/Install-Linux-tar.txt", eol: "unix") } - private void buildTarGz(boolean bundleJre) { + private void buildTarGz(String jreDirectoryPath) { def tarRoot = buildContext.linuxDistributionCustomizer.rootDirectoryName(buildContext.buildNumber) - def suffix = bundleJre ? "" : "-no-jdk" + def suffix = jreDirectoryPath != null ? "" : "-no-jdk" def tarPath = "$buildContext.paths.artifacts/${buildContext.productProperties.baseArtifactName(buildContext.buildNumber)}${suffix}.tar" def extraBins = buildContext.linuxDistributionCustomizer.extraExecutables def paths = [buildContext.paths.distAll, unixDistPath] - if (bundleJre) { - paths += buildContext.paths.linuxJre + if (jreDirectoryPath != null) { + paths += jreDirectoryPath extraBins += "jre/jre/bin/*" } - buildContext.messages.block("Build Linux tar.gz archive${bundleJre ? "" : " (without JRE)"}") { + buildContext.messages.block("Build Linux tar.gz archive${jreDirectoryPath != null ? "" : " (without JRE)"}") { buildContext.ant.tar(tarfile: tarPath, longfile: "gnu") { paths.each { tarfileset(dir: it, prefix: tarRoot) { diff --git a/build/groovy/org/jetbrains/intellij/build/impl/MacDmgBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/MacDmgBuilder.groovy index d42694bebabe..f73736c37bcf 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/MacDmgBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/MacDmgBuilder.groovy @@ -48,24 +48,25 @@ class MacDmgBuilder { remoteDir += "-" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).replace(':', '-') } def dmgBuilder = new MacDmgBuilder(buildContext, remoteDir, macHostProperties) - if (buildContext.paths.macJreTarGz != null && new File(buildContext.paths.macJreTarGz).exists()) { - dmgBuilder.doSignAndBuildDmg(macZipPath, true) + def jreArchivePath = buildContext.bundledJreManager.findMacJreArchive() + if (jreArchivePath != null) { + dmgBuilder.doSignAndBuildDmg(macZipPath, jreArchivePath) } else { - buildContext.messages.info("Skipping building Mac OS distribution with bundled JRE because JRE archive doesn't exist: $buildContext.paths.macJreTarGz") + buildContext.messages.info("Skipping building Mac OS distribution with bundled JRE because JRE archive is missing") } if (buildContext.options.buildDmgWithoutBundledJre) { - dmgBuilder.doSignAndBuildDmg(macZipPath, false) + dmgBuilder.doSignAndBuildDmg(macZipPath, null) } } - private void doSignAndBuildDmg(String macZipPath, boolean bundleJre) { - def suffix = bundleJre ? "" : "-no-jdk" + private void doSignAndBuildDmg(String macZipPath, String jreArchivePath) { + def suffix = jreArchivePath != null ? "" : "-no-jdk" String targetFileName = buildContext.productProperties.baseArtifactName(buildContext.buildNumber) + suffix def sitFilePath = "$artifactsPath/${targetFileName}.sit" ant.copy(file: macZipPath, tofile: sitFilePath) ftpAction("mkdir") {} - signMacZip(sitFilePath, targetFileName, bundleJre) + signMacZip(sitFilePath, targetFileName, jreArchivePath) buildDmg(targetFileName) } @@ -109,12 +110,12 @@ class MacDmgBuilder { buildContext.notifyArtifactBuilt(dmgFilePath) } - private def signMacZip(String sitFilePath, String targetFileName, boolean bundleJre) { + private def signMacZip(String sitFilePath, String targetFileName, String jreArchivePath) { buildContext.messages.progress("Signing ${targetFileName}.sit") - if (bundleJre) { + if (jreArchivePath != null) { ftpAction("put") { - ant.fileset(file: buildContext.paths.macJreTarGz) + ant.fileset(file: jreArchivePath) } } @@ -129,7 +130,7 @@ class MacDmgBuilder { } } - String jreFileNameArgument = bundleJre ? " \"${PathUtilRt.getFileName(buildContext.paths.macJreTarGz)}\"" : "" + String jreFileNameArgument = jreArchivePath != null ? " \"${PathUtilRt.getFileName(jreArchivePath)}\"" : "" sshExec("$remoteDir/signapp.sh ${targetFileName} ${buildContext.fullBuildNumber} ${this.macHostProperties.userName}" + " ${this.macHostProperties.password} \"${this.macHostProperties.codesignString}\"$jreFileNameArgument") ftpAction("get", true, null, 3) { diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy index e5ce7896e353..25f065e2d530 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy @@ -26,10 +26,12 @@ import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName class WinExeInstallerBuilder { private final BuildContext buildContext private final GantBuilder ant + private final String jreDirectoryPath - WinExeInstallerBuilder(BuildContext buildContext) { + WinExeInstallerBuilder(BuildContext buildContext, String jreDirectoryPath) { this.buildContext = buildContext ant = buildContext.ant + this.jreDirectoryPath = jreDirectoryPath } void buildInstaller(String winDistPath) { @@ -47,15 +49,15 @@ class WinExeInstallerBuilder { ant.mkdir(dir: "$box/bin") ant.mkdir(dir: "$box/nsiconf") - def bundleJre = buildContext.windowsDistributionCustomizer.bundleJre - if (bundleJre && !new File(buildContext.paths.winJre).exists()) { - buildContext.messages.info("JRE won't be bundled with Windows installer because JRE directory doesn't exist: ${buildContext.paths.winJre}") + def bundleJre = buildContext.windowsDistributionCustomizer.bundledJreArchitecture != null + if (bundleJre && jreDirectoryPath == null) { + buildContext.messages.info("JRE won't be bundled with Windows installer because JRE archive is missing") bundleJre = false } if (bundleJre) { ant.copy(todir: "$box/bin") { - fileset(dir: "${buildContext.paths.winJre}/jre") { + fileset(dir: "$jreDirectoryPath/jre") { include(name: "**/msvcr71.dll") } } @@ -83,13 +85,7 @@ class WinExeInstallerBuilder { } if (bundleJre) { ant.fileset(dir: box, includes: "bin/msvcr71.dll") - ant.fileset(dir: buildContext.paths.winJre, includes: "jre/**/*") - //todo[nik] how tools.jar is excluded? - if (buildContext.productProperties.toolsJarRequired) { - ant.fileset(dir: buildContext.paths.winJre) { - include(name: "jre/lib/tools.jar") - } - } + ant.fileset(dir: jreDirectoryPath, includes: "jre/**/*") } } diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index f988b000657c..48992f449e00 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -51,20 +51,22 @@ class WindowsDistributionBuilder { buildWinLauncher(JvmArchitecture.x32) buildWinLauncher(JvmArchitecture.x64) buildContext.windowsDistributionCustomizer.copyAdditionalFiles(buildContext, winDistPath) - def customJrePath = buildContext.windowsDistributionCustomizer.bundleJre && new File(buildContext.paths.winJre).exists() ? buildContext.paths.winJre : null - buildWinZip(customJrePath, ".win") - String oracleJrePath = buildContext.paths.oracleWinJre - if (buildContext.windowsDistributionCustomizer.buildZipWithBundledOracleJre) { - if (new File(oracleJrePath, "jre").exists()) { + + def arch = buildContext.windowsDistributionCustomizer.bundledJreArchitecture + def jreDirectoryPath = arch != null ? buildContext.bundledJreManager.extractWinJre(arch) : null + buildWinZip(jreDirectoryPath, ".win") + if (arch != null && buildContext.windowsDistributionCustomizer.buildZipWithBundledOracleJre) { + String oracleJrePath = buildContext.bundledJreManager.extractOracleWinJre(arch) + if (oracleJrePath != null) { buildWinZip(oracleJrePath, "-oracle-win") } else { - buildContext.messages.warning("Skipping building Windows zip archive with bundled Oracle JRE: ${oracleJrePath}/jre doesn't exist") + buildContext.messages.warning("Skipping building Windows zip archive with bundled Oracle JRE because JRE archive is missing") } } buildContext.executeStep("Build Windows Exe Installer", BuildOptions.WINDOWS_EXE_INSTALLER_STEP) { - new WinExeInstallerBuilder(buildContext).buildInstaller(winDistPath) + new WinExeInstallerBuilder(buildContext, jreDirectoryPath).buildInstaller(winDistPath) } } @@ -189,13 +191,13 @@ IDS_VM_OPTIONS=$vmOptions } } - private void buildWinZip(String pathToJreToBundle, String zipNameSuffix) { + private void buildWinZip(String jreDirectoryPath, String zipNameSuffix) { buildContext.messages.block("Build Windows ${zipNameSuffix}.zip distribution") { def targetPath = "$buildContext.paths.artifacts/${buildContext.productProperties.baseArtifactName(buildContext.buildNumber)}${zipNameSuffix}.zip" def zipPrefix = buildContext.windowsDistributionCustomizer.rootDirectoryName(buildContext.buildNumber) def dirs = [buildContext.paths.distAll, winDistPath] - if (pathToJreToBundle != null) { - dirs += pathToJreToBundle + if (jreDirectoryPath != null) { + dirs += jreDirectoryPath } buildContext.ant.zip(zipfile: targetPath) { dirs.each {