mirror of
https://github.com/JHUAPL/Glum.git
synced 2026-01-09 08:57:55 -05:00
[1] Updates to improve the ParseUtil functionality. [2] Added check for null font argument.
306 lines
10 KiB
Python
Executable File
306 lines
10 KiB
Python
Executable File
#! /usr/bin/env python3
|
|
|
|
import argparse
|
|
import datetime
|
|
import fileinput
|
|
import glob
|
|
import os
|
|
import re
|
|
import shutil
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import traceback
|
|
|
|
|
|
# Define the (baseline) version
|
|
baseVersion = "2.1.0"
|
|
|
|
# Define relevant base names
|
|
appBaseName = 'Glum'
|
|
libBaseName = 'glum'
|
|
|
|
# Define the libraries Glum depends on
|
|
libList = ['guava-18.0.jar', 'miglayout-3.7.2-swing.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
|
|
Glum library.
|
|
"""
|
|
# 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, '-C', 'bin', '.']
|
|
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 buildManifestFile(aManifestFN):
|
|
"""Generates the manifest file that is placed within the application jar.
|
|
"""
|
|
manifestFile = open(aManifestFN, 'w')
|
|
manifestFile.write('Manifest-Version: 1.0\n')
|
|
manifestFile.write('Comment-Info: Auto generated by buildRelease\n')
|
|
|
|
exeDate = time.localtime()
|
|
buildDateStr = time.strftime('%Y%b%d %H:%M:%S', exeDate)
|
|
manifestFile.write('Comment-Time: ' + buildDateStr + '\n')
|
|
# libStr = ' '.join('lib/' + aName for aName in libList)
|
|
# manifestFile.write('Class-Path: ' + libStr + '\n')
|
|
# manifestFile.write('Main-Class: glum.app.AppGlum\n')
|
|
manifestFile.close()
|
|
|
|
|
|
def buildRelease(aExtraTag, aDoNotClean=False):
|
|
"""Method that builds a release of Glum. Upon sucessful execution
|
|
the following will be created:
|
|
- glum-<version>.jar
|
|
- glum-<version>-src.jar
|
|
"""
|
|
# Define the version to build
|
|
# Retrieve the date stamp to utilize as the base version for this release
|
|
# zios_2021Jan: Should we utilize chrono versioning or major.minor.path versioning
|
|
exeDate = datetime.date.today()
|
|
# baseVersion = exeDate.strftime('%Y.%m.%d')
|
|
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')
|
|
|
|
# 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 len(failMsgL) > 0:
|
|
errPrintln('Aborting ' + appBaseName + ' release build. Reasons:')
|
|
for aFailMsg in failMsgL:
|
|
errPrintln(' - ' + aFailMsg)
|
|
errPrintln('')
|
|
exit(-1)
|
|
|
|
# # Bail if the documents have not been updated to reflect the version to be built
|
|
# isPass = True
|
|
# dstPath = os.path.join(workPath, 'doc')
|
|
# for aDoc in ['ChangeLog.txt', 'ReadMe.txt']:
|
|
# srcPath = os.path.join(installPath, 'doc', aDoc)
|
|
# isPass &= checkDocVersion(srcPath, version)
|
|
#
|
|
# # Bail if any documents have versions that do not match. They should be updated.
|
|
# if isPass == False:
|
|
# errPrintln('Please update the documentation files before a release is built.')
|
|
# errPrintln('Build has been aborted.\n')
|
|
# exit(-1)
|
|
|
|
# Auto update the AppInfo file with the version info
|
|
appInfoSrcFile = 'src/glum/app/AppInfo.java'
|
|
isVersionFound = False
|
|
for line in fileinput.FileInput(appInfoSrcFile, inplace=1):
|
|
if re.match('^\s*private\s*static\s*String\s*Version\s*=.*', line) != None:
|
|
line = '\tprivate static String Version = "' + version + '";\n'
|
|
isVersionFound = True
|
|
print(line, end='')
|
|
|
|
if isVersionFound == False:
|
|
errPrintln('\nFailed to locate version declaration in library!')
|
|
errPrintln('\tVersion has NOT have been updated.')
|
|
errPrintln('\tSearched file: ' + appInfoSrcFile + '\n')
|
|
|
|
|
|
# Build the library jar
|
|
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)
|
|
|
|
print(appBaseName + ' release ' + version + ' built. Assets:')
|
|
for aFilePath in [jarBinPathFN, jarSrcPathFN]:
|
|
print(' - ' + aFilePath)
|
|
print('')
|
|
|
|
|
|
def checkDocVersion(aFile, aVersion):
|
|
"""Method that returns true if the version in the documentation file, aFile
|
|
matches the provided version. The documentation file should be a simple text
|
|
file where the version is recorded on the 2nd line. The 2nd line is expected
|
|
to match the following pattern:
|
|
Version: <aVersion>
|
|
|
|
If the version does not match then the expected input vs the actual input
|
|
will be logged to stderr. This method is useful to allow a release to be
|
|
built and ensuring that the documentation files have been updated.
|
|
"""
|
|
verStr = 'Version: ' + aVersion
|
|
|
|
workFileInput = fileinput.FileInput(aFile, mode = 'rb')
|
|
for line in workFileInput:
|
|
lineNum = workFileInput.lineno()
|
|
|
|
# Convert from bytes to string. If there is an issue then just assume
|
|
# the empty string.
|
|
try:
|
|
lineStr = line.decode("utf-8")
|
|
lineStr = lineStr.rstrip()
|
|
except:
|
|
lineStr = ''
|
|
|
|
if lineNum == 2 and lineStr != verStr:
|
|
errPrintln('Documentation file does not match version.')
|
|
errPrintln(' File: ' + aFile)
|
|
errPrintln(' [Line-2] Actual: ' + lineStr)
|
|
errPrintln(' [Line-2] Expected: ' + verStr)
|
|
errPrintln('')
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
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 glum.app.AppGlum) and the
|
|
output will be parsed. Any failures will result in the abrupt exit of this
|
|
script."""
|
|
try:
|
|
cpStr = aJarBinPath
|
|
exeCmd = [javaExe, '-cp', cpStr, 'glum.app.AppGlum', '--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)
|