0

Merge branch 'logging' of git://github.com/alexjurkiewicz/Minecraft-Overviewer

This commit is contained in:
Andrew Brown
2010-09-30 22:50:23 -04:00
3 changed files with 44 additions and 27 deletions

17
gmap.py
View File

@@ -26,6 +26,9 @@ from optparse import OptionParser
import re import re
import multiprocessing import multiprocessing
import time import time
import logging
logging.basicConfig(level=logging.INFO,format="%(asctime)s [%(levelname)s] %(message)s")
import world import world
import quadtree import quadtree
@@ -46,6 +49,8 @@ def main():
parser.add_option("--cachedir", dest="cachedir", help="Sets the directory where the Overviewer will save chunk images, which is an intermediate step before the tiles are generated. You must use the same directory each time to gain any benefit from the cache. If not set, this defaults to your world directory.") parser.add_option("--cachedir", dest="cachedir", help="Sets the directory where the Overviewer will save chunk images, which is an intermediate step before the tiles are generated. You must use the same directory each time to gain any benefit from the cache. If not set, this defaults to your world directory.")
parser.add_option("--chunklist", dest="chunklist", help="A file containing, on each line, a path to a chunkfile to update. Instead of scanning the world directory for chunks, it will just use this list. Normal caching rules still apply.") parser.add_option("--chunklist", dest="chunklist", help="A file containing, on each line, a path to a chunkfile to update. Instead of scanning the world directory for chunks, it will just use this list. Normal caching rules still apply.")
parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg. NOTE: png will always be used as the intermediate image format.") parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg. NOTE: png will always be used as the intermediate image format.")
parser.add_option("-q", "--quiet", dest="quiet", action="count", default=0, help="Print less output. You can specify this option multiple times.")
parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0, help="Print more output. You can specify this option multiple times.")
options, args = parser.parse_args() options, args = parser.parse_args()
@@ -93,6 +98,14 @@ def main():
else: else:
imgformat = 'png' imgformat = 'png'
logging.getLogger().setLevel(
logging.getLogger().level + 10*options.quiet)
logging.getLogger().setLevel(
logging.getLogger().level - 10*options.verbose)
logging.info("Welcome to Minecraft Overviewer!")
logging.debug("Current log level: {0}".format(logging.getLogger().level))
# First generate the world's chunk images # First generate the world's chunk images
w = world.WorldRenderer(worlddir, cachedir, chunklist=chunklist) w = world.WorldRenderer(worlddir, cachedir, chunklist=chunklist)
w.go(options.procs) w.go(options.procs)
@@ -110,7 +123,7 @@ def delete_all(worlddir, tiledir):
for f in filenames: for f in filenames:
if matcher.match(f): if matcher.match(f):
filepath = os.path.join(dirpath, f) filepath = os.path.join(dirpath, f)
print "Deleting {0}".format(filepath) logging.info("Deleting {0}".format(filepath))
os.unlink(filepath) os.unlink(filepath)
# Now delete all /hash/ files in the tile dir. # Now delete all /hash/ files in the tile dir.
@@ -119,7 +132,7 @@ def delete_all(worlddir, tiledir):
for f in filenames: for f in filenames:
if f.endswith(".hash"): if f.endswith(".hash"):
filepath = os.path.join(dirpath, f) filepath = os.path.join(dirpath, f)
print "Deleting {0}".format(filepath) logging.info("Deleting {0}".format(filepath))
os.unlink(filepath) os.unlink(filepath)
def list_worlds(): def list_worlds():

View File

@@ -23,6 +23,7 @@ import re
import shutil import shutil
import collections import collections
import json import json
import logging
from PIL import Image from PIL import Image
@@ -45,7 +46,7 @@ def catch_keyboardinterrupt(func):
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except KeyboardInterrupt: except KeyboardInterrupt:
print "Ctrl-C caught!" logging.error("Ctrl-C caught!")
raise Exception("Exiting") raise Exception("Exiting")
except: except:
import traceback import traceback
@@ -111,8 +112,8 @@ class QuadtreeGen(object):
else: else:
if not complete % 1000 == 0: if not complete % 1000 == 0:
return return
print "{0}/{1} tiles complete on level {2}/{3}".format( logging.info("{0}/{1} tiles complete on level {2}/{3}".format(
complete, total, level, self.p) complete, total, level, self.p))
def write_html(self, zoomlevel, imgformat): def write_html(self, zoomlevel, imgformat):
"""Writes out index.html""" """Writes out index.html"""
@@ -258,12 +259,12 @@ class QuadtreeGen(object):
curdepth = self._get_cur_depth() curdepth = self._get_cur_depth()
if curdepth != -1: if curdepth != -1:
if self.p > curdepth: if self.p > curdepth:
print "Your map seemes to have expanded beyond its previous bounds." logging.warning("Your map seemes to have expanded beyond its previous bounds.")
print "Doing some tile re-arrangements... just a sec..." logging.warning( "Doing some tile re-arrangements... just a sec...")
for _ in xrange(self.p-curdepth): for _ in xrange(self.p-curdepth):
self._increase_depth() self._increase_depth()
elif self.p < curdepth: elif self.p < curdepth:
print "Your map seems to have shrunk. Re-arranging tiles, just a sec..." logging.warning("Your map seems to have shrunk. Re-arranging tiles, just a sec...")
for _ in xrange(curdepth - self.p): for _ in xrange(curdepth - self.p):
self._decrease_depth() self._decrease_depth()
@@ -279,11 +280,11 @@ class QuadtreeGen(object):
results = collections.deque() results = collections.deque()
complete = 0 complete = 0
total = 4**self.p total = 4**self.p
print "Rendering highest zoom level of tiles now." logging.info("Rendering highest zoom level of tiles now.")
print "There are {0} tiles to render".format(total) logging.info("There are {0} tiles to render".format(total))
print "There are {0} total levels to render".format(self.p) logging.info("There are {0} total levels to render".format(self.p))
print "Don't worry, each level has only 25% as many tiles as the last." logging.info("Don't worry, each level has only 25% as many tiles as the last.")
print "The others will go faster" logging.info("The others will go faster")
for result in self._apply_render_worldtiles(pool): for result in self._apply_render_worldtiles(pool):
results.append(result) results.append(result)
if len(results) > 10000: if len(results) > 10000:
@@ -308,7 +309,7 @@ class QuadtreeGen(object):
assert len(results) == 0 assert len(results) == 0
complete = 0 complete = 0
total = 4**zoom total = 4**zoom
print "Starting level", level logging.info("Starting level {0}".format(level))
for result in self._apply_render_inntertile(pool, zoom): for result in self._apply_render_inntertile(pool, zoom):
results.append(result) results.append(result)
if len(results) > 10000: if len(results) > 10000:
@@ -324,7 +325,7 @@ class QuadtreeGen(object):
self.print_statusline(complete, total, level, True) self.print_statusline(complete, total, level, True)
print "Done" logging.info("Done")
pool.close() pool.close()
pool.join() pool.join()
@@ -561,8 +562,7 @@ def render_worldtile(chunks, colstart, colend, rowstart, rowend, path, imgformat
# corrupting it), then this could error. # corrupting it), then this could error.
# Since we have no easy way of determining how this chunk was # Since we have no easy way of determining how this chunk was
# generated, we need to just ignore it. # generated, we need to just ignore it.
print "Error opening file", chunkfile logging.warning("Could not open chunk '{0}' ({1})".format(chunkfile,e))
print "(Error was {0})".format(e)
try: try:
# Remove the file so that the next run will re-generate it. # Remove the file so that the next run will re-generate it.
os.unlink(chunkfile) os.unlink(chunkfile)
@@ -571,12 +571,12 @@ def render_worldtile(chunks, colstart, colend, rowstart, rowend, path, imgformat
# Ignore if file doesn't exist, another task could have already # Ignore if file doesn't exist, another task could have already
# removed it. # removed it.
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
print "Could not remove the corrupt chunk!" logging.warning("Could not remove chunk '{0}'!".format(chunkfile))
raise raise
else: else:
print "Removed the corrupt file" logging.warning("Removed the corrupt file")
print "You will need to re-run the Overviewer to fix this chunk" logging.warning("You will need to re-run the Overviewer to fix this chunk")
continue continue
xpos = -192 + (col-colstart)*192 xpos = -192 + (col-colstart)*192

View File

@@ -18,6 +18,7 @@ import os
import os.path import os.path
import multiprocessing import multiprocessing
import sys import sys
import logging
import numpy import numpy
@@ -170,8 +171,9 @@ class WorldRenderer(object):
def go(self, procs): def go(self, procs):
"""Starts the render. This returns when it is finished""" """Starts the render. This returns when it is finished"""
print "Scanning chunks" logging.info("Scanning chunks")
raw_chunks = self._find_chunkfiles() raw_chunks = self._find_chunkfiles()
logging.debug("Done scanning chunks")
# Translate chunks to our diagonal coordinate system # Translate chunks to our diagonal coordinate system
mincol, maxcol, minrow, maxrow, chunks = _convert_coords(raw_chunks) mincol, maxcol, minrow, maxrow, chunks = _convert_coords(raw_chunks)
@@ -205,9 +207,11 @@ class WorldRenderer(object):
p = f.split(".") p = f.split(".")
all_chunks.append((base36decode(p[1]), base36decode(p[2]), all_chunks.append((base36decode(p[1]), base36decode(p[2]),
os.path.join(dirpath, f))) os.path.join(dirpath, f)))
logging.debug((base36decode(p[1]), base36decode(p[2]),
os.path.join(dirpath, f)))
if not all_chunks: if not all_chunks:
print "Error: No chunks found!" logging.error("Error: No chunks found!")
sys.exit(1) sys.exit(1)
return all_chunks return all_chunks
@@ -228,7 +232,7 @@ class WorldRenderer(object):
results = {} results = {}
if processes == 1: if processes == 1:
# Skip the multiprocessing stuff # Skip the multiprocessing stuff
print "Rendering chunks synchronously since you requested 1 process" logging.debug("Rendering chunks synchronously since you requested 1 process")
for i, (col, row, chunkfile) in enumerate(chunks): for i, (col, row, chunkfile) in enumerate(chunks):
if inclusion_set and (col, row) not in inclusion_set: if inclusion_set and (col, row) not in inclusion_set:
# Skip rendering, just find where the existing image is # Skip rendering, just find where the existing image is
@@ -242,9 +246,9 @@ class WorldRenderer(object):
results[(col, row)] = result results[(col, row)] = result
if i > 0: if i > 0:
if 1000 % i == 0 or i % 1000 == 0: if 1000 % i == 0 or i % 1000 == 0:
print "{0}/{1} chunks rendered".format(i, len(chunks)) logging.info("{0}/{1} chunks rendered".format(i, len(chunks)))
else: else:
print "Rendering chunks in {0} processes".format(processes) logging.debug("Rendering chunks in {0} processes".format(processes))
pool = multiprocessing.Pool(processes=processes) pool = multiprocessing.Pool(processes=processes)
asyncresults = [] asyncresults = []
for col, row, chunkfile in chunks: for col, row, chunkfile in chunks:
@@ -267,10 +271,10 @@ class WorldRenderer(object):
results[(col, row)] = result.get() results[(col, row)] = result.get()
if i > 0: if i > 0:
if 1000 % i == 0 or i % 1000 == 0: if 1000 % i == 0 or i % 1000 == 0:
print "{0}/{1} chunks rendered".format(i, len(asyncresults)) logging.info("{0}/{1} chunks rendered".format(i, len(asyncresults)))
pool.join() pool.join()
print "Done!" logging.info("Done!")
return results return results