Shucks, that was a lot more complicated than I thought

The mod time of a target directory can't be reliably checked using the files, so we need to compare
the modificaiton times of each source and destination image file as we go.
This commit is contained in:
Jamie Doornbos
2013-01-31 00:28:12 -08:00
committed by Michael Bayne
parent 6ec4fb5c4f
commit 9647cfb968
2 changed files with 141 additions and 104 deletions
@@ -77,24 +77,29 @@ public class BundleWriter
} }
/** /**
* Tests if the target is newer than the given time. Note that if we are in directory-mode, * Tests if the target bundle is newer than the given time. Note that if we are in
* false is returned. * directory-mode, false is returned.
*/ */
public boolean isNewerThan (long newest) public boolean isNewerThan (long newest)
{ {
if (_jar != null) { if (_jar != null) {
return _target.lastModified() > newest; return _target.lastModified() > newest;
} else { } else {
File []files = _target.listFiles();
if (files == null) {
return false;
}
for (File file : files) {
if (file.lastModified() < newest) {
return false; return false;
} }
} }
return true;
/**
* Tests if a given path within the target bundle is newer than a given time. Note that if
* we are in jar mode, false is returned.
*/
public boolean isPathNewerThan (String path, long newest)
{
if (_jar != null) {
return false;
} else {
File f = new File(_target, path);
return f.lastModified() > newest;
} }
} }
@@ -43,6 +43,7 @@ import org.xml.sax.SAXException;
import com.samskivert.io.PersistenceException; import com.samskivert.io.PersistenceException;
import com.samskivert.io.StreamUtil; import com.samskivert.io.StreamUtil;
import com.samskivert.util.HashIntMap; import com.samskivert.util.HashIntMap;
import com.samskivert.util.IntMap;
import com.threerings.resource.FastImageIO; import com.threerings.resource.FastImageIO;
@@ -131,6 +132,9 @@ public class TileSetBundler
/** Loads images for the bundle. */ /** Loads images for the bundle. */
public final ImageProvider improv; public final ImageProvider improv;
/** Modification time of the newest source file. */
public final long newestSource;
/** /**
* Creates a new writer. * Creates a new writer.
* *
@@ -138,11 +142,13 @@ public class TileSetBundler
* @param bundle contains the tilesets we'd like to save out to the bundle. * @param bundle contains the tilesets we'd like to save out to the bundle.
* @param improv the image provider. * @param improv the image provider.
*/ */
public Writer (BundleWriter bwriter, TileSetBundle bundle, ImageProvider improv) public Writer (BundleWriter bwriter, TileSetBundle bundle, ImageProvider improv,
long newestSource)
{ {
this.bundle = bundle; this.bundle = bundle;
this.bwriter = bwriter; this.bwriter = bwriter;
this.improv = improv; this.improv = improv;
this.newestSource = newestSource;
} }
/** /**
@@ -399,7 +405,7 @@ public class TileSetBundler
} }
}; };
return new Writer(target, bundle, improv).imageBase(bundleDesc.getParent()); return new Writer(target, bundle, improv, newest).imageBase(bundleDesc.getParent());
} }
/** /**
@@ -417,7 +423,29 @@ public class TileSetBundler
// bundle till we're done iterating. // bundle till we're done iterating.
HashIntMap<TileSet> toUpdate = new HashIntMap<TileSet>(); HashIntMap<TileSet> toUpdate = new HashIntMap<TileSet>();
while (iditer.hasNext()) { while (iditer.hasNext()) {
int tileSetId = iditer.next().intValue(); processBundleImage(iditer.next().intValue(), target, toUpdate);
}
target.bundle.putAll(toUpdate);
writeUpdatedBundle(target);
// finally close up the jar file and call ourself done
target.bwriter.close();
} catch (Exception e) {
// remove the incomplete jar file and rethrow the exception
target.bwriter.close();
if (!target.bwriter.delete()) {
log.warning("Failed to close botched bundle '" + target + "'.");
}
String errmsg = "Failed to create bundle " + target + ": " + e;
throw (IOException) new IOException(errmsg).initCause(e);
}
}
protected static void processBundleImage (
int tileSetId, Writer target, IntMap<TileSet> toUpdate) throws IOException
{
TileSet set = target.bundle.getTileSet(tileSetId); TileSet set = target.bundle.getTileSet(tileSetId);
String imagePath = set.getImagePath(); String imagePath = set.getImagePath();
@@ -425,21 +453,29 @@ public class TileSetBundler
if (imagePath == null) { if (imagePath == null) {
log.warning("Tileset contains no image path " + log.warning("Tileset contains no image path " +
"[set=" + set + "]. It ain't gonna work."); "[set=" + set + "]. It ain't gonna work.");
continue; return;
} }
File ifile = new File(target.imageBase, imagePath);
long sourceTime = Math.max(target.newestSource, ifile.lastModified());
// if this is an object tileset, trim it // if this is an object tileset, trim it
if (target.trim && (set instanceof ObjectTileSet)) { if (target.trim && (set instanceof ObjectTileSet)) {
// set the tileset up with an image provider; we
// need to do this so that we can trim it!
set.setImageProvider(target.improv);
// add .raw if requested // add .raw if requested
if (target.raw) { if (target.raw) {
imagePath = adjustImagePath(imagePath); imagePath = adjustImagePath(imagePath);
} }
if (target.bwriter.isPathNewerThan(imagePath, sourceTime)) {
return;
}
OutputStream dest = target.bwriter.startNewFile(imagePath); OutputStream dest = target.bwriter.startNewFile(imagePath);
// set the tileset up with an image provider; we
// need to do this so that we can trim it!
set.setImageProvider(target.improv);
try { try {
// create a trimmed object tileset, which will // create a trimmed object tileset, which will
// write the trimmed tileset image to the target file // write the trimmed tileset image to the target file
@@ -462,22 +498,22 @@ public class TileSetBundler
} else { } else {
// read the image file and convert it to our custom // read the image file and convert it to our custom
// format in the bundle // format in the bundle
File ifile = new File(target.imageBase, imagePath);
try { try {
BufferedImage image = ImageIO.read(ifile); BufferedImage image = ImageIO.read(ifile);
if (target.raw && FastImageIO.canWrite(image)) { if (target.raw && FastImageIO.canWrite(image)) {
imagePath = adjustImagePath(imagePath); imagePath = adjustImagePath(imagePath);
// NOTE: DirectoryTileSetBundler used to check the modification time if (!target.bwriter.isPathNewerThan(imagePath, sourceTime)) {
// of the target image here. There may be something to it, but it
// looked unnecessary
OutputStream dest = target.bwriter.startNewFile(imagePath); OutputStream dest = target.bwriter.startNewFile(imagePath);
set.setImagePath(imagePath); set.setImagePath(imagePath);
FastImageIO.write(image, dest); FastImageIO.write(image, dest);
}
} else { } else {
if (!target.bwriter.isPathNewerThan(imagePath, sourceTime)) {
OutputStream dest = target.bwriter.startNewFile(imagePath); OutputStream dest = target.bwriter.startNewFile(imagePath);
FileInputStream imgin = new FileInputStream(ifile); FileInputStream imgin = new FileInputStream(ifile);
StreamUtil.copy(imgin, dest); StreamUtil.copy(imgin, dest);
} }
}
} catch (Exception e) { } catch (Exception e) {
String msg = "Failure bundling image " + ifile + String msg = "Failure bundling image " + ifile +
": " + e; ": " + e;
@@ -485,7 +521,16 @@ public class TileSetBundler
} }
} }
} }
target.bundle.putAll(toUpdate);
protected static void writeUpdatedBundle (Writer target)
throws IOException
{
String meta = target.json != null ?
BundleUtil.METADATA_JSON_PATH : BundleUtil.METADATA_PATH;
if (target.bwriter.isPathNewerThan(meta, target.newestSource)) {
return;
}
// now write a serialized representation of the tileset bundle // now write a serialized representation of the tileset bundle
if (target.json != null) { if (target.json != null) {
@@ -499,30 +544,17 @@ public class TileSetBundler
array.add(tset); array.add(tset);
} }
// now write a serialized representation of the tileset bundle OutputStream fout = target.bwriter.startNewFile(meta);
OutputStream fout = target.bwriter.startNewFile(BundleUtil.METADATA_JSON_PATH);
fout.write(array.toString().getBytes()); fout.write(array.toString().getBytes());
fout.close(); fout.close();
} else { } else {
// object to the bundle jar file
ObjectOutputStream oout = new ObjectOutputStream( ObjectOutputStream oout = new ObjectOutputStream(
target.bwriter.startNewFile(BundleUtil.METADATA_PATH)); target.bwriter.startNewFile(BundleUtil.METADATA_PATH));
oout.writeObject(target.bundle); oout.writeObject(target.bundle);
oout.flush(); oout.flush();
} }
// finally close up the jar file and call ourself done
target.bwriter.close();
} catch (Exception e) {
// remove the incomplete jar file and rethrow the exception
target.bwriter.close();
if (!target.bwriter.delete()) {
log.warning("Failed to close botched bundle '" + target + "'.");
}
String errmsg = "Failed to create bundle " + target + ": " + e;
throw (IOException) new IOException(errmsg).initCause(e);
}
} }
/** Replaces the image suffix with <code>.raw</code>. */ /** Replaces the image suffix with <code>.raw</code>. */