Files
Glum/tools/buildRelease
Norberto Lopez b01a6095f8 Changes for 2.1.0:
[1] Updates to improve the ParseUtil functionality.

[2] Added check for null font argument.
2025-07-30 18:06:33 -04:00

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)