build scripts redesign: rewritten script which finds and extracts JREs

This commit is contained in:
nik
2016-07-12 10:53:01 +03:00
parent e527a30df2
commit 1822a716db
9 changed files with 174 additions and 63 deletions
@@ -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 {
@@ -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
/**
@@ -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"
}
}
@@ -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
}
}
}
@@ -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")
@@ -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) {
@@ -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) {
@@ -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/**/*")
}
}
@@ -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 {