Updated logic to support

- Code cleanup / refactor
- Improved Java versioning related logic
- Added support for Java version range (rather than just minimum version)
- Added support for JRE updating
- Improved update revert logic
- Added support to untar jvm tar.gz archives
This commit is contained in:
Norberto Lopez
2016-05-07 03:57:18 +00:00
parent 04956c9172
commit 1e5402ea82
14 changed files with 1337 additions and 547 deletions

View File

@@ -10,10 +10,12 @@ import glum.task.*;
import glum.unit.DateUnit;
import glum.util.ThreadUtil;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.*;
import java.security.MessageDigest;
import java.util.*;
@@ -21,13 +23,13 @@ import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import distMaker.digest.Digest;
import distMaker.digest.DigestUtils;
import distMaker.gui.PickReleasePanel;
import distMaker.jre.*;
import distMaker.node.*;
import distMaker.platform.AppleUtils;
import distMaker.platform.PlatformUtils;
public class DistMakerEngine
@@ -110,6 +112,14 @@ public class DistMakerEngine
return currRelease;
}
/**
* Returns the URL where software updates for this application are retrieved from.
*/
public URL getUpdateSite()
{
return updateSiteUrl;
}
/**
* returns
*
@@ -154,7 +164,6 @@ public class DistMakerEngine
private void initialize()
{
File appPath, cfgFile;
BufferedReader br;
DateUnit dateUnit;
String currInstr, strLine;
String appName, verName, buildStr;
@@ -180,11 +189,8 @@ public class DistMakerEngine
}
// Read in the configuration file
br = null;
try
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile))))
{
br = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile)));
// Read the lines
currInstr = "None";
while (true)
@@ -215,10 +221,6 @@ public class DistMakerEngine
{
aExp.printStackTrace();
}
finally
{
IoUtil.forceClose(br);
}
if (appName == null || verName == null)
{
@@ -343,7 +345,7 @@ public class DistMakerEngine
}
// Download the release
isPass = downloadRelease(aTask, chosenItem, deltaPath);
isPass = downloadAppRelease(aTask, chosenItem, deltaPath);
if (isPass == false || aTask.isActive() == false)
{
IoUtil.deleteDirectory(deltaPath);
@@ -370,6 +372,29 @@ public class DistMakerEngine
aMsg += "Please check installation configuration.";
}
// If the parentFrame is not visible then delay the showing until it is visible
if (parentFrame.isVisible() == false)
{
final String tmpMsg = aMsg;
parentFrame.addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent aEvent)
{
msgPanel.setTitle("Application Updater");
msgPanel.setInfo(tmpMsg);
msgPanel.setVisible(true);
// Deregister for events after the parentFrame is made visible
parentFrame.removeComponentListener(this);
}
});
return;
}
// Transform tabs to 3 spaces
aMsg = aMsg.replace("\t", " ");
// Display the message
msgPanel.setTitle("Application Updater");
msgPanel.setInfo(aMsg);
@@ -381,7 +406,7 @@ public class DistMakerEngine
* <P>
* Returns true if the release was downloaded properly.
*/
private boolean downloadRelease(Task aTask, AppRelease aRelease, File destPath)
private boolean downloadAppRelease(Task aTask, AppRelease aRelease, File destPath)
{
AppCatalog staleCat, updateCat;
Node staleNode, updateNode;
@@ -390,7 +415,6 @@ public class DistMakerEngine
Task mainTask, tmpTask;
double progressVal;
long tmpFileLen;
boolean isPass;
try
{
@@ -404,20 +428,21 @@ public class DistMakerEngine
return false;
}
// 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, null) == false)
return false;
// Load the stale catalog
catalogFile = new File(DistUtils.getAppPath(), "catalog.txt");
staleCat = DistUtils.readAppCatalog(aTask, catalogFile, staleUrl);
if (staleCat == null)
return false;
// Download the update app catalog to the (local) delta location (Progress -> [0% - 1%])
File appNewPath = new File(destPath, "app");
appNewPath.mkdirs();
catUrl = IoUtil.createURL(updateUrl.toString() + "/catalog.txt");
catalogFile = new File(appNewPath, "catalog.txt");
if (DistUtils.downloadFile(new PartialTask(aTask, 0.00, 0.01), catUrl, catalogFile, refCredential, -1L, null) == false)
return false;
// Load the update catalog
catalogFile = new File(destPath, "catalog.txt");
updateCat = DistUtils.readAppCatalog(aTask, catalogFile, updateUrl);
if (updateCat == null)
return false;
@@ -433,136 +458,29 @@ public class DistMakerEngine
// Set up the mainTask for downloading of remote content (Progress -> [1% - 95%])
mainTask = new PartialTask(aTask, 0.01, 0.94);
// Ensure our JRE version is sufficient for this release
// Ensure our JRE version is compatible for this release
JreRelease targJre = null;
JreVersion currJreVer = DistUtils.getJreVersion();
JreVersion targJreVer = updateCat.getJreVersion();
if (targJreVer != null && JreVersion.getBetterVersion(targJreVer, currJreVer) != currJreVer)
if (updateCat.isJreVersionCompatible(currJreVer) == false)
{
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.");
// Bail if we failed to download a compatible JRE
targJre = downloadJreUpdate(mainTask, updateCat, destPath, releaseSizeFull);
if (targJre == null)
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;
// Update the progress to reflect the downloaded / updated JRE
releaseSizeCurr += targJre.getFileLen();
releaseSizeFull += targJre.getFileLen();
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())
{
boolean isPass;
// Bail if we have been aborted
if (mainTask.isActive() == false)
return false;
@@ -580,9 +498,9 @@ public class DistMakerEngine
{
// 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)
// - This may fail, (but the failure is recoverable and this serves just as an optimization)
// isPass = staleNode.transferContentTo(tmpTask, refCredential, destPath);
isPass = staleNode.transferContentTo(new SilentTask(), refCredential, destPath);
isPass = staleNode.transferContentTo(new SilentTask(), refCredential, appNewPath);
if (isPass == true)
mainTask.infoAppendln("\t(L) " + staleNode.getFileName());
}
@@ -590,7 +508,7 @@ public class DistMakerEngine
// Use the remote update copy, if we were not able to use a local stale copy
if (isPass == false && mainTask.isActive() == true)
{
isPass = updateNode.transferContentTo(tmpTask, refCredential, destPath);
isPass = updateNode.transferContentTo(tmpTask, refCredential, appNewPath);
if (isPass == true)
mainTask.infoAppendln("\t(R) " + updateNode.getFileName());
}
@@ -601,7 +519,7 @@ public class DistMakerEngine
mainTask.infoAppendln("Failed to download from update site.");
mainTask.infoAppendln("\tSite: " + updateUrl);
mainTask.infoAppendln("\tFile: " + updateNode.getFileName());
mainTask.infoAppendln("\tDest: " + destPath);
mainTask.infoAppendln("\tDest: " + appNewPath);
return false;
}
@@ -610,11 +528,246 @@ public class DistMakerEngine
progressVal = releaseSizeCurr / (releaseSizeFull + 0.00);
mainTask.setProgress(progressVal);
}
mainTask.infoAppendln("Finished downloading release.\n");
// Update the platform configuration files
isPass = updatePlatformConfigFiles(aTask, aRelease);
try
{
PlatformUtils.updateAppRelease(aRelease);
}
catch(ErrorDM aExp)
{
aTask.infoAppendln("Failed updating application configuration.");
printErrorDM(aTask, aExp, 1);
return false;
}
return isPass;
// Retrieve the reference to the appCfgFile
File appCfgFile = PlatformUtils.getConfigurationFile();
// Create the delta.cmd file which provides the Updater with the clean activities to perform (based on fail / pass conditions)
File deltaCmdFile = new File(destPath, "delta.cmd");
try (FileWriter tmpFW = new FileWriter(deltaCmdFile))
{
if (targJre != null)
{
File rootPath = DistUtils.getAppPath().getParentFile();
JreVersion targJreVer = targJre.getVersion();
tmpFW.write("# Define the fail section (clean up for failure)\n");
tmpFW.write("sect,fail\n");
tmpFW.write("copy," + "delta/" + appCfgFile.getName() + ".old," + MiscUtils.getRelativePath(rootPath, appCfgFile) + "\n");
tmpFW.write("move,jre" + targJreVer.getLabel() + ",delta" + "\n");
tmpFW.write("reboot\n\n");
tmpFW.write("# Define the pass section (clean up for success)\n");
tmpFW.write("sect,pass\n");
tmpFW.write("trash,jre" + currJreVer.getLabel() + "\n");
tmpFW.write("exit\n\n");
}
else
{
tmpFW.write("# Define the fail section (clean up for failure)\n");
tmpFW.write("sect,fail\n");
tmpFW.write("exit\n\n");
tmpFW.write("# Define the pass section (clean up for success)\n");
tmpFW.write("sect,pass\n");
tmpFW.write("exit\n\n");
}
tmpFW.write("# Define the reboot section\n");
tmpFW.write("sect,reboot\n");
tmpFW.write("exit\n\n");
tmpFW.write("# Define the test section\n");
tmpFW.write("sect,test\n");
tmpFW.write("exit\n\n");
}
catch(IOException aExp)
{
aTask.infoAppendln("Failed to generate the delta.cfg file.");
aTask.infoAppendln(ThreadUtil.getStackTrace(aExp));
return false;
}
// We are done if there was no updated JRE
if (targJre == null)
return true;
// Since an updated JRE was needed...
// Moved the JRE (unpacked folder) from its drop path to the proper location
File jreDropPath = new File(destPath, "jre" + targJre.getVersion().getLabel());
File jreTargPath = PlatformUtils.getJreLocation(targJre);
jreTargPath.getParentFile().setWritable(true);
if (jreDropPath.renameTo(jreTargPath) == false)
{
aTask.infoAppendln("Failed to move the updated JRE to its target location!");
aTask.infoAppendln("\t Current path: " + jreDropPath);
aTask.infoAppendln("\tOfficial path: " + jreTargPath);
return false;
}
// Backup the application configuration
try
{
Files.copy(appCfgFile.toPath(), new File(destPath, appCfgFile.getName() + ".old").toPath(), StandardCopyOption.COPY_ATTRIBUTES);
}
catch(IOException aExp)
{
aTask.infoAppendln("Failed to backup application configuration file: " + deltaCmdFile);
aTask.infoAppendln(ThreadUtil.getStackTrace(aExp));
return false;
}
// Update the application configuration to reflect the proper JRE
try
{
PlatformUtils.setJreVersion(targJre.getVersion());
}
catch(ErrorDM aExp)
{
aTask.infoAppendln("Failed to update the configuration to point to the updated JRE!");
aTask.infoAppendln("\tCurrent JRE: " + currJreVer.getLabel());
aTask.infoAppendln("\t Chosen JRE: " + targJre.getVersion().getLabel());
printErrorDM(aTask, aExp, 1);
// Remove the just installed JRE
IoUtil.deleteDirectory(jreTargPath);
return false;
}
return true;
}
/**
* Helper method to download a compatible JreRelease for the AppCatalog to the specified destPath.
* <P>
* On success the JreVersion that was downloaded is returned.
*/
private JreRelease downloadJreUpdate(Task aTask, AppCatalog aUpdateCat, File aDestPath, long releaseSizeFull)
{
List<JreRelease> jreList;
// Ensure our JRE version is compatible for this release
JreVersion currJreVer = DistUtils.getJreVersion();
// Let the user know why their version is not compatible
String updnStr = "downgraded";
if (aUpdateCat.isJreVersionTooOld(currJreVer) == true)
updnStr = "upgraded";
aTask.infoAppendln("Your current JRE is not compatible with this release. It will need to be " + updnStr + "!");
aTask.infoAppendln("\tCurrent JRE: " + currJreVer.getLabel());
aTask.infoAppendln("\tMinimun JRE: " + aUpdateCat.getMinJreVersion().getLabel());
JreVersion tmpJreVer = aUpdateCat.getMaxJreVersion();
if (tmpJreVer != null)
aTask.infoAppendln("\tMaximun JRE: " + tmpJreVer.getLabel());
aTask.infoAppendln("");
// Bail if we are running a bundled JRE
if (DistUtils.isJreBundled() == false)
{
aTask.infoAppend("This is the non bundled JRE version of the application. You are running the system JRE. ");
aTask.infoAppendln("Please update the JRE (or path) to reflect a compatible JRE version.\n");
return null;
}
// 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 null;
}
if (jreList.size() == 0)
{
aTask.infoAppendln("No JRE releases found!");
aTask.infoAppendln("Please contact the update site adminstartor.");
return null;
}
// Retrieve the latest appropriate JreRelease
String platform = PlatformUtils.getPlatform();
jreList = JreUtils.getMatchingPlatforms(jreList, platform);
if (jreList.size() == 0)
{
aTask.infoAppendln("There are no JRE releases available for the platform: " + platform + "!");
return null;
}
// Retrieve the JRE that is compatible from the list
JreRelease pickJre = aUpdateCat.getCompatibleJre(jreList);
if (pickJre == null)
{
aTask.infoAppendln("There are no compatible JREs found on the deploy site. Available JREs: " + jreList.size());
for (JreRelease aJreRelease : jreList)
aTask.infoAppendln("\t" + aJreRelease.getFileName() + " ---> (JRE: " + aJreRelease.getVersion().getLabel() + ")");
aTask.infoAppendln("\nPlease contact the update site adminstartor.");
return null;
}
JreVersion pickJreVer = pickJre.getVersion();
// Update the number of bytes to be retrieved to take into account the JRE which we will be downloading
long tmpFileLen = pickJre.getFileLen();
releaseSizeFull += tmpFileLen;
// Download the JRE
Digest targDigest, testDigest;
targDigest = pickJre.getDigest();
MessageDigest msgDigest;
msgDigest = DigestUtils.getDigest(targDigest.getType());
aTask.infoAppendln("Downloading JRE... Version: " + pickJreVer.getLabel());
URL srcUrl = IoUtil.createURL(updateSiteUrl.toString() + "/jre/" + pickJreVer.getLabel() + "/" + pickJre.getFileName());
File dstFile = new File(aDestPath, pickJre.getFileName());
Task tmpTask = new PartialTask(aTask, aTask.getProgress(), (tmpFileLen * 0.75) / (releaseSizeFull + 0.00));
if (DistUtils.downloadFile(tmpTask, srcUrl, dstFile, refCredential, tmpFileLen, msgDigest) == false)
return null;
// 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 null;
}
// Unpack the JRE at the unpack location
aTask.infoAppendln("Finshed downloading JRE. Unpacking JRE...");
File jreRootPath = null;
File jreTargPath = new File(aDestPath, "jre" + pickJreVer.getLabel());
try
{
// Create the working unpack folder where the JRE will be initially unpacked to.
File unpackPath = new File(aDestPath, "unpack");
unpackPath.mkdirs();
// Unpack the JRE to the working unpack folder and ensure that the unpacked JRE results in a 1 top level root folder.
tmpTask = new PartialTask(aTask, aTask.getProgress(), (tmpFileLen * 0.25) / (releaseSizeFull + 0.00));
MiscUtils.unTar(tmpTask, dstFile, unpackPath);
File[] 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);
jreRootPath = fileArr[0];
// Moved the unpacked JRE to aDestPath/jre/ folder and remove the working unpack folder and the tar.gz file
jreRootPath.renameTo(jreTargPath);
unpackPath.delete();
dstFile.delete();
}
catch(Exception aExp)
{
aTask.infoAppendln("Failed to properly untar archive. The update has been aborted.");
aTask.infoAppendln("\tTar File: " + dstFile);
aTask.infoAppendln("\tDestination: " + jreTargPath);
return null;
}
return pickJre;
}
/**
@@ -652,6 +805,39 @@ public class DistMakerEngine
displayNotice(msg);
}
/**
* Helper method that prints the exception of ErrorDM in an intelligent fashion to the specified task.
* <P>
* All ErrorDM exceptions (and their causes) will be printed. If the cause is not of type ErrorDM then the stack trace will be printed as well.
*/
private void printErrorDM(Task aTask, ErrorDM aErrorDM, int numTabs)
{
Throwable cause;
String tabStr;
tabStr = Strings.repeat("\t", numTabs);
aTask.infoAppendln(tabStr + "Reason: " + aErrorDM.getMessage());
cause = aErrorDM.getCause();
while (cause != null)
{
if (cause instanceof ErrorDM)
{
aTask.infoAppendln(tabStr + "Reason: " + cause.getMessage());
}
else
{
aTask.infoAppendln(tabStr + "StackTrace: ");
aTask.infoAppendln(ThreadUtil.getStackTrace(cause));
break;
}
cause = aErrorDM.getCause();
}
aTask.infoAppendln("");
}
/**
* Helper method that prompts the user for forms of input depending on the state of the App
* <P>
@@ -675,11 +861,8 @@ public class DistMakerEngine
return;
}
// Remove the retrieved update, and restore the platform configuration files to this (running) release
// It is necessary to do this, since the user may later cancel the update request and it is important to
// leave the program and configuration files in a stable state.
IoUtil.deleteDirectory(deltaPath);
updatePlatformConfigFiles(aTask, currRelease);
// Revert the update
revertUpdate(aTask);
}
// Query the user of the version to update to
@@ -695,37 +878,126 @@ public class DistMakerEngine
}
/**
* Helper method to update platform specific configuration files
* Helper method that "reverts" an update. After this method is called the DistMaker application's configuration should be in the same state as before an
* update was applied. Reverting consists of the following:
* <UL>
* <LI>Removal of any downloaded and installed JRE
* <LI>Removing the delta directory
* <LI>Removing the delta.cfg file
* </UL>
* <P>
* There should not be any issues with this roll back process. However if there are a best effort will be made to continue rolling back the updates - note
* that the application might be in an unstable state - and may not be able to be restarted.
*/
private boolean updatePlatformConfigFiles(Task aTask, AppRelease aRelease)
private void revertUpdate(Task aTask)
{
File installPath, pFile;
String errMsg;
// Get the top level install path
installPath = DistUtils.getAppPath().getParentFile();
// 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)
// Revert our application's configuration (which will be loaded when it is restarted) to reflect the proper JRE
try
{
errMsg = null;
if (pFile.setWritable(true) == false)
errMsg = "Failure. No writable permmisions for file: " + pFile;
else
errMsg = AppleUtils.updateVersion(pFile, aRelease.getVersion());
if (errMsg != null)
{
aTask.infoAppendln(errMsg);
return false;
}
JreVersion currJreVer = DistUtils.getJreVersion();
PlatformUtils.setJreVersion(currJreVer);
}
catch(ErrorDM aExp)
{
aTask.infoAppendln("Failed to revert application's JRE!");
aTask.infoAppendln("\tApplication may be in an unstable state.");
printErrorDM(aTask, aExp, 1);
}
return true;
// Revert any platform specific config files
try
{
PlatformUtils.updateAppRelease(currRelease);
}
catch(ErrorDM aExp)
{
aTask.infoAppendln("Failed to revert application configuration!");
aTask.infoAppendln("\tApplication may be in an unstable state.");
printErrorDM(aTask, aExp, 1);
}
// Determine the path to the delta (update) folder
File rootPath = DistUtils.getAppPath().getParentFile();
File deltaPath = new File(rootPath, "delta");
// It is necessary to do this, since the user may later cancel the update request and it is important to
// leave the program and configuration files in a stable state.
// Execute any trash commands from the "fail" section of the delta.cmd file
File deltaCmdFile = new File(deltaPath, "delta.cmd");
try (BufferedReader br = MiscUtils.openFileAsBufferedReader(deltaCmdFile))
{
String currSect = null;
while (true)
{
String inputStr = br.readLine();
// Delta command files should always have a proper exit (or reboot) and thus never arrive here
if (inputStr == null)
throw new ErrorDM("Command file (" + deltaCmdFile + ") is incomplete.");
// Ignore empty lines and comments
if (inputStr.isEmpty() == true || inputStr.startsWith("#") == true)
continue;
// Tokenize the input and retrieve the command
String[] strArr = inputStr.split(",");
String cmdStr = strArr[0];
// Skip to next line when we read a new section
if (strArr.length == 2 && cmdStr.equals("sect") == true)
{
currSect = strArr[1];
continue;
}
// Skip to the next line if we are not in the "fail" section
if (currSect != null && currSect.equals("fail") == false)
continue;
else if (currSect == null)
throw new ErrorDM("Command specified outside of section. Command: " + inputStr);
// Exit if we reach the exit or reboot command
if (strArr.length == 1 && cmdStr.equals("exit") == true)
break;
else if (strArr.length == 1 && cmdStr.equals("reboot") == true)
break;
// Execute the individual (trash) commands
if (strArr.length == 2 && cmdStr.equals("trash") == true)
{
// Resolve the argument to the corresponding file and ensure it is relative to our rootPath
File tmpFile = new File(rootPath, strArr[1]).getCanonicalFile();
if (MiscUtils.getRelativePath(rootPath, tmpFile) == null)
throw new ErrorDM("File (" + tmpFile + ") is not relative to folder: " + rootPath);
if (tmpFile.isFile() == true)
{
if (tmpFile.delete() == false)
throw new ErrorDM("Failed to delete file: " + tmpFile);
}
else if (tmpFile.isDirectory() == true)
{
if (IoUtil.deleteDirectory(tmpFile) == false)
throw new ErrorDM("Failed to delete folder: " + tmpFile);
}
else
{
throw new ErrorDM("File type is not recognized: " + tmpFile);
}
}
}
}
catch(IOException aExp)
{
aTask.infoAppendln("Failed to revert application configuration!");
aTask.infoAppendln("\tApplication may be in an unstable state.");
aTask.infoAppendln(ThreadUtil.getStackTrace(aExp));
}
// Remove the entire delta folder
if (IoUtil.deleteDirectory(deltaPath) == false)
throw new ErrorDM("Failed to delete folder: " + deltaPath);
}
}

View File

@@ -12,6 +12,8 @@ import glum.util.ThreadUtil;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.*;
@@ -75,24 +77,6 @@ public class DistUtils
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.
*/
@@ -117,6 +101,26 @@ public class DistUtils
return isDevelopersEnvironment;
}
/**
* Utility method to determine if the JRE is embedded with this application.
*/
public static boolean isJreBundled()
{
Path rootPath, jrePath;
// Get the top level folder of our installation
rootPath = getAppPath().toPath().getParent();
// Get the path to the JRE
jrePath = Paths.get(System.getProperty("java.home"));
// Determine if the java.home JRE is a subdirectory of the top level app folder
if (jrePath.startsWith(rootPath) == true)
return true;
return false;
}
/**
* Downloads the specified file from srcUrl to destFile. Returns true on success
* <P>
@@ -383,28 +387,23 @@ public class DistUtils
public static AppCatalog readAppCatalog(Task aTask, File aCatalogFile, URL aUpdateUrl)
{
List<Node> nodeList;
JreVersion jreVersion;
InputStream inStream;
BufferedReader bufReader;
JreVersion minJreVersion, maxJreVersion;
DigestType digestType;
String errMsg, strLine;
errMsg = null;
nodeList = new ArrayList<>();
jreVersion = null;
minJreVersion = null;
maxJreVersion = null;
// Default to DigestType of MD5
digestType = DigestType.MD5;
inStream = null;
bufReader = null;
try
try (BufferedReader bufReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(aCatalogFile))));)
{
String[] tokens;
// Read the contents of the file
inStream = new FileInputStream(aCatalogFile);
bufReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(inStream)));
while (true)
{
strLine = bufReader.readLine();
@@ -447,16 +446,18 @@ public class DistUtils
else
digestType = tmpDigestType;
}
else if (tokens.length == 2 && tokens[0].equals("jre") == true)
else if ((tokens.length == 2 || tokens.length == 3) && tokens[0].equals("jre") == true)
{
if (jreVersion != null)
if (minJreVersion != null)
{
aTask.infoAppendln("JRE version has already been specified. Current ver: " + jreVersion.getLabel() + " Requested ver: " + tokens[1]
aTask.infoAppendln("JRE version has already been specified. Current ver: " + minJreVersion.getLabel() + " Requested ver: " + tokens[1]
+ ". Skipping...");
continue;
}
jreVersion = new JreVersion(tokens[1]);
minJreVersion = new JreVersion(tokens[1]);
if (tokens.length == 3)
maxJreVersion = new JreVersion(tokens[2]);
}
else
{
@@ -468,11 +469,6 @@ public class DistUtils
{
errMsg = ThreadUtil.getStackTrace(aExp);
}
finally
{
IoUtil.forceClose(inStream);
IoUtil.forceClose(bufReader);
}
// See if we are in a valid state
if (errMsg != null)
@@ -487,7 +483,7 @@ public class DistUtils
return null;
}
return new AppCatalog(jreVersion, nodeList);
return new AppCatalog(nodeList, minJreVersion, maxJreVersion);
}
/**

View File

@@ -0,0 +1,37 @@
package distMaker;
/**
* Generic runtime exception thrown by various DistMaker modules/routines.
*/
public class ErrorDM extends RuntimeException
{
private static final long serialVersionUID = 1L;
// State vars
private String subject;
public ErrorDM(Throwable aCause, String aMessage, String aSubject)
{
super(aMessage, aCause);
subject = aSubject;
}
public ErrorDM(Throwable aCause, String aMessage)
{
this(aCause, aMessage, null);
}
public ErrorDM(String aMessage)
{
this(null, aMessage, null);
}
/**
* Returns the subject specific to this error. May be null if this is just a generic error.
*/
public String getSubject()
{
return subject;
}
}

View File

@@ -1,47 +1,54 @@
package distMaker;
import glum.task.Task;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.zip.GZIPInputStream;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import com.google.common.io.CountingInputStream;
/**
* Collection of generic utility methods that should be migrated to another library.
* Collection of generic utility methods that should be migrated to another library / class.
*/
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.
* Utility 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
* 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'};
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>.
* Utility 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
* The returned string will always be of length 9
*/
public static Set<PosixFilePermission> convertUnixModeToPFP(int aMode)
{
@@ -49,9 +56,143 @@ public class MiscUtils
}
/**
* Helper method to output the specified strings to aFile
* Returns the relative path component of aAbsolutePath relative to aBasePath.
* <P>
* Returns null if aAbsolutePath does not start with aBasePath.
*/
public static boolean writeDoc(File aFile, List<String> strList)
public static String getRelativePath(File aBasePath, File aAbsolutePath)
{
Path relPath;
// Bail if aAbsolutePath does not start with aBasePath
if (aAbsolutePath.toPath().startsWith(aBasePath.toPath()) == false)
return null;
relPath = aBasePath.toPath().relativize(aAbsolutePath.toPath());
return relPath.toString();
}
/**
* Utility method that returns a BufferedReader corresponding to the specified file.
* <P>
* This helps reduce boiler plate code.
*/
public static BufferedReader openFileAsBufferedReader(File aFile) throws IOException
{
return new BufferedReader(new InputStreamReader(new FileInputStream(aFile)));
}
/**
* Untar an input file into an output file.
* <P>
* Source based off of:<BR>
* http://stackoverflow.com/questions/315618/how-do-i-extract-a-tar-file-in-java/7556307#7556307
* <P>
*
* The output file is created in the output folder, having the same name as the input file, minus the '.tar' extension.
*
* @param inputFile
* the input .tar file
* @param aDestPath
* The destination folder where the content will be dumped.
* @throws IOException
* @throws FileNotFoundException
*
* @return The {@link List} of {@link File}s with the untared content.
* @throws ArchiveException
*/
public static List<File> unTar(Task aTask, final File inputFile, final File aDestPath) throws FileNotFoundException, IOException, ArchiveException
{
Map<File, Long> pathMap;
InputStream iStream;
final List<File> untaredFiles = new ArrayList<>();
long fullLen = inputFile.length();
// Open up the stream to the tar file (set up a counting stream to allow for progress updates)
CountingInputStream cntStream = new CountingInputStream(new FileInputStream(inputFile));
iStream = cntStream;
if (inputFile.getName().toUpperCase().endsWith(".GZ") == true)
iStream = new GZIPInputStream(iStream);
pathMap = new LinkedHashMap<>();
final TarArchiveInputStream debInputStream = (TarArchiveInputStream)new ArchiveStreamFactory().createArchiveInputStream("tar", iStream);
TarArchiveEntry entry = null;
while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null)
{
final File outputFile = new File(aDestPath, entry.getName());
if (entry.isDirectory())
{
if (!outputFile.exists())
{
if (!outputFile.mkdirs())
{
throw new IllegalStateException(String.format("Couldn't create directory %s.", outputFile.getAbsolutePath()));
}
}
long tmpUtc = entry.getModTime().getTime();
outputFile.setLastModified(tmpUtc);
pathMap.put(outputFile, tmpUtc);
}
else if (entry.isSymbolicLink() == true)
{
File tmpFile = new File(entry.getLinkName());
Path outLink = Files.createSymbolicLink(outputFile.toPath(), tmpFile.toPath());
long tmpUtc = entry.getModTime().getTime();
outputFile.setLastModified(tmpUtc);
}
else if (entry.isFile() == true)
{
final OutputStream outputFileStream = new FileOutputStream(outputFile);
IOUtils.copy(debInputStream, outputFileStream);
outputFileStream.close();
// Update the modified time of the file
long tmpUtc = entry.getModTime().getTime();
outputFile.setLastModified(tmpUtc);
}
else
{
System.err.println(String.format("Unrecognized entry: %s", entry.getName()));
}
// Update the mode on all (non symbolic) files / paths
int mode = entry.getMode();
if (entry.isSymbolicLink() == false)
{
String permStr;
permStr = convertUnixModeToStr(mode);
Files.setPosixFilePermissions(outputFile.toPath(), PosixFilePermissions.fromString(permStr));
// System.out.println(String.format("\tMode: %d %x %s %s name: %s", mode, mode, Integer.toOctalString(mode), permStr, entry.getName()));
}
untaredFiles.add(outputFile);
// Update the progress bar
aTask.infoUpdate("\tUnpacked: " + entry.getName());
long currLen = cntStream.getCount();
aTask.setProgress(currLen / (fullLen + 0.0));
}
debInputStream.close();
// Update all of the times on the folders last
for (File aDir : pathMap.keySet())
aDir.setLastModified(pathMap.get(aDir));
aTask.infoAppendln("\tUnpacked: " + untaredFiles.size() + " files\n");
return untaredFiles;
}
/**
* Helper method to output the specified strings to aFile
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void writeDoc(File aFile, List<String> strList)
{
// Output the strList
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aFile)));)
@@ -60,13 +201,10 @@ public class MiscUtils
for (String aStr : strList)
bw.write(aStr + '\n');
}
catch(Exception aExp)
catch(IOException aExp)
{
aExp.printStackTrace();
return false;
throw new ErrorDM(aExp, "Failed to write the file: " + aFile);
}
return true;
}
}

View File

@@ -8,6 +8,7 @@ import glum.gui.component.GSlider;
import glum.gui.panel.GlassPanel;
import glum.gui.panel.generic.MessagePanel;
import glum.unit.ByteUnit;
import glum.util.ThreadUtil;
import glum.zio.raw.ZioRaw;
import java.awt.*;
@@ -22,6 +23,7 @@ import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import distMaker.ErrorDM;
import distMaker.platform.MemUtils;
import distMaker.platform.PlatformUtils;
import static distMaker.platform.MemUtils.KB_SIZE;
@@ -123,9 +125,26 @@ public class MemoryConfigPanel extends GlassPanel implements ActionListener, Zio
targMemSize = (long)targMemS.getModelValue();
targMemSize = roundToMB(targMemSize);
// Bail if we are not able to set the DistMaker max heap memory
if (PlatformUtils.setMaxHeapMem(warnPanel, targMemSize) == false)
return;
try
{
// Delegate the updating of the memory
PlatformUtils.setMaxHeapMem(targMemSize);
}
catch(ErrorDM aExp)
{
String subjectStr = aExp.getSubject();
if (subjectStr == null)
subjectStr = "Application Configuration Error";
String messageStr = aExp.getMessage();
if (aExp.getCause() != null)
messageStr += "\n\n" + ThreadUtil.getStackTrace(aExp.getCause());
// Show the user the details of the failure
warnPanel.setTitle(subjectStr);
warnPanel.setInfo(messageStr);
warnPanel.setVisible(true);
}
// Update our state vars
instMemSize = targMemSize;

View File

@@ -14,6 +14,7 @@ import java.util.*;
import distMaker.digest.Digest;
import distMaker.digest.DigestType;
import distMaker.platform.PlatformUtils;
public class JreUtils
{
@@ -29,6 +30,7 @@ public class JreUtils
BufferedReader bufReader;
DigestType digestType;
String errMsg, strLine;
String version;
errMsg = null;
retList = new ArrayList<>();
@@ -36,6 +38,7 @@ public class JreUtils
// Default to DigestType of MD5
digestType = DigestType.MD5;
version = null;
inStream = null;
bufReader = null;
@@ -62,6 +65,8 @@ public class JreUtils
; // 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("name") == true && tokens[1].equals("JRE") == true)
; // Nothing to do - we just entered the "JRE" section
else if (tokens.length == 2 && tokens[0].equals("digest") == true)
{
DigestType tmpDigestType;
@@ -72,17 +77,35 @@ public class JreUtils
else
digestType = tmpDigestType;
}
else if (tokens.length == 6 && tokens[0].equals("jre") == true)
else if (tokens.length == 2 && tokens[0].equals("jre") == true)
{
String platform, version, filename, digestStr;
version = tokens[1];
}
else if (tokens.length == 4 && tokens[0].equals("F") == true)
{
String platform, filename, digestStr;
long fileLen;
if (version == null)
{
aTask.infoAppendln("Skipping input: " + strLine);
aTask.infoAppendln("\tJRE version has not been specifed. Missing input line: jre,<jreVersion>");
continue;
}
// Form the JreRelease
digestStr = tokens[1];
platform = tokens[2];
version = tokens[3];
fileLen = GuiUtil.readLong(tokens[4], -1);
filename = tokens[5];
fileLen = GuiUtil.readLong(tokens[2], -1);
filename = tokens[3];
platform = PlatformUtils.getPlatformOfJreTarGz(filename);
if (platform == null)
{
aTask.infoAppendln("Skipping input: " + strLine);
aTask.infoAppendln("\tFailed to determine the target platform of the JRE.");
continue;
}
retList.add(new JreRelease(platform, version, filename, new Digest(digestType, digestStr), fileLen));
}
else

View File

@@ -24,7 +24,7 @@ public class JreVersion implements Comparable<JreVersion>
* <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
* Returns null if the better version can not be determined or if the versions are equal.
*/
public static JreVersion getBetterVersion(JreVersion verA, JreVersion verB)
{
@@ -35,10 +35,12 @@ public class JreVersion implements Comparable<JreVersion>
tokenA = verA.getLabel().split("[._]");
tokenB = verB.getLabel().split("[._]");
// Default return JreVersion is verA or the version that is more specific
defaultVer = verA;
// Default JreVersion is the version that is more specific
defaultVer = null;
if (tokenA.length < tokenB.length)
defaultVer = verB;
else if (tokenB.length < tokenA.length)
defaultVer = verA;
// Set the idxCnt to the less specific JreVersion
idxCnt = tokenA.length;

View File

@@ -5,7 +5,7 @@ import java.util.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import distMaker.jre.JreVersion;
import distMaker.jre.*;
/**
* Object that describes the structure (files, folders, and JRE version) of a Java application.
@@ -13,23 +13,98 @@ import distMaker.jre.JreVersion;
public class AppCatalog
{
/** The minimum JRE version required. */
private JreVersion jreVersion;
private JreVersion minJreVer;
/** The maximum JRE version allowed. This will be null if there is no maximum. */
private JreVersion maxJreVer;
/** A mapping of filename to to corresponding Node */
private ImmutableMap<String, Node> nodeMap;
public AppCatalog(JreVersion aJreVersion, List<Node> aNodeList)
public AppCatalog(List<Node> aNodeList, JreVersion aMinJreVer, JreVersion aMaxJreVer)
{
jreVersion = aJreVersion;
minJreVer = aMinJreVer;
maxJreVer = aMaxJreVer;
nodeMap = ImmutableMap.copyOf(formNameMap(aNodeList));
}
/**
* Returns the minimum JreVersion required.
* Returns the most recent JRE from the specified release that is compatible with this Appcatalog.
* <P>
* Returns null if there are no JREs that are compatible.
*/
public JreVersion getJreVersion()
public JreRelease getCompatibleJre(List<JreRelease> aJreList)
{
return jreVersion;
// Sort the platforms, but reverse the order so that the newest version is first
Collections.sort(aJreList);
Collections.reverse(aJreList);
for (JreRelease aRelease : aJreList)
{
if (isJreVersionTooNew(aRelease.getVersion()) == true)
continue;
if (isJreVersionTooOld(aRelease.getVersion()) == true)
continue;
return aRelease;
}
return null;
}
/**
* Returns the minimum JreVersion that is compatible.
*/
public JreVersion getMinJreVersion()
{
return minJreVer;
}
/**
* Returns the maximum JreVersion that is compatible.
*/
public JreVersion getMaxJreVersion()
{
return maxJreVer;
}
public boolean isJreVersionCompatible(JreVersion aJreVer)
{
// Check to make sure aJreVer is not too old
if (isJreVersionTooOld(aJreVer) == true)
return false;
// Check to make sure aJreVer is not too new
if (isJreVersionTooNew(aJreVer) == true)
return false;
// The version aJreVer must be compatible
return true;
}
/**
* Returns true if the specified version is not compatible (too new) with this AppCatalog.
*/
public boolean isJreVersionTooNew(JreVersion aJreVer)
{
// Check to make sure aJreVer is not too old
if (maxJreVer != null && JreVersion.getBetterVersion(maxJreVer, aJreVer) == aJreVer)
return true;
return false;
}
/**
* Returns true if the specified version is not compatible (too old) with this AppCatalog.
*/
public boolean isJreVersionTooOld(JreVersion aJreVer)
{
// Check to make sure aJreVer is not too old
if (minJreVer != null && JreVersion.getBetterVersion(minJreVer, aJreVer) == minJreVer)
return true;
return false;
}
/**
@@ -54,7 +129,7 @@ public class AppCatalog
* 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)
private Map<String, Node> formNameMap(List<Node> aNodeList)
{
Map<String, Node> retMap;

View File

@@ -71,9 +71,9 @@ public class AppRelease implements Comparable<AppRelease>, QueryItem<LookUp>
}
@Override
public void setValue(@SuppressWarnings("unused") LookUp aEnum, @SuppressWarnings("unused") Object aObj)
public void setValue(LookUp aEnum, Object aObj)
{
throw new RuntimeException("Unsupported operation");
throw new RuntimeException("Unsupported operation setValue(aEnum: " + aEnum + " aObj: " + aObj + ")");
}
@Override

View File

@@ -1,7 +1,8 @@
package distMaker.platform;
import java.io.File;
import java.io.FileOutputStream;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -11,30 +12,22 @@ import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
import distMaker.DistUtils;
import distMaker.*;
import distMaker.jre.JreVersion;
/**
* 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
private static File getPlistFile()
public static File getPlistFile()
{
File installPath;
File pFile;
@@ -42,58 +35,54 @@ public class AppleUtils
// Get the top level install path
installPath = DistUtils.getAppPath().getParentFile();
// Attempt to locate the pList file
// Attempt to locate the pList file (from one of the possible locations)
pFile = new File(installPath, "Info.plist");
if (pFile.isFile() == false)
pFile = new File(installPath.getParentFile(), "Info.plist");
// Bail if we failed to locate the plist file
if (pFile.exists() == false)
throw new ErrorDM("The plist file could not be located.");
// Bail if the plist file is not a regular file.
if (pFile.isFile() == false)
pFile = null;
throw new ErrorDM("The plist file does not appear to be a regular file: " + pFile);
return pFile;
}
/**
* Utility method to update the specified max memory (-Xmx) value in the plist file (aFile) to the specified maxMemVal.
* Utility method to update the specified version in the plist file (pFile) to the new version.
* <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.
* Note this method is very brittle, and assumes that the version will occur in the sibling node which immediately follows the node with a value of
* CFBundleVersion. TODO: Consider reducing brittleness.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static String updateMaxMem(long numBytes)
public static void updateAppVersion(String aNewVersion)
{
// Utilize the system pList file and delegate.
return updateMaxMem(numBytes, getPlistFile());
updateAppVersion(aNewVersion, getPlistFile());
}
/**
* Utility method to update the specified max memory (-Xmx) value in the plist file (aFile) to the specified maxMemVal.
* Utility method to update the specified version in the plist file (pFile) to the new version.
* <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.
* Note this method is very brittle, and assumes that the version will occur in the sibling node which immediately follows the node with a value of
* CFBundleVersion. TODO: Consider reducing brittleness.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static String updateMaxMem(long numBytes, File pFile)
public static void updateAppVersion(String aNewVersin, File pFile)
{
Document doc;
Element docElement;
String evalStr, updateStr;
NodeList dictList, childList;
Node childNode, targNode;
Element evalE, arrE, memE;
String tagStr, valStr, currKeyVal;
int zios_Clean;
NodeList nodeList;
Node keyNode, strNode;
// 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.
// Bail if the pFile is not writable.
if (pFile.setWritable(true) == false)
return "The plist file is not writeable: " + pFile;
throw new ErrorDM("The plist file is not writeable: " + pFile);
// Load the XML document via the javax.xml.parsers.* package
try
@@ -103,14 +92,148 @@ public class AppleUtils
}
catch(Exception aExp)
{
aExp.printStackTrace();
return "Failed to parse XML document. File: " + pFile;
throw new ErrorDM(aExp, "Failed to parse XML document. File: " + pFile);
}
nodeList = docElement.getElementsByTagName("*");
for (int c1 = 0; c1 < nodeList.getLength(); c1++)
{
keyNode = nodeList.item(c1).getFirstChild();
if (keyNode != null && keyNode.getNodeValue().equals("CFBundleVersion") == true)
{
System.out.println("Updating contents of file: " + pFile);
strNode = nodeList.item(c1 + 1).getFirstChild();
System.out.println(" Old Version: " + strNode.getNodeValue());
strNode.setNodeValue(aNewVersin);
System.out.println(" New Version: " + strNode.getNodeValue());
}
}
// Update the file with the changed document
saveDoc(pFile, doc);
}
/**
* Utility method to update the JRE to point to the specified path in the system plist file.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateJreVersion(JreVersion aJreVersion)
{
// Utilize the system pList file and delegate.
updateJreVersion(aJreVersion, getPlistFile());
}
/**
* Utility method to update the JRE to point to the specified path in the plist file (pFile).
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateJreVersion(JreVersion aJreVersion, File pFile)
{
List<String> inputList;
String evalStr, tmpStr;
int currLineNum, targLineNum;
// Bail if the pFile is not writable
if (pFile.setWritable(true) == false)
throw new ErrorDM("The pFile is not writeable: " + pFile);
// Process our input
inputList = new ArrayList<>();
try (BufferedReader br = MiscUtils.openFileAsBufferedReader(pFile))
{
// Read the lines
currLineNum = 0;
targLineNum = -1;
while (true)
{
evalStr = br.readLine();
if (evalStr == null)
break;
// Record the start of the JVMRunitme section. Note the JRE should be specified on the next line
tmpStr = evalStr.trim();
if (tmpStr.equals("<key>JVMRuntime</key>") == true)
targLineNum = currLineNum + 1;
inputList.add(evalStr);
currLineNum++;
}
}
catch(IOException aExp)
{
throw new ErrorDM(aExp, "Failed while processing the pFile: " + pFile);
}
// Update the pFile
String regex = "<string>(.*?)</string>";
String repStr = "<string>jre" + aJreVersion.getLabel() + "</string>";
if (targLineNum == -1)
throw new ErrorDM("[" + pFile + "] The pFile does not specify a 'JVMRuntime' section.");
else if (targLineNum >= inputList.size())
throw new ErrorDM("[" + pFile + "] The pFile appears to be incomplete!");
else
inputList.set(targLineNum, inputList.get(targLineNum).replaceFirst(regex, repStr));
// Write the pFile
MiscUtils.writeDoc(pFile, inputList);
}
/**
* Utility method to update the specified max memory (-Xmx) value in the system plist file 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateMaxMem(long numBytes)
{
// Utilize the system pList file and delegate.
updateMaxMem(numBytes, getPlistFile());
}
/**
* Utility method to update the specified max memory (-Xmx) value in the plist file (pFile) 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateMaxMem(long numBytes, File pFile)
{
Document doc;
Element docElement;
String evalStr, updateStr;
NodeList dictList, childList;
Node childNode, targNode;
Element evalE, arrE, memE;
String tagStr, valStr, currKeyVal;
int zzz_Clean_this;
// Bail if the pFile is not writable.
if (pFile.setWritable(true) == false)
throw new ErrorDM("The plist file is not writeable: " + pFile);
// Load the XML document via the javax.xml.parsers.* package
try
{
doc = loadDoc(pFile);
docElement = doc.getDocumentElement();
}
catch(Exception aExp)
{
throw new ErrorDM(aExp, "Failed to parse XML document. File: " + pFile);
}
// Locate the <dict> element
dictList = docElement.getElementsByTagName("dict");
if (dictList.getLength() == 0)
return "No <dict> element found! File: " + pFile;
throw new ErrorDM("No <dict> element found! File: " + pFile);
arrE = null;
currKeyVal = null;
@@ -148,7 +271,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>\nFile: " + pFile;
throw new ErrorDM("Failed to locate the element <array> following the element: <key>JVMOptions</key>\nFile: " + pFile);
memE = null;
childList = arrE.getChildNodes();
@@ -192,57 +315,11 @@ 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 + "\nFile: " + pFile;
throw new ErrorDM("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: " + pFile);
return saveDoc(pFile, doc);
}
/**
* Utility method to update the specified version in the plist file (aFile) to the new version.
* <P>
* Note this method is very brittle, and assumes that the version will occur in the sibling node which immediately follows the node with a value of
* CFBundleVersion.
*/
public static String updateVersion(File aFile, String aNewVersin)
{
Document doc;
Element docElement;
NodeList nodeList;
Node keyNode, strNode;
// Load the XML document via the javax.xml.parsers.* package
try
{
doc = loadDoc(aFile);
docElement = doc.getDocumentElement();
}
catch(Exception aExp)
{
aExp.printStackTrace();
return "Failed to parse XML document. File: " + aFile;
}
nodeList = docElement.getElementsByTagName("*");
for (int c1 = 0; c1 < nodeList.getLength(); c1++)
{
keyNode = nodeList.item(c1).getFirstChild();
if (keyNode != null && keyNode.getNodeValue().equals("CFBundleVersion") == true)
{
System.out.println("Updating contents of file: " + aFile);
strNode = nodeList.item(c1 + 1).getFirstChild();
System.out.println(" Old Version: " + strNode.getNodeValue());
strNode.setNodeValue(aNewVersin);
System.out.println(" New Version: " + strNode.getNodeValue());
}
}
// Update the file with the changed document
return saveDoc(aFile, doc);
saveDoc(pFile, doc);
}
/**
@@ -264,8 +341,10 @@ public class AppleUtils
/**
* Helper method to output aDoc to the specified file.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
private static String saveDoc(File aFile, Document aDoc)
private static void saveDoc(File aFile, Document aDoc)
{
try (FileOutputStream oStream = new FileOutputStream(aFile);)
{
@@ -282,11 +361,8 @@ public class AppleUtils
}
catch(Exception aExp)
{
aExp.printStackTrace();
return "Failed to write the file: " + aFile;
throw new ErrorDM(aExp, "Failed to write the file: " + aFile);
}
return null;
}
}

View File

@@ -5,20 +5,114 @@ import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import distMaker.DistUtils;
import distMaker.MiscUtils;
import distMaker.*;
import distMaker.jre.JreVersion;
public class LinuxUtils
{
/**
* Utility method to update the JRE to reflect the specified path.
* Returns the executable script used to launch the JVM.
* <P>
* TODO: Complete this comment and method.
* If there are multiple launch scripts then this method may grab the wrong file and fail.
* <P>
* 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static boolean updateJrePath(File aPath)
public static File getScriptFile()
{
int zios_finish;
return false;
File[] fileArr;
File installPath;
File retFile;
installPath = DistUtils.getAppPath().getParentFile();
fileArr = installPath.listFiles();
// Attempt to locate the path that matches run* file
retFile = null;
for (File aFile : fileArr)
{
if (aFile.getName().startsWith("run") == true)
retFile = aFile;
}
// Bail if we failed to locate a regular file
if (retFile == null)
throw new ErrorDM("The script file could not be located.");
// Ensure the file is a regular fie
if (retFile.isFile() == false)
throw new ErrorDM("The script file is NOT a regular file.");
// Ensure the file is executable. If this is really the script file used to launch us then it should be executable!
if (Files.isExecutable(retFile.toPath()) == false)
throw new ErrorDM("The script file is NOT executable.");
return retFile;
}
/**
* Utility method to update the configuration to reflect the specified JRE version.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateJreVersion(JreVersion aJreVersion)
{
// Utilize the system scriptFile and delegate.
updateJreVersion(aJreVersion, getScriptFile());
}
/**
* Utility method to update the configuration to reflect the specified JRE version.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateJreVersion(JreVersion aJreVersion, File aScriptFile)
{
List<String> inputList;
String evalStr, tmpStr;
int currLineNum, targLineNum;
// Bail if the scritpFile is not writable
if (aScriptFile.setWritable(true) == false)
throw new ErrorDM("The script file is not writeable: " + aScriptFile);
// Process our input
inputList = new ArrayList<>();
try (BufferedReader br = MiscUtils.openFileAsBufferedReader(aScriptFile))
{
// Read the lines
currLineNum = 0;
targLineNum = -1;
while (true)
{
evalStr = br.readLine();
if (evalStr == null)
break;
// Locate where the java executable is specified
tmpStr = evalStr.trim();
if (tmpStr.startsWith("javaExe=") == true)
targLineNum = currLineNum;
inputList.add(evalStr);
currLineNum++;
}
}
catch(IOException aExp)
{
throw new ErrorDM(aExp, "Failed while processing the script file: " + aScriptFile);
}
// Update the script
if (targLineNum != -1)
inputList.set(targLineNum, "javaExe=../jre" + aJreVersion.getLabel() + "/bin/java");
else
throw new ErrorDM("[" + aScriptFile + "] The script does not specify 'javaExe'.");
// Write the scriptFile
MiscUtils.writeDoc(aScriptFile, inputList);
}
/**
@@ -29,28 +123,39 @@ public class LinuxUtils
* <P>
* 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static String updateMaxMem(long numBytes)
public static void updateMaxMem(long numBytes)
{
// Utilize the system scriptFile and delegate.
updateMaxMem(numBytes, getScriptFile());
}
/**
* Utility method to update the specified maxMem var in the script (aFile) to the requested number of bytes.
* <P>
* Note this method assumes the specified file is a shell script built by DistMaker where the var maxMem holds the proper (right side) specification for the
* JVM's -Xmx value.
* <P>
* 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateMaxMem(long numBytes, File aScriptFile)
{
List<String> inputList;
File scriptFile;
String evalStr, memStr, tmpStr;
int currLineNum, injectLineNum, targLineNum;
// 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;
// Bail if the scriptFile is not writable
if (aScriptFile.setWritable(true) == false)
throw new ErrorDM("The script file is not writeable: " + aScriptFile);
// Process our input
inputList = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(scriptFile)));)
try (BufferedReader br = MiscUtils.openFileAsBufferedReader(aScriptFile))
{
// Read the lines
currLineNum = 0;
@@ -73,10 +178,9 @@ public class LinuxUtils
currLineNum++;
}
}
catch(Exception aExp)
catch(IOException aExp)
{
aExp.printStackTrace();
return "Failed while processing the script file: " + scriptFile;
throw new ErrorDM(aExp, "Failed while processing the script file: " + aScriptFile);
}
// Determine the memStr to use
@@ -96,48 +200,8 @@ public class LinuxUtils
inputList.add(1, "maxMem=" + memStr + "\n");
}
// Update the script
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;
}
/**
* Returns the executable script used to launch the JVM. If one can not be determined then this method will return null.
* <P>
* If there are multiple launch scripts then this method may grab the wrong file and fail.
* <P>
* 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.
*/
private static File getScriptFile()
{
File[] fileArr;
File installPath;
File retFile;
installPath = DistUtils.getAppPath().getParentFile();
fileArr = installPath.listFiles();
// Attempt to locate the path that matches run* file
retFile = null;
for (File aFile : fileArr)
{
if (aFile.getName().startsWith("run") == true)
retFile = aFile;
}
if (retFile == null)
return null;
if (retFile.isFile() == false && Files.isExecutable(retFile.toPath()) == false)
return null;
System.out.println("Linux launch file: " + retFile);
return retFile;
// Write the scriptFile
MiscUtils.writeDoc(aScriptFile, inputList);
}
}

View File

@@ -1,104 +1,171 @@
package distMaker.platform;
import glum.gui.panel.generic.MessagePanel;
import java.io.File;
import distMaker.DistUtils;
import distMaker.ErrorDM;
import distMaker.jre.JreRelease;
import distMaker.jre.JreVersion;
import distMaker.node.AppRelease;
public class PlatformUtils
{
/**
* Utility method that returns the platform specific configuration file for the java application.
*/
public static File getConfigurationFile()
{
File cfgFile;
String platform;
platform = PlatformUtils.getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
cfgFile = AppleUtils.getPlistFile();
else if (platform.equals("LINUX") == true)
cfgFile = LinuxUtils.getScriptFile();
else if (platform.equals("WINDOWS") == true)
cfgFile = WindowsUtils.getConfigFile();
else
throw new ErrorDM("Unsupported platform: " + platform);
return cfgFile;
}
/**
* Utility method that returns the path where the specified JRE should be unpacked to.
*/
public static File getJreLocation(JreRelease aJreRelease)
{
// Delegate to actual worker method
return getJreLocation(aJreRelease.getVersion());
}
/**
* Utility method that returns the path where the specified JRE should be unpacked to.
*/
public static File getJreLocation(JreVersion aJreVersion)
{
String platform, versionStr;
File jrePath, installPath;
jrePath = null;
installPath = DistUtils.getAppPath();
versionStr = aJreRelease.getVersion().getLabel();
versionStr = aJreVersion.getLabel();
platform = DistUtils.getPlatform().toUpperCase();
platform = PlatformUtils.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)
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.
* Returns the platform (Apple, Linux, or Windows) on which the current JRE is running on.
*/
public static boolean setJreLocation(File aPath)
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 platform of the JRE file.
* <P>
* This only examines the filename to determine the platform.
*/
public static String getPlatformOfJreTarGz(String aFileName)
{
aFileName = aFileName.toUpperCase();
if (aFileName.contains("LINUX") == true)
return "Linux";
if (aFileName.contains("MACOSX") == true)
return "Apple";
if (aFileName.contains("WINDOWS") == true)
return "Windows";
return null;
}
/**
* Utility method to configure the JRE version used by the (active) DistMaker distribution.
* <P>
* Note this will only take effect after the application has been restarted.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*
* @param aJrePath
* Path to top of the JRE.
*/
public static void setJreVersion(JreVersion aJreVersion)
{
String platform;
boolean isPass;
isPass = false;
platform = DistUtils.getPlatform().toUpperCase();
// Delegate to the proper platform code
platform = PlatformUtils.getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
isPass = AppleUtils.updateJrePath(aPath);
AppleUtils.updateJreVersion(aJreVersion);
else if (platform.equals("LINUX") == true)
isPass = LinuxUtils.updateJrePath(aPath);
else if (platform.equals("Windows") == true)
isPass = WindowsUtils.updateJrePath(aPath);
return isPass;
LinuxUtils.updateJreVersion(aJreVersion);
else if (platform.equals("WINDOWS") == true)
WindowsUtils.updateJreVersion(aJreVersion);
else
throw new ErrorDM("Unrecognized platform: " + platform);
}
/**
* Utility method to configure the (active) DistMaker distribution to use the specified maxMem.
* <P>
* Method will return false on failure.
* Note this will only take effect after the application has been restarted.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*
* @param warnPanel
* GUI message panel to route error messages.
* @param maxMemSize
* Maximum heap memory in bytes.
*/
public static boolean setMaxHeapMem(MessagePanel warnPanel, long maxMemSize)
public static void setMaxHeapMem(long maxMemSize)
{
String platform;
String errMsg;
// Delegate to the proper platform code
errMsg = null;
platform = DistUtils.getPlatform().toUpperCase();
platform = PlatformUtils.getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
errMsg = AppleUtils.updateMaxMem(maxMemSize);
AppleUtils.updateMaxMem(maxMemSize);
else if (platform.equals("LINUX") == true)
errMsg = LinuxUtils.updateMaxMem(maxMemSize);
else if (platform.equals("Windows") == true)
errMsg = WindowsUtils.updateMaxMem(maxMemSize);
LinuxUtils.updateMaxMem(maxMemSize);
else if (platform.equals("WINDOWS") == true)
WindowsUtils.updateMaxMem(maxMemSize);
else
errMsg = "Unrecognized platform: " + platform;
throw new ErrorDM(null, "Unrecognized platform: " + platform, "Unsupported 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.");
/**
* Utility method to update the (active) DistMaker distribution to reflect the specified AppRelease.
* <P>
* Note this will only take effect after the application has been restarted.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateAppRelease(AppRelease aRelease)
{
String platform;
warnPanel.setInfo(errMsg);
warnPanel.setVisible(true);
return false;
}
return true;
// Delegate to the proper platform code
platform = getPlatform().toUpperCase();
if (platform.equals("APPLE") == true)
AppleUtils.updateAppVersion(aRelease.getVersion());
}
}

View File

@@ -4,20 +4,87 @@ import java.io.*;
import java.util.ArrayList;
import java.util.List;
import distMaker.DistUtils;
import distMaker.MiscUtils;
import distMaker.*;
import distMaker.jre.JreVersion;
public class WindowsUtils
{
/**
* Utility method to update the JRE to reflect the specified path.
* Returns the l4j runtime configuration file. If one can not be determined then this method will return null.
* <P>
* TODO: Complete this comment and method.
* If the configuration file is determined but does not exist, then an empty configuration file will be created.
* <P>
* Note this method looks for a file that ends in .l4j.cfg, or an exe file and creates the corresponding config file.
* <P>
* If there are multiple .exe or .l4j.cfg files, then this method may grab the wrong file and fail.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static boolean updateJrePath(File aPath)
public static File getConfigFile()
{
int zios_finish;
return false;
File[] fileArr;
File installPath;
File retFile;
installPath = DistUtils.getAppPath().getParentFile();
fileArr = installPath.listFiles();
// Attempt to locate the <appExe>.l4j.ini file
retFile = null;
for (File aFile : fileArr)
{
if (aFile.getName().endsWith(".l4j.ini") == true)
retFile = aFile;
}
if (retFile == null)
{
for (File aFile : fileArr)
{
if (aFile.getName().endsWith(".exe") == true)
retFile = new File(aFile.getParentFile(), aFile.getName().substring(0, aFile.getName().length() - 4) + ".l4j.ini");
}
}
if (retFile == null)
throw new ErrorDM("The config file could not be located.");
if (retFile.isFile() == false)
{
try
{
retFile.createNewFile();
}
catch(IOException aExp)
{
throw new ErrorDM(aExp, "A default config file could not be created.");
}
}
System.out.println("Windows config file: " + retFile);
return retFile;
}
/**
* Utility method to update the configuration to reflect the specified JRE version.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateJreVersion(JreVersion aJreVersion)
{
// Utilize the system configFile and delegate.
updateJreVersion(aJreVersion, getConfigFile());
}
/**
* Utility method to update the configuration to reflect the specified JRE version.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateJreVersion(JreVersion aJreVersion, File aConfigFile)
{
int zzz_incomplete_logic;
throw new ErrorDM("The logic is incomplete.");
}
/**
@@ -25,24 +92,39 @@ public class WindowsUtils
* <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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static String updateMaxMem(long numBytes)
public static void updateMaxMem(long numBytes)
{
// Utilize the system configFile and delegate.
updateMaxMem(numBytes, getConfigFile());
}
/**
* 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.
* <P>
* On failure this method will throw an exception of type ErrorDM.
*/
public static void updateMaxMem(long numBytes, File aConfigFile)
{
File configFile;
List<String> inputList;
String strLine, updateStr;
boolean isProcessed;
// Bail if we fail to locate the configFile.
configFile = getConfigFile();
if (configFile != null && configFile.isFile() == true)
return "The config file could not be located.";
// Bail if the configFile is not writable
aConfigFile = getConfigFile();
if (aConfigFile.setWritable(true) == false)
throw new ErrorDM("The config file is not writeable: " + aConfigFile);
isProcessed = false;
inputList = new ArrayList<>();
// Process our input
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(configFile))))
try (BufferedReader br = MiscUtils.openFileAsBufferedReader(aConfigFile))
{
// Read the lines
while (true)
@@ -72,72 +154,11 @@ public class WindowsUtils
}
catch(Exception aExp)
{
aExp.printStackTrace();
return "Failed while processing the config file: " + configFile;
throw new ErrorDM(aExp, "Failed while processing the config file: " + aConfigFile);
}
// Update the script
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;
}
/**
* Returns the l4j runtime configuration file. If one can not be determined then this method will return null.
* <P>
* If the configuration file is determined but does not exist, then an empty configuration file will be created.
* <P>
* Note this method looks for a file that ends in .l4j.cfg, or an exe file and creates the corresponding config file.
* <P>
* If there are multiple .exe or .l4j.cfg files, then this method may grab the wrong file and fail.
*/
public static File getConfigFile()
{
File[] fileArr;
File installPath;
File retFile;
installPath = DistUtils.getAppPath().getParentFile();
fileArr = installPath.listFiles();
// Attempt to locate the <appExe>.l4j.ini file
retFile = null;
for (File aFile : fileArr)
{
if (aFile.getName().endsWith(".l4j.ini") == true)
retFile = aFile;
}
if (retFile == null)
{
for (File aFile : fileArr)
{
if (aFile.getName().endsWith(".exe") == true)
retFile = new File(aFile.getParentFile(), aFile.getName().substring(0, aFile.getName().length() - 4) + ".l4j.ini");
}
}
if (retFile == null)
return null;
if (retFile.isFile() == false)
{
try
{
retFile.createNewFile();
}
catch(IOException aExp)
{
aExp.printStackTrace();
return null;
}
}
System.out.println("Windows config file: " + retFile);
return retFile;
MiscUtils.writeDoc(aConfigFile, inputList);
}
}

Binary file not shown.