Source

jaraco.deploy / jaraco / deploy / python.py

"""
Support for building Python environments on Ubuntu 10.04 servers in
isolated environments.
"""
from fabric.api import run, cd, sudo
from fabric.contrib import files
from fabric.context_managers import hide, settings

import packaging

def install_prerequisites():
	status = sudo('aptitude build-dep -y python2.6')
	packages = packaging.parse_new_packages(status)
	return packages

def _needs_prerequisites():
	status = run('aptitude -s build-dep -y python2.6')
	packages = packaging.parse_new_packages(status)
	return bool(packages)

def _get_home():
	return run('echo ~').splitlines()[-1]

def install_python(versions='2.7.1,2.6.6,2.5.5'):
	"""
	Install the specified python versions (comma-separated) to the
	user's home directory. Requires sudo if any prerequisites are not
	already installed.
	"""
	root = _get_home()
	installed = install_prerequisites() if _needs_prerequisites() else []
	try:
		# install the first version as primary and the subsequent versions
		#  as alternate.
		alt=False
		for ver in versions.split(','):
			install_python_version(root, ver, alt)
			alt=True
	finally:
		# we don't need these any more
		remove_prerequisites(installed)
		
def install_python_version(root, ver, alt=False):
	"""
	Install a given version of Python from source to the specified
	root (aka prefix).
	If `alt` is indicated, Python will be installed as alternate (i.e.
	no `python` executable).
	"""
	longver = 'Python-%(ver)s' % vars()
	if not files.exists(longver):
		run('wget http://python.org/ftp/python/{ver}/{longver}.tgz -O - | tar xz'.format(**vars()))
	with cd(longver):
		run('./configure --prefix {root}'.format(**vars()))
		run('make')
		type = 'altinstall' if alt else 'install'
		run('make {type}'.format(**vars()))
	run('rm -R {longver}'.format(**vars()))

def remove_prerequisites(which=None):
	if which is None:
		# these are the packages installed for build-dep python26 on
		#  a "clean" ubuntu 10.04 box.
		which = ('autoconf debhelper blt-dev gdb libbluetooth-dev '
			'libdb4.8-dev libffi-dev libncursesw5-dev libreadline-dev '
			'libsqlite3-dev libssl-dev sharutils tk8.5-dev zlib1g-dev')
	else:
		which = ' '.join(which)
	if not which:
		return
	sudo('aptitude remove -y ' + which)

def install_setuptools(pyvers = '2.5,2.6,2.7'):
	"""
	Install setuptools 0.6c11 for the various versions of Python. The
	last version installed will be default for commands such as
	easy_install.
	"""
	for pyver in pyvers.split(','):
		eggname = 'setuptools-0.6c11-py{pyver}.egg'.format(**vars())
		run('wget http://pypi.python.org/packages/{pyver}/s/setuptools/{eggname}'.format(**vars()))
		run('sh {eggname}'.format(**vars()))
		run('rm {eggname}'.format(**vars()))

def install_distribute():
	run('wget http://python-distribute.org/distribute_setup.py -O - | python')
	run('rm distribute-0.6.*.tar.gz')

def install_virtualenv():
	"Install virtualenv to the default setuptools-enabled Python"
	run('easy_install virtualenv')

def cleanup():
	"clean up the build Python environments"
	run('rm -R bin include lib share')

def remove_singly_installed_package(package_expr):
	"""
	Remove package from easy_install.pth
	This is particularly useful when you run into infinite loops when
	attempting to eggmonster to upgrade a package that's
	singly-installed.
	Be careful that package_expr matches exactly the package you're
	seeking to remove. (such as pear-2.1-py)
	"""
	easy_install_pth = run(
		'''python -c "import os, distutils.sysconfig; print(os.path.join(distutils.sysconfig.get_python_lib(), 'easy-install.pth'))"''')
	cmd = "grep '{package_expr}' " + easy_install_pth
	cmd = cmd.format(**vars())
	print cmd
	cmd = "sed -i '/{package_expr}/d' " + easy_install_pth
	cmd = cmd.format(**vars())
	sudo(cmd)