Updated logic to support

- Code cleanup / refactor
- Improved Java versioning related logic
- Reworked jvmRelease -> jvmVerSpec
- Added support for deployed JREs
This commit is contained in:
Norberto Lopez
2016-05-07 03:53:54 +00:00
parent 0b17f51795
commit 04956c9172
8 changed files with 516 additions and 191 deletions

View File

@@ -20,25 +20,22 @@ def buildRelease(args, buildPath):
# Retrieve vars of interest
appName = args.name
version = args.version
jreRelease = args.jreVersion
jreVerSpec = args.jreVerSpec
platformStr = 'apple'
# Check our system environment before proceeding
if checkSystemEnvironment() == False:
return
# Attempt to locate a default JRE if None is specified in the args.
if jreRelease == None:
jreRelease = jreUtils.getDefaultJreRelease(platformStr)
# Let the user know if the 'user' specified JRE is not available and locate an alternative
elif jreUtils.getJreTarGzFile(platformStr, jreRelease) == None:
print('[Warning] User specified JRE ({0}) is not available for {1} platform. Searching for alternative...'.format(jreRelease, platformStr.capitalize()))
jreRelease = jreUtils.getDefaultJreRelease(platformStr)
args.jreRelease = jreRelease
# Select the jreTarGzFile to utilize for static releases
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, jreVerSpec)
if jreTarGzFile == None:
# Let the user know if the 'user' specified JRE is not available and locate an alternative
print('[Warning] User specified JRE ({0}) is not available for {1} platform. Searching for alternative...'.format(jreVerSpec, platformStr.capitalize()))
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, None)
# Form the list of distributions to build (dynamic and static JREs)
# Form the list of distributions to build (dynamic and static releases)
distList = [(appName + '-' + version, None)]
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, jreRelease)
if jreTarGzFile != None:
distList.append((appName + '-' + version + '-jre', jreTarGzFile))
@@ -47,7 +44,7 @@ def buildRelease(args, buildPath):
print('Building {0} distribution: {1}'.format(platformStr.capitalize(), aDistName))
# Let the user know of the JRE tar.gz we are going to build with
if aJreTarGzFile != None:
print('\tUtilizing jreRelease: ' + aJreTarGzFile)
print('\tUtilizing JRE: ' + aJreTarGzFile)
# Create a tmp folder and build the static release to the tmp folder
tmpPath = tempfile.mkdtemp(prefix=platformStr, dir=buildPath)
@@ -62,9 +59,9 @@ def buildRelease(args, buildPath):
print('\tForming DMG image. File: ' + dmgFile)
proc = miscUtils.executeAndLog(cmd, "\t\tgenisoimage: ")
if proc.returncode != 0:
print('\tError: Failed to form DMG image. Return code: ' + str(proc.returncode))
print('\tError: Failed to form DMG image. Return code: ' + str(proc.returncode) + '\n')
else:
print('\tFinished building release: ' + os.path.basename(dmgFile))
print('\tFinished building release: ' + os.path.basename(dmgFile) + '\n')
# Perform cleanup
shutil.rmtree(tmpPath)
@@ -136,7 +133,6 @@ def buildDistTree(buildPath, rootPath, args, jreTarGzFile):
appName = args.name
bgFile = args.bgFile
icnsFile = args.icnsFile
jreRelease = args.jreRelease
# Form the symbolic link which points to /Applications
srcPath = '/Applications'
@@ -208,7 +204,7 @@ def buildDistTree(buildPath, rootPath, args, jreTarGzFile):
# Form the Info.plist file
dstPath = os.path.join(rootPath, appName + '.app', 'Contents', 'Info.plist')
if jreTarGzFile != None:
buildPListInfoStatic(dstPath, args)
buildPListInfoStatic(dstPath, args, jreTarGzFile)
else:
buildPListInfoShared(dstPath, args)
@@ -353,7 +349,7 @@ def buildPListInfoShared(destFile, args):
f.close()
def buildPListInfoStatic(destFile, args):
def buildPListInfoStatic(destFile, args, jreTarGzFile):
# Retrieve vars of interest
icnsStr = None
if args.icnsFile != None:
@@ -386,7 +382,7 @@ def buildPListInfoStatic(destFile, args):
tupList.append(('CFBundleVersion', args.version))
tupList.append(('NSHighResolutionCapable', 'true'))
tupList.append(('NSHumanReadableCopyright', ''))
jrePath = 'jre' + args.jreRelease
jrePath = jreUtils.getBasePathForJreTarGzFile(jreTarGzFile)
tupList.append(('JVMRuntime', jrePath))
tupList.append(('JVMMainClassName', 'appLauncher.AppLauncher'))

View File

@@ -1,7 +1,7 @@
#! /usr/bin/env python
from __future__ import print_function
import argparse
import distutils.spawn
import getpass
import math
import os
@@ -12,31 +12,14 @@ import sys
import tempfile
import time
#import buildCatalog
import distutils.spawn
import jreUtils
import miscUtils
import appleUtils
import linuxUtils
import windowsUtils
class FancyArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
self._action_defaults = {}
argparse.ArgumentParser.__init__(self, *args, **kwargs)
def convert_arg_line_to_args(self, arg_line):
# Add the line as an argument if it does not appear to be a comment
if len(arg_line) > 0 and arg_line.strip()[0] != '#':
yield arg_line
# argsparse.ArgumentParser.convert_arg_line_to_args(arg_line)
# else:
# print('Skipping line: ' + arg_line)
# # Example below will break all space separated lines into individual arguments
# for arg in arg_line.split():
# if not arg.strip():
# continue
# yield arg
from miscUtils import ErrorDM
from miscUtils import FancyArgumentParser
def buildCatalogFile(args, deltaPath):
@@ -49,11 +32,11 @@ def buildCatalogFile(args, deltaPath):
records.append(record)
# Record the JRE required
jreVersion = args.jreVersion
if jreVersion == None:
jreVersion = jreUtils.getDefaultJrVersion()
if jreVersion != None:
record = ('jre', jreVersion)
jreVerSpec = args.jreVerSpec
if jreVerSpec == None:
jreVerSpec = [jreUtils.getDefaultJreVerStr()]
if jreVerSpec != None:
record = ('jre', ",".join(jreVerSpec))
records.append(record)
snipLen = len(deltaPath) + 1
@@ -101,13 +84,14 @@ def buildCatalogFile(args, deltaPath):
f.write('exit\n')
f.close()
def checkForRequiredApplications():
"""Method to ensure we have all of the required applications installed to support building of distributions
The current set of applications required are:
java, jar, genisoimage, ImageMagick:convert"""
def checkForRequiredApplicationsAndExit():
"""Method to ensure we have all of the required applications installed to support building of distributions.
If there are mandatory applications that are missing then this will be printed to stderr and the program will exit.
The current set of required applications are:
java, jar, genisoimage"""
evalPath = distutils.spawn.find_executable('java')
errList = []
warnList = []
if evalPath == None:
errList.append('Failed while trying to locate java. Please install Java')
evalPath = distutils.spawn.find_executable('jar')
@@ -116,26 +100,36 @@ def checkForRequiredApplications():
evalPath = distutils.spawn.find_executable('genisoimage')
if evalPath == None:
errList.append('Failed while trying to locate genisoimage. Please install genisoimage')
# Bail if there are no issues
if len(errList) == 0:
return
# Log the issues and exit
print('There are configuration errors with the environment or system.')
# print('System Path:' + str(sys.path))
print('Please correct the following:')
for aError in errList:
print('\t' + aError)
warnList = checkForSuggestedApplications()
if len(warnList) > 0:
print('In addition please fix the following for full program functionality:')
for aWarn in warnList:
print('\t' + aWarn)
sys.exit(0)
def checkForSuggestedApplications():
"""Method to check for any suggested missing applications. If all suggested applications are installed then this method will return None,
otherwise it will return a list of messages which describe the missing applications and the corresponding missing functionality.
The current set of suggested applications are:
ImageMagick:convert"""
warnList = []
evalPath = distutils.spawn.find_executable('convert')
if evalPath == None:
warnList.append('Application \'convert\' was not found. Please install (ImageMagick) convert')
warnList.append('\tWindows icons will not be supported when using argument: -iconFile.')
if len(errList) > 0:
print('There are configuration errors with the environment or system.')
# print('System Path:' + str(sys.path))
print('Please correct the following:')
for aError in errList:
print('\t' + aError)
if len(warnList) > 0:
print('Please correct the following for full program functionality:')
for aWarn in warnList:
print('\t' + aWarn)
sys.exit(0)
if len(warnList) > 0:
print('There are configuration issues with the environment or system.')
print('Please correct the following for full program functionality:')
for aWarn in warnList:
print('\t' + aWarn)
return warnList
def getClassPath(javaCodePath):
@@ -176,7 +170,9 @@ if __name__ == "__main__":
parser.add_argument('-appArgs', help='Application arguments. Note that this argument must ALWAYS be the last specified!', nargs=argparse.REMAINDER, default=[])
parser.add_argument('-dataCode', '-dc', help='A list of supporting folders for the application.', nargs='+', default=[])
parser.add_argument('-javaCode', '-jc', help='A folder which contains the Java build.')
parser.add_argument('-jreVersion', help='JRE version to utilize. This should be a value like 1.7 or 1.8 or 1.8.34. Note there should be corresponding tar.gz JREs for each platform in the folder ~/jre/', default=None)
parser.add_argument('-jreVersion', dest='jreVerSpec', help='JRE version to utilize. This should be either 1 or 2 values where each value should be something like 1.7 or 1.8 or 1.8.0_34. '
+ 'If 2 values are specified than the second value must be later than the first value. Any static build will be built with the latest allowable JRE.'
+ ' Note there should be corresponding tar.gz JREs for each platform in the folder ~/jre/', nargs='+', default=None)
parser.add_argument('-jvmArgs', help='JVM arguments.', nargs='+', default=[])
parser.add_argument('-classPath', help='Class path listing of jar files relative to javaCode. Leave blank for auto determination.', nargs='+', default=[])
parser.add_argument('-debug', help='Turn on debug options for built applications.', action='store_true', default=False)
@@ -194,8 +190,8 @@ if __name__ == "__main__":
parser.print_help()
exit()
# Check to ensure all of the required applications are installed
checkForRequiredApplications()
# Check to ensure all of the required applications are installed before proceeding
checkForRequiredApplicationsAndExit()
# Parse the args
parser.formatter_class.max_help_position = 50
@@ -212,13 +208,27 @@ if __name__ == "__main__":
errList.append('-mainClass')
if len(errList) != 0:
print('At a minimum the following must be specified: ' + str(errList) + '.\nExiting...')
exit();
exit()
# Ensure the reserved 'jre' name is not utilized
if args.name.lower() == 'jre':
print('The application can not be named: {}. That name is reserved for the JRE.'.format(args.name))
exit()
#
# # Ensure java options are specified properly
# if (args.javaCode == None and args.mainClass != None) or (args.javaCode != None and args.mainClass == None):
# print('Both javaCode and mainClass must be specified, if either are specified. Exiting...')
# exit();
# Validate the jreVerSpec argument
try:
jreUtils.validateJreVersionSpec(args.jreVerSpec)
except ErrorDM as aExp:
print('The specified jreVerVersion is invalid. Input: {}'.format(args.jreVerSpec))
print(' ' + aExp.message, file=sys.stderr)
exit()
# Form the classPath if none specified
if args.javaCode != None and len(args.classPath) == 0:
args.classPath = getClassPath(args.javaCode)
@@ -242,6 +252,14 @@ if __name__ == "__main__":
print(' [ERROR] The release appears to be built. Path: ' + buildPath)
exit(-1)
# Let the user know of any missing functionality
warnList = checkForSuggestedApplications()
if len(warnList) > 0:
print('All suggested applications are not installed. There will be reduced functionality:')
for aWarn in warnList:
print('\t' + aWarn)
print()
# Form the buildPath
os.makedirs(buildPath)
@@ -292,3 +310,5 @@ if __name__ == "__main__":
srcPath = os.path.join(miscUtils.getInstallRoot(), "deployAppDist.py")
shutil.copy(srcPath, buildPath)
print('Finished building all distributions.\n')

View File

@@ -119,6 +119,7 @@ def addRelease(appName, version, buildDate):
# Update the version info
addReleaseInfo(installPath, appName, version, buildDate)
print('Application {} ({}) has been deployed to location: {}'.format(appName, version, args.deployRoot))
def delRelease(appName, version, buildDate):

View File

@@ -0,0 +1,192 @@
#! /usr/bin/env python
from __future__ import print_function
import argparse
import getpass
import math
import os
import shutil
import signal
import subprocess
import sys
import miscUtils
import jreUtils
from miscUtils import ErrorDM
def addRelease(version):
# Normalize the JVM version for consistency
version = jreUtils.normalizeJvmVerStr(version)
# Check to see if the deployed location already exists
installPath = os.path.join(rootPath, 'jre')
if os.path.isdir(installPath) == False:
print('A JRE has never been deployed to the root location: ' + args.deployRoot)
print('Create a new release of the JRE at the specified location?')
input = raw_input('--> ').upper()
if input != 'Y' and input != 'YES':
print('Release will not be made for JRE version: ' + version)
exit()
# Build the deployed location
os.makedirs(installPath)
# Check to see if the deploy version already exists
versionPath = os.path.join(installPath, version)
if os.path.isdir(versionPath) == True:
print('JREs with version, ' + version + ', has already been deployed.')
print(' The JREs have already been deployed.')
exit()
# Update the version info
addReleaseInfo(installPath, version)
print('JRE ({}) has been deployed to location: {}'.format(version, args.deployRoot))
def addReleaseInfo(installPath, verStr):
verFile = os.path.join(installPath, 'jreCatalog.txt')
# Create the release info file
if os.path.isfile(verFile) == False:
f = open(verFile, 'w')
f.write('name' + ',' + 'JRE' + '\n')
f.write('digest' + ',' + 'sha256' + '\n\n')
f.close()
# Locate the list of JRE files with a matching verStr
jreFiles = jreUtils.getJreTarGzFilesForVerStr(verStr)
if len(jreFiles) == 0:
raise ErrorDM('No JREs were located for the version: ' + verStr)
# Updated the release info file
f = open(verFile, 'a')
f.write("jre,{}\n".format(verStr))
for aFile in jreFiles:
stat = os.stat(aFile)
digestStr = miscUtils.computeDigestForFile(aFile, 'sha256')
# platformStr = jreUtils.getPlatformForJre(aFile)
# stat = os.stat(aFile)
# fileLen = os.path.s
# f.write("jre,{},{},{},{},{}\n".format(verStr, platformStr, os.path.basename(aFile), fileLen, digestStr))
f.write("F,{},{},{}\n".format(digestStr, stat.st_size, os.path.basename(aFile)))
f.write('\n')
f.close()
destPath = os.path.join(installPath, verStr)
os.makedirs(destPath)
# Copy over the JRE files to the proper path
for aFile in jreFiles:
shutil.copy(aFile, destPath)
destFile = os.path.join(destPath, aFile)
os.chmod(destFile, 0644)
def delRelease(verStr):
# Normalize the JVM version for consistency
verStr = jreUtils.normalizeJvmVerStr(verStr)
# Check to see if the deployed location already exists
installPath = os.path.join(rootPath, 'jre')
if os.path.isdir(installPath) == False:
print('A JRE has never been deployed to the root location: ' + args.deployRoot)
print('There are no JRE releases to remove. ')
exit()
# Check to see if the deploy version already exists
versionPath = os.path.join(installPath, verStr)
if os.path.isdir(versionPath) == False:
print('JREs with version, ' + verStr + ', has not been deployed.')
print(' There is nothing to remove.')
exit()
# Update the version info
delReleaseInfo(installPath, verStr)
# Remove the release from the deployed location
shutil.rmtree(versionPath)
def delReleaseInfo(installPath, version):
verFile = os.path.join(installPath, 'jreCatalog.txt')
# Bail if the release info file does not exist
if os.path.isfile(verFile) == False:
print('Failed to locate deployment release info file: ' + verFile)
print('Aborting removal action for version: ' + version)
exit()
# Read the file
inputLineL = []
isDeleteMode = False
f = open(verFile, 'r')
for line in f:
tokens = line[:-1].split(',', 1);
# Switch to deleteMode when we find a matching JRE release
if len(tokens) == 2 and tokens[0] == 'jre' and tokens[1] == version:
isDeleteMode = True
continue
# Switch out of deleteMode when we find a different JRE release
elif len(tokens) == 2 and tokens[0] == 'jre' and tokens[1] != version:
isDeleteMode = False
# Skip over the input line if we are in deleteMode
elif isDeleteMode == True:
continue
# Save off the input line
inputLineL.append(line)
f.close()
# Write the updated file
f = open(verFile, 'w')
for aLine in inputLineL:
f.write(aLine)
f.close()
if __name__ == "__main__":
argv = sys.argv;
argc = len(argv);
# Logic to capture Ctrl-C and bail
signal.signal(signal.SIGINT, miscUtils.handleSignal)
# Retrieve the location of the scriptPath
scriptPath = os.path.realpath(__file__)
scriptPath = os.path.dirname(scriptPath)
# Set up the argument parser
parser = argparse.ArgumentParser(prefix_chars='-', add_help=False, fromfile_prefix_chars='@')
parser.add_argument('-help', '-h', help='Show this help message and exit.', action='help')
parser.add_argument('-remove', help='Remove the specified JRE distribution.', action='store_true', default=False)
parser.add_argument('-version', help='The fully qualified JRE version to deploy.', required=True)
parser.add_argument('deployRoot', help='Root location to deploy the specified JRE distribution.')
# Intercept any request for a help message and bail
for aArg in argv:
if aArg == '-h' or aArg == '-help':
parser.print_help()
exit()
# Parse the args
parser.formatter_class.max_help_position = 50
args = parser.parse_args()
rootPath = args.deployRoot
# Uninstall the JRE, if remove argument is specified
version = args.version
if args.remove == True:
try:
delRelease(version)
except ErrorDM as aExp:
print('Failed to remove JREs with version: ' + version)
print(' ' + aExp.message, file=sys.stderr)
else:
try:
addRelease(version)
except ErrorDM as aExp:
print('Failed to deploy JREs with version: ' + version)
print(' ' + aExp.message, file=sys.stderr)

View File

@@ -7,9 +7,11 @@ import subprocess
import tempfile
import miscUtils
from miscUtils import ErrorDM
# Globals
# The global variable defaultJreVersion is a hint for which (tar.gz) JRE release to
# The global variable defaultVersionStr is a hint for which (tar.gz) JRE release to
# default to. Note if this variable is not specified then the latest JRE release
# located in the appropriate <installPath>/jre directory will be utilized.
#
@@ -17,64 +19,67 @@ import miscUtils
# <installpath>/jre/jre-<VERSION>-<PLATFORM>-x64.tar.gz
# where PLATFORM is one of the following: apple, linux, windows
# where VERSION is something like: 8u73
# For example the Linux JRE 1.8.73 tar.gz release would be:
# For example the Linux JRE 1.8.0_73 tar.gz release would be:
# <installpath>/jre/jre-8u73-linux-x64.tar.gz
defaultJreVersion = '1.8'
defaultVersionStr = '1.8'
def getDefaultJreRelease(aPlatform):
"""Utility method to locate the default JRE to utilize. The returned value will be a string such as 1.8.73"""
# Return the default if it is hard wired (and is available)
if 'defaultJreVersion' in globals():
jreTarGzFile = getJreTarGzFile(aPlatform, defaultJreVersion)
if jreTarGzFile == None:
print('[WARNING] The specified default JRE for the ' + aPlatform.capitalize() + ' platform is: ' + defaultJreVersion + '. However this JRE is not installed! <---')
else:
return '1.' + '.'.join(getJreTarGzVersion(jreTarGzFile))
jreTarGzFile = getJreTarGzFile(aPlatform, None)
if jreTarGzFile == None:
return None
return '1.' + '.'.join(getJreTarGzVersion(jreTarGzFile))
def getDefaultJreVersion():
"""Returns the default JRE version. This will return None if a default JRE version has not been specified
and one can not be determined."""
if 'defaultJreVersion' in globals():
return defaultJreVersion;
return None
def doesJreVersionMatch(aRequestVer, aEvaluateVer):
"""Returns true if aEvaluateVer is a match for the requested version. Note that aEvaluateVer is considered
a match if each (available) component corresponds to the component in a aRequestVer. aRequestVer must
not be any more specific than aEvaluateVer"""
if len(aRequestVer) > len(aEvaluateVer):
return False
# check each component for equality
for r, e in zip(aRequestVer, aEvaluateVer):
if r != e:
return False
return True
def getBasePathForJreTarGzFile(aJreTarGzFile):
"""Returns the JRE (base) path that should be used to access the JRE found in the specified JRE tar.gz.
This is needed since different JRE tar.gz files have been found to have different top level paths. Using
this method ensures consistency between JRE tar.gz releases after the tar.gz file is unpacked."""
verDescr = getJreTarGzVersion(aJreTarGzFile);
if verDescr == None:
raise Exception("File name (' + aJreTarGzFile + ') does not conform to proper JRE tar.gz name specification.")
basePath = 'jre1.' + '.'.join(verDescr)
verArr = getJreTarGzVerArr(aJreTarGzFile);
if verArr == None:
raise ErrorDM('File name (' + aJreTarGzFile + ') does not conform to proper JRE tar.gz name specification.')
basePath = 'jre' + verArrToVerStr(verArr)
return basePath;
def getJreTarGzFile(aPlatform, aJreRelease):
"""Returns the JRE tar.gz file for the appropriate platform and JRE release. This will return None if
there is no file that is sufficient for the request. Note if you do not care about any specific update
for a major version of JAVA then just specify the major version. Example '1.8' instead of '1.8.73'"""
def getDefaultJreVerStr():
"""Returns the default JRE version. This will return None if a default JRE version has not been specified
and one can not be determined."""
if 'defaultVersionStr' in globals():
return defaultVersionStr;
return None
def getJreTarGzFilesForVerStr(aVerStr):
"""Returns the JRE tar.gz files matching the specified specific JRE version specification. This will return an empty
list if there is no JRE tar.gz files that is sufficient for the request.
The version must be fully qualified (must specify platform, major, minor, and update components). If it is not then
an ErrorDM will be raised. An example of a valid fully qualified version string is: '1.8.0_73'"""
appInstallRoot = miscUtils.getInstallRoot()
appInstallRoot = os.path.dirname(appInstallRoot)
# Retrieve the target version - and ensure it is fully qualified
targVer = verStrToVerArr(aVerStr)
if len(targVer) != 4:
raise ErrorDM('The specified version is not a fully qualified version. Version: ' + aVerStr)
# Search all the appropriate tar.gz JREs for exact matches in our JRE folder
retList = []
matchName = "jre-*-*-x64.tar.gz";
searchPath = os.path.join(os.path.abspath(appInstallRoot), 'jre', matchName)
# for aFile in ['jre-8u739-windows-x64.tar.gz', 'jre-8u60-windows-x64.tar.gz', 'jre-7u27-windows-x64.tar.gz']:
for aFile in glob.glob(searchPath):
# Ensure that the aFile's JVM version is an exact match of targVer
tmpVer = getJreTarGzVerArr(aFile)
if targVer != tmpVer:
continue
retList.append(aFile);
return sorted(retList)
def getJreTarGzFile(aPlatform, aJvmVerSpec):
"""Returns the JRE tar.gz file for the appropriate platform and JRE release. If there are several possible
matches then the tar.gz with the latest version will be rteurned.
This will return None if there is no file that is sufficient for the request. Note if you do not care about
any specific update for a major version of JAVA then just specify the major version. Example '1.8' instead of
1.8.0_73'"""
appInstallRoot = miscUtils.getInstallRoot()
appInstallRoot = os.path.dirname(appInstallRoot)
@@ -83,18 +88,13 @@ def getJreTarGzFile(aPlatform, aJreRelease):
if platStr == 'apple':
platStr = 'macosx'
# Transform the version from a string into a list of (version) components. Due to SUNs funny naming
# conventions we automatically strip the first part of the string if it matches '1.'
# Some examples:
# '1.8' ---> [8] [1.8.0] ---> [8, 0]
# '1.8.73' ---> [8, 73]
reqVer = []
if aJreRelease != None:
if aJreRelease.startswith("1.") == True:
aJreRelease = aJreRelease[2:]
reqVer = aJreRelease.split(".")
reqVer = [y for y in reqVer if y != '']
# print str(reqVer)
# Retrieve the min and max JVM versions from aJvmVerSpec
minJvmVer = None
if aJvmVerSpec != None and len(aJvmVerSpec) >= 1:
minJvmVer = verStrToVerArr(aJvmVerSpec[0])
maxJvmVer = None
if aJvmVerSpec != None and len(aJvmVerSpec) == 2:
maxJvmVer = verStrToVerArr(aJvmVerSpec[1])
# Search all the appropriate tar.gz JREs for the best match from our JRE folder
matchList = []
@@ -102,10 +102,13 @@ def getJreTarGzFile(aPlatform, aJreRelease):
searchPath = os.path.join(os.path.abspath(appInstallRoot), 'jre', searchName)
# for file in ['jre-8u739-windows-x64.tar.gz', 'jre-8u60-windows-x64.tar.gz', 'jre-7u27-windows-x64.tar.gz']:
for file in glob.glob(searchPath):
# Determine if the tar.gz version is a match for the reqVer
tmpVer = getJreTarGzVersion(file)
if doesJreVersionMatch(reqVer, tmpVer) == True:
matchList.append(file);
# Ensure that the file's JVM version is in range of minJvmVer and maxJvmVer
tmpVer = getJreTarGzVerArr(file)
if minJvmVer != None and isVerAfterAB(minJvmVer, tmpVer) == True:
continue
if maxJvmVer != None and isVerAfterAB(tmpVer, maxJvmVer) == True:
continue
matchList.append(file);
# Determine the best match of all the matches
bestMatch = None
@@ -114,13 +117,13 @@ def getJreTarGzFile(aPlatform, aJreRelease):
bestMatch = aFile
continue
bestVer = getJreTarGzVersion(bestMatch)
testVer = getJreTarGzVersion(aFile)
bestVer = getJreTarGzVerArr(bestMatch)
testVer = getJreTarGzVerArr(aFile)
for b, t in zip(bestVer, testVer):
if b == t:
continue
try:
if int(t) > int(b):
if t > b:
bestMatch = aFile
break;
except:
@@ -129,15 +132,17 @@ def getJreTarGzFile(aPlatform, aJreRelease):
return bestMatch
def getJreTarGzVersion(aFile):
def getJreTarGzVerArr(aFile):
"""Returns the version corresponding to the passed in JRE tar.gz file.
The returned value will be a list consisting of the (major, minor) components of the version.
The returned value will be a list consisting of the (platform, major, minor, update) integer components of the version.
The file naming convention is expected to be:
jre-<A>u<B>-*.tar.gz
jre-<B>u<D>-*.tar.gz
where:
A ---> The major version
B ---> The minor version
B ---> The major version
D ---> The update version
Note that the platform version <A> will be assumed to be: 1
Note that the minor version <C> will be assumed to be: 0
"""
# Retrieve the version component of the fileName
fileName = os.path.basename(aFile)
@@ -151,10 +156,26 @@ def getJreTarGzVersion(aFile):
# Determine the version based on the pattern '<A>u<B>' where:
# if there is no <B> component then just assume 0 for minor version
retVer = verStr.split('u')
if len(retVer) == 1:
retVer.append(0)
return retVer
tokenArr = verStr.split('u')
retVerArr = [1, int(tokenArr[0]), 0]
if len(retVerArr) == 1:
retVerArr.append(0)
else:
retVerArr.append(int(tokenArr[1]))
return retVerArr
def normalizeJvmVerStr(aVerStr):
"""Returns a normalized JVM version corresponding to the string. Normalization consists of ensuring all of the components
of the version are separated by '.' except if applicable the third '.' is changed into '_'. This is useful so that referencing
JVM versions is consistent. Some examples of normalization are:
1.8 ---> 1.8
1.8.0.73 ---> 1.8.0_73
1.7.0_55 ---> 1.7.0_55
"""
verArr = verStrToVerArr(aVerStr)
retVerStr = verArrToVerStr(verArr)
return retVerStr
def unpackAndRenameToStandard(aJreTarGzFile, aDestPath):
@@ -185,3 +206,85 @@ def unpackAndRenameToStandard(aJreTarGzFile, aDestPath):
# Remove the the temporary path
os.rmdir(tmpPath)
def validateJreVersionSpec(aVerSpec):
"""Method that ensures that the specified aVerSpec is a valid definition. A valid JVM version spec can be composed of the following
- None: The jreVersion was not specified and should default to DistMaker's default values.
- A list of 1: The value defines the minimum allowable JRE version
- A list of 2: The 2 value defines the 2 JRE versions. The first is the minimum value. The second is the maximum value
Furthermore each JRE version must be a valid specification. Examples of valid specifications are:
1.7, 1.8.0, 1.8.0_73"""
# Bail if no version was specified
if aVerSpec == None:
return
# Ensure the number of arguments are correct. Must be 1 or 2
if (len(aVerSpec) in [1, 2]) == False:
raise ErrorDM('The parameter jreVersion can either be 1 or 2 values. The first value is the minVersion and (if specified) the later is the maxVersion. Values provided: ' + str(len(aVerSpec)))
# Ensure the minVer is valid
minVer = verStrToVerArr(aVerSpec[0])
if minVer == None:
raise ErrorDM('The specified string: "' + aVerSpec[0] + ' is not a valid JRE version specification.')
if len(aVerSpec) == 1:
return
# Ensure the maxVer is valid and is after minVer
maxVer = verStrToVerArr(aVerSpec[1])
if maxVer == None:
raise ErrorDM('The specified string: "' + aVerSpec[1] + ' is not a valid JRE version specification.')
# Ensure the minVer is not later than the maxVer. Note it is ok if it is equal
if isVerAfterAB(minVer, maxVer) == True:
raise ErrorDM('In the parameter jreVersion, the minVer ({0}) is later than the maxVer ({1}).'.format(aVerSpec[0], aVerSpec[1]))
def verStrToVerArr(aVerStr):
"""Utility method to convert a jvm version string to the equivalent integral version (list) component. If the specified version is not a valid jvm version
then an ErrorDM will be raised. Each component in the array will be integral. Note typical versions follow this pattern: <langVer>.<majVer>.<minVer>_<upVer>
Thus the following will get transformed to:
'1.7.0 ---> [1, 7, 0]
'1.8' ---> [1, 8]
'1.8.0_73' ---> [1, 8, 0, 73]"""
verStrArr = re.compile("[._]").split(aVerStr)
# Transform from string list to integer list
try:
retVerArr = [int(val) for val in verStrArr]
except:
raise ErrorDM('Invalid JVM version: ' + aVerStr)
return retVerArr
def verArrToVerStr(aVerArr):
"""Utility method to convert an integral version (list) to the equivalent jvm version string. If the specified version is not a valid jvm version
then an ErrorDM will be raised. Each component in the list must be integral. Note typical versions follow this pattern: <langVer>.<majVer>.<minVer>_<upVer>
Thus the following will get transformed to:
[1, 7, 0] ---> '1.7.0'
[1, 8] ---> '1.8'
[1, 8, 0, 73] ---> '1.8.0_73'"""
# Transform from integer list to string
if len(aVerArr) <= 3:
retVerStr = ".".join(str(x) for x in aVerArr)
return retVerStr
else:
retVerStr = ".".join(str(x) for x in aVerArr[0:3])
retVerStr += '_' + ".".join(str(x) for x in aVerArr[3:])
return retVerStr
def isVerAfterAB(aJvmVerA, aJvmVerB):
"""Returns True if the specified JvmVerA is later than aJvmVerB. Both versions should be composed of a list of integers. Typically this list would be formed
from the method verStrToVerArr. Note that if one version has more detail than the other and all others are previous components are equivalent then the more
detailed version will be considered later (since it can be assumed that the missing details refer to the very first issue)"""
for a, b in zip(aJvmVerA, aJvmVerB):
if a == b:
continue
if a > b:
return True
else:
return False
# Since all other components are equal then verA is better than verB only if it is more detailed
if len(aJvmVerA) > len(aJvmVerB):
return True
return False

View File

@@ -18,25 +18,22 @@ def buildRelease(args, buildPath):
# Retrieve vars of interest
appName = args.name
version = args.version
jreRelease = args.jreVersion
jreVerSpec = args.jreVerSpec
platformStr = 'linux'
# Check our system environment before proceeding
if checkSystemEnvironment() == False:
return
# Attempt to locate a default JRE if None is specified in the args.
if jreRelease == None:
jreRelease = jreUtils.getDefaultJreRelease(platformStr)
# Let the user know if the 'user' specified JRE is not available and locate an alternative
elif jreUtils.getJreTarGzFile(platformStr, jreRelease) == None:
print('[Warning] User specified JRE ({0}) is not available for {1} platform. Searching for alternative...'.format(jreRelease, platformStr.capitalize()))
jreRelease = jreUtils.getDefaultJreRelease(platformStr)
args.jreRelease = jreRelease
# Select the jreTarGzFile to utilize for static releases
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, jreVerSpec)
if jreTarGzFile == None:
# Let the user know if the 'user' specified JRE is not available and locate an alternative
print('[Warning] User specified JRE ({0}) is not available for {1} platform. Searching for alternative...'.format(jreVerSpec, platformStr.capitalize()))
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, None)
# Form the list of distributions to build (dynamic and static JREs)
distList = [(appName + '-' + version, None)]
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, jreRelease)
if jreTarGzFile != None:
distList.append((appName + '-' + version + '-jre', jreTarGzFile))
@@ -48,7 +45,7 @@ def buildRelease(args, buildPath):
print('Building {0} distribution: {1}'.format(platformStr.capitalize(), aDistName))
# Let the user know of the JRE release we are going to build with
if aJreTarGzFile != None:
print('\tUtilizing jreRelease: ' + jreRelease)
print('\tUtilizing JRE: ' + aJreTarGzFile)
# Create the (top level) distribution folder
dstPath = os.path.join(tmpPath, aDistName)
@@ -62,7 +59,7 @@ def buildRelease(args, buildPath):
print('\tForming tar.gz file: ' + tarFile)
childPath = aDistName
subprocess.check_call(["tar", "-czf", tarFile, "-C", tmpPath, childPath], stderr=subprocess.STDOUT)
print('\tFinished building release: ' + os.path.basename(tarFile))
print('\tFinished building release: ' + os.path.basename(tarFile) + '\n')
# Perform cleanup
shutil.rmtree(tmpPath)
@@ -73,7 +70,6 @@ def buildDistTree(buildPath, rootPath, args, jreTarGzFile):
appInstallRoot = miscUtils.getInstallRoot()
appInstallRoot = os.path.dirname(appInstallRoot)
appName = args.name
jreRelease = args.jreRelease
# Form the app contents folder
srcPath = os.path.join(buildPath, "delta")

View File

@@ -1,4 +1,5 @@
#! /usr/bin/env python
import argparse
import hashlib
import os
import time
@@ -8,6 +9,31 @@ import sys
import logUtils
class FancyArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
self._action_defaults = {}
argparse.ArgumentParser.__init__(self, *args, **kwargs)
def convert_arg_line_to_args(self, arg_line):
# Add the line as an argument if it does not appear to be a comment
if len(arg_line) > 0 and arg_line.strip()[0] != '#':
yield arg_line
# argsparse.ArgumentParser.convert_arg_line_to_args(arg_line)
# else:
# print('Skipping line: ' + arg_line)
# # Example below will break all space separated lines into individual arguments
# for arg in arg_line.split():
# if not arg.strip():
# continue
# yield arg
class ErrorDM(Exception):
"""Base class for exceptions in this module."""
pass
def checkRoot():
"""Determines if the script is running with root priveleges."""
# This logic will may break on SELinux systems
@@ -19,16 +45,16 @@ def checkRoot():
# Source: http://stackoverflow.com/questions/1131220/get-md5-hash-of-a-files-without-open-it-in-python
def computeDigestForFile(evalFile, digest, block_size=2**20):
def computeDigestForFile(evalFile, digestType, block_size=2**20):
# Select the proper hash algorithm
if digest == 'md5':
if digestType == 'md5':
hash = hashlib.md5()
elif digest == 'sha256':
elif digestType == 'sha256':
hash = hashlib.sha256()
elif digest == 'sha512':
elif digestType == 'sha512':
hash = hashlib.sha512()
else:
raise Exception('Unrecognized hash function: ' + digest);
raise ErrorDM('Unrecognized hash function: ' + digestType);
f = open(evalFile, 'rb')
while True:
@@ -44,14 +70,11 @@ def getInstallRoot():
"""Returns the root path where the running script is installed."""
argv = sys.argv;
installRoot = os.path.dirname(argv[0])
# print('appInstallRoot: ' + appInstallRoot)
return installRoot
def executeAndLog(command, indentStr=""):
"""Executes the specified command via subprocess and logs all (stderr,stdout) output to the console"""
# proc = subprocess.
# proc.returncode = -1
try:
proc = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
proc.wait()
@@ -70,8 +93,6 @@ def executeAndLog(command, indentStr=""):
class Proc:
returncode = None
proc = Proc
# proc = None
return proc
# if proc.returncode != 0:

View File

@@ -17,25 +17,22 @@ def buildRelease(args, buildPath):
# Retrieve vars of interest
appName = args.name
version = args.version
jreRelease = args.jreVersion
jreVerSpec = args.jreVerSpec
platformStr = 'windows'
# Check our system environment before proceeding
if checkSystemEnvironment() == False:
return
# Attempt to locate a default JRE if none is specified in the args.
if jreRelease == None:
jreRelease = jreUtils.getDefaultJreRelease(platformStr)
# Let the user know if the 'user' specified JRE is not available and locate an alternative
elif jreUtils.getJreTarGzFile(platformStr, jreRelease) == None:
print('[Warning] User specified JRE ({0}) is not available for {1} platform. Searching for alternative...'.format(jreRelease, platformStr.capitalize()))
jreRelease = jreUtils.getDefaultJreRelease(platformStr)
args.jreRelease = jreRelease
# Select the jreTarGzFile to utilize for static releases
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, jreVerSpec)
if jreTarGzFile == None:
# Let the user know if the 'user' specified JRE is not available and locate an alternative
print('[Warning] User specified JRE ({0}) is not available for {1} platform. Searching for alternative...'.format(jreVerSpec, platformStr.capitalize()))
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, None)
# Form the list of distributions to build (dynamic and static JREs)
distList = [(appName + '-' + version, None)]
jreTarGzFile = jreUtils.getJreTarGzFile(platformStr, jreRelease)
if jreTarGzFile != None:
distList.append((appName + '-' + version + '-jre', jreTarGzFile))
@@ -47,7 +44,7 @@ def buildRelease(args, buildPath):
print('Building {0} distribution: {1}'.format(platformStr.capitalize(), aDistName))
# Let the user know of the JRE tar.gz we are going to build with
if aJreTarGzFile != None:
print('\tUtilizing jreRelease: ' + aJreTarGzFile)
print('\tUtilizing JRE: ' + aJreTarGzFile)
# Create the (top level) distribution folder
dstPath = os.path.join(tmpPath, aDistName)
@@ -63,9 +60,9 @@ def buildRelease(args, buildPath):
proc = miscUtils.executeAndLog(cmd, "\t\tjar: ")
if proc.returncode != 0:
print('\tError: Failed to form zip file. Return code: ' + str(proc.returncode))
print('\tAborting build of release: ' + os.path.basename(zipFile))
print('\tAborting build of release: ' + os.path.basename(zipFile) + '\n')
else:
print('\tFinished building release: ' + os.path.basename(zipFile))
print('\tFinished building release: ' + os.path.basename(zipFile) + '\n')
# Perform cleanup
shutil.rmtree(tmpPath)
@@ -76,7 +73,6 @@ def buildDistTree(buildPath, rootPath, args, jreTarGzFile):
appInstallRoot = miscUtils.getInstallRoot()
appInstallRoot = os.path.dirname(appInstallRoot)
appName = args.name
jreRelease = args.jreRelease
# Form the app contents folder
srcPath = os.path.join(buildPath, "delta")
@@ -180,7 +176,7 @@ def buildLaunch4JConfig(destFile, args, jreTarGzFile, iconFile):
jrePath = jreUtils.getBasePathForJreTarGzFile(jreTarGzFile)
writeln(f, 2, "<path>" + jrePath + "</path>");
else:
jreVer = getJreMajorVersion(args.jreRelease)
jreVer = getJreMajorVersion(args.jreVerSpec[0])
writeln(f, 2, "<minVersion>" + jreVer + "</minVersion>"); # Valid values: '1.7.0' or '1.8.0' ...
writeln(f, 2, "<jdkPreference>preferJre</jdkPreference>"); # Valid values: jreOnlyjdkOnly|preferJre|preferJdk
for aJvmArg in args.jvmArgs:
@@ -216,15 +212,15 @@ def checkSystemEnvironment():
return True
def getJreMajorVersion(aJreRelease):
def getJreMajorVersion(aJreVerStr):
"""Returns the minimum version of the JRE to utilize based on the passed in JRE release.
The passed in value should be of the form X.X.X ---> example: 1.8.73 would result in 1.8.0
If aJreRelease is invalid then returns the default value of: 1.8.0"""
if aJreRelease == None: return '1.8.0'
verList = aJreRelease.split('.')
The passed in value should be of the form X.X.X ---> example: 1.8.0_73 would result in 1.8.0
If aJreVerStr is invalid then returns the default value of: 1.8.0"""
if aJreVerStr == None: return '1.8.0'
verList = aJreVerStr.split('.')
if len(verList) == 2: verList.append('0')
if len(verList) == 3 and verList[2] == '': verList[2] = '0'
if len(verList) != 3: return '1.8.0'
if len(verList) < 3: return '1.8.0'
try:
[int(y) for y in verList]
except: