mirror of
https://github.com/JHUAPL/DistMaker.git
synced 2026-01-09 14:37:54 -05:00
Initial release
This commit is contained in:
BIN
lib/miglayout-3.7.2-sources.jar
Normal file
BIN
lib/miglayout-3.7.2-sources.jar
Normal file
Binary file not shown.
BIN
lib/miglayout-3.7.2-swing.jar
Normal file
BIN
lib/miglayout-3.7.2-swing.jar
Normal file
Binary file not shown.
BIN
lib/miglayout-3.7.2.jar
Normal file
BIN
lib/miglayout-3.7.2.jar
Normal file
Binary file not shown.
267
src/distMaker/DistMakerEngine.java
Normal file
267
src/distMaker/DistMakerEngine.java
Normal file
@@ -0,0 +1,267 @@
|
||||
package distMaker;
|
||||
|
||||
import glum.gui.panel.task.FullTaskPanel;
|
||||
import glum.io.IoUtil;
|
||||
import glum.net.Credential;
|
||||
import glum.reflect.FunctionRunnable;
|
||||
import glum.task.Task;
|
||||
import glum.unit.DateUnit;
|
||||
import glum.util.ThreadUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import distMaker.gui.PickReleasePanel;
|
||||
|
||||
public class DistMakerEngine
|
||||
{
|
||||
// State vars
|
||||
private URL updateUrl;
|
||||
private Release currRelease;
|
||||
private Credential refCredential;
|
||||
|
||||
// Gui vars
|
||||
private JFrame parentFrame;
|
||||
private PickReleasePanel pickVersionPanel;
|
||||
|
||||
public DistMakerEngine(JFrame aParentFrame, URL aUpdateUrl)
|
||||
{
|
||||
updateUrl = aUpdateUrl;
|
||||
refCredential = null;
|
||||
parentFrame = aParentFrame;
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that will notify the user that updates are being checked for
|
||||
*/
|
||||
public void checkForUpdates()
|
||||
{
|
||||
FullTaskPanel taskPanel;
|
||||
String appName;
|
||||
|
||||
appName = currRelease.getName();
|
||||
|
||||
// Setup our TaskPanel
|
||||
taskPanel = new FullTaskPanel(parentFrame, true, false);
|
||||
taskPanel.setTitle(appName + ": Checking for updates...");
|
||||
taskPanel.setSize(640, taskPanel.getPreferredSize().height);
|
||||
taskPanel.setVisible(true);
|
||||
|
||||
// Launch the actual checking of updates in a separate worker thread
|
||||
ThreadUtil.launchRunnable(new FunctionRunnable(this, "checkForUpdatesWorker", taskPanel), "thread-checkForUpdates");
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that the corresponding application has been fully initialized.
|
||||
*/
|
||||
public void markSystemFullyStarted()
|
||||
{
|
||||
// TODO: Flush this 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)
|
||||
{
|
||||
refCredential = null;
|
||||
if (aUsername == null || aPassword == null)
|
||||
return;
|
||||
|
||||
refCredential = new Credential(aUsername, aPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to fully set up this object
|
||||
*/
|
||||
private void initialize()
|
||||
{
|
||||
File appPath, cfgFile;
|
||||
BufferedReader br;
|
||||
DateUnit dateUnit;
|
||||
String currInstr, strLine;
|
||||
String appName, verName, deployStr;
|
||||
long deployTime;
|
||||
|
||||
currRelease = null;
|
||||
appName = null;
|
||||
verName = null;
|
||||
deployStr = null;
|
||||
|
||||
// Locate the official DistMaker configuration file associated with this release
|
||||
appPath = DistUtils.getAppPath();
|
||||
cfgFile = new File(appPath, "app.cfg");
|
||||
|
||||
// Bail if there is no configuration file
|
||||
if (cfgFile.isFile() == false)
|
||||
return;
|
||||
|
||||
// Read in the configuration file
|
||||
br = null;
|
||||
try
|
||||
{
|
||||
br = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile)));
|
||||
|
||||
// Read the lines
|
||||
currInstr = "None";
|
||||
while (true)
|
||||
{
|
||||
strLine = br.readLine();
|
||||
|
||||
// Bail once we get to the end of the file
|
||||
if (strLine == null)
|
||||
break;
|
||||
|
||||
// Update the current instruction, if one specified
|
||||
if (strLine.startsWith("-") == true)
|
||||
currInstr = strLine;
|
||||
// Skip empty lines / comments
|
||||
else if (strLine.isEmpty() == true || strLine.startsWith("#") == true)
|
||||
; // Nothing to do
|
||||
// Process the name instruction
|
||||
else if (currInstr.equals("-name") == true)
|
||||
appName = strLine;
|
||||
else if (currInstr.equals("-version") == true)
|
||||
verName = strLine;
|
||||
else if (currInstr.equals("-deployDate") == true)
|
||||
deployStr = strLine;
|
||||
}
|
||||
|
||||
}
|
||||
catch (IOException aExp)
|
||||
{
|
||||
aExp.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IoUtil.forceClose(br);
|
||||
}
|
||||
|
||||
if (appName == null || verName == null || deployStr == null)
|
||||
{
|
||||
System.out.println("Failed to properly parse DistMaker config file: " + cfgFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Form the installed Release
|
||||
dateUnit = new DateUnit("", "yyyyMMMdd HH:mm:ss");
|
||||
deployTime = dateUnit.parseString(deployStr, 0);
|
||||
currRelease = new Release(appName, verName, deployTime);
|
||||
|
||||
// Form the PickReleasePanel
|
||||
pickVersionPanel = new PickReleasePanel(parentFrame, currRelease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that does the heavy lifting of the checking for updates.
|
||||
* <P>
|
||||
* This method will be called via reflection.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void checkForUpdatesWorker(Task aTask)
|
||||
{
|
||||
List<Release> fullList;
|
||||
Release chosenItem;
|
||||
File destPath;
|
||||
String appName;
|
||||
boolean isPass;
|
||||
|
||||
// Determine the destination where to drop the release
|
||||
destPath = new File(DistUtils.getAppPath().getParentFile(), "delta");
|
||||
|
||||
// Status info
|
||||
appName = currRelease.getName();
|
||||
aTask.infoAppendln("Application: " + appName + " - " + currRelease.getVersion() + '\n');
|
||||
|
||||
// Retrieve the list of available releases
|
||||
aTask.infoAppendln("Checking for updates...\n");
|
||||
fullList = DistUtils.getAvailableReleases(aTask, updateUrl, appName, refCredential);
|
||||
if (fullList == null)
|
||||
return;
|
||||
|
||||
// Prompt the user for the Release
|
||||
aTask.infoAppendln("Please select the release to install...");
|
||||
pickVersionPanel.setConfiguration(fullList);
|
||||
pickVersionPanel.setVisibleAsModal();
|
||||
chosenItem = pickVersionPanel.getChosenItem();
|
||||
if (chosenItem == null)
|
||||
{
|
||||
aTask.infoAppendln("No release specified. Update has been aborted.");
|
||||
aTask.abort();
|
||||
return;
|
||||
}
|
||||
|
||||
// Log the user chosen action
|
||||
aTask.infoAppendln("\tRelease chosen: " + chosenItem.getVersion());
|
||||
if (currRelease.getDeployTime() < chosenItem.getDeployTime())
|
||||
aTask.infoAppendln("\t" + appName + " will be updated...");
|
||||
else
|
||||
aTask.infoAppendln("\t" + appName + " will be reverted...");
|
||||
|
||||
// Download the release
|
||||
isPass = downloadRelease(aTask, chosenItem, destPath);
|
||||
if (isPass == false || aTask.isActive() == false)
|
||||
{
|
||||
IoUtil.deleteDirectory(destPath);
|
||||
aTask.infoAppendln("Application update aborted.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify the user of success
|
||||
aTask.infoAppendln(appName + " has been updated to version: " + chosenItem.getDeployTime() + ".");
|
||||
aTask.infoAppendln("These updates will become active when " + appName + " is restarted.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to download the specified release.
|
||||
* <P>
|
||||
* Returns true if the release was downloaded properly.
|
||||
*/
|
||||
private boolean downloadRelease(Task aTask, Release aRelease, File destPath)
|
||||
{
|
||||
List<File> fileList;
|
||||
String baseUrlStr, srcUrlStr;
|
||||
URL srcUrl;
|
||||
int clipLen;
|
||||
boolean isPass;
|
||||
|
||||
// Retrieve the list of files to download
|
||||
fileList = DistUtils.getFileListForRelease(aTask, updateUrl, aRelease, destPath, refCredential);
|
||||
|
||||
// Compute some baseline vars
|
||||
baseUrlStr = updateUrl.toString() + "/" + aRelease.getVersion() + "/";
|
||||
clipLen = destPath.getAbsolutePath().length();
|
||||
|
||||
// Download the individual files
|
||||
for (File aFile : fileList)
|
||||
{
|
||||
// Bail if we have been aborted
|
||||
if (aTask.isActive() == false)
|
||||
return false;
|
||||
|
||||
srcUrlStr = baseUrlStr + aFile.getAbsolutePath().substring(clipLen);
|
||||
srcUrl = IoUtil.createURL(srcUrlStr);
|
||||
|
||||
aTask.infoAppendln(srcUrlStr + " -> " + aFile);
|
||||
aFile.getParentFile().mkdirs();
|
||||
isPass = IoUtil.copyUrlToFile(srcUrl, aFile);// , Username, Password);
|
||||
if (isPass == false)
|
||||
{
|
||||
aFile.delete();
|
||||
aTask.infoAppendln("Failed to download resource: " + srcUrl);
|
||||
aTask.infoAppendln("\tSource: " + srcUrlStr);
|
||||
aTask.infoAppendln("\tDest: " + aFile);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
261
src/distMaker/DistUtils.java
Normal file
261
src/distMaker/DistUtils.java
Normal file
@@ -0,0 +1,261 @@
|
||||
package distMaker;
|
||||
|
||||
import glum.gui.GuiUtil;
|
||||
import glum.io.IoUtil;
|
||||
import glum.net.*;
|
||||
import glum.reflect.ReflectUtil;
|
||||
import glum.task.Task;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class DistUtils
|
||||
{
|
||||
/**
|
||||
* Utility method to determine the path where the application is installed.
|
||||
* <P>
|
||||
* If this application is not a formal DistMaker application, then the parent folder corresponding to the folder
|
||||
* which contains this jar will be returned.
|
||||
*/
|
||||
public static File getAppPath()
|
||||
{
|
||||
File jarPath, currPath, testPath;
|
||||
|
||||
jarPath = ReflectUtil.getInstalledRootDir(DistUtils.class);
|
||||
|
||||
currPath = jarPath;
|
||||
while (currPath != null)
|
||||
{
|
||||
currPath = currPath.getParentFile();
|
||||
testPath = new File(currPath, "app.cfg");
|
||||
if (testPath.isFile() == true)
|
||||
return testPath;
|
||||
}
|
||||
|
||||
// Return default location
|
||||
return jarPath.getParentFile().getParentFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of available releases.
|
||||
*/
|
||||
public static List<Release> getAvailableReleases(Task aTask, URL aUpdateUrl, String appName, Credential aCredential)
|
||||
{
|
||||
List<Release> fullList;
|
||||
URL catUrl;
|
||||
URLConnection connection;
|
||||
InputStream inStream;
|
||||
BufferedReader bufReader;
|
||||
String errMsg;
|
||||
|
||||
errMsg = null;
|
||||
fullList = Lists.newArrayList();
|
||||
catUrl = IoUtil.createURL(aUpdateUrl.toString() + "/" + appName + "/" + "releaseInfo.txt");
|
||||
|
||||
connection = null;
|
||||
inStream = null;
|
||||
bufReader = null;
|
||||
try
|
||||
{
|
||||
String[] tokens;
|
||||
String strLine, verName;
|
||||
long deployTime;
|
||||
|
||||
// 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(",");
|
||||
if (strLine.isEmpty() == true || strLine.startsWith("#") == true)
|
||||
; // Nothing to do
|
||||
else if (tokens.length == 2 && tokens[0].equals("name") == true)
|
||||
; // Nothing to do
|
||||
else if (tokens.length != 2)
|
||||
aTask.infoAppendln("Unreconized line: " + strLine);
|
||||
else
|
||||
// if (tokens.length == 2)
|
||||
{
|
||||
verName = tokens[0];
|
||||
deployTime = GuiUtil.readLong(tokens[1], 0);
|
||||
fullList.add(new Release(appName, verName, deployTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException aExp)
|
||||
{
|
||||
Result aResult;
|
||||
|
||||
aExp.printStackTrace();
|
||||
errMsg = "The update site, " + aUpdateUrl + ", is not available.\n\t";
|
||||
|
||||
aResult = NetUtil.getResult(aExp, connection);
|
||||
switch (aResult)
|
||||
{
|
||||
case BadCredentials:
|
||||
errMsg += "The update site is password protected and bad credentials were provided.";
|
||||
break;
|
||||
|
||||
case ConnectFailure:
|
||||
case UnreachableHost:
|
||||
case UnsupportedConnection:
|
||||
errMsg += "The update site appears to be unreachable.";
|
||||
break;
|
||||
|
||||
case Interrupted:
|
||||
errMsg += "The retrival of the catalog file has been interrupted.";
|
||||
break;
|
||||
|
||||
case InvalidResource:
|
||||
errMsg += "The remote catalog file, releaseInfo.txt, does not appear to be valid.";
|
||||
break;
|
||||
|
||||
default:
|
||||
errMsg += "An undefined error occurred while retrieving the remote catalog file.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 occured
|
||||
else if (fullList.size() == 0)
|
||||
errMsg = "The update URL appears to be invalid.";
|
||||
else if (fullList.size() == 1)
|
||||
errMsg = "There are no updates of " + appName + ". Only one release has been made.";
|
||||
|
||||
// Bail if there were issues
|
||||
if (errMsg != null)
|
||||
{
|
||||
aTask.infoAppendln(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
return fullList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of files (relative to destPath) that are needed for the specified release.
|
||||
*/
|
||||
public static List<File> getFileListForRelease(Task aTask, URL aUpdateUrl, Release aRelease, File destPath, Credential aCredential)
|
||||
{
|
||||
List<File> fullList;
|
||||
URL md5sumUrl;
|
||||
URLConnection connection;
|
||||
InputStream inStream;
|
||||
BufferedReader bufReader;
|
||||
String errMsg;
|
||||
|
||||
errMsg = null;
|
||||
fullList = Lists.newArrayList();
|
||||
md5sumUrl = IoUtil.createURL(aUpdateUrl.toString() + "/" + aRelease.getName() + "/" + aRelease.getVersion() + "/delta/md5sum.txt");
|
||||
|
||||
connection = null;
|
||||
inStream = null;
|
||||
bufReader = null;
|
||||
try
|
||||
{
|
||||
String[] tokens;
|
||||
String strLine, filename;
|
||||
|
||||
// Read the contents of the file
|
||||
connection = md5sumUrl.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(",");
|
||||
if (strLine.isEmpty() == true || strLine.startsWith("#") == true)
|
||||
; // Nothing to do
|
||||
else if (tokens.length != 2)
|
||||
aTask.infoAppendln("Unreconized line: " + strLine);
|
||||
else
|
||||
// if (tokens.length == 2)
|
||||
{
|
||||
filename = tokens[1];
|
||||
fullList.add(new File(destPath, filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException aExp)
|
||||
{
|
||||
Result aResult;
|
||||
|
||||
aExp.printStackTrace();
|
||||
errMsg = "The update site, " + aUpdateUrl + ", is not available.\n\t";
|
||||
|
||||
aResult = NetUtil.getResult(aExp, connection);
|
||||
switch (aResult)
|
||||
{
|
||||
case BadCredentials:
|
||||
errMsg += "The update site is password protected and bad credentials were provided.";
|
||||
break;
|
||||
|
||||
case ConnectFailure:
|
||||
case UnreachableHost:
|
||||
case UnsupportedConnection:
|
||||
errMsg += "The update site appears to be unreachable.";
|
||||
break;
|
||||
|
||||
case Interrupted:
|
||||
errMsg += "The retrival of the md5sum file has been interrupted.";
|
||||
break;
|
||||
|
||||
case InvalidResource:
|
||||
errMsg += "The remote md5sum file, md5sumInfo.txt, does not appear to be valid.";
|
||||
break;
|
||||
|
||||
default:
|
||||
errMsg += "An undefined error occurred while retrieving the remote md5sum file.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 occured
|
||||
else if (fullList.size() == 0)
|
||||
errMsg = "The md5sum URL appears to be invalid.";
|
||||
|
||||
// Bail if there were issues
|
||||
if (errMsg != null)
|
||||
{
|
||||
aTask.infoAppendln(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
return fullList;
|
||||
}
|
||||
|
||||
}
|
||||
7
src/distMaker/LookUp.java
Normal file
7
src/distMaker/LookUp.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package distMaker;
|
||||
|
||||
public enum LookUp
|
||||
{
|
||||
VersionName,
|
||||
DeployTime,
|
||||
}
|
||||
76
src/distMaker/Release.java
Normal file
76
src/distMaker/Release.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package distMaker;
|
||||
|
||||
import glum.database.QueryItem;
|
||||
|
||||
|
||||
public class Release implements Comparable<Release>, QueryItem<LookUp>
|
||||
{
|
||||
private String appName;
|
||||
private String verName;
|
||||
private long deployTime;
|
||||
|
||||
public Release(String aAppName, String aVerName, long aDeployTime)
|
||||
{
|
||||
appName = aAppName;
|
||||
verName = aVerName;
|
||||
deployTime = aDeployTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formal name of the application
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version name corresponding to this distribution
|
||||
*/
|
||||
public String getVersion()
|
||||
{
|
||||
return verName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which this version was deployed (made available to the public/customer)
|
||||
*/
|
||||
public long getDeployTime()
|
||||
{
|
||||
return deployTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Release o)
|
||||
{
|
||||
if (deployTime < o.deployTime)
|
||||
return -1;
|
||||
else if (deployTime > o.deployTime)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(LookUp aEnum)
|
||||
{
|
||||
switch (aEnum)
|
||||
{
|
||||
case DeployTime:
|
||||
return deployTime;
|
||||
|
||||
case VersionName:
|
||||
return verName;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(LookUp aEnum, Object aObj)
|
||||
{
|
||||
throw new RuntimeException("Unsupported operation");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user