Added support for configurable digest

Changed -jreRelease to -jreVersion
Added preliminary support for JRE updating
Code cleanup / refactoring
This commit is contained in:
Norberto Lopez
2016-04-06 14:29:59 +00:00
parent 641c68ae9f
commit 342cf73bd9
33 changed files with 1423 additions and 449 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -20,7 +20,7 @@ def buildRelease(args, buildPath):
# Retrieve vars of interest
appName = args.name
version = args.version
jreRelease = args.jreRelease
jreRelease = args.jreVersion
platformStr = 'apple'
# Check our system environment before proceeding
@@ -384,6 +384,7 @@ def buildPListInfoStatic(destFile, args):
tupList.append(('CFBundlePackageType', 'APPL'))
tupList.append(('CFBundleSignature', '????'))
tupList.append(('CFBundleVersion', args.version))
tupList.append(('NSHighResolutionCapable', 'true'))
tupList.append(('NSHumanReadableCopyright', ''))
jrePath = 'jre' + args.jreRelease
tupList.append(('JVMRuntime', jrePath))

View File

@@ -39,11 +39,23 @@ class FancyArgumentParser(argparse.ArgumentParser):
# yield arg
def buildCatalogFile(deltaPath):
# Build the delta md5sum catalog
def buildCatalogFile(args, deltaPath):
# Build the delta catalog
records = []
# Record the digest used
digestType = args.digest
record = ('digest', digestType)
records.append(record)
# Record the JRE required
jreVersion = args.jreVersion
if jreVersion == None:
jreVersion = jreUtils.getDefaultJrVersion()
if jreVersion != None:
record = ('jre', jreVersion)
records.append(record)
snipLen = len(deltaPath) + 1
# for root, dirNames, fileNames in os.walk(deltaPath, onerror=failTracker.recordError):
for root, dirNames, fileNames in os.walk(deltaPath):
@@ -73,22 +85,20 @@ def buildCatalogFile(deltaPath):
elif os.path.isfile(fullPath) == True:
# Gather the various stats of the specified file
stat = os.stat(fullPath)
md5sum = miscUtils.computeMd5ForFile(fullPath)
digestVal = miscUtils.computeDigestForFile(fullPath, digestType)
relPath = fullPath[snipLen:]
record = ('F', md5sum, str(stat.st_size), relPath)
record = ('F', digestVal, str(stat.st_size), relPath)
records.append(record)
else:
print("Undefined node. Full path: " + fullPath + "\n")
# Save the records to the catalog file
dstPath = os.path.join(deltaPath, "catalog.txt")
f = open(dstPath, 'wb')
for aRecord in records:
if len(aRecord) == 2:
f.write(aRecord[0] + ',' + aRecord[1] + '\n')
else:
f.write(aRecord[0] + ',' + aRecord[1] + ',' + aRecord[2] + ',' + aRecord[3] + '\n')
f.write(','.join(aRecord) + '\n')
f.write('exit\n')
f.close()
def checkForRequiredApplications():
@@ -166,7 +176,7 @@ 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('-jreRelease', help='JRE release to utilize. Note there should be a corresponding folder in ~/jre/<platform>/', default=None)
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('-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)
@@ -174,7 +184,8 @@ if __name__ == "__main__":
parser.add_argument('-bgFile', help='Background file used for apple dmg file.')
parser.add_argument('-iconFile', help='PNG file used for linux/windows icon.')
parser.add_argument('-icnsFile', help='Icon file used for apple build.')
parser.add_argument('-forceSingleInstance', help='Force the application to have only one instance..', default=False)
parser.add_argument('-forceSingleInstance', help='Force the application to have only one instance.', default=False)
parser.add_argument('-digest', help='Digest used to ensure integrity of application upgrades. Default: sha256', choices=['md5', 'sha256', 'sha512'], default='sha256')
# parser.add_argument('-bundleId', help='Apple specific id descriptor.')
# Intercept any request for a help message and bail
@@ -265,8 +276,8 @@ if __name__ == "__main__":
dstPath = os.path.join(buildPath, "delta/app.cfg")
miscUtils.buildAppLauncherConfig(dstPath, args)
# Build the delta md5sum catalog
buildCatalogFile(deltaPath)
# Build the delta catalog
buildCatalogFile(args, deltaPath)
# Build the Apple release
appleUtils.buildRelease(args, buildPath)
@@ -278,6 +289,6 @@ if __name__ == "__main__":
windowsUtils.buildRelease(args, buildPath)
# Copy over the deploy script
srcPath = os.path.join(miscUtils.getInstallRoot(), "deployDist.py")
srcPath = os.path.join(miscUtils.getInstallRoot(), "deployAppDist.py")
shutil.copy(srcPath, buildPath)

View File

@@ -28,15 +28,15 @@ def getDistInfo(distPath):
exeMode = line;
elif exeMode == '-name' and len(line) > 0:
appName = line
elif exeMode == '-version' and len(line) > 0:
elif exeMode == '-version' and len(line) > 0:
version = line
elif exeMode == '-buildDate' and len(line) > 0:
elif exeMode == '-buildDate' and len(line) > 0:
buildDate = line
f.close()
if appName == None or version == None or buildDate == None:
print('Distribution corresponding to the folder: ' + distPath + ' does not appear to be valid!')
print('The configuration file, ' + cfgFile+ ', is not valid.')
print('The configuration file, ' + cfgFile + ', is not valid.')
print('Release will not be made for app ' + appName)
exit()
@@ -150,7 +150,7 @@ if __name__ == "__main__":
# Logic to capture Ctrl-C and bail
signal.signal(signal.SIGINT, handleSignal)
# Retrive the location of the scriptPath
# Retrieve the location of the scriptPath
scriptPath = os.path.realpath(__file__)
scriptPath = os.path.dirname(scriptPath)

0
script/deployJreDist.py Executable file
View File

View File

@@ -9,7 +9,7 @@ import tempfile
import miscUtils
# Globals
# The global variable defaultJreRelease is a hint for which (tar.gz) JRE release to
# The global variable defaultJreVersion 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.
#
@@ -19,16 +19,16 @@ import miscUtils
# where VERSION is something like: 8u73
# For example the Linux JRE 1.8.73 tar.gz release would be:
# <installpath>/jre/jre-8u73-linux-x64.tar.gz
defaultJreRelease = '1.8'
defaultJreVersion = '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 'defaultJreRelease' in globals():
jreTarGzFile = getJreTarGzFile(aPlatform, defaultJreRelease)
if 'defaultJreVersion' in globals():
jreTarGzFile = getJreTarGzFile(aPlatform, defaultJreVersion)
if jreTarGzFile == None:
print('[WARNING] The specified default JRE for the ' + aPlatform.capitalize() + ' platform is: ' + defaultJreRelease + '. However this JRE is not installed! <---')
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))
@@ -38,6 +38,14 @@ def getDefaultJreRelease(aPlatform):
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
@@ -125,7 +133,7 @@ def getJreTarGzVersion(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 file naming convenition is expected to be:
The file naming convention is expected to be:
jre-<A>u<B>-*.tar.gz
where:
A ---> The major version
@@ -159,7 +167,7 @@ def unpackAndRenameToStandard(aJreTarGzFile, aDestPath):
if os.path.isdir(aDestPath) == False:
os.makedirs(aDestPath)
# Unpack to a tempory folder at aDestPath
# Unpack to a temporary folder at aDestPath
tmpPath = tempfile.mkdtemp(dir=aDestPath)
subprocess.check_call(["tar", "-xf", aJreTarGzFile, "-C", tmpPath], stderr=subprocess.STDOUT)
@@ -174,6 +182,6 @@ def unpackAndRenameToStandard(aJreTarGzFile, aDestPath):
targPath = os.path.join(aDestPath, jreBasePath)
os.rename(fileList[0], targPath)
# Remove the the tempory path
# Remove the the temporary path
os.rmdir(tmpPath)

View File

@@ -18,7 +18,7 @@ def buildRelease(args, buildPath):
# Retrieve vars of interest
appName = args.name
version = args.version
jreRelease = args.jreRelease
jreRelease = args.jreVersion
platformStr = 'linux'
# Check our system environment before proceeding
@@ -122,6 +122,13 @@ def buildBashScript(destFile, args, jreTarGzFile):
f.write('# mutations to this script while it is running\n')
f.write('{ # Do not remove this bracket! \n\n')
f.write('# Define where the Java executable is located\n')
if jreTarGzFile == None:
f.write('javaExe=java\n\n')
else:
jrePath = jreUtils.getBasePathForJreTarGzFile(jreTarGzFile)
f.write('javaExe=../' + jrePath + '/bin/java\n\n')
f.write('# Define the maximum memory to allow the application to utilize\n')
if maxMem == None:
f.write('#maxMem=512m # Uncomment out this line to change from defaults.\n\n')
@@ -142,10 +149,7 @@ def buildBashScript(destFile, args, jreTarGzFile):
f.write(' xmxStr=\'-Xmx\'$maxMem\n')
f.write('fi\n\n')
exeCmd = 'java ' + jvmArgsStr + '$xmxStr '
if jreTarGzFile != None:
jrePath = jreUtils.getBasePathForJreTarGzFile(jreTarGzFile)
exeCmd = '../' + jrePath + '/bin/java ' + jvmArgsStr + '$xmxStr '
exeCmd = '$javaExe ' + jvmArgsStr + '$xmxStr '
exeCmd = exeCmd + '-Djava.system.class.loader=appLauncher.RootClassLoader -cp ../launcher/appLauncher.jar appLauncher.AppLauncher $*'
f.write('# Run the application\n')
f.write(exeCmd + '\n\n')

View File

@@ -19,16 +19,25 @@ def checkRoot():
# Source: http://stackoverflow.com/questions/1131220/get-md5-hash-of-a-files-without-open-it-in-python
def computeMd5ForFile(evalFile, block_size=2**20):
def computeDigestForFile(evalFile, digest, block_size=2**20):
# Select the proper hash algorithm
if digest == 'md5':
hash = hashlib.md5()
elif digest == 'sha256':
hash = hashlib.sha256()
elif digest == 'sha512':
hash = hashlib.sha512()
else:
raise Exception('Unrecognized hash function: ' + digest);
f = open(evalFile, 'rb')
md5 = hashlib.md5()
while True:
data = f.read(block_size)
if not data:
break
md5.update(data)
hash.update(data)
f.close()
return md5.hexdigest()
return hash.hexdigest()
def getInstallRoot():

View File

@@ -17,7 +17,7 @@ def buildRelease(args, buildPath):
# Retrieve vars of interest
appName = args.name
version = args.version
jreRelease = args.jreRelease
jreRelease = args.jreVersion
platformStr = 'windows'
# Check our system environment before proceeding

View File

@@ -10,33 +10,31 @@ import glum.task.*;
import glum.unit.DateUnit;
import glum.util.ThreadUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.*;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.google.common.base.Joiner;
import distMaker.digest.Digest;
import distMaker.digest.DigestUtils;
import distMaker.gui.PickReleasePanel;
import distMaker.node.FileNode;
import distMaker.node.Node;
import distMaker.jre.*;
import distMaker.node.*;
import distMaker.platform.AppleUtils;
import distMaker.platform.PlatformUtils;
public class DistMakerEngine
{
// State vars
private URL updateSiteUrl;
private Release currRelease;
private AppRelease currRelease;
private Credential refCredential;
// Gui vars
@@ -52,10 +50,8 @@ public class DistMakerEngine
refCredential = null;
parentFrame = aParentFrame;
msgPanel = new MessagePanel(parentFrame);
msgPanel.setSize(700, 400);
promptPanel = new PromptPanel(parentFrame);
promptPanel.setSize(500, 300);
msgPanel = new MessagePanel(parentFrame, "Untitled", 700, 400);
promptPanel = new PromptPanel(parentFrame, "Untitled", 500, 300);
initialize();
}
@@ -109,38 +105,39 @@ public class DistMakerEngine
* <LI>running from a developers environment (Ex: Eclipse IDE)
* <LI>If the software application was not properly packaged (or has become corrupt) with DistMaker.
*/
public Release getCurrentRelease()
public AppRelease getCurrentRelease()
{
return currRelease;
}
/**
* returns
*
* @return
*/
public UpdateStatus isUpToDate()
{
LoggingTask task = new LoggingTask();
String appName = currRelease.getName();
List<Release> unsortedReleaseList = DistUtils.getAvailableReleases(task, updateSiteUrl, appName, refCredential);
LoggingTask task = new LoggingTask();
String appName = currRelease.getName();
List<AppRelease> unsortedReleaseList = DistUtils.getAvailableAppReleases(task, updateSiteUrl, appName, refCredential);
if (unsortedReleaseList == null) {
// The update check failed, so return a status of false with a message about the problem
String msg = Joiner.on("; ").join(task.getMessages());
return new UpdateStatus(msg);
}
// Sort the items, and isolate the newest item
LinkedList<Release> fullList = new LinkedList<>(unsortedReleaseList);
Collections.sort(fullList);
Release newestRelease = fullList.removeLast();
if (unsortedReleaseList == null)
{
// The update check failed, so return a status of false with a message about the problem
String msg = Joiner.on("; ").join(task.getMessages());
return new UpdateStatus(msg);
}
// Sort the items, and isolate the newest item
LinkedList<AppRelease> fullList = new LinkedList<>(unsortedReleaseList);
Collections.sort(fullList);
AppRelease newestRelease = fullList.removeLast();
// The check succeeded, so return wether or not the app is up to date.
return new UpdateStatus(newestRelease.equals(currRelease));
// The check succeeded, so return whether or not the app is up to date.
return new UpdateStatus(newestRelease.equals(currRelease));
}
/**
* Sets in the credentials used to access the update site. If either argument is null, then the credentials will be
* cleared out.
* Sets in the credentials used to access the update site. If either argument is null, then the credentials will be cleared out.
*/
public void setCredentials(String aUsername, char[] aPassword)
{
@@ -214,7 +211,7 @@ public class DistMakerEngine
}
}
catch (IOException aExp)
catch(IOException aExp)
{
aExp.printStackTrace();
}
@@ -226,7 +223,7 @@ public class DistMakerEngine
if (appName == null || verName == null)
{
displayNotice(null);
System.out.println("Failed to properly parse DistMaker config file: " + cfgFile);
System.err.println("Failed to properly parse DistMaker config file: " + cfgFile);
return;
}
@@ -237,7 +234,7 @@ public class DistMakerEngine
if (buildStr != null)
buildTime = dateUnit.parseString(buildStr, 0);
currRelease = new Release(appName, verName, buildTime);
currRelease = new AppRelease(appName, verName, buildTime);
// Notify the user, if the application has been successfully updated
markSystemFullyStarted();
@@ -255,8 +252,8 @@ public class DistMakerEngine
@SuppressWarnings("unused")
private void checkForUpdatesWorker(FullTaskPanel aTask, UpdateCheckListener listener)
{
List<Release> fullList;
Release chosenItem;
List<AppRelease> fullList;
AppRelease chosenItem;
File installPath, deltaPath;
String appName;
boolean isPass;
@@ -271,7 +268,7 @@ public class DistMakerEngine
// Retrieve the list of available releases
aTask.infoAppendln("Checking for updates...\n");
fullList = DistUtils.getAvailableReleases(aTask, updateSiteUrl, appName, refCredential);
fullList = DistUtils.getAvailableAppReleases(aTask, updateSiteUrl, appName, refCredential);
if (fullList == null)
{
aTask.abort();
@@ -281,21 +278,23 @@ public class DistMakerEngine
// a successful test has been done, so notify the listener
listener.checkForNewVersionsPerformed();
// In case there is only the current version, don't show the update selection panel.
// Just show a short message that everything is up to date, and abort.
// (This check used to be in the getAvailableReleases() call above, but I needed
// that to not throw an error for the case of only one release, so I moved that
// check here.)
if (fullList.size() == 1) {
if (fullList.get(0).equals(currRelease)) {
// There is only one release out there, and its the same
// as the one being run, so there is nothing to update.
String msg = "There are no updates of " + appName + ". Only one release has been made.";
aTask.infoAppendln(msg);
aTask.abort();
return;
}
}
// In case there is only the current version, don't show the update selection panel.
// Just show a short message that everything is up to date, and abort.
// (This check used to be in the getAvailableReleases() call above, but I needed
// that to not throw an error for the case of only one release, so I moved that
// check here.)
if (fullList.size() == 1)
{
if (fullList.get(0).equals(currRelease))
{
// There is only one release out there, and its the same
// as the one being run, so there is nothing to update.
String msg = "There are no updates of " + appName + ". Only one release has been made.";
aTask.infoAppendln(msg);
aTask.abort();
return;
}
}
// Hide the taskPanel
aTask.setVisible(false);
@@ -309,7 +308,7 @@ public class DistMakerEngine
aFuncRunnable = new FunctionRunnable(this, "queryUserForInput", aTask, deltaPath, fullList);
SwingUtilities.invokeAndWait(aFuncRunnable);
}
catch (Exception aExp)
catch(Exception aExp)
{
aExp.printStackTrace();
}
@@ -382,14 +381,15 @@ public class DistMakerEngine
* <P>
* Returns true if the release was downloaded properly.
*/
private boolean downloadRelease(Task aTask, Release aRelease, File destPath)
private boolean downloadRelease(Task aTask, AppRelease aRelease, File destPath)
{
Map<String, Node> staleMap, updateMap;
AppCatalog staleCat, updateCat;
Node staleNode, updateNode;
URL catUrl, staleUrl, updateUrl;
File catalogFile;
Task mainTask, tmpTask;
long nodeFileLen;
double progressVal;
long tmpFileLen;
boolean isPass;
try
@@ -397,7 +397,7 @@ public class DistMakerEngine
staleUrl = DistUtils.getAppPath().toURI().toURL();
updateUrl = IoUtil.createURL(updateSiteUrl.toString() + "/" + aRelease.getName() + "/" + aRelease.getVersion() + "/delta");
}
catch (MalformedURLException aExp)
catch(MalformedURLException aExp)
{
aTask.infoAppendln(ThreadUtil.getStackTrace(aExp));
aExp.printStackTrace();
@@ -407,51 +407,182 @@ public class DistMakerEngine
// Download the update catalog to the (local) delta location (Progress -> [0% - 1%])
catUrl = IoUtil.createURL(updateUrl.toString() + "/catalog.txt");
catalogFile = new File(destPath, "catalog.txt");
if (DistUtils.downloadFile(new PartialTask(aTask, 0.00, 0.01), catUrl, catalogFile, refCredential, -1L) == false)
if (DistUtils.downloadFile(new PartialTask(aTask, 0.00, 0.01), catUrl, catalogFile, refCredential, -1L, null) == false)
return false;
// Load the map of stale nodes
// Load the stale catalog
catalogFile = new File(DistUtils.getAppPath(), "catalog.txt");
staleMap = DistUtils.readCatalog(aTask, catalogFile, staleUrl);
if (staleMap == null)
staleCat = DistUtils.readAppCatalog(aTask, catalogFile, staleUrl);
if (staleCat == null)
return false;
// Load the map of update nodes
// Load the update catalog
catalogFile = new File(destPath, "catalog.txt");
updateMap = DistUtils.readCatalog(aTask, catalogFile, updateUrl);
if (updateMap == null)
updateCat = DistUtils.readAppCatalog(aTask, catalogFile, updateUrl);
if (updateCat == null)
return false;
// Determine the total number of bytes to be transferred
// Determine the total number of bytes to be transferred and set up the mainTask
long releaseSizeFull = 0L, releaseSizeCurr = 0L;
for (Node aNode : updateMap.values())
for (Node aNode : updateCat.getAllNodesList())
{
if (aNode instanceof FileNode)
releaseSizeFull += ((FileNode)aNode).getFileLen();
}
// Download the individual files (Progress -> [1% - 95%])
double progressVal = 0.00;
// Set up the mainTask for downloading of remote content (Progress -> [1% - 95%])
mainTask = new PartialTask(aTask, 0.01, 0.94);
mainTask.infoAppendln("Downloading release: " + aRelease.getVersion() + " Nodes: " + updateMap.size());
for (String aFileName : updateMap.keySet())
// Ensure our JRE version is sufficient for this release
JreVersion currJreVer = DistUtils.getJreVersion();
JreVersion targJreVer = updateCat.getJreVersion();
if (targJreVer != null && JreVersion.getBetterVersion(targJreVer, currJreVer) != currJreVer)
{
List<JreRelease> jreList;
aTask.infoAppendln("Your current JRE is too old. It will need to be updated!");
aTask.infoAppendln("\tCurrent JRE: " + currJreVer.getLabel());
aTask.infoAppendln("\tMinimun JRE: " + targJreVer.getLabel() + "\n");
// Get list of all available JREs
jreList = JreUtils.getAvailableJreReleases(aTask, updateSiteUrl, refCredential);
if (jreList == null)
{
aTask.infoAppendln("The update site has not had any JREs deployed.");
aTask.infoAppendln("Please contact the update site adminstartor.");
return false;
}
if (jreList.size() == 0)
{
aTask.infoAppendln("No JRE releases found!");
aTask.infoAppendln("Please contact the update site adminstartor.");
return false;
}
// Retrieve the latest appropriate JreRelease
String platform = DistUtils.getPlatform();
jreList = JreUtils.getMatchingPlatforms(jreList, platform);
if (jreList.size() == 0)
{
aTask.infoAppendln("There are no JRE releases available for the platform: " + platform + "!");
return false;
}
JreRelease pickJre = jreList.get(0);
JreVersion pickJreVer = pickJre.getVersion();
if (JreVersion.getBetterVersion(pickJreVer, targJreVer) == currJreVer)
{
aTask.infoAppendln("The latest available JRE on the update site is not recent enought!");
aTask.infoAppendln("Minimun required JRE: " + targJreVer.getLabel());
aTask.infoAppendln("Latest available JRE: " + pickJreVer.getLabel());
return false;
}
// Update the number of bytes to be retrieved to take into account the JRE which we will be downloading
// and form the appropriate tmpTask
tmpFileLen = pickJre.getFileLen();
releaseSizeFull += tmpFileLen;
tmpTask = new PartialTask(mainTask, mainTask.getProgress(), tmpFileLen / (releaseSizeFull + 0.00));
// Download the JRE
Digest targDigest, testDigest;
targDigest = pickJre.getDigest();
MessageDigest msgDigest;
msgDigest = DigestUtils.getDigest(targDigest.getType());
mainTask.infoAppendln("Downloading JRE... Version: " + pickJre.getVersion().getLabel());
URL srcUrl = IoUtil.createURL(updateSiteUrl.toString() + "/jre/" + pickJre.getFileName());
File dstFile = new File(new File(destPath, "jre"), pickJre.getFileName());
DistUtils.downloadFile(tmpTask, srcUrl, dstFile, refCredential, tmpFileLen, msgDigest);
// Validate that the JRE was downloaded successfully
testDigest = new Digest(targDigest.getType(), msgDigest.digest());
if (targDigest.equals(testDigest) == false)
{
aTask.infoAppendln("The download of the JRE appears to be corrupted.");
aTask.infoAppendln("\tFile: " + dstFile);
aTask.infoAppendln("\t\tExpected " + targDigest.getDescr());
aTask.infoAppendln("\t\tRecieved " + testDigest.getDescr() + "\n");
return false;
}
releaseSizeCurr += tmpFileLen;
progressVal = releaseSizeCurr / (releaseSizeFull + 0.00);
mainTask.setProgress(progressVal);
// TODO: Unpack the JRE at the proper location and then delete it
File jrePath = PlatformUtils.getJreLocation(pickJre);
try
{
int finish_me_and_clean_me;
// Files.createTempDirectory(dstFile, prefix, attrs)
// Files.createTempDir();
File unpackPath;
unpackPath = new File(destPath, "jre/unpack");
unpackPath.mkdirs();
MiscUtils.unTar(dstFile, unpackPath);
File[] fileArr;
fileArr = unpackPath.listFiles();
if (fileArr.length != 1 && fileArr[0].isDirectory() == false)
throw new Exception("Expected only one (top level) folder to be unpacked. Items extracted: " + fileArr.length + " Path: " + unpackPath);
File jreUnpackedPath;
jreUnpackedPath = fileArr[0];
// Moved the unpacked file to the "standardized" jrePath
jreUnpackedPath.renameTo(jrePath);
// MiscUtils.unTar(dstFile, jrePath);
// TODO: Remove the unpacked folder...
}
catch(Exception aExp)
{
aTask.infoAppendln("Failed to untar archive. The update has been aborted.");
aTask.infoAppendln("\tTar File: " + dstFile);
aTask.infoAppendln("\tDestination: " + jrePath);
return false;
}
// TODO: Update the launch script or launch config file to point to the proper JRE
if (PlatformUtils.setJreLocation(jrePath) == false)
{
aTask.infoAppendln("Failed to update the configuration to point to the updated JRE!");
aTask.infoAppendln("\tCurrent JRE: " + currJreVer.getLabel());
aTask.infoAppendln("\t Chosen JRE: " + pickJreVer.getLabel());
return false;
}
return true;
// TODO: Eventually remove the old JRE - perhaps from the app launcher
}
// Download the individual application files
mainTask.infoAppendln("Downloading release: " + aRelease.getVersion() + " Nodes: " + updateCat.getAllNodesList().size());
for (Node aNode : updateCat.getAllNodesList())
{
// Bail if we have been aborted
if (mainTask.isActive() == false)
return false;
updateNode = updateMap.get(aFileName);
staleNode = staleMap.get(aFileName);
nodeFileLen = 0L;
updateNode = aNode;
staleNode = staleCat.getNode(updateNode.getFileName());
tmpFileLen = 0L;
if (updateNode instanceof FileNode)
nodeFileLen = ((FileNode)updateNode).getFileLen();
tmpTask = new PartialTask(mainTask, mainTask.getProgress(), nodeFileLen / (releaseSizeFull + 0.00));
tmpFileLen = ((FileNode)updateNode).getFileLen();
tmpTask = new PartialTask(mainTask, mainTask.getProgress(), tmpFileLen / (releaseSizeFull + 0.00));
// Attempt to use the local copy
isPass = false;
if (staleNode != null && updateNode.areContentsEqual(staleNode) == true)
{
isPass = staleNode.transferContentTo(tmpTask, refCredential, destPath);
// Note we pass the SilentTask since
// - This should be fairly fast since this should result in a local disk copy
// - This may fail, (but the failuer is recoverable and this serves just as an optimization)
// isPass = staleNode.transferContentTo(tmpTask, refCredential, destPath);
isPass = staleNode.transferContentTo(new SilentTask(), refCredential, destPath);
if (isPass == true)
mainTask.infoAppendln("\t(L) " + staleNode.getFileName());
}
@@ -475,7 +606,7 @@ public class DistMakerEngine
}
// Update the progress
releaseSizeCurr += nodeFileLen;
releaseSizeCurr += tmpFileLen;
progressVal = releaseSizeCurr / (releaseSizeFull + 0.00);
mainTask.setProgress(progressVal);
}
@@ -487,8 +618,7 @@ public class DistMakerEngine
}
/**
* Notification that the corresponding application has been fully initialized. This helper method will notify the
* user on the status of any update.
* Notification that the corresponding application has been fully initialized. This helper method will notify the user on the status of any update.
*/
private void markSystemFullyStarted()
{
@@ -528,9 +658,9 @@ public class DistMakerEngine
* This method will be called via reflection.
*/
@SuppressWarnings("unused")
private void queryUserForInput(Task aTask, File deltaPath, List<Release> fullList)
private void queryUserForInput(Task aTask, File deltaPath, List<AppRelease> fullList)
{
Release chosenItem;
AppRelease chosenItem;
// Query the user, if the wish to destroy the old update
if (deltaPath.isDirectory() == true)
@@ -567,7 +697,7 @@ public class DistMakerEngine
/**
* Helper method to update platform specific configuration files
*/
private boolean updatePlatformConfigFiles(Task aTask, Release aRelease)
private boolean updatePlatformConfigFiles(Task aTask, AppRelease aRelease)
{
File installPath, pFile;
String errMsg;

View File

@@ -12,8 +12,13 @@ import glum.util.ThreadUtil;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.*;
import distMaker.digest.Digest;
import distMaker.digest.DigestType;
import distMaker.jre.JreVersion;
import distMaker.node.*;
public class DistUtils
@@ -59,6 +64,35 @@ public class DistUtils
return jarPath.getParentFile().getParentFile();
}
/**
* Returns the JreVersion for the JRE which we are running on.
*/
public static JreVersion getJreVersion()
{
String jreVer;
jreVer = System.getProperty("java.version");
return new JreVersion(jreVer);
}
/**
* Returns the platform (Apple, Linux, or Windows) on which the current JRE is running on.
*/
public static String getPlatform()
{
String osName;
osName = System.getProperty("os.name").toUpperCase();
if (osName.startsWith("LINUX") == true)
return "Linux";
if (osName.startsWith("MAC OS X") == true)
return "Apple";
if (osName.startsWith("WINDOWS") == true)
return "Windows";
return System.getProperty("os.name");
}
/**
* Returns the code associated with the update.
*/
@@ -86,12 +120,11 @@ public class DistUtils
/**
* Downloads the specified file from srcUrl to destFile. Returns true on success
* <P>
* Note the passed in task's progress will be updated from 0% to 100% at file download completion, If the specified
* file size is invalid (aFileSize <= 0) or the download turns out to be bigger than the specified size then there
* will be no progress update while the file is being downloaded - only at completion.
* Note the passed in task's progress will be updated from 0% to 100% at file download completion, If the specified file size is invalid (aFileSize <= 0) or
* the download turns out to be bigger than the specified size then there will be no progress update while the file is being downloaded - only at completion.
*/
@SuppressWarnings("resource")
public static boolean downloadFile(Task aTask, URL aUrl, File aFile, Credential aCredential, long aFileSize)
public static boolean downloadFile(Task aTask, URL aUrl, File aFile, Credential aCredential, long aFileSize, MessageDigest aDigest)
{
URLConnection connection;
InputStream inStream;
@@ -122,6 +155,8 @@ public class DistUtils
// Open the input/output streams
inStream = NetUtil.getInputStream(connection, aCredential);
if (aDigest != null)
inStream = new DigestInputStream(inStream, aDigest);
outStream = new FileOutputStream(aFile);
// Copy the bytes from the instream to the outstream
@@ -162,7 +197,7 @@ public class DistUtils
// Mark aTask's progress as complete since the file was downloaded.
aTask.setProgress(1.0);
}
catch (IOException aExp)
catch(IOException aExp)
{
errMsg = getErrorCodeMessage(aUrl, connection, aExp);
aTask.infoAppendln(errMsg);
@@ -180,9 +215,9 @@ public class DistUtils
/**
* Returns the list of available releases.
*/
public static List<Release> getAvailableReleases(Task aTask, URL aUpdateUrl, String appName, Credential aCredential)
public static List<AppRelease> getAvailableAppReleases(Task aTask, URL aUpdateUrl, String appName, Credential aCredential)
{
List<Release> fullList;
List<AppRelease> fullList;
URL catUrl;
URLConnection connection;
InputStream inStream;
@@ -232,13 +267,17 @@ public class DistUtils
dateUnit = new DateUnit("", "yyyyMMMdd HH:mm:ss");
buildTime = dateUnit.parseString(tokens[1], 0);
fullList.add(new Release(appName, verName, buildTime));
fullList.add(new AppRelease(appName, verName, buildTime));
}
}
}
catch (IOException aExp)
catch(IOException aExp)
{
// Friendly error message
errMsg = getErrorCodeMessage(aUpdateUrl, connection, aExp);
// Add the stack trace
errMsg += "\n\n" + ThreadUtil.getStackTrace(aExp);
}
finally
{
@@ -248,7 +287,7 @@ public class DistUtils
// See if we are in a valid state
if (errMsg != null)
; // Nothing to do, as an earlier error has occured
; // Nothing to do, as an earlier error has occurred
else if (fullList.size() == 0)
errMsg = "The update URL appears to be invalid.";
@@ -271,9 +310,6 @@ public class DistUtils
Result result;
String errMsg;
// Dump the stack trace
aExp.printStackTrace();
// Form a user friendly exception
errMsg = "The update site, " + aUpdateUrl + ", is not available.\n\t";
@@ -311,9 +347,8 @@ public class DistUtils
}
/**
* Utility method to determine if the specified path is fully writable by this process. This is done by making sure
* that all folders and child folders are writable by the current process. Note after this method is called, all
* folders will have the write permission bit set.
* Utility method to determine if the specified path is fully writable by this process. This is done by making sure that all folders and child folders are
* writable by the current process. Note after this method is called, all folders will have the write permission bit set.
*/
public static boolean isFullyWriteable(File aPath)
{
@@ -343,31 +378,33 @@ public class DistUtils
}
/**
* Returns a map of Nodes which describe the full content of an update specified in <aUpdateUrl>/catalog.txt
* Returns the AppCatalog which describe the full content of an update specified in <aUpdateUrl>/catalog.txt
*/
public static Map<String, Node> readCatalog(Task aTask, File catalogFile, URL aUpdateUrl)
public static AppCatalog readAppCatalog(Task aTask, File aCatalogFile, URL aUpdateUrl)
{
Map<String, Node> retMap;
List<Node> nodeList;
JreVersion jreVersion;
InputStream inStream;
BufferedReader bufReader;
String errMsg;
DigestType digestType;
String errMsg, strLine;
errMsg = null;
retMap = new LinkedHashMap<>();
nodeList = new ArrayList<>();
jreVersion = null;
// Default to DigestType of MD5
digestType = DigestType.MD5;
inStream = null;
bufReader = null;
try
{
String[] tokens;
String strLine, filename, md5sum;
long fileLen;
// Read the contents of the file
inStream = new FileInputStream(catalogFile);
inStream = new FileInputStream(aCatalogFile);
bufReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(inStream)));
// Read the lines
while (true)
{
strLine = bufReader.readLine();
@@ -379,17 +416,47 @@ public class DistUtils
tokens = strLine.split(",", 4);
if (strLine.isEmpty() == true || strLine.startsWith("#") == true)
; // Nothing to do
else if (tokens.length >= 1 && tokens[0].equals("exit") == true)
break; // Bail once we get the 'exit' command
else if (tokens.length == 2 && tokens[0].equals("P") == true)
{
String filename;
// Form the PathNode
filename = tokens[1];
retMap.put(filename, new PathNode(aUpdateUrl, filename));
nodeList.add(new PathNode(aUpdateUrl, filename));
}
else if (tokens.length == 4 && tokens[0].equals("F") == true)
{
md5sum = tokens[1];
String filename, digestStr;
long fileLen;
// Form the FileNode
digestStr = tokens[1];
fileLen = GuiUtil.readLong(tokens[2], -1);
filename = tokens[3];
retMap.put(filename, new FileNode(aUpdateUrl, filename, md5sum, fileLen));
nodeList.add(new FileNode(aUpdateUrl, filename, new Digest(digestType, digestStr), fileLen));
}
else if (tokens.length == 2 && tokens[0].equals("digest") == true)
{
DigestType tmpDigestType;
tmpDigestType = DigestType.parse(tokens[1]);
if (tmpDigestType == null)
aTask.infoAppendln("Failed to locate DigestType for: " + tokens[1]);
else
digestType = tmpDigestType;
}
else if (tokens.length == 2 && tokens[0].equals("jre") == true)
{
if (jreVersion != null)
{
aTask.infoAppendln("JRE version has already been specified. Current ver: " + jreVersion.getLabel() + " Requested ver: " + tokens[1]
+ ". Skipping...");
continue;
}
jreVersion = new JreVersion(tokens[1]);
}
else
{
@@ -397,7 +464,7 @@ public class DistUtils
}
}
}
catch (IOException aExp)
catch(IOException aExp)
{
errMsg = ThreadUtil.getStackTrace(aExp);
}
@@ -410,7 +477,7 @@ public class DistUtils
// See if we are in a valid state
if (errMsg != null)
; // Nothing to do, as an earlier error has occurred
else if (retMap.size() == 0)
else if (nodeList.size() == 0)
errMsg = "The catalog appears to be invalid.";
// Bail if there were issues
@@ -420,12 +487,11 @@ public class DistUtils
return null;
}
return retMap;
return new AppCatalog(jreVersion, nodeList);
}
/**
* Utility method to switch the DistMaker library into debug mode. You should never call this method unless you are
* modifying the DistMaker library.
* Utility method to switch the DistMaker library into debug mode. You should never call this method unless you are modifying the DistMaker library.
* <P>
* This functionality only exists to allow rapid development of DistMaker
*/

View File

@@ -0,0 +1,72 @@
package distMaker;
import java.io.*;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.List;
import java.util.Set;
/**
* Collection of generic utility methods that should be migrated to another library.
*/
public class MiscUtils
{
public static void unTar(final File inputFile, final File aDestPath) throws Exception
{
throw new Exception("Incomplete...");
}
/**
* Helper method to convert a Unix base-10 mode into the equivalent string.
* <P>
* Example: 493 -> 'rwxr-xr-x'
* <P>
* The returned string will always be of length 9
*/
public static String convertUnixModeToStr(int aMode)
{
char permArr[] = {'r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x'};
for (int c1 = 8; c1 >= 0; c1--)
{
if (((aMode >> c1) & 0x01) != 1)
permArr[8 - c1] = '-';
}
return new String(permArr);
}
/**
* Helper method to convert a Unix base-10 mode into the Set<PosixFilePermission>.
* <P>
* Example: 493 -> 'rwxr-xr-x'
* <P>
* The returned string will always be of length 9
*/
public static Set<PosixFilePermission> convertUnixModeToPFP(int aMode)
{
return PosixFilePermissions.fromString(convertUnixModeToStr(aMode));
}
/**
* Helper method to output the specified strings to aFile
*/
public static boolean writeDoc(File aFile, List<String> strList)
{
// Output the strList
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aFile)));)
{
// Write the lines
for (String aStr : strList)
bw.write(aStr + '\n');
}
catch(Exception aExp)
{
aExp.printStackTrace();
return false;
}
return true;
}
}

View File

@@ -2,36 +2,36 @@ package distMaker;
public class UpdateStatus
{
private final boolean isUpToDate;
private final boolean errorDeterminingState;
private final String errorMessage;
private final boolean isUpToDate;
private final boolean errorDeterminingState;
private final String errorMessage;
public UpdateStatus(boolean isUpToDate)
{
this.isUpToDate = isUpToDate;
this.errorDeterminingState = false;;
this.errorMessage = "";
}
public UpdateStatus(boolean isUpToDate)
{
this.isUpToDate = isUpToDate;
this.errorDeterminingState = false;
this.errorMessage = "";
}
public UpdateStatus(String errorMessage)
{
this.isUpToDate = false;
this.errorDeterminingState = true;
this.errorMessage = errorMessage;
}
public UpdateStatus(String errorMessage)
{
this.isUpToDate = false;
this.errorDeterminingState = true;
this.errorMessage = errorMessage;
}
public boolean isUpToDate()
{
return isUpToDate;
}
public boolean isUpToDate()
{
return isUpToDate;
}
public boolean isErrorDeterminingState()
{
return errorDeterminingState;
}
public boolean isErrorDeterminingState()
{
return errorDeterminingState;
}
public String getErrorMessage()
{
return errorMessage;
}
public String getErrorMessage()
{
return errorMessage;
}
}

View File

@@ -0,0 +1,83 @@
package distMaker.digest;
import java.util.Arrays;
public class Digest
{
private final DigestType digestType;
private final byte[] digestValueArr;
public Digest(DigestType aDigestType, byte[] aDigestValueArr)
{
digestType = aDigestType;
digestValueArr = Arrays.copyOf(aDigestValueArr, aDigestValueArr.length);
}
public Digest(DigestType aDigestType, String aHexStr)
{
digestType = aDigestType;
digestValueArr = DigestUtils.hexStr2ByteArr(aHexStr);
}
/**
* Returns a user friendly description (string) of this digest result.
* <P>
* The result will be DigestType:hexDigestValue
*/
public String getDescr()
{
return "" + digestType + ":" + getValueAsString();
}
/**
* Returns the DigestType associated with this Digest.
*/
public DigestType getType()
{
return digestType;
}
/**
* Returns the actual digest (as a string) associated with this Digest.
*/
public byte[] getValue()
{
return Arrays.copyOf(digestValueArr, digestValueArr.length);
}
/**
* Returns the actual digest (as a string) associated with this Digest.
*/
public String getValueAsString()
{
return DigestUtils.byteArr2HexStr(digestValueArr);
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((digestType == null) ? 0 : digestType.hashCode());
result = prime * result + Arrays.hashCode(digestValueArr);
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Digest other = (Digest)obj;
if (digestType != other.digestType)
return false;
if (!Arrays.equals(digestValueArr, other.digestValueArr))
return false;
return true;
}
}

View File

@@ -0,0 +1,46 @@
package distMaker.digest;
public enum DigestType
{
// Weak digest - but very fast
MD5("MD5"),
// Fairly strong digest type (with good performance on 32 bit machines)
SHA256("SHA-256"),
// Very strong digest type
SHA512("SHA-512");
// State vars
private String algName;
private DigestType(String aAlgName)
{
algName = aAlgName;
}
/**
* Returns the official digest algorithm name.
*
* @see http://docs.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html#AppA
*/
public String getAlgName()
{
return algName;
}
/**
* Returns the corresponding DigestType.
*/
public static DigestType parse(String aStr)
{
if (aStr.equalsIgnoreCase("MD5") == true)
return MD5;
if (aStr.equalsIgnoreCase("SHA256") == true)
return SHA256;
if (aStr.equalsIgnoreCase("SHA512") == true)
return SHA512;
return null;
}
}

View File

@@ -0,0 +1,68 @@
package distMaker.digest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
/**
* Collection of utility methods to ease working with the MessageDigest and associated classes.
*/
public class DigestUtils
{
/**
* Utility method that will throw a RuntimeExcepption if the specified digest function is not found.
* <P>
* Algorithm should be MD5, SHA-256, SHA-512, ...
* <P>
* See: http://docs.oracle.com/javase/1.8.0/docs/guide/security/CryptoSpec.html#AppA
*/
public static MessageDigest getDigest(String aAlgorithm)
{
MessageDigest retDigest;
try
{
retDigest = MessageDigest.getInstance(aAlgorithm);
}
catch(NoSuchAlgorithmException aExp)
{
throw new RuntimeException("Digest not found. Digest algorith not found: " + aAlgorithm);
}
return retDigest;
}
/**
* Utility method that will throw a RuntimeExcepption if the specified digest function is not found.
* <P>
* See: http://docs.oracle.com/javase/1.8.0/docs/guide/security/CryptoSpec.html#AppA
*/
public static MessageDigest getDigest(DigestType aDigestType)
{
return getDigest(aDigestType.getAlgName());
}
/**
* Utility method that returns the hex string corresponding to the byte array.
*/
public static String byteArr2HexStr(byte[] aByteArr)
{
String retStr;
retStr = (new HexBinaryAdapter()).marshal(aByteArr).toLowerCase();
return retStr;
}
/**
* Utility method that returns a byte array corresponding to the hex string.
*/
public static byte[] hexStr2ByteArr(String aHexStr)
{
byte[] retArr;
retArr = (new HexBinaryAdapter()).unmarshal(aHexStr);
return retArr;
}
}

View File

@@ -23,7 +23,7 @@ import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import distMaker.platform.MemUtils;
import distMaker.platform.PlatformUtils;
import static distMaker.platform.MemUtils.KB_SIZE;
import static distMaker.platform.MemUtils.MB_SIZE;
import static distMaker.platform.MemUtils.GB_SIZE;
@@ -48,11 +48,11 @@ public class MemoryConfigPanel extends GlassPanel implements ActionListener, Zio
private long targMemSize;
/**
* Constructor where the developer specifies the max heap memory. Be careful about using this method, as if a value
* is specified too large, then the program may become non operational on the next run.
* Constructor where the developer specifies the max heap memory. Be careful about using this method, as if a value is specified too large, then the program
* may become non operational on the next run.
* <P>
* Should the program become non operational then the end user would have to manually configure the config/script
* files by hand or a reinstall would be required.
* Should the program become non operational then the end user would have to manually configure the config/script files by hand or a reinstall would be
* required.
*/
public MemoryConfigPanel(Component aParent, long aMaxMemSize)
{
@@ -74,8 +74,8 @@ public class MemoryConfigPanel extends GlassPanel implements ActionListener, Zio
}
/**
* Constructor where the DistMaker framework attempts to determine the appropriate maxMexSize. Should, the DistMaker
* framework fail to determine the installed system memory, then 4GB will be assumed as the installed system memory.
* Constructor where the DistMaker framework attempts to determine the appropriate maxMexSize. Should, the DistMaker framework fail to determine the
* installed system memory, then 4GB will be assumed as the installed system memory.
*/
public MemoryConfigPanel(Component aParent)
{
@@ -124,7 +124,7 @@ public class MemoryConfigPanel extends GlassPanel implements ActionListener, Zio
targMemSize = roundToMB(targMemSize);
// Bail if we are not able to set the DistMaker max heap memory
if (MemUtils.setMaxHeapMem(warnPanel, targMemSize) == false)
if (PlatformUtils.setMaxHeapMem(warnPanel, targMemSize) == false)
return;
// Update our state vars
@@ -242,8 +242,7 @@ public class MemoryConfigPanel extends GlassPanel implements ActionListener, Zio
}
/**
* Utility method to round (floor) values to the nearest megabyte. The returned value is guaranteed to be at least 1
* megabyte.
* Utility method to round (floor) values to the nearest megabyte. The returned value is guaranteed to be at least 1 megabyte.
* <P>
* The input value, aSize, should be specified in bytes, and the returned value will be specified in bytes.
*/

View File

@@ -25,7 +25,7 @@ import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import distMaker.LookUp;
import distMaker.Release;
import distMaker.node.AppRelease;
public class PickReleasePanel extends GlassPanel implements ActionListener, ZioRaw, ListSelectionListener
{
@@ -34,19 +34,19 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
// GUI vars
private JLabel titleL;
private JRadioButton newestRB, olderRB;
private ItemListPanel<Release> listPanel;
private ItemListPanel<AppRelease> listPanel;
private QueryTableCellRenderer col0Renderer, col1Renderer;
private JButton abortB, proceedB;
private JTextArea infoTA, warnTA;
private Font smallFont;
// State vars
private StaticItemProcessor<Release> myItemProcessor;
private Release chosenItem;
private Release installedItem;
private Release newestItem;
private StaticItemProcessor<AppRelease> myItemProcessor;
private AppRelease chosenItem;
private AppRelease installedItem;
private AppRelease newestItem;
public PickReleasePanel(Component aParent, Release aInstalledItem)
public PickReleasePanel(Component aParent, AppRelease aInstalledItem)
{
super(aParent);
@@ -67,7 +67,7 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
/**
* Returns the Release selected by the user. This will be null if the user aborted the action.
*/
public Release getChosenItem()
public AppRelease getChosenItem()
{
return chosenItem;
}
@@ -75,7 +75,7 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
/**
* Sets in the configuration of available versions
*/
public void setConfiguration(List<Release> itemList)
public void setConfiguration(List<AppRelease> itemList)
{
DateUnit dateUnit;
// String currBuildStr;
@@ -84,7 +84,7 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
String appName, infoMsg;
// Sort the items, and isolate the newest item
LinkedList<Release> linkedList;
LinkedList<AppRelease> linkedList;
linkedList = new LinkedList<>(itemList);
Collections.sort(linkedList);
Collections.reverse(linkedList); // reverse the list to show most recent versions on top
@@ -210,7 +210,7 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
private JPanel buildItemListTablePanel()
{
QueryComposer<LookUp> aComposer;
QueryItemHandler<Release> aItemHandler;
QueryItemHandler<AppRelease> aItemHandler;
DateUnit dateUnit;
dateUnit = new DateUnit("", "yyyyMMMdd HH:mm");
@@ -225,10 +225,10 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
aComposer.setRenderer(LookUp.Version, col0Renderer);
aComposer.setRenderer(LookUp.BuildTime, col1Renderer);
aItemHandler = new QueryItemHandler<Release>(aComposer);
myItemProcessor = new StaticItemProcessor<Release>();
aItemHandler = new QueryItemHandler<AppRelease>(aComposer);
myItemProcessor = new StaticItemProcessor<AppRelease>();
listPanel = new ItemListPanel<Release>(aItemHandler, myItemProcessor, false, false);
listPanel = new ItemListPanel<AppRelease>(aItemHandler, myItemProcessor, false, false);
listPanel.setSortingEnabled(false);
listPanel.addListSelectionListener(this);
return listPanel;
@@ -239,7 +239,7 @@ public class PickReleasePanel extends GlassPanel implements ActionListener, ZioR
*/
private void updateGui()
{
Release pickItem;
AppRelease pickItem;
String warnMsg;
boolean isEnabled;

View File

@@ -0,0 +1,102 @@
package distMaker.jre;
import distMaker.digest.Digest;
/**
* Immutable class that describes a JRE Release.
* <P>
* The reference fileName should be a compressed (tar.gz) JRE.
*/
public class JreRelease implements Comparable<JreRelease>
{
private String platform;
private JreVersion version;
private Digest digest;
private String fileName;
private long fileLen;
public JreRelease(String aPlatform, String aVersion, String aFileName, Digest aDigest, long aFileLen)
{
platform = aPlatform;
version = new JreVersion(aVersion);
fileName = aFileName;
digest = aDigest;
fileLen = aFileLen;
}
/**
* Returns the Digest associated with the JRE (tar.gz) file.
*/
public Digest getDigest()
{
return digest;
}
/**
* Returns the version of the JRE corresponding to this release.
*/
public JreVersion getVersion()
{
return version;
}
/**
* Returns true if the specified platform matches our platform.
*/
public boolean isPlatformMatch(String aPlatform)
{
String platformStr;
// Consider this JreRelease a match if our platform is contained within aPlatform
platformStr = platform.toUpperCase();
if (aPlatform.toUpperCase().contains(platformStr) == true)
return true;
// If our platform == APPLE - then check to see if aPlatform mathes against 'MACOSX'
if (platformStr.equals("APPLE") == true && aPlatform.toUpperCase().contains("MACOSX") == true)
return true;
return false;
}
/**
* Returns the length of the associated file
*/
public long getFileLen()
{
return fileLen;
}
/**
* Returns the filename of this (tar.gz) JRE release.
*/
public String getFileName()
{
return fileName;
}
@Override
public int compareTo(JreRelease aItem)
{
int cmpVal;
cmpVal = platform.compareTo(aItem.platform);
if (cmpVal != 0)
return cmpVal;
cmpVal = version.compareTo(aItem.version);
if (cmpVal != 0)
return cmpVal;
cmpVal = fileName.compareTo(aItem.fileName);
if (cmpVal != 0)
return cmpVal;
cmpVal = Long.compare(fileLen, aItem.fileLen);
if (cmpVal != 0)
return cmpVal;
return 0;
}
}

View File

@@ -0,0 +1,149 @@
package distMaker.jre;
import glum.gui.GuiUtil;
import glum.io.IoUtil;
import glum.net.Credential;
import glum.net.NetUtil;
import glum.task.Task;
import glum.util.ThreadUtil;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import distMaker.digest.Digest;
import distMaker.digest.DigestType;
public class JreUtils
{
/**
* Returns a list of all the available JRE releases specified in &lt;aUpdateSiteUrl&gt;/jre/jreCatalog.txt
*/
public static List<JreRelease> getAvailableJreReleases(Task aTask, URL aUpdateSiteUrl, Credential aCredential)
{
List<JreRelease> retList;
URL catUrl;
URLConnection connection;
InputStream inStream;
BufferedReader bufReader;
DigestType digestType;
String errMsg, strLine;
errMsg = null;
retList = new ArrayList<>();
catUrl = IoUtil.createURL(aUpdateSiteUrl.toString() + "/jre/jreCatalog.txt");
// Default to DigestType of MD5
digestType = DigestType.MD5;
inStream = null;
bufReader = null;
try
{
String[] tokens;
// Read the contents of the file
connection = catUrl.openConnection();
inStream = NetUtil.getInputStream(connection, aCredential);
bufReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(inStream)));
// Read the lines
while (true)
{
strLine = bufReader.readLine();
// Bail once we are done
if (strLine == null)
break;
tokens = strLine.split(",", 4);
if (strLine.isEmpty() == true || strLine.startsWith("#") == true)
; // Nothing to do
else if (tokens.length >= 1 && tokens[0].equals("exit") == true)
break; // Bail once we get the 'exit' command
else if (tokens.length == 2 && tokens[0].equals("digest") == true)
{
DigestType tmpDigestType;
tmpDigestType = DigestType.parse(tokens[1]);
if (tmpDigestType == null)
aTask.infoAppendln("Failed to locate DigestType for: " + tokens[1]);
else
digestType = tmpDigestType;
}
else if (tokens.length == 6 && tokens[0].equals("jre") == true)
{
String platform, version, filename, digestStr;
long fileLen;
// Form the JreRelease
digestStr = tokens[1];
platform = tokens[2];
version = tokens[3];
fileLen = GuiUtil.readLong(tokens[4], -1);
filename = tokens[5];
retList.add(new JreRelease(platform, version, filename, new Digest(digestType, digestStr), fileLen));
}
else
{
aTask.infoAppendln("Unreconized line: " + strLine);
}
}
}
catch(FileNotFoundException aExp)
{
errMsg = "Failed to locate resource: " + catUrl;
}
catch(IOException aExp)
{
errMsg = ThreadUtil.getStackTrace(aExp);
}
finally
{
IoUtil.forceClose(inStream);
IoUtil.forceClose(bufReader);
}
// See if we are in a valid state
if (errMsg != null)
; // Nothing to do, as an earlier error has occurred
else if (retList.size() == 0)
errMsg = "The catalog appears to be invalid.";
// Bail if there were issues
if (errMsg != null)
{
aTask.infoAppendln(errMsg);
return null;
}
return retList;
}
/**
* Utility method that returns a list of matching JREs. The list will be sorted in order from newest to oldest. All returned JREs will have a platform that
* matches aPlatform.
*/
public static List<JreRelease> getMatchingPlatforms(List<JreRelease> aJreList, String aPlatform)
{
List<JreRelease> retList;
// Grab all JREs with a matching platforms
retList = new ArrayList<>();
for (JreRelease aRelease : aJreList)
{
if (aRelease.isPlatformMatch(aPlatform) == false)
continue;
retList.add(aRelease);
}
// Sort the platforms, but reverse the order so that the newest version is first
Collections.sort(retList);
Collections.reverse(retList);
return retList;
}
}

View File

@@ -0,0 +1,82 @@
package distMaker.jre;
import glum.gui.GuiUtil;
public class JreVersion implements Comparable<JreVersion>
{
private String version;
public JreVersion(String aVersion)
{
version = aVersion;
}
/**
* Returns the version of the JRE as a string.
*/
public String getLabel()
{
return version;
}
/**
* Utility method that returns the better version.
* <P>
* The better version is defined as the later version (and the more specific version).
* <P>
* Returns null if the better version can not be determined
*/
public static JreVersion getBetterVersion(JreVersion verA, JreVersion verB)
{
JreVersion defaultVer;
String[] tokenA, tokenB;
int valA, valB, idxCnt;
tokenA = verA.getLabel().split("[._]");
tokenB = verB.getLabel().split("[._]");
// Default return JreVersion is verA or the version that is more specific
defaultVer = verA;
if (tokenA.length < tokenB.length)
defaultVer = verB;
// Set the idxCnt to the less specific JreVersion
idxCnt = tokenA.length;
if (tokenB.length < tokenA.length)
idxCnt = tokenB.length;
// Compare each component of the version string. Each component should be separated by '.'
// Assume each component is an integer where larger values correspond to later versions
for (int c1 = 0; c1 < idxCnt; c1++)
{
valA = GuiUtil.readInt(tokenA[c1], -1);
valB = GuiUtil.readInt(tokenB[c1], -1);
if (valA == -1 && valB == -1)
return null;
if (valB == -1 || valA > valB)
return verA;
if (valA == -1 || valB > valA)
return verB;
}
// Defaults to verA
return defaultVer;
}
@Override
public int compareTo(JreVersion aItem)
{
JreVersion tmpVer;
// Note the natural ordering is from oldest version to most recent version
tmpVer = JreVersion.getBetterVersion(this, aItem);
if (tmpVer == aItem)
return -1;
if (tmpVer == this)
return +1;
return 0;
}
}

View File

@@ -0,0 +1,68 @@
package distMaker.node;
import java.util.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import distMaker.jre.JreVersion;
/**
* Object that describes the structure (files, folders, and JRE version) of a Java application.
*/
public class AppCatalog
{
/** The minimum JRE version required. */
private JreVersion jreVersion;
/** A mapping of filename to to corresponding Node */
private ImmutableMap<String, Node> nodeMap;
public AppCatalog(JreVersion aJreVersion, List<Node> aNodeList)
{
jreVersion = aJreVersion;
nodeMap = ImmutableMap.copyOf(formNameMap(aNodeList));
}
/**
* Returns the minimum JreVersion required.
*/
public JreVersion getJreVersion()
{
return jreVersion;
}
/**
* Returns the Node corresponding to the specified name.
*/
public Node getNode(String aName)
{
return nodeMap.get(aName);
}
/**
* Returns the full list of Nodes
*/
public ImmutableList<Node> getAllNodesList()
{
return nodeMap.values().asList();
}
/**
* Helper method to form the map used to quickly locate a Node with the corresponding filename.
* <P>
* TODO: This should be renamed formNameMap to formDigestMap<BR>
* TODO: This should probably be a mapping of Digest to Node rather than filename to Node
*/
public Map<String, Node> formNameMap(List<Node> aNodeList)
{
Map<String, Node> retMap;
retMap = new LinkedHashMap<>();
for (Node aNode : aNodeList)
retMap.put(aNode.getFileName(), aNode);
return retMap;
}
}

View File

@@ -1,17 +1,18 @@
package distMaker;
package distMaker.node;
import distMaker.LookUp;
import glum.database.QueryItem;
/**
* Immutable object that has information relevant to the packaged software.
*/
public class Release implements Comparable<Release>, QueryItem<LookUp>
public class AppRelease implements Comparable<AppRelease>, QueryItem<LookUp>
{
private final String appName;
private final String version;
private final long buildTime;
public Release(String aAppName, String aVersion, long aBuildTime)
public AppRelease(String aAppName, String aVersion, long aBuildTime)
{
appName = aAppName;
version = aVersion;
@@ -43,7 +44,7 @@ public class Release implements Comparable<Release>, QueryItem<LookUp>
}
@Override
public int compareTo(Release o)
public int compareTo(AppRelease o)
{
if (buildTime < o.buildTime)
return -1;
@@ -95,7 +96,7 @@ public class Release implements Comparable<Release>, QueryItem<LookUp>
return false;
if (getClass() != obj.getClass())
return false;
Release other = (Release)obj;
AppRelease other = (AppRelease)obj;
if (appName == null)
{
if (other.appName != null)

View File

@@ -6,21 +6,27 @@ import glum.task.Task;
import java.io.File;
import java.net.URL;
import java.security.MessageDigest;
import distMaker.DistUtils;
import distMaker.digest.Digest;
import distMaker.digest.DigestUtils;
/**
* Immutable node describing a File.
*/
public class FileNode implements Node
{
protected URL rootUrl;
protected String md5sum;
protected String fileName;
protected long fileLen;
private final URL rootUrl;
private final Digest digest;
private final String fileName;
private final long fileLen;
public FileNode(URL aRootUrl, String aFileName, String aMd5sum, long aFileLen)
public FileNode(URL aRootUrl, String aFileName, Digest aDigest, long aFileLen)
{
rootUrl = aRootUrl;
fileName = aFileName;
md5sum = aMd5sum;
digest = aDigest;
fileLen = aFileLen;
}
@@ -33,7 +39,7 @@ public class FileNode implements Node
return false;
fNode = (FileNode)aNode;
if (fNode.md5sum.equals(md5sum) == false)
if (fNode.digest.equals(digest) == false)
return false;
if (fNode.fileName.equals(fileName) == false)
return false;
@@ -62,6 +68,8 @@ public class FileNode implements Node
{
URL srcUrl;
File dstFile;
Digest tmpDigest;
boolean isPass;
// Determine the source URL to copy the contents from
srcUrl = IoUtil.createURL(rootUrl.toString() + "/" + fileName);
@@ -69,6 +77,23 @@ public class FileNode implements Node
// Determine the file to transfer the contents to
dstFile = new File(dstPath, fileName);
return DistUtils.downloadFile(aTask, srcUrl, dstFile, aCredential, fileLen);
// Download the file
MessageDigest msgDigest = DigestUtils.getDigest(digest.getType());
isPass = DistUtils.downloadFile(aTask, srcUrl, dstFile, aCredential, fileLen, msgDigest);
if (isPass == false)
return false;
// Validate that the file was downloaded successfully
tmpDigest = new Digest(digest.getType(), msgDigest.digest());
if (digest.equals(tmpDigest) == false)
{
aTask.infoAppendln("\nThe download of the application appears to be corrupted.");
aTask.infoAppendln("\tFile: " + fileName);
aTask.infoAppendln("\t\tExpected " + digest.getDescr());
aTask.infoAppendln("\t\tRecieved " + tmpDigest.getDescr() + "\n");
return false;
}
return true;
}
}

View File

@@ -8,12 +8,15 @@ import java.net.URL;
public class PathNode implements Node
{
protected URL rootUrl;
protected String fileName;
// private final URL rootUrl;
private final String fileName;
/**
* Immutable node describing a File.
*/
public PathNode(URL aRootUrl, String aFileName)
{
rootUrl = aRootUrl;
// rootUrl = aRootUrl;
fileName = aFileName;
}

View File

@@ -1,7 +1,5 @@
package distMaker.platform;
import glum.io.IoUtil;
import java.io.File;
import java.io.FileOutputStream;
@@ -13,11 +11,47 @@ import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
import distMaker.DistUtils;
/**
* Utility class which contains a set of methods to interact with an Apple Info.plist file.
*/
public class AppleUtils
{
/**
* Utility method to update the JRE to reflect the specified path.
* <P>
* TODO: Complete this comment and method.
*/
public static boolean updateJrePath(File aPath)
{
int zios_finish;
return false;
}
/**
* Returns the plist file used to configure apple applications.
* <P>
* Two locations will be searched.... TODO: Add more details of those locations.
*/
private static File getPlistFile()
{
File installPath;
File pFile;
// Get the top level install path
installPath = DistUtils.getAppPath().getParentFile();
// Attempt to locate the pList file
pFile = new File(installPath, "Info.plist");
if (pFile.isFile() == false)
pFile = new File(installPath.getParentFile(), "Info.plist");
if (pFile.isFile() == false)
pFile = null;
return pFile;
}
/**
* Utility method to update the specified max memory (-Xmx) value in the plist file (aFile) to the specified maxMemVal.
* <P>
@@ -26,7 +60,21 @@ public class AppleUtils
*
* @return Returns null on success or an error message describing the issue.
*/
public static String updateMaxMem(File aFile, long numBytes)
public static String updateMaxMem(long numBytes)
{
// Utilize the system pList file and delegate.
return updateMaxMem(numBytes, getPlistFile());
}
/**
* Utility method to update the specified max memory (-Xmx) value in the plist file (aFile) to the specified maxMemVal.
* <P>
* In order for this method to succeed there must be a valid JVMOptions section followed by an array of string elements of JVM arguments. The array element
* may be empty but must be specified.
*
* @return Returns null on success or an error message describing the issue.
*/
public static String updateMaxMem(long numBytes, File pFile)
{
Document doc;
Element docElement;
@@ -37,22 +85,32 @@ public class AppleUtils
String tagStr, valStr, currKeyVal;
int zios_Clean;
// Bail if we failed to locate the pList file.
if (pFile == null)
return "The plist file could not be located.";
// Bail if the plist file is not a regular file.
if (pFile.isFile() == false)
return "The plist file does not appear to be a regular file: " + pFile;
// Bail if the plist file is not writeable.
if (pFile.setWritable(true) == false)
return "The plist file is not writeable: " + pFile;
// Load the XML document via the javax.xml.parsers.* package
try
{
doc = loadDoc(aFile);
doc = loadDoc(pFile);
docElement = doc.getDocumentElement();
}
catch(Exception aExp)
{
aExp.printStackTrace();
return "Failed to parse XML document. File: " + aFile;
return "Failed to parse XML document. File: " + pFile;
}
// Locate the <dict> element
dictList = docElement.getElementsByTagName("dict");
if (dictList.getLength() == 0)
return "No <dict> element found!";
return "No <dict> element found! File: " + pFile;
arrE = null;
currKeyVal = null;
@@ -90,7 +148,7 @@ public class AppleUtils
// Bail if we failed to locate the array element
if (arrE == null)
return "Failed to locate the element <array> following the element: <key>JVMOptions</key>";
return "Failed to locate the element <array> following the element: <key>JVMOptions</key>\nFile: " + pFile;
memE = null;
childList = arrE.getChildNodes();
@@ -134,12 +192,12 @@ public class AppleUtils
evalStr = targNode.getNodeValue();
updateStr = MemUtils.transformMaxMemHeapString(evalStr, numBytes);
if (updateStr == null)
return "Failed to transform the memory spec value. Original value: " + evalStr;
return "Failed to transform the memory spec value. Original value: " + evalStr + "\nFile: " + pFile;
targNode.setNodeValue(updateStr);
// Update the file with the changed document
System.out.println("Updating contents of file: " + aFile);
return saveDoc(aFile, doc);
System.out.println("Updating contents of file: " + pFile);
return saveDoc(pFile, doc);
}
/**
@@ -209,10 +267,7 @@ public class AppleUtils
*/
private static String saveDoc(File aFile, Document aDoc)
{
FileOutputStream oStream;
oStream = null;
try
try (FileOutputStream oStream = new FileOutputStream(aFile);)
{
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.INDENT, "yes");
@@ -223,7 +278,6 @@ public class AppleUtils
// tr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "roles.dtd");
// Serialize the Document
oStream = new FileOutputStream(aFile);
tr.transform(new DOMSource(aDoc), new StreamResult(oStream));
}
catch(Exception aExp)
@@ -231,10 +285,6 @@ public class AppleUtils
aExp.printStackTrace();
return "Failed to write the file: " + aFile;
}
finally
{
IoUtil.forceClose(oStream);
}
return null;
}

View File

@@ -1,16 +1,26 @@
package distMaker.platform;
import glum.io.IoUtil;
import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import distMaker.DistUtils;
import distMaker.MiscUtils;
public class LinuxUtils
{
/**
* Utility method to update the JRE to reflect the specified path.
* <P>
* TODO: Complete this comment and method.
*/
public static boolean updateJrePath(File aPath)
{
int zios_finish;
return false;
}
/**
* Utility method to update the specified maxMem var in the script (aFile) to the requested number of bytes.
* <P>
@@ -20,22 +30,28 @@ public class LinuxUtils
* If the maxMem var definition is moved in the script file to after the launch of the application then this method will (silently) fail to configure the
* value needed to launch the JVM.
*/
public static boolean updateMaxMem(File aFile, long numBytes)
public static String updateMaxMem(long numBytes)
{
BufferedReader br;
List<String> inputList;
File scriptFile;
String evalStr, memStr, tmpStr;
int currLineNum, injectLineNum, targLineNum;
inputList = new ArrayList<>();
int zios_clean;
// Bail if we fail to locate the scriptFile.
scriptFile = getScriptFile();
if (scriptFile == null)
return "The script file could not be located.";
// Bail if the script file is not a regular file.
if (scriptFile.isFile() == false)
return "The script file does not appear to be a regular file: " + scriptFile;
// Bail if the script file is not writeable.
if (scriptFile.setWritable(true) == false)
return "The script file is not writeable: " + scriptFile;
// Process our input
br = null;
try
inputList = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(scriptFile)));)
{
br = new BufferedReader(new InputStreamReader(new FileInputStream(aFile)));
// Read the lines
currLineNum = 0;
targLineNum = -1;
@@ -60,11 +76,7 @@ public class LinuxUtils
catch(Exception aExp)
{
aExp.printStackTrace();
return false;
}
finally
{
IoUtil.forceClose(br);
return "Failed while processing the script file: " + scriptFile;
}
// Determine the memStr to use
@@ -85,8 +97,12 @@ public class LinuxUtils
}
// Update the script
System.out.println("Updating contents of file: " + aFile);
return writeDoc(aFile, inputList);
System.out.println("Updating contents of file: " + scriptFile);
if (MiscUtils.writeDoc(scriptFile, inputList) == false)
return "Failed to write the script file: " + scriptFile;
// On success return null
return null;
}
/**
@@ -97,7 +113,7 @@ public class LinuxUtils
* TODO: In the future the launch script should pass itself as an argument to the JVM and DistMaker should keep track of that. If the script is significantly
* manipulated from the original the launch file may be improperly detected.
*/
public static File getScriptFile()
private static File getScriptFile()
{
File[] fileArr;
File installPath;
@@ -124,34 +140,4 @@ public class LinuxUtils
return retFile;
}
/**
* Helper method to output the specified strings to aFile
*/
public static boolean writeDoc(File aFile, List<String> strList)
{
BufferedWriter bw;
// Output the strList
bw = null;
try
{
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aFile)));
// Write the lines
for (String aStr : strList)
bw.write(aStr + '\n');
}
catch(Exception aExp)
{
aExp.printStackTrace();
return false;
}
finally
{
IoUtil.forceClose(bw);
}
return true;
}
}

View File

@@ -1,16 +1,12 @@
package distMaker.platform;
import glum.gui.panel.generic.MessagePanel;
import glum.reflect.ReflectUtil;
import glum.unit.ByteUnit;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
import distMaker.DistUtils;
public class MemUtils
{
// Constants
@@ -19,8 +15,8 @@ public class MemUtils
public static final long GB_SIZE = 1024 * 1024 * 1024;
/**
* Utility method that attempts to compute the installed system memory (ram). If the installed system ram can not be
* computed, then the system is assumed to have 4 GB.
* Utility method that attempts to compute the installed system memory (ram). If the installed system ram can not be computed, then the system is assumed to
* have 4 GB.
*/
public static long getInstalledSystemMemory()
{
@@ -61,107 +57,7 @@ public class MemUtils
}
/**
* Utility method to configure the (active) DistMaker distribution to use the specified maxMem.
* <P>
* Method will return false on failure.
*
* @param warnPanel
* GUI message panel to route error messages.
* @param maxMemSize
* Maximum heap memory in bytes.
*/
public static boolean setMaxHeapMem(MessagePanel warnPanel, long maxMemSize)
{
File installPath, pFile, configFile, scriptFile;
String errMsg;
boolean isValidPlatform;
// Get the top level install path
installPath = DistUtils.getAppPath().getParentFile();
isValidPlatform = false;
// Apple specific platform files
pFile = new File(installPath, "Info.plist");
if (pFile.isFile() == false)
pFile = new File(installPath.getParentFile(), "Info.plist");
if (pFile.isFile() == true)
{
isValidPlatform = true;
errMsg = null;
if (pFile.setWritable(true) == false)
errMsg = "Failure. No writable permissions.";
else
errMsg = AppleUtils.updateMaxMem(pFile, maxMemSize);
if (errMsg != null)
{
errMsg = "File: " + pFile + "\n " + errMsg;
warnPanel.setTitle("Failed setting Apple properties.");
warnPanel.setInfo(errMsg);
warnPanel.setVisible(true);
return false;
}
}
// Linux specific platform files
scriptFile = LinuxUtils.getScriptFile();
if (scriptFile != null && scriptFile.isFile() == true)
{
isValidPlatform = true;
errMsg = null;
if (scriptFile.setWritable(true) == false)
errMsg = "Failure. No writable permmisions for file: " + scriptFile;
else if (LinuxUtils.updateMaxMem(scriptFile, maxMemSize) == false)
errMsg = "Failure. Failed to update file: " + scriptFile;
if (errMsg != null)
{
warnPanel.setTitle("Failed setting Linux configuration.");
warnPanel.setInfo(errMsg);
warnPanel.setVisible(true);
return false;
}
}
// Windows specific platform files
configFile = WindowsUtils.getConfigFile();
if (configFile != null && configFile.isFile() == true)
{
isValidPlatform = true;
errMsg = null;
if (WindowsUtils.updateMaxMem(configFile, maxMemSize) == false)
errMsg = "Failure. Failed to update file: " + configFile;
if (errMsg != null)
{
warnPanel.setTitle("Failed setting Windows configuration.");
warnPanel.setInfo(errMsg);
warnPanel.setVisible(true);
return false;
}
}
// Bail if no valid platform found
if (isValidPlatform == false)
{
errMsg = "This does not appear to be a valid DistMaker build. Memory changes will not take effect.";
warnPanel.setTitle("No valid DistMaker platform located.");
warnPanel.setInfo(errMsg);
warnPanel.setVisible(true);
return false;
}
return true;
}
/**
* Utility method that takes an inputStr, locates the fragment -Xmx*, and replaces the fragment with the appropriate
* -Xmx with respect to numBytes.
* Utility method that takes an inputStr, locates the fragment -Xmx*, and replaces the fragment with the appropriate -Xmx with respect to numBytes.
* <P>
* This method is a bit brittle in that it assumes the -Xmx string is surrounded with 1 white space character.
* <P>

View File

@@ -0,0 +1,104 @@
package distMaker.platform;
import glum.gui.panel.generic.MessagePanel;
import java.io.File;
import distMaker.DistUtils;
import distMaker.jre.JreRelease;
public class PlatformUtils
{
/**
* Utility method that returns the path where the specified JRE should be unpacked to.
*/
public static File getJreLocation(JreRelease aJreRelease)
{
String platform, versionStr;
File jrePath, installPath;
jrePath = null;
installPath = DistUtils.getAppPath();
versionStr = aJreRelease.getVersion().getLabel();
platform = DistUtils.getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
jrePath = new File(installPath.getParentFile(), "PlugIns/jre" + versionStr);
else if (platform.equals("LINUX") == true)
jrePath = new File(installPath.getParentFile(), "jre" + versionStr);
else if (platform.equals("Windows") == true)
jrePath = new File(installPath.getParentFile(), "jre" + versionStr);
return jrePath;
}
/**
* Utility method to configure the JRE location used by the active DistMaker distribution.
* <P>
* Note this will only take effect after the application has been relaunched.
*/
public static boolean setJreLocation(File aPath)
{
String platform;
boolean isPass;
isPass = false;
platform = DistUtils.getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
isPass = AppleUtils.updateJrePath(aPath);
else if (platform.equals("LINUX") == true)
isPass = LinuxUtils.updateJrePath(aPath);
else if (platform.equals("Windows") == true)
isPass = WindowsUtils.updateJrePath(aPath);
return isPass;
}
/**
* Utility method to configure the (active) DistMaker distribution to use the specified maxMem.
* <P>
* Method will return false on failure.
*
* @param warnPanel
* GUI message panel to route error messages.
* @param maxMemSize
* Maximum heap memory in bytes.
*/
public static boolean setMaxHeapMem(MessagePanel warnPanel, long maxMemSize)
{
String platform;
String errMsg;
// Delegate to the proper platform code
errMsg = null;
platform = DistUtils.getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
errMsg = AppleUtils.updateMaxMem(maxMemSize);
else if (platform.equals("LINUX") == true)
errMsg = LinuxUtils.updateMaxMem(maxMemSize);
else if (platform.equals("Windows") == true)
errMsg = WindowsUtils.updateMaxMem(maxMemSize);
else
errMsg = "Unrecognized platform: " + platform;
// Display the warnPanel with the the error condition
if (errMsg != null)
{
if (platform.equals("APPLE") == true)
warnPanel.setTitle("Failed setting Apple properties.");
else if (platform.equals("LINUX") == true)
warnPanel.setTitle("Failed setting Linux configuration.");
else if (platform.equals("Windows") == true)
warnPanel.setTitle("Failed setting Windows configuration.");
else
warnPanel.setTitle("Platform is not supported.");
warnPanel.setInfo(errMsg);
warnPanel.setVisible(true);
return false;
}
return true;
}
}

View File

@@ -1,38 +1,49 @@
package distMaker.platform;
import glum.io.IoUtil;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import distMaker.DistUtils;
import distMaker.MiscUtils;
public class WindowsUtils
{
/**
* Utility method to update the specified max memory (-Xmx) value in the text file (aFile) to the specified
* maxMemVal.
* Utility method to update the JRE to reflect the specified path.
* <P>
* Note this method is very brittle, and assumes that there is a single value where the string, -Xmx, is specified in
* the script. It assumes this string will be surrounded by a single space character on each side.
* TODO: Complete this comment and method.
*/
public static boolean updateMaxMem(File aFile, long numBytes)
public static boolean updateJrePath(File aPath)
{
BufferedReader br;
int zios_finish;
return false;
}
/**
* Utility method to update the specified max memory (-Xmx) value in the text file (aFile) to the specified maxMemVal.
* <P>
* Note this method is very brittle, and assumes that there is a single value where the string, -Xmx, is specified in the script. It assumes this string will
* be surrounded by a single space character on each side.
*/
public static String updateMaxMem(long numBytes)
{
File configFile;
List<String> inputList;
String strLine, updateStr;
boolean isProcessed;
inputList = new ArrayList<>();
// Bail if we fail to locate the configFile.
configFile = getConfigFile();
if (configFile != null && configFile.isFile() == true)
return "The config file could not be located.";
isProcessed = false;
inputList = new ArrayList<>();
// Process our input
br = null;
try
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(configFile))))
{
br = new BufferedReader(new InputStreamReader(new FileInputStream(aFile)));
// Read the lines
while (true)
{
@@ -62,16 +73,16 @@ public class WindowsUtils
catch(Exception aExp)
{
aExp.printStackTrace();
return false;
}
finally
{
IoUtil.forceClose(br);
return "Failed while processing the config file: " + configFile;
}
// Update the script
System.out.println("Updating contents of file: " + aFile);
return LinuxUtils.writeDoc(aFile, inputList);
System.out.println("Updating contents of file: " + configFile);
if (MiscUtils.writeDoc(configFile, inputList) == false)
return "Failed to write the config file: " + configFile;
// On success return null
return null;
}
/**

Binary file not shown.

View File

@@ -71,7 +71,7 @@ def buildRelease(version, doNotClean=False):
# Copy the scripts
dstPath = os.path.join(workPath, 'script')
os.mkdir(dstPath)
for aScript in ['appleUtils.py', 'linuxUtils.py', 'windowsUtils.py', 'buildDist.py', 'deployDist.py', 'jreUtils.py', 'logUtils.py', 'miscUtils.py']:
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)