The illustrious beginnings of Getdown.
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
<!-- build configuration -->
|
||||||
|
<project name="getdown" default="compile" basedir=".">
|
||||||
|
|
||||||
|
<!-- various basic settings -->
|
||||||
|
<property name="app.name" value="getdown"/>
|
||||||
|
<property name="src.dir" value="src/java"/>
|
||||||
|
<property name="deploy.dir" value="dist"/>
|
||||||
|
<property name="dist.jar" value="${app.name}.jar"/>
|
||||||
|
|
||||||
|
<!-- we want to access the environment -->
|
||||||
|
<property environment="env"/>
|
||||||
|
<property name="java.libraries" value="${env.JAVA_LIBS}"/>
|
||||||
|
|
||||||
|
<!-- used when generating javadocs -->
|
||||||
|
<property name="javadoc.dir" value="${deploy.dir}/docs"/>
|
||||||
|
<property name="doc.packages" value="com.threerings.getdown.*"/>
|
||||||
|
<property name="doc.overview" value="com/threerings/getdown/overview.html"/>
|
||||||
|
<property name="copy.pre" value="Copyright © 2004"/>
|
||||||
|
<property name="copyright.holder" value="Three Rings Design, Inc."/>
|
||||||
|
<property name="copy.post" value="All Rights Reserved."/>
|
||||||
|
|
||||||
|
<!-- declare our classpath -->
|
||||||
|
<path id="clazzpath">
|
||||||
|
<fileset dir="${java.libraries}" includesfile="lib/LIBS"/>
|
||||||
|
<fileset dir="lib" includes="**/*.jar"/>
|
||||||
|
<pathelement location="${deploy.dir}/classes"/>
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!-- prepares the application directories -->
|
||||||
|
<target name="prepare">
|
||||||
|
<mkdir dir="${deploy.dir}"/>
|
||||||
|
<mkdir dir="${deploy.dir}/classes"/>
|
||||||
|
<mkdir dir="${javadoc.dir}"/>
|
||||||
|
<!-- copy media and properties into the target directory -->
|
||||||
|
<copy todir="${deploy.dir}/classes">
|
||||||
|
<fileset dir="${src.dir}" includes="**/*.jpg"/>
|
||||||
|
<fileset dir="${src.dir}" includes="**/*.png"/>
|
||||||
|
<fileset dir="${src.dir}" includes="**/*.properties"/>
|
||||||
|
</copy>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- cleans out the built application -->
|
||||||
|
<target name="clean">
|
||||||
|
<delete dir="${deploy.dir}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- build the java class files -->
|
||||||
|
<target name="compile" depends="prepare">
|
||||||
|
<javac srcdir="${src.dir}" destdir="${deploy.dir}/classes"
|
||||||
|
debug="on" optimize="off" deprecation="on"
|
||||||
|
classpathref="clazzpath" includeAntRuntime="no"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- build the javadoc documentation -->
|
||||||
|
<target name="javadoc" depends="prepare">
|
||||||
|
<javadoc sourcepath="${src.dir}"
|
||||||
|
packagenames="${doc.packages}"
|
||||||
|
windowtitle="${app.name} API"
|
||||||
|
doctitle="${app.name} API"
|
||||||
|
overview="${src.dir}/${doc.overview}"
|
||||||
|
bottom="${copy.pre} ${copyright.holder} ${copy.post}"
|
||||||
|
destdir="${javadoc.dir}">
|
||||||
|
<classpath refid="clazzpath"/>
|
||||||
|
<link href="http://www.samskivert.com/code/samskivert/javadoc"/>
|
||||||
|
<link href="http://java.sun.com/products/jdk/1.4/docs/api"/>
|
||||||
|
</javadoc>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- a target for rebuilding everything -->
|
||||||
|
<target name="all" depends="clean,prepare,compile,javadoc,dist"/>
|
||||||
|
|
||||||
|
<!-- builds our distribution files -->
|
||||||
|
<target name="dist" depends="prepare,compile">
|
||||||
|
<jar destfile="${deploy.dir}/${dist.jar}" manifest="lib/manifest.mf"
|
||||||
|
basedir="${deploy.dir}/classes"/>
|
||||||
|
</target>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Main-Class: com.threerings.getdown.launcher.Getdown
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// $Id: Log.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder class that contains a reference to the log object used by
|
||||||
|
* the Getdown code.
|
||||||
|
*/
|
||||||
|
public class Log
|
||||||
|
{
|
||||||
|
public static com.samskivert.util.Log log =
|
||||||
|
new com.samskivert.util.Log("getdown");
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void debug (String message)
|
||||||
|
{
|
||||||
|
log.debug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void info (String message)
|
||||||
|
{
|
||||||
|
log.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void warning (String message)
|
||||||
|
{
|
||||||
|
log.warning(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void logStackTrace (Throwable t)
|
||||||
|
{
|
||||||
|
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
//
|
||||||
|
// $Id: Application.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown.data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.samskivert.io.NestableIOException;
|
||||||
|
import com.samskivert.text.MessageUtil;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import com.threerings.getdown.Log;
|
||||||
|
import com.threerings.getdown.util.ConfigUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and provide access to the information contained in the
|
||||||
|
* <code>getdown.txt</code> configuration file.
|
||||||
|
*/
|
||||||
|
public class Application
|
||||||
|
{
|
||||||
|
/** The name of our configuration file. */
|
||||||
|
public static final String CONFIG_FILE = "getdown.txt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an application instance which records the location of the
|
||||||
|
* <code>getdown.txt</code> configuration file from the supplied
|
||||||
|
* application directory.
|
||||||
|
*/
|
||||||
|
public Application (File appdir)
|
||||||
|
{
|
||||||
|
_appdir = appdir;
|
||||||
|
_config = new File(appdir, CONFIG_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a resource that refers to the application configuration
|
||||||
|
* file itself.
|
||||||
|
*/
|
||||||
|
public Resource getConfigResource ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return new Resource(_appbase, _appdir, CONFIG_FILE);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Booched appbase '" + _appbase + "'!?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of the code {@link Resource} objects used by this
|
||||||
|
* application.
|
||||||
|
*/
|
||||||
|
public List getCodeResources ()
|
||||||
|
{
|
||||||
|
return _codes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of the non-code {@link Resource} objects used by
|
||||||
|
* this application.
|
||||||
|
*/
|
||||||
|
public List getResources ()
|
||||||
|
{
|
||||||
|
return _resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the application to parse its <code>getdown.txt</code>
|
||||||
|
* configuration and prepare itself for operation. The application
|
||||||
|
* base URL will be parsed first so that if there are errors
|
||||||
|
* discovered later, the caller can use the application base to
|
||||||
|
* download a new <code>config.txt</code> file and try again.
|
||||||
|
*
|
||||||
|
* @exception IOException thrown if there is an error reading the file
|
||||||
|
* or an error encountered during its parsing.
|
||||||
|
*/
|
||||||
|
public void init ()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// parse our configuration file
|
||||||
|
HashMap cdata = ConfigUtil.parseConfig(_config);
|
||||||
|
|
||||||
|
// first determine our application base, this way if anything goes
|
||||||
|
// wrong later in the process, our caller can use the appbase to
|
||||||
|
// download a new configuration file
|
||||||
|
String appbase = (String)cdata.get("appbase");
|
||||||
|
if (appbase == null) {
|
||||||
|
throw new IOException("m.missing_appbase");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// make sure there's a trailing slash
|
||||||
|
if (!appbase.endsWith("/")) {
|
||||||
|
appbase = appbase + "/";
|
||||||
|
}
|
||||||
|
_appbase = new URL(appbase);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = MessageUtil.tcompose("m.invalid_appbase", appbase);
|
||||||
|
throw new NestableIOException(err, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract our version information
|
||||||
|
String vstr = (String)cdata.get("version");
|
||||||
|
if (vstr != null) {
|
||||||
|
try {
|
||||||
|
_version = Integer.parseInt(vstr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = MessageUtil.tcompose("m.invalid_version", vstr);
|
||||||
|
throw new NestableIOException(err, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine our application class name
|
||||||
|
_class = (String)cdata.get("class");
|
||||||
|
if (_class == null) {
|
||||||
|
throw new IOException("m.missing_class");
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse our code resources
|
||||||
|
String[] codes = ConfigUtil.getMultiValue(cdata, "code");
|
||||||
|
if (codes == null) {
|
||||||
|
throw new IOException("m.missing_code");
|
||||||
|
}
|
||||||
|
for (int ii = 0; ii < codes.length; ii++) {
|
||||||
|
try {
|
||||||
|
_codes.add(new Resource(_appbase, _appdir, codes[ii]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warning("Invalid code resource '" + codes[ii] + "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse our non-code resources
|
||||||
|
String[] rsrcs = ConfigUtil.getMultiValue(cdata, "resource");
|
||||||
|
if (rsrcs != null) {
|
||||||
|
for (int ii = 0; ii < rsrcs.length; ii++) {
|
||||||
|
try {
|
||||||
|
_resources.add(new Resource(_appbase, _appdir, rsrcs[ii]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warning("Invalid resource '" + rsrcs[ii] + "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transfer our JVM arguments
|
||||||
|
String[] jvmargs = ConfigUtil.getMultiValue(cdata, "jvmarg");
|
||||||
|
if (jvmargs != null) {
|
||||||
|
for (int ii = 0; ii < jvmargs.length; ii++) {
|
||||||
|
_jvmargs.add(jvmargs[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transfer our application arguments
|
||||||
|
String[] appargs = ConfigUtil.getMultiValue(cdata, "apparg");
|
||||||
|
if (appargs != null) {
|
||||||
|
for (int ii = 0; ii < appargs.length; ii++) {
|
||||||
|
_appargs.add(appargs[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log.info("Parsed application " + _appbase);
|
||||||
|
// Log.info("Version: " + _version);
|
||||||
|
// Log.info("Class: " + _class);
|
||||||
|
// Log.info("Code: " + StringUtil.toString(_codes.iterator()));
|
||||||
|
// Log.info("Resources: " + StringUtil.toString(_resources.iterator()));
|
||||||
|
// Log.info("JVM Args: " + StringUtil.toString(_jvmargs.iterator()));
|
||||||
|
// Log.info("App Args: " + StringUtil.toString(_appargs.iterator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected File _appdir;
|
||||||
|
protected File _config;
|
||||||
|
|
||||||
|
protected int _version = -1;
|
||||||
|
protected URL _appbase;
|
||||||
|
protected String _class;
|
||||||
|
|
||||||
|
protected ArrayList _codes = new ArrayList();
|
||||||
|
protected ArrayList _resources = new ArrayList();
|
||||||
|
|
||||||
|
protected ArrayList _jvmargs = new ArrayList();
|
||||||
|
protected ArrayList _appargs = new ArrayList();
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
//
|
||||||
|
// $Id: Digest.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown.data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.samskivert.text.MessageUtil;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import com.threerings.getdown.util.ConfigUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the <code>digest.txt</code> file and the computing and
|
||||||
|
* processing of MD5 digests for an application.
|
||||||
|
*/
|
||||||
|
public class Digest
|
||||||
|
{
|
||||||
|
/** The name of our MD5 digest file. */
|
||||||
|
public static final String DIGEST_FILE = "digest.txt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a digest instance which will parse and validate the
|
||||||
|
* <code>digest.txt</code> in the supplied application directory.
|
||||||
|
*/
|
||||||
|
public Digest (File appdir)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// parse and validate our digest file contents
|
||||||
|
String metaDigest = "";
|
||||||
|
StringBuffer data = new StringBuffer();
|
||||||
|
List pairs = ConfigUtil.parsePairs(new File(appdir, DIGEST_FILE));
|
||||||
|
for (Iterator iter = pairs.iterator(); iter.hasNext(); ) {
|
||||||
|
String[] pair = (String[])iter.next();
|
||||||
|
if (pair[0].equals(DIGEST_FILE)) {
|
||||||
|
metaDigest = pair[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_digests.put(pair[0], pair[1]);
|
||||||
|
note(data, pair[0], pair[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we've reached the end, validate our contents
|
||||||
|
MessageDigest md = getMessageDigest();
|
||||||
|
byte[] contents = data.toString().getBytes("UTF-8");
|
||||||
|
String md5 = StringUtil.hexlate(md.digest(contents));
|
||||||
|
if (!md5.equals(metaDigest)) {
|
||||||
|
String err = MessageUtil.tcompose(
|
||||||
|
"m.invalid_digest_file", metaDigest, md5);
|
||||||
|
throw new IOException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the stored digest value for the file with the supplied
|
||||||
|
* path, or null if no digest exists for a file with that path.
|
||||||
|
*/
|
||||||
|
public String getDigest (String path)
|
||||||
|
{
|
||||||
|
return (String)_digests.get(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a digest file at the specified location using the supplied
|
||||||
|
* list of resources.
|
||||||
|
*/
|
||||||
|
public static void createDigest (List resources, File output)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
MessageDigest md = getMessageDigest();
|
||||||
|
StringBuffer data = new StringBuffer();
|
||||||
|
PrintWriter pout = new PrintWriter(
|
||||||
|
new OutputStreamWriter(new FileOutputStream(output), "UTF-8"));
|
||||||
|
|
||||||
|
// compute and append the MD5 digest of each resource in the list
|
||||||
|
for (Iterator iter = resources.iterator(); iter.hasNext(); ) {
|
||||||
|
Resource rsrc = (Resource)iter.next();
|
||||||
|
String path = rsrc.getPath();
|
||||||
|
String digest = rsrc.computeDigest(md);
|
||||||
|
note(data, path, digest);
|
||||||
|
pout.println(path + " = " + digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally compute and append the digest for the file contents
|
||||||
|
md.reset();
|
||||||
|
byte[] contents = data.toString().getBytes("UTF-8");
|
||||||
|
pout.println(DIGEST_FILE + " = " +
|
||||||
|
StringUtil.hexlate(md.digest(contents)));
|
||||||
|
|
||||||
|
pout.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used by {@link #createDigest} and {@link Digest}. */
|
||||||
|
protected static void note (StringBuffer data, String path, String digest)
|
||||||
|
{
|
||||||
|
data.append(path).append(" = ").append(digest).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used by {@link #createDigest} and {@link Digest}. */
|
||||||
|
protected static MessageDigest getMessageDigest ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return MessageDigest.getInstance("MD5");
|
||||||
|
} catch (NoSuchAlgorithmException nsae) {
|
||||||
|
throw new RuntimeException("JVM does not support MD5. Gurp!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HashMap _digests = new HashMap();
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// $Id: Resource.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown.data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models a single file resource used by an {@link Application}.
|
||||||
|
*/
|
||||||
|
public class Resource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a resource with the supplied application base URL and
|
||||||
|
* resource path.
|
||||||
|
*/
|
||||||
|
public Resource (URL appbase, File appdir, String path)
|
||||||
|
throws MalformedURLException
|
||||||
|
{
|
||||||
|
_path = path;
|
||||||
|
_remote = new URL(appbase, path);
|
||||||
|
_local = new File(appdir, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path associated with this resource.
|
||||||
|
*/
|
||||||
|
public String getPath ()
|
||||||
|
{
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the MD5 hash of this resource's underlying file.
|
||||||
|
* <em>Note:</m> This is both CPU and I/O intensive.
|
||||||
|
*/
|
||||||
|
public String computeDigest (MessageDigest md)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
md.reset();
|
||||||
|
byte[] buffer = new byte[DIGEST_BUFFER_SIZE];
|
||||||
|
int read;
|
||||||
|
FileInputStream fin = new FileInputStream(_local);
|
||||||
|
while ((read = fin.read(buffer)) != -1) {
|
||||||
|
md.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
return StringUtil.hexlate(md.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this instance.
|
||||||
|
*/
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
// return _path;
|
||||||
|
// return _netloc.toString();
|
||||||
|
return _local.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main (String[] args)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Resource rsrc = new Resource(
|
||||||
|
new URL("file:/"), new File("."), args[0]);
|
||||||
|
System.out.println("MD5: " + rsrc.computeDigest(
|
||||||
|
MessageDigest.getInstance("MD5")));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String _path;
|
||||||
|
protected URL _remote;
|
||||||
|
protected File _local;
|
||||||
|
|
||||||
|
protected final static int DIGEST_BUFFER_SIZE = 5 * 1025;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
//
|
||||||
|
// $Id: Getdown.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown.launcher;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import com.threerings.getdown.Log;
|
||||||
|
import com.threerings.getdown.data.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the main control for the Getdown application updater and
|
||||||
|
* deployment system.
|
||||||
|
*/
|
||||||
|
public class Getdown
|
||||||
|
{
|
||||||
|
public Getdown (File appDir)
|
||||||
|
{
|
||||||
|
_app = new Application(appDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
_app.init();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main (String[] args)
|
||||||
|
{
|
||||||
|
// ensure the proper parameters are passed
|
||||||
|
if (args.length != 1) {
|
||||||
|
System.err.println("Usage: java -jar getdown.jar app_dir");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure a valid directory was supplied
|
||||||
|
File appDir = new File(args[0]);
|
||||||
|
if (!appDir.exists() || !appDir.isDirectory()) {
|
||||||
|
Log.warning("Invalid app_dir '" + args[0] + "'.");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Getdown app = new Getdown(appDir);
|
||||||
|
app.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Application _app;
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// $Id: DigesterTask.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.BuildException;
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
|
||||||
|
import com.samskivert.util.CollectionUtil;
|
||||||
|
|
||||||
|
import com.threerings.getdown.data.Application;
|
||||||
|
import com.threerings.getdown.data.Digest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ant task used to create a <code>digest.txt</code> for a Getdown
|
||||||
|
* application deployment.
|
||||||
|
*/
|
||||||
|
public class DigesterTask extends Task
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sets the application directory.
|
||||||
|
*/
|
||||||
|
public void setAppdir (File appdir)
|
||||||
|
{
|
||||||
|
_appdir = appdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the actual work of the task.
|
||||||
|
*/
|
||||||
|
public void execute () throws BuildException
|
||||||
|
{
|
||||||
|
// make sure appdir is set
|
||||||
|
if (_appdir == null) {
|
||||||
|
String errmsg = "Must specify the path to the application " +
|
||||||
|
"directory via the 'appdir' attribute.";
|
||||||
|
throw new BuildException(errmsg);
|
||||||
|
}
|
||||||
|
File target = new File(_appdir, Digest.DIGEST_FILE);
|
||||||
|
System.out.println("Generating digest file '" + target + "'...");
|
||||||
|
|
||||||
|
// create our application and instruct it to parse its business
|
||||||
|
Application app = new Application(_appdir);
|
||||||
|
try {
|
||||||
|
app.init();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new BuildException("Error parsing getdown.txt: " +
|
||||||
|
ioe.getMessage(), ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList rsrcs = new ArrayList();
|
||||||
|
rsrcs.add(app.getConfigResource());
|
||||||
|
CollectionUtil.addAll(rsrcs, app.getCodeResources().iterator());
|
||||||
|
CollectionUtil.addAll(rsrcs, app.getResources().iterator());
|
||||||
|
|
||||||
|
// now generate the digest file
|
||||||
|
try {
|
||||||
|
Digest.createDigest(rsrcs, target);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new BuildException("Error creating digest: " +
|
||||||
|
ioe.getMessage(), ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The application directory in which we're creating a digest file. */
|
||||||
|
protected File _appdir;
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
//
|
||||||
|
// $Id: ConfigUtil.java,v 1.1 2004/07/02 11:01:21 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.getdown.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a file containing key/value pairs and returns a {@link HashMap}
|
||||||
|
* with the values. Keys may be repeated, in which case they will be made
|
||||||
|
* to reference an array of values.
|
||||||
|
*/
|
||||||
|
public class ConfigUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parses a configuration file containing key/value pairs. The file
|
||||||
|
* must be in the UTF-8 encoding.
|
||||||
|
*
|
||||||
|
* @return a list of <code>String[]</code> instances containing the
|
||||||
|
* key/value pairs in the order they were parsed from the file.
|
||||||
|
*/
|
||||||
|
public static List parsePairs (File config)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
ArrayList pairs = new ArrayList();
|
||||||
|
|
||||||
|
// parse our configuration file
|
||||||
|
BufferedReader bin = new BufferedReader(
|
||||||
|
new InputStreamReader(new FileInputStream(config), "UTF-8"));
|
||||||
|
String line = null;
|
||||||
|
while ((line = bin.readLine()) != null) {
|
||||||
|
// nix comments
|
||||||
|
int cidx = line.indexOf("#");
|
||||||
|
if (cidx != -1) {
|
||||||
|
line = line.substring(0, cidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim whitespace and skip blank lines
|
||||||
|
line = line.trim();
|
||||||
|
if (StringUtil.blank(line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse our key/value pair
|
||||||
|
String[] pair = new String[2];
|
||||||
|
int eidx = line.indexOf("=");
|
||||||
|
if (eidx != -1) {
|
||||||
|
pair[0] = line.substring(0, eidx).trim();
|
||||||
|
pair[1] = line.substring(eidx+1).trim();
|
||||||
|
} else {
|
||||||
|
pair[0] = line;
|
||||||
|
pair[1] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs.add(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a configuration file containing key/value pairs. The file
|
||||||
|
* must be in the UTF-8 encoding.
|
||||||
|
*
|
||||||
|
* @return a map from keys to values, where a value will be an array
|
||||||
|
* of strings if more than one key/value pair in the config file was
|
||||||
|
* associated with the same key.
|
||||||
|
*/
|
||||||
|
public static HashMap parseConfig (File config)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
List pairs = parsePairs(config);
|
||||||
|
HashMap data = new HashMap();
|
||||||
|
|
||||||
|
for (Iterator iter = pairs.iterator(); iter.hasNext(); ) {
|
||||||
|
String[] pair = (String[])iter.next();
|
||||||
|
Object value = data.get(pair[0]);
|
||||||
|
if (value == null) {
|
||||||
|
data.put(pair[0], pair[1]);
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
data.put(pair[0], new String[] { (String)value, pair[1] });
|
||||||
|
} else if (value instanceof String[]) {
|
||||||
|
String[] values = (String[])value;
|
||||||
|
String[] nvalues = new String[values.length+1];
|
||||||
|
System.arraycopy(values, 0, nvalues, 0, values.length);
|
||||||
|
nvalues[values.length] = pair[1];
|
||||||
|
data.put(pair[0], nvalues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Massages a single string into an array and leaves existing array
|
||||||
|
* values as is. Simplifies access to parameters that are expected to
|
||||||
|
* be arrays.
|
||||||
|
*/
|
||||||
|
public static String[] getMultiValue (HashMap data, String name)
|
||||||
|
{
|
||||||
|
Object value = data.get(name);
|
||||||
|
if (value instanceof String) {
|
||||||
|
return new String[] { (String)value };
|
||||||
|
} else {
|
||||||
|
return (String[])value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user