Skip to content
This repository
Browse code

Adding setup.py files

  • Loading branch information...
commit a29a5b02bcf13c75dcd307c99a5322c2b108338e 1 parent 88bf6e4
Richard Leland richleland authored

Showing 4 changed files with 514 additions and 0 deletions. Show diff stats Hide diff stats

  1. +8 0 .gitignore
  2. +4 0 MANIFEST.in
  3. +477 0 distribute_setup.py
  4. +25 0 setup.py
8 .gitignore
... ... @@ -1 +1,9 @@
1 1 *.pyc
  2 +.DS_Store
  3 +*.log
  4 +*.db
  5 +dist/
  6 +*.egg
  7 +*.egg-info
  8 +*.gz
  9 +build/
4 MANIFEST.in
... ... @@ -0,0 +1,4 @@
  1 +include README
  2 +include distribute_setup.py
  3 +recursive-include docs *
  4 +recursive-exclude test *
477 distribute_setup.py
... ... @@ -0,0 +1,477 @@
  1 +#!python
  2 +"""Bootstrap distribute installation
  3 +
  4 +If you want to use setuptools in your package's setup.py, just include this
  5 +file in the same directory with it, and add this to the top of your setup.py::
  6 +
  7 + from distribute_setup import use_setuptools
  8 + use_setuptools()
  9 +
  10 +If you want to require a specific version of setuptools, set a download
  11 +mirror, or use an alternate download directory, you can do so by supplying
  12 +the appropriate options to ``use_setuptools()``.
  13 +
  14 +This file can also be run as a script to install or upgrade setuptools.
  15 +"""
  16 +import os
  17 +import sys
  18 +import time
  19 +import fnmatch
  20 +import tempfile
  21 +import tarfile
  22 +from distutils import log
  23 +
  24 +try:
  25 + from site import USER_SITE
  26 +except ImportError:
  27 + USER_SITE = None
  28 +
  29 +try:
  30 + import subprocess
  31 +
  32 + def _python_cmd(*args):
  33 + args = (sys.executable,) + args
  34 + return subprocess.call(args) == 0
  35 +
  36 +except ImportError:
  37 + # will be used for python 2.3
  38 + def _python_cmd(*args):
  39 + args = (sys.executable,) + args
  40 + # quoting arguments if windows
  41 + if sys.platform == 'win32':
  42 + def quote(arg):
  43 + if ' ' in arg:
  44 + return '"%s"' % arg
  45 + return arg
  46 + args = [quote(arg) for arg in args]
  47 + return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
  48 +
  49 +DEFAULT_VERSION = "0.6.10"
  50 +DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
  51 +SETUPTOOLS_FAKED_VERSION = "0.6c11"
  52 +
  53 +SETUPTOOLS_PKG_INFO = """\
  54 +Metadata-Version: 1.0
  55 +Name: setuptools
  56 +Version: %s
  57 +Summary: xxxx
  58 +Home-page: xxx
  59 +Author: xxx
  60 +Author-email: xxx
  61 +License: xxx
  62 +Description: xxx
  63 +""" % SETUPTOOLS_FAKED_VERSION
  64 +
  65 +
  66 +def _install(tarball):
  67 + # extracting the tarball
  68 + tmpdir = tempfile.mkdtemp()
  69 + log.warn('Extracting in %s', tmpdir)
  70 + old_wd = os.getcwd()
  71 + try:
  72 + os.chdir(tmpdir)
  73 + tar = tarfile.open(tarball)
  74 + _extractall(tar)
  75 + tar.close()
  76 +
  77 + # going in the directory
  78 + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
  79 + os.chdir(subdir)
  80 + log.warn('Now working in %s', subdir)
  81 +
  82 + # installing
  83 + log.warn('Installing Distribute')
  84 + if not _python_cmd('setup.py', 'install'):
  85 + log.warn('Something went wrong during the installation.')
  86 + log.warn('See the error message above.')
  87 + finally:
  88 + os.chdir(old_wd)
  89 +
  90 +
  91 +def _build_egg(egg, tarball, to_dir):
  92 + # extracting the tarball
  93 + tmpdir = tempfile.mkdtemp()
  94 + log.warn('Extracting in %s', tmpdir)
  95 + old_wd = os.getcwd()
  96 + try:
  97 + os.chdir(tmpdir)
  98 + tar = tarfile.open(tarball)
  99 + _extractall(tar)
  100 + tar.close()
  101 +
  102 + # going in the directory
  103 + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
  104 + os.chdir(subdir)
  105 + log.warn('Now working in %s', subdir)
  106 +
  107 + # building an egg
  108 + log.warn('Building a Distribute egg in %s', to_dir)
  109 + _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
  110 +
  111 + finally:
  112 + os.chdir(old_wd)
  113 + # returning the result
  114 + log.warn(egg)
  115 + if not os.path.exists(egg):
  116 + raise IOError('Could not build the egg.')
  117 +
  118 +
  119 +def _do_download(version, download_base, to_dir, download_delay):
  120 + egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
  121 + % (version, sys.version_info[0], sys.version_info[1]))
  122 + if not os.path.exists(egg):
  123 + tarball = download_setuptools(version, download_base,
  124 + to_dir, download_delay)
  125 + _build_egg(egg, tarball, to_dir)
  126 + sys.path.insert(0, egg)
  127 + import setuptools
  128 + setuptools.bootstrap_install_from = egg
  129 +
  130 +
  131 +def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
  132 + to_dir=os.curdir, download_delay=15, no_fake=True):
  133 + # making sure we use the absolute path
  134 + to_dir = os.path.abspath(to_dir)
  135 + was_imported = 'pkg_resources' in sys.modules or \
  136 + 'setuptools' in sys.modules
  137 + try:
  138 + try:
  139 + import pkg_resources
  140 + if not hasattr(pkg_resources, '_distribute'):
  141 + if not no_fake:
  142 + _fake_setuptools()
  143 + raise ImportError
  144 + except ImportError:
  145 + return _do_download(version, download_base, to_dir, download_delay)
  146 + try:
  147 + pkg_resources.require("distribute>="+version)
  148 + return
  149 + except pkg_resources.VersionConflict:
  150 + e = sys.exc_info()[1]
  151 + if was_imported:
  152 + sys.stderr.write(
  153 + "The required version of distribute (>=%s) is not available,\n"
  154 + "and can't be installed while this script is running. Please\n"
  155 + "install a more recent version first, using\n"
  156 + "'easy_install -U distribute'."
  157 + "\n\n(Currently using %r)\n" % (version, e.args[0]))
  158 + sys.exit(2)
  159 + else:
  160 + del pkg_resources, sys.modules['pkg_resources'] # reload ok
  161 + return _do_download(version, download_base, to_dir,
  162 + download_delay)
  163 + except pkg_resources.DistributionNotFound:
  164 + return _do_download(version, download_base, to_dir,
  165 + download_delay)
  166 + finally:
  167 + if not no_fake:
  168 + _create_fake_setuptools_pkg_info(to_dir)
  169 +
  170 +def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
  171 + to_dir=os.curdir, delay=15):
  172 + """Download distribute from a specified location and return its filename
  173 +
  174 + `version` should be a valid distribute version number that is available
  175 + as an egg for download under the `download_base` URL (which should end
  176 + with a '/'). `to_dir` is the directory where the egg will be downloaded.
  177 + `delay` is the number of seconds to pause before an actual download
  178 + attempt.
  179 + """
  180 + # making sure we use the absolute path
  181 + to_dir = os.path.abspath(to_dir)
  182 + try:
  183 + from urllib.request import urlopen
  184 + except ImportError:
  185 + from urllib2 import urlopen
  186 + tgz_name = "distribute-%s.tar.gz" % version
  187 + url = download_base + tgz_name
  188 + saveto = os.path.join(to_dir, tgz_name)
  189 + src = dst = None
  190 + if not os.path.exists(saveto): # Avoid repeated downloads
  191 + try:
  192 + log.warn("Downloading %s", url)
  193 + src = urlopen(url)
  194 + # Read/write all in one block, so we don't create a corrupt file
  195 + # if the download is interrupted.
  196 + data = src.read()
  197 + dst = open(saveto, "wb")
  198 + dst.write(data)
  199 + finally:
  200 + if src:
  201 + src.close()
  202 + if dst:
  203 + dst.close()
  204 + return os.path.realpath(saveto)
  205 +
  206 +
  207 +def _patch_file(path, content):
  208 + """Will backup the file then patch it"""
  209 + existing_content = open(path).read()
  210 + if existing_content == content:
  211 + # already patched
  212 + log.warn('Already patched.')
  213 + return False
  214 + log.warn('Patching...')
  215 + _rename_path(path)
  216 + f = open(path, 'w')
  217 + try:
  218 + f.write(content)
  219 + finally:
  220 + f.close()
  221 + return True
  222 +
  223 +
  224 +def _same_content(path, content):
  225 + return open(path).read() == content
  226 +
  227 +def _no_sandbox(function):
  228 + def __no_sandbox(*args, **kw):
  229 + try:
  230 + from setuptools.sandbox import DirectorySandbox
  231 + def violation(*args):
  232 + pass
  233 + DirectorySandbox._old = DirectorySandbox._violation
  234 + DirectorySandbox._violation = violation
  235 + patched = True
  236 + except ImportError:
  237 + patched = False
  238 +
  239 + try:
  240 + return function(*args, **kw)
  241 + finally:
  242 + if patched:
  243 + DirectorySandbox._violation = DirectorySandbox._old
  244 + del DirectorySandbox._old
  245 +
  246 + return __no_sandbox
  247 +
  248 +@_no_sandbox
  249 +def _rename_path(path):
  250 + new_name = path + '.OLD.%s' % time.time()
  251 + log.warn('Renaming %s into %s', path, new_name)
  252 + os.rename(path, new_name)
  253 + return new_name
  254 +
  255 +def _remove_flat_installation(placeholder):
  256 + if not os.path.isdir(placeholder):
  257 + log.warn('Unkown installation at %s', placeholder)
  258 + return False
  259 + found = False
  260 + for file in os.listdir(placeholder):
  261 + if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
  262 + found = True
  263 + break
  264 + if not found:
  265 + log.warn('Could not locate setuptools*.egg-info')
  266 + return
  267 +
  268 + log.warn('Removing elements out of the way...')
  269 + pkg_info = os.path.join(placeholder, file)
  270 + if os.path.isdir(pkg_info):
  271 + patched = _patch_egg_dir(pkg_info)
  272 + else:
  273 + patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
  274 +
  275 + if not patched:
  276 + log.warn('%s already patched.', pkg_info)
  277 + return False
  278 + # now let's move the files out of the way
  279 + for element in ('setuptools', 'pkg_resources.py', 'site.py'):
  280 + element = os.path.join(placeholder, element)
  281 + if os.path.exists(element):
  282 + _rename_path(element)
  283 + else:
  284 + log.warn('Could not find the %s element of the '
  285 + 'Setuptools distribution', element)
  286 + return True
  287 +
  288 +
  289 +def _after_install(dist):
  290 + log.warn('After install bootstrap.')
  291 + placeholder = dist.get_command_obj('install').install_purelib
  292 + _create_fake_setuptools_pkg_info(placeholder)
  293 +
  294 +@_no_sandbox
  295 +def _create_fake_setuptools_pkg_info(placeholder):
  296 + if not placeholder or not os.path.exists(placeholder):
  297 + log.warn('Could not find the install location')
  298 + return
  299 + pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
  300 + setuptools_file = 'setuptools-%s-py%s.egg-info' % \
  301 + (SETUPTOOLS_FAKED_VERSION, pyver)
  302 + pkg_info = os.path.join(placeholder, setuptools_file)
  303 + if os.path.exists(pkg_info):
  304 + log.warn('%s already exists', pkg_info)
  305 + return
  306 +
  307 + log.warn('Creating %s', pkg_info)
  308 + f = open(pkg_info, 'w')
  309 + try:
  310 + f.write(SETUPTOOLS_PKG_INFO)
  311 + finally:
  312 + f.close()
  313 +
  314 + pth_file = os.path.join(placeholder, 'setuptools.pth')
  315 + log.warn('Creating %s', pth_file)
  316 + f = open(pth_file, 'w')
  317 + try:
  318 + f.write(os.path.join(os.curdir, setuptools_file))
  319 + finally:
  320 + f.close()
  321 +
  322 +def _patch_egg_dir(path):
  323 + # let's check if it's already patched
  324 + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
  325 + if os.path.exists(pkg_info):
  326 + if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
  327 + log.warn('%s already patched.', pkg_info)
  328 + return False
  329 + _rename_path(path)
  330 + os.mkdir(path)
  331 + os.mkdir(os.path.join(path, 'EGG-INFO'))
  332 + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
  333 + f = open(pkg_info, 'w')
  334 + try:
  335 + f.write(SETUPTOOLS_PKG_INFO)
  336 + finally:
  337 + f.close()
  338 + return True
  339 +
  340 +
  341 +def _before_install():
  342 + log.warn('Before install bootstrap.')
  343 + _fake_setuptools()
  344 +
  345 +
  346 +def _under_prefix(location):
  347 + if 'install' not in sys.argv:
  348 + return True
  349 + args = sys.argv[sys.argv.index('install')+1:]
  350 + for index, arg in enumerate(args):
  351 + for option in ('--root', '--prefix'):
  352 + if arg.startswith('%s=' % option):
  353 + top_dir = arg.split('root=')[-1]
  354 + return location.startswith(top_dir)
  355 + elif arg == option:
  356 + if len(args) > index:
  357 + top_dir = args[index+1]
  358 + return location.startswith(top_dir)
  359 + elif option == '--user' and USER_SITE is not None:
  360 + return location.startswith(USER_SITE)
  361 + return True
  362 +
  363 +
  364 +def _fake_setuptools():
  365 + log.warn('Scanning installed packages')
  366 + try:
  367 + import pkg_resources
  368 + except ImportError:
  369 + # we're cool
  370 + log.warn('Setuptools or Distribute does not seem to be installed.')
  371 + return
  372 + ws = pkg_resources.working_set
  373 + try:
  374 + setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
  375 + replacement=False))
  376 + except TypeError:
  377 + # old distribute API
  378 + setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
  379 +
  380 + if setuptools_dist is None:
  381 + log.warn('No setuptools distribution found')
  382 + return
  383 + # detecting if it was already faked
  384 + setuptools_location = setuptools_dist.location
  385 + log.warn('Setuptools installation detected at %s', setuptools_location)
  386 +
  387 + # if --root or --preix was provided, and if
  388 + # setuptools is not located in them, we don't patch it
  389 + if not _under_prefix(setuptools_location):
  390 + log.warn('Not patching, --root or --prefix is installing Distribute'
  391 + ' in another location')
  392 + return
  393 +
  394 + # let's see if its an egg
  395 + if not setuptools_location.endswith('.egg'):
  396 + log.warn('Non-egg installation')
  397 + res = _remove_flat_installation(setuptools_location)
  398 + if not res:
  399 + return
  400 + else:
  401 + log.warn('Egg installation')
  402 + pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
  403 + if (os.path.exists(pkg_info) and
  404 + _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
  405 + log.warn('Already patched.')
  406 + return
  407 + log.warn('Patching...')
  408 + # let's create a fake egg replacing setuptools one
  409 + res = _patch_egg_dir(setuptools_location)
  410 + if not res:
  411 + return
  412 + log.warn('Patched done.')
  413 + _relaunch()
  414 +
  415 +
  416 +def _relaunch():
  417 + log.warn('Relaunching...')
  418 + # we have to relaunch the process
  419 + args = [sys.executable] + sys.argv
  420 + sys.exit(subprocess.call(args))
  421 +
  422 +
  423 +def _extractall(self, path=".", members=None):
  424 + """Extract all members from the archive to the current working
  425 + directory and set owner, modification time and permissions on
  426 + directories afterwards. `path' specifies a different directory
  427 + to extract to. `members' is optional and must be a subset of the
  428 + list returned by getmembers().
  429 + """
  430 + import copy
  431 + import operator
  432 + from tarfile import ExtractError
  433 + directories = []
  434 +
  435 + if members is None:
  436 + members = self
  437 +
  438 + for tarinfo in members:
  439 + if tarinfo.isdir():
  440 + # Extract directories with a safe mode.
  441 + directories.append(tarinfo)
  442 + tarinfo = copy.copy(tarinfo)
  443 + tarinfo.mode = 448 # decimal for oct 0700
  444 + self.extract(tarinfo, path)
  445 +
  446 + # Reverse sort directories.
  447 + if sys.version_info < (2, 4):
  448 + def sorter(dir1, dir2):
  449 + return cmp(dir1.name, dir2.name)
  450 + directories.sort(sorter)
  451 + directories.reverse()
  452 + else:
  453 + directories.sort(key=operator.attrgetter('name'), reverse=True)
  454 +
  455 + # Set correct owner, mtime and filemode on directories.
  456 + for tarinfo in directories:
  457 + dirpath = os.path.join(path, tarinfo.name)
  458 + try:
  459 + self.chown(tarinfo, dirpath)
  460 + self.utime(tarinfo, dirpath)
  461 + self.chmod(tarinfo, dirpath)
  462 + except ExtractError:
  463 + e = sys.exc_info()[1]
  464 + if self.errorlevel > 1:
  465 + raise
  466 + else:
  467 + self._dbg(1, "tarfile: %s" % e)
  468 +
  469 +
  470 +def main(argv, version=DEFAULT_VERSION):
  471 + """Install or upgrade setuptools and EasyInstall"""
  472 + tarball = download_setuptools()
  473 + _install(tarball)
  474 +
  475 +
  476 +if __name__ == '__main__':
  477 + main(sys.argv[1:])
25 setup.py
... ... @@ -0,0 +1,25 @@
  1 +import os, distribute_setup
  2 +distribute_setup.use_setuptools()
  3 +from setuptools import setup, find_packages
  4 +
  5 +readme = os.path.join(os.path.dirname(__file__), 'README')
  6 +long_description = open(readme).read()
  7 +
  8 +setup(
  9 + name = "python-postmark",
  10 + version = "0.2.0",
  11 + packages = find_packages(),
  12 +
  13 + author = "Dave Martorana & Richard Cooper",
  14 + # license = 'BSD',
  15 + description = "Postmark library for Python 2.4 and greater.",
  16 + long_description = long_description,
  17 + url = "http://github.com/themartorana/python-postmark",
  18 + classifiers=[
  19 + 'Development Status :: 3 - Alpha',
  20 + 'Environment :: Web Environment',
  21 + 'Intended Audience :: Developers',
  22 + 'Operating System :: OS Independent',
  23 + 'Programming Language :: Python',
  24 + ]
  25 +)

0 comments on commit a29a5b0

Please sign in to comment.
Something went wrong with that request. Please try again.