0

Merge branch 'py-package'

Conflicts:
	setup.py
This commit is contained in:
Aaron Griffith
2011-07-10 18:05:25 -04:00
45 changed files with 198 additions and 71 deletions

16
.gitignore vendored
View File

@@ -1,5 +1,8 @@
*.pyc *.pyc
build MANIFEST
build/
dist/
Minecraft_Overviewer.egg-info
terrain.png terrain.png
cachedir* cachedir*
@@ -14,10 +17,13 @@ ImPlatform.h
Imaging.h Imaging.h
# various forms of compiled c_overviewer extensions # various forms of compiled c_overviewer extensions
c_overviewer.so overviewer_core/c_overviewer.so
c_overviewer.pyd overviewer_core/c_overviewer.pyd
c_overviewer_d.pyd overviewer_core/c_overviewer_d.pyd
c_overviewer.dylib overviewer_core/c_overviewer.dylib
# generated version file
overviewer_core/overviewer_version.py
# Mac OS X noise # Mac OS X noise
.DS_Store .DS_Store

9
MANIFEST.in Normal file
View File

@@ -0,0 +1,9 @@
include COPYING.txt
include README.rst
include CONTRIBUTORS.rst
include overviewer.py
include sample.settings.py
recursive-include contrib/ *.py
recursive-include overviewer_core/*.py
recursive-include overviewer_core/src/ *.c *.h
recursive-include overviewer_core/data/ *.png *.js index.html style.css

View File

@@ -22,14 +22,13 @@ if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
import os import os
import os.path import os.path
from configParser import ConfigOptionParser
import re import re
import subprocess import subprocess
import multiprocessing import multiprocessing
import time import time
import logging import logging
import util
import platform import platform
from overviewer_core import util
logging.basicConfig(level=logging.INFO,format="%(asctime)s [%(levelname)s] %(message)s") logging.basicConfig(level=logging.INFO,format="%(asctime)s [%(levelname)s] %(message)s")
@@ -37,7 +36,7 @@ this_dir = util.get_program_path()
# make sure the c_overviewer extension is available # make sure the c_overviewer extension is available
try: try:
import c_overviewer from overviewer_core import c_overviewer
except ImportError: except ImportError:
## if this is a frozen windows package, the following error messages about ## if this is a frozen windows package, the following error messages about
## building the c_overviewer extension are not appropriate ## building the c_overviewer extension are not appropriate
@@ -49,7 +48,7 @@ except ImportError:
## try to find the build extension ## try to find the build extension
ext = os.path.join(this_dir, "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so")) ext = os.path.join(this_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
if os.path.exists(ext): if os.path.exists(ext):
print "Something has gone wrong importing the c_overviewer extension. Please" print "Something has gone wrong importing the c_overviewer extension. Please"
print "make sure it is up-to-date (clean and rebuild)" print "make sure it is up-to-date (clean and rebuild)"
@@ -57,14 +56,17 @@ except ImportError:
print "You need to compile the c_overviewer module to run Minecraft Overviewer." print "You need to compile the c_overviewer module to run Minecraft Overviewer."
print "Run `python setup.py build`, or see the README for details." print "Run `python setup.py build`, or see the README for details."
import traceback
traceback.print_exc()
sys.exit(1) sys.exit(1)
if hasattr(sys, "frozen"): if hasattr(sys, "frozen"):
pass # we don't bother with a compat test since it should always be in sync pass # we don't bother with a compat test since it should always be in sync
elif "extension_version" in dir(c_overviewer): elif "extension_version" in dir(c_overviewer):
# check to make sure the binary matches the headers # check to make sure the binary matches the headers
if os.path.exists(os.path.join(this_dir, "src", "overviewer.h")): if os.path.exists(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")):
with open(os.path.join(this_dir, "src", "overviewer.h")) as f: with open(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")) as f:
lines = f.readlines() lines = f.readlines()
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines) lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
if lines: if lines:
@@ -76,12 +78,10 @@ else:
print "Please rebuild your c_overviewer module. It is out of date!" print "Please rebuild your c_overviewer module. It is out of date!"
sys.exit(1) sys.exit(1)
from overviewer_core.configParser import ConfigOptionParser
from overviewer_core import optimizeimages, world, quadtree
from overviewer_core import googlemap, rendernode
import optimizeimages
import world
import quadtree
import googlemap
import rendernode
helptext = """ helptext = """
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir> %prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>
@@ -124,14 +124,14 @@ def main():
if options.version: if options.version:
print "Minecraft-Overviewer"
print "Git version: %s" % util.findGitVersion()
try: try:
import overviewer_version import overviewer_core.overviewer_version as overviewer_version
if hasattr(sys, "frozen"): print "Minecraft-Overviewer %s" % overviewer_version.VERSION
print "py2exe version build on %s" % overviewer_version.BUILD_DATE print "Git commit: %s" % overviewer_version.HASH
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS) print "built on %s" % overviewer_version.BUILD_DATE
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS)
except: except:
print "version info not found"
pass pass
sys.exit(0) sys.exit(0)

View File

View File

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 563 B

View File

Before

Width:  |  Height:  |  Size: 401 B

After

Width:  |  Height:  |  Size: 401 B

View File

Before

Width:  |  Height:  |  Size: 672 B

After

Width:  |  Height:  |  Size: 672 B

View File

Before

Width:  |  Height:  |  Size: 374 B

After

Width:  |  Height:  |  Size: 374 B

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 368 B

After

Width:  |  Height:  |  Size: 368 B

View File

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 708 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

@@ -24,6 +24,7 @@ import json
import util import util
from c_overviewer import get_render_mode_inheritance from c_overviewer import get_render_mode_inheritance
import overviewer_version
""" """
This module has routines related to generating a Google Maps-based This module has routines related to generating a Google Maps-based
@@ -98,7 +99,11 @@ class MapGen(object):
blank.save(os.path.join(tileDir, "blank."+quadtree.imgformat)) blank.save(os.path.join(tileDir, "blank."+quadtree.imgformat))
# copy web assets into destdir: # copy web assets into destdir:
mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir) global_assets = os.path.join(util.get_program_path(), "overviewer_core", "data", "web_assets")
if not os.path.isdir(global_assets):
global_assets = os.path.join(util.get_program_path(), "web_assets")
mirror_dir(global_assets, self.destdir)
# do the same with the local copy, if we have it # do the same with the local copy, if we have it
if self.web_assets_path: if self.web_assets_path:
mirror_dir(self.web_assets_path, self.destdir) mirror_dir(self.web_assets_path, self.destdir)
@@ -131,9 +136,9 @@ class MapGen(object):
indexpath = os.path.join(self.destdir, "index.html") indexpath = os.path.join(self.destdir, "index.html")
index = open(indexpath, 'r').read() index = open(indexpath, 'r').read()
index = index.replace( index = index.replace("{time}", str(strftime("%a, %d %b %Y %H:%M:%S %Z", localtime())))
"{time}", str(strftime("%a, %d %b %Y %H:%M:%S %Z", localtime()))) versionstr = "%s (%s)" % (overviewer_version.VERSION, overviewer_version.HASH[:7])
index = index.replace("{version}", util.findGitVersion()) index = index.replace("{version}", versionstr)
with open(os.path.join(self.destdir, "index.html"), 'w') as output: with open(os.path.join(self.destdir, "index.html"), 'w') as output:
output.write(index) output.write(index)

View File

@@ -33,13 +33,13 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) {
return NULL; return NULL;
} }
textures = PyImport_ImportModule("textures"); textures = PyImport_ImportModule("overviewer_core.textures");
/* ensure none of these pointers are NULL */ /* ensure none of these pointers are NULL */
if ((!textures)) { if ((!textures)) {
return NULL; return NULL;
} }
chunk_mod = PyImport_ImportModule("chunk"); chunk_mod = PyImport_ImportModule("overviewer_core.chunk");
/* ensure none of these pointers are NULL */ /* ensure none of these pointers are NULL */
if ((!chunk_mod)) { if ((!chunk_mod)) {
return NULL; return NULL;

View File

@@ -14,6 +14,7 @@
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>. # with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
import sys import sys
import imp
import os import os
import os.path import os.path
import zipfile import zipfile
@@ -32,8 +33,8 @@ def _find_file(filename, mode="rb"):
This searches the following locations in this order: This searches the following locations in this order:
* the textures_path given in the config file (if present) * the textures_path given in the config file (if present)
* The program dir (same dir as this file) * The program dir (same dir as overviewer.py)
* The program dir / textures * The overviewer_core textures dir
* On Darwin, in /Applications/Minecraft * On Darwin, in /Applications/Minecraft
* Inside minecraft.jar, which is looked for at these locations * Inside minecraft.jar, which is looked for at these locations
@@ -53,9 +54,14 @@ def _find_file(filename, mode="rb"):
if os.path.exists(path): if os.path.exists(path):
return open(path, mode) return open(path, mode)
path = os.path.join(programdir, "textures", filename) path = os.path.join(programdir, "overviewer_core", "data", "textures", filename)
if os.path.exists(path): if os.path.exists(path):
return open(path, mode) return open(path, mode)
elif hasattr(sys, "frozen") or imp.is_frozen("__main__"):
# windows special case, when the package dir doesn't exist
path = os.path.join(programdir, "textures", filename)
if os.path.exists(path):
return open(path, mode)
if sys.platform == "darwin": if sys.platform == "darwin":
path = os.path.join("/Applications/Minecraft", filename) path = os.path.join("/Applications/Minecraft", filename)

View File

@@ -21,19 +21,22 @@ import imp
import os import os
import os.path import os.path
import sys import sys
from subprocess import Popen, PIPE
def get_program_path(): def get_program_path():
if hasattr(sys, "frozen") or imp.is_frozen("__main__"): if hasattr(sys, "frozen") or imp.is_frozen("__main__"):
return os.path.dirname(sys.executable) return os.path.dirname(sys.executable)
else: else:
try: try:
return os.path.dirname(__file__) # normally, we're in ./overviewer_core/util.py
# we want ./
return os.path.dirname(os.path.dirname(__file__))
except NameError: except NameError:
return os.path.dirname(sys.argv[0]) return os.path.dirname(sys.argv[0])
# does not require git, very likely to work everywhere
def findGitVersion(): def findGitHash():
this_dir = get_program_path() this_dir = get_program_path()
if os.path.exists(os.path.join(this_dir,".git")): if os.path.exists(os.path.join(this_dir,".git")):
with open(os.path.join(this_dir,".git","HEAD")) as f: with open(os.path.join(this_dir,".git","HEAD")) as f:
@@ -46,6 +49,24 @@ def findGitVersion():
else: else:
return data return data
else: else:
try:
import overviewer_version
return overviewer_version.HASH
except:
return "unknown"
def findGitVersion():
try:
p = Popen(['git', 'describe', '--tags'], stdout=PIPE, stderr=PIPE)
p.stderr.close()
line = p.stdout.readlines()[0]
if line.startswith('release-'):
line = line.split('-', 1)[1]
# turn 0.1.2-50-somehash into 0.1.2-50
# and 0.1.3 into 0.1.3
line = '-'.join(line.split('-', 2)[:2])
return line.strip()
except:
try: try:
import overviewer_version import overviewer_version
return overviewer_version.VERSION return overviewer_version.VERSION

154
setup.py Normal file → Executable file
View File

@@ -1,26 +1,60 @@
from distutils.core import setup, Extension #!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension
from distutils.command.build import build from distutils.command.build import build
from distutils.command.clean import clean from distutils.command.clean import clean
from distutils.command.build_ext import build_ext from distutils.command.build_ext import build_ext
from distutils.command.sdist import sdist
from distutils.dir_util import remove_tree from distutils.dir_util import remove_tree
from distutils.sysconfig import get_python_inc from distutils.sysconfig import get_python_inc
from distutils import log from distutils import log
import os, os.path import sys, os, os.path
import glob import glob
import platform import platform
import time import time
import overviewer_core.util as util
try: try:
import py2exe import py2exe
except ImportError: except ImportError:
py2exe = None py2exe = None
try:
import py2app
from setuptools.extension import Extension
except ImportError:
py2app = None
# now, setup the keyword arguments for setup # now, setup the keyword arguments for setup
# (because we don't know until runtime if py2exe is available) # (because we don't know until runtime if py2exe/py2app is available)
setup_kwargs = {} setup_kwargs = {}
setup_kwargs['options'] = {}
setup_kwargs['ext_modules'] = [] setup_kwargs['ext_modules'] = []
setup_kwargs['cmdclass'] = {} setup_kwargs['cmdclass'] = {}
setup_kwargs['options'] = {}
#
# metadata
#
# Utility function to read the README file.
# Used for the long_description. It's nice, because now 1) we have a top level
# README file and 2) it's easier to type in the README file than to put a raw
# string in below ...
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setup_kwargs['name'] = 'Minecraft-Overviewer'
setup_kwargs['version'] = util.findGitVersion()
setup_kwargs['description'] = 'Generates large resolution images of a Minecraft map.'
setup_kwargs['url'] = 'http://overviewer.org/'
setup_kwargs['author'] = 'Andrew Brown'
setup_kwargs['author_email'] = 'brownan@gmail.com'
setup_kwargs['license'] = 'GNU General Public License v3'
setup_kwargs['long_description'] = read('README.rst')
# top-level files that should be included as documentation
doc_files = ['COPYING.txt', 'README.rst', 'CONTRIBUTORS.rst', 'sample.settings.py']
# helper to create a 'data_files'-type sequence recursively for a given dir # helper to create a 'data_files'-type sequence recursively for a given dir
def recursive_data_files(src, dest=None): def recursive_data_files(src, dest=None):
@@ -46,9 +80,9 @@ def recursive_data_files(src, dest=None):
if py2exe is not None: if py2exe is not None:
setup_kwargs['console'] = ['overviewer.py'] setup_kwargs['console'] = ['overviewer.py']
setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png', 'textures/fire.png', 'textures/portal.png']), setup_kwargs['data_files'] = [('', doc_files)]
('', ['COPYING.txt', 'README.rst'])] setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/textures', 'textures')
setup_kwargs['data_files'] += recursive_data_files('web_assets') setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/web_assets', 'web_assets')
setup_kwargs['zipfile'] = None setup_kwargs['zipfile'] = None
if platform.system() == 'Windows' and '64bit' in platform.architecture(): if platform.system() == 'Windows' and '64bit' in platform.architecture():
b = 3 b = 3
@@ -56,6 +90,28 @@ if py2exe is not None:
b = 1 b = 1
setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter'} setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter'}
#
# py2app options
#
if py2app is not None:
setup_kwargs['app'] = ['overviewer.py']
setup_kwargs['options']['py2app'] = {'argv_emulation' : False}
setup_kwargs['setup_requires'] = ['py2app']
#
# script, package, and data
#
setup_kwargs['packages'] = ['overviewer_core']
setup_kwargs['scripts'] = ['overviewer.py']
setup_kwargs['package_data'] = {'overviewer_core':
['data/textures/*',
'data/web_assets/*']}
if py2exe is None:
setup_kwargs['data_files'] = [('share/doc/minecraft-overviewer', doc_files)]
# #
# c_overviewer extension # c_overviewer extension
# #
@@ -79,20 +135,23 @@ except:
# used to figure out what files to compile # used to figure out what files to compile
render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave'] render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave']
c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c', 'src/rendermodes.c'] c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c']
c_overviewer_files += map(lambda mode: 'src/rendermode-%s.c' % (mode,), render_modes) c_overviewer_files += map(lambda mode: 'rendermode-%s.c' % (mode,), render_modes)
c_overviewer_files += ['src/Draw.c'] c_overviewer_files += ['Draw.c']
c_overviewer_includes = ['src/overviewer.h', 'src/rendermodes.h'] c_overviewer_includes = ['overviewer.h', 'rendermodes.h']
c_overviewer_files = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_files)
c_overviewer_includes = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_includes)
setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[]))
setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[]))
# tell build_ext to build the extension in-place # tell build_ext to build the extension in-place
# (NOT in build/) # (NOT in build/)
setup_kwargs['options']['build_ext'] = {'inplace' : 1} setup_kwargs['options']['build_ext'] = {'inplace' : 1}
# tell the build command to only run build_ext
build.sub_commands = [('build_ext', None)]
# custom clean command to remove in-place extension # custom clean command to remove in-place extension
# and the version file
class CustomClean(clean): class CustomClean(clean):
def run(self): def run(self):
# do the normal cleanup # do the normal cleanup
@@ -101,7 +160,7 @@ class CustomClean(clean):
# try to remove '_composite.{so,pyd,...}' extension, # try to remove '_composite.{so,pyd,...}' extension,
# regardless of the current system's extension name convention # regardless of the current system's extension name convention
build_ext = self.get_finalized_command('build_ext') build_ext = self.get_finalized_command('build_ext')
pretty_fname = build_ext.get_ext_filename('c_overviewer') pretty_fname = build_ext.get_ext_filename('overviewer_core.c_overviewer')
fname = pretty_fname fname = pretty_fname
if os.path.exists(fname): if os.path.exists(fname):
try: try:
@@ -114,8 +173,43 @@ class CustomClean(clean):
else: else:
log.debug("'%s' does not exist -- can't clean it", log.debug("'%s' does not exist -- can't clean it",
pretty_fname) pretty_fname)
versionpath = os.path.join("overviewer_core", "overviewer_version.py")
try:
if not self.dry_run:
os.remove(versionpath)
log.info("removing '%s'", versionpath)
except OSError:
log.warn("'%s' could not be cleaned -- permission denied", versionpath)
class CustomBuild(build_ext): def generate_version_py():
try:
outstr = ""
outstr += "VERSION=%r\n" % util.findGitVersion()
outstr += "HASH=%r\n" % util.findGitHash()
outstr += "BUILD_DATE=%r\n" % time.asctime()
outstr += "BUILD_PLATFORM=%r\n" % platform.processor()
outstr += "BUILD_OS=%r\n" % platform.platform()
f = open("overviewer_core/overviewer_version.py", "w")
f.write(outstr)
f.close()
except:
print "WARNING: failed to build overview_version file"
class CustomSDist(sdist):
def run(self):
# generate the version file
generate_version_py()
sdist.run(self)
class CustomBuild(build):
def run(self):
# generate the version file
generate_version_py()
build.run(self)
print "\nBuild Complete"
class CustomBuildExt(build_ext):
def build_extensions(self): def build_extensions(self):
c = self.compiler.compiler_type c = self.compiler.compiler_type
if c == "msvc": if c == "msvc":
@@ -123,32 +217,18 @@ class CustomBuild(build_ext):
for e in self.extensions: for e in self.extensions:
e.extra_link_args.append("/MANIFEST") e.extra_link_args.append("/MANIFEST")
# build in place, and in the build/ tree
self.inplace = False
build_ext.build_extensions(self)
self.inplace = True
build_ext.build_extensions(self) build_ext.build_extensions(self)
if py2exe is not None:
# define a subclass of py2exe to build our version file on the fly
class CustomPy2exe(py2exe.build_exe.py2exe):
def run(self):
try:
import util
f = open("overviewer_version.py", "w")
f.write("VERSION=%r\n" % util.findGitVersion())
f.write("BUILD_DATE=%r\n" % time.asctime())
f.write("BUILD_PLATFORM=%r\n" % platform.processor())
f.write("BUILD_OS=%r\n" % platform.platform())
f.close()
setup_kwargs['data_files'].append(('.', ['overviewer_version.py']))
except:
print "WARNING: failed to build overview_version file"
py2exe.build_exe.py2exe.run(self)
setup_kwargs['cmdclass']['py2exe'] = CustomPy2exe
setup_kwargs['cmdclass']['clean'] = CustomClean setup_kwargs['cmdclass']['clean'] = CustomClean
setup_kwargs['cmdclass']['build_ext'] = CustomBuild setup_kwargs['cmdclass']['sdist'] = CustomSDist
setup_kwargs['cmdclass']['build'] = CustomBuild
setup_kwargs['cmdclass']['build_ext'] = CustomBuildExt
### ###
setup(**setup_kwargs) setup(**setup_kwargs)
print "\nBuild Complete"