mirror of
https://github.com/JHUAPL/DistMaker.git
synced 2026-01-09 14:37:54 -05:00
282 lines
9.4 KiB
Python
Executable File
282 lines
9.4 KiB
Python
Executable File
#! /usr/bin/env python3
|
|
|
|
import argparse
|
|
import glob
|
|
import os
|
|
import shutil
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import traceback
|
|
|
|
|
|
# Define the (baseline) version
|
|
baseVersion = "0.71"
|
|
|
|
# Define relevant base names
|
|
appBaseName = 'DistMaker'
|
|
libBaseName = 'distMaker'
|
|
|
|
# Define the libraries DistMaker depends on
|
|
libList = ['glum-2.0.0.jar', 'guava-18.0.jar']
|
|
#libList += ['commons-compress-1.15.jar']
|
|
|
|
# Define the paths to various executables
|
|
antPath = '/spare/apache/apache-ant-1.10.8'
|
|
antExe = os.path.join(antPath, 'bin/ant')
|
|
jdkPath = '/spare/jdk-17'
|
|
jarExe = os.path.join(jdkPath, 'bin/jar')
|
|
javaExe = os.path.join(jdkPath, 'bin/java')
|
|
|
|
|
|
def checkForInstalledApps():
|
|
"""Checks for installed applications needed to build a release of the
|
|
DistMaker library / package.
|
|
"""
|
|
# Ensure required applications are installed
|
|
errList = []
|
|
for aPath in [antExe, jarExe, javaExe]:
|
|
if os.path.exists(aPath) == False:
|
|
errList.append('System executable is missing: ' + aPath)
|
|
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)
|
|
sys.exit(0)
|
|
|
|
|
|
def buildLibraryJar(aVersion):
|
|
"""Method that builds the library jars. Upon sucessful execution
|
|
jar files (binary + source) will be generated.
|
|
"""
|
|
# Note it is assumed that this is run from the path /proj/glum/
|
|
|
|
# Compile the java files
|
|
# Run the Ant script to build the class files
|
|
os.environ["JAVA_HOME"] = jdkPath
|
|
exeCmd = [antExe, '-f', 'tools/build.xml', 'compile']
|
|
retCode = subprocess.call(exeCmd)
|
|
if retCode != 0:
|
|
print('Failed while trying to run ant script. Exiting...\n')
|
|
sys.exit(0)
|
|
print('Finished executing Ant script.\n')
|
|
|
|
# Generate the manifest file
|
|
manifestFN = 'release/Manifest.txt'
|
|
# buildManifestFile(manifestFN)
|
|
|
|
# Build the (bin) jar file
|
|
jarBinFN = 'release/' + libBaseName + '-' + aVersion + '.jar'
|
|
# exeCmd = [jarExe, 'cfm', jarBinFN, manifestFN, '-C', 'bin/classes', '.']
|
|
exeCmd = [jarExe, 'cfM', jarBinFN, '-C', 'bin/classes', '.']
|
|
retCode = subprocess.call(exeCmd)
|
|
if retCode != 0:
|
|
print('Failed to build jar file: ' + jarBinFN)
|
|
exit(-1)
|
|
|
|
# Build the (src) jar file
|
|
jarSrcFN = 'release/' + libBaseName + '-' + aVersion + '-src.jar'
|
|
exeCmd = ['zip', '-D9q', '../' + jarSrcFN, '-r', '.']
|
|
retCode = subprocess.call(exeCmd, cwd='./src')
|
|
if retCode != 0:
|
|
print('Failed to build jar file: ' + jarSrcFN)
|
|
exit(-1)
|
|
|
|
# Remove the manifest file
|
|
# os.remove(manifestFN)
|
|
|
|
def buildRelease(aExtraTag, aDoNotClean=False):
|
|
"""Method that builds a release of DistMaker. Upon sucessful execution
|
|
the following will be created:
|
|
- distMaker-<version>.jar
|
|
- distMaker-<version>-src.jar
|
|
- DistMaker-<version>.tar.gz
|
|
"""
|
|
# Define the version to build
|
|
version = baseVersion
|
|
if aExtraTag != None:
|
|
if aExtraTag.startswith('.') or aExtraTag.startswith('-'):
|
|
version = baseVersion + aExtraTag
|
|
else:
|
|
version = baseVersion + '-' + aExtraTag
|
|
|
|
# Retrieve the install path
|
|
installPath = getInstallRoot()
|
|
installPath = os.path.dirname(installPath)
|
|
|
|
# Define the paths of interest
|
|
jarBinPathFN = os.path.join(installPath, 'release', libBaseName + '-' + version + '.jar')
|
|
jarSrcPathFN = os.path.join(installPath, 'release', libBaseName + '-' + version + '-src.jar')
|
|
|
|
workPath = os.path.join(installPath, 'release', appBaseName + '-' + version)
|
|
destFileGZ = os.path.join(installPath, 'release', appBaseName + '-' + version + '.tar.gz')
|
|
|
|
# Let the user know of the version we are building
|
|
print('Building ' + appBaseName + ' release ' + version + '...\n')
|
|
|
|
# Bail if there is a prior build
|
|
failMsgL = []
|
|
if os.path.exists(jarBinPathFN) == True:
|
|
failMsgL += ['Library binary file already exists: ' + jarBinPathFN]
|
|
if os.path.exists(jarSrcPathFN) == True:
|
|
failMsgL += ['Library source file already exists: ' + jarSrcPathFN]
|
|
if os.path.exists(workPath) == True:
|
|
failMsgL += ['Release folder already exists: ' + workPath]
|
|
if os.path.exists(destFileGZ) == True:
|
|
failMsgL += ['Release package already exists: ' + destFileGZ]
|
|
|
|
if len(failMsgL) > 0:
|
|
errPrintln('Aborting ' + appBaseName + ' release build. Reasons:')
|
|
for aFailMsg in failMsgL:
|
|
errPrintln(' - ' + aFailMsg)
|
|
errPrintln('')
|
|
exit(-1)
|
|
|
|
# Build the library jars
|
|
buildLibraryJar(version)
|
|
|
|
# Confirm that we have built the class files properly by retrieving the
|
|
# version from the built application jar and comparing it to our version.
|
|
tmpVersion = getLibraryBinVersion(jarBinPathFN)
|
|
if tmpVersion != version:
|
|
print('Failure: Embedded release: {} Expected: {}\n\tAborting...'.format(tmpVersion, version))
|
|
exit(-1)
|
|
|
|
# Laydown the structure, and let the user know of the version we are building
|
|
os.mkdir(workPath)
|
|
|
|
# Copy the regular documents
|
|
dstPath = os.path.join(workPath, 'doc')
|
|
os.mkdir(dstPath)
|
|
for aFile in ['QuickStartGuide.pdf', 'ReadMe.txt']:
|
|
srcPath = os.path.join(installPath, 'doc', aFile)
|
|
shutil.copy2(srcPath, dstPath)
|
|
|
|
# Copy the legal documents
|
|
dstPath = os.path.join(workPath, 'doc/legal')
|
|
os.mkdir(dstPath)
|
|
for aFile in glob.glob('doc/legal/*txt'):
|
|
srcPath = os.path.join(installPath, aFile)
|
|
shutil.copy2(srcPath, dstPath)
|
|
|
|
# Copy the libraries
|
|
dstPath = os.path.join(workPath, 'lib')
|
|
os.mkdir(dstPath)
|
|
for aLib in libList:
|
|
srcPath = os.path.join(installPath, 'lib', aLib)
|
|
shutil.copy2(srcPath, dstPath)
|
|
|
|
# Copy the (newly) built DistMaker (binary) library
|
|
shutil.copy2(jarBinPathFN, dstPath)
|
|
|
|
# Copy the scripts
|
|
dstPath = os.path.join(workPath, 'script')
|
|
os.mkdir(dstPath)
|
|
for aScript in ['appleUtils.py', 'linuxUtils.py', 'windowsUtils.py', 'buildDist.py', 'deployAppDist.py', 'deployJreDist.py', 'jreUtils.py', 'logUtils.py', 'miscUtils.py']:
|
|
srcPath = os.path.join(installPath, 'script', aScript)
|
|
shutil.copy2(srcPath, dstPath)
|
|
|
|
# Setup the template tree
|
|
dstPath = os.path.join(workPath, 'template')
|
|
os.makedirs(dstPath + '/apple')
|
|
os.makedirs(dstPath + '/background')
|
|
os.makedirs(dstPath + '/launch4j')
|
|
for aFile in ['appLauncher.jar', 'JreCatalog.txt', 'apple/.DS_Store.template', 'apple/JavaAppLauncher', 'background/background.png', 'launch4j/launch4j-3.14-linux-x64.tgz', 'launch4j/launch4j-3.14-linux.tgz', 'launch4j/launch4j-3.14-macosx-x86.tgz']:
|
|
srcPath = os.path.join(installPath, 'template', aFile)
|
|
shutil.copy2(srcPath, dstPath + '/' + aFile)
|
|
|
|
# Form the archive
|
|
exeCmd = ['tar', '-czf', destFileGZ, '-C', os.path.dirname(workPath), os.path.basename(workPath)]
|
|
retCode = subprocess.call(exeCmd)
|
|
if retCode != 0:
|
|
print('Failed to build tar.gz file: ' + destFileGZ)
|
|
exit(-1)
|
|
|
|
# Remove the workPath
|
|
if aDoNotClean == False:
|
|
shutil.rmtree(workPath)
|
|
|
|
print(appBaseName + ' release ' + version + ' built. Assets:')
|
|
for aFilePath in [jarBinPathFN, jarSrcPathFN, destFileGZ]:
|
|
print(' - ' + aFilePath)
|
|
print('')
|
|
|
|
|
|
def errPrintln(aMessage=''):
|
|
"""Print the specified string with a trailing newline to stderr. Each tab
|
|
character will be replaced with: 3 spaces"""
|
|
aMessage = aMessage.replace('\t', ' ')
|
|
sys.stderr.write(aMessage + '\n')
|
|
|
|
|
|
def getLibraryBinVersion(aJarBinPath):
|
|
"""Method that will return the version of the specified binary jar file.
|
|
The binary jar file will be queried (package distmaker.DistApp) and the
|
|
output will be parsed. Any failures will result in the abrupt exit of this
|
|
script."""
|
|
try:
|
|
cpStr = aJarBinPath
|
|
cpStr += ':lib/' + ':lib/'.join(libList)
|
|
exeCmd = [javaExe, '-cp', cpStr, 'distMaker.DistApp', '--version']
|
|
output = subprocess.check_output(exeCmd).decode('utf-8')
|
|
version = output.split()[1].strip()
|
|
return version
|
|
except Exception as aExp:
|
|
traceback.print_exc()
|
|
exit(-1)
|
|
|
|
|
|
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 handleSignal(signal, frame):
|
|
"""Signal handler, typically used to capture ctrl-c."""
|
|
print('User aborted processing!')
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Logic to capture Ctrl-C and bail
|
|
signal.signal(signal.SIGINT, handleSignal)
|
|
|
|
# Require python version 3.6 or later
|
|
targVer = (3, 6)
|
|
if sys.version_info < targVer:
|
|
print('The installed version of python is too old. Please upgrade.')
|
|
print(' Current version: ' + '.'.join(str(i) for i in sys.version_info))
|
|
print(' Require version: ' + '.'.join(str(i) for i in targVer))
|
|
sys.exit(-1)
|
|
|
|
tmpDescr = 'Utility to build a ' + appBaseName + ' release\n'
|
|
parser = argparse.ArgumentParser(prefix_chars='-', description=tmpDescr, add_help=False, fromfile_prefix_chars='@')
|
|
parser.add_argument('--help', '-h', help='Show this help message and exit.', action='help')
|
|
parser.add_argument('--doNotClean', default=False, action='store_true', help='Do NOT remove temporary work folder created while generating release.')
|
|
parser.add_argument('--doFullBuild', default=False, action='store_true', help='Force a full build of the main jar file. (Unsupported action)')
|
|
parser.add_argument('--extraTag', default=None, action='store', help='Specify an extra tag for to the version.')
|
|
|
|
# Intercept any request for a help message and bail
|
|
argv = sys.argv;
|
|
if '-h' in argv or '-help' in argv or '--help' in argv:
|
|
parser.print_help()
|
|
exit()
|
|
|
|
# Parse the args
|
|
parser.formatter_class.max_help_position = 50
|
|
args = parser.parse_args()
|
|
|
|
# TODO: Finish this functionality
|
|
if args.doFullBuild == True:
|
|
print("Unsupported action: [--doFullBuild]. Skipping...")
|
|
|
|
# Ensure required applications are installed
|
|
checkForInstalledApps()
|
|
|
|
buildRelease(args.extraTag, args.doNotClean)
|