Files
python-build/pythonbrew
T
utahvich aa81df9486 updated
2010-10-02 21:35:38 +09:00

360 lines
11 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import urllib
import errno
import re
import shutil
import filecmp
import subprocess
import getopt
VERSION = "0.1"
if os.environ.has_key("PYTHONBREW_ROOT"):
ROOT = os.environ["PYTHONBREW_ROOT"]
else:
ROOT = "%s/python/pythonbrew" % os.environ["HOME"]
PYTHONDLSITE = "http://www.python.org/ftp/python/%s/%s"
EZSETUPDLSITE = "http://peak.telecommunity.com/dist/ez_setup.py"
class PythonbrewOptions(object):
def __init__(self):
self._prog = sys.argv[0]
self._args = sys.argv[1:]
self._opts = {}
try:
(opts, args) = getopt.getopt(self._args, "hf", ["help", "force", "build-options="])
except getopt.GetoptError:
self._help()
sys.exit()
for o, a in opts:
if o in ("-h", "--help"):
self._help()
sys.exit()
if o in ("-f", "--force"):
self._opts["force"] = True
if o in ("--build-options"):
self._opts["build-options"] = a;
self._args = args
if len(self._args) == 0:
self._help()
sys.exit()
def get_prog(self):
return self._prog
def get_cmd(self):
return self._args[0]
def get_opt(self, idx):
if idx+1 >= len(self._args):
return None
return self._args[idx+1]
def force(self):
return self._opts.get("force") == True
def build_options(self):
if self._opts.has_key("build-options"):
return self._opts.get("build-options")
else:
return ""
def _help(self):
print """=== USAGE:
pythonbrew [options] [init|install|installed|switch|off|version]
# Initialize
pythonbrew init
# Install pythonbrew
pythonbrew install
# Install some Pythons
pythonbrew install Python-2.6.6
pythonbrew install Python-2.5.5
pythonbrew --build-options="CC=gcc_4.1" install Python-2.4.3
# Switch python in the $PATH
pythonbrew switch Python-2.6.6
pythonbrew switch /path/to/Python-2.5.5/
pythonbrew switch /path/to/python
# Disable pythonbrew
pythonbrew off
# Version
pythonbrew version
=== COMMANDS:
= init
Run this once to setup the pythonbrew directory ready for installing
pythons into. Run it again if you decide to change PYTHONBREW_ROOT.
= install Python-<version>
Build and install the given version of python.
= installed
List the installed versions of python.
= switch Python-<version>
Switch to the given version.
= switch /path/to/Python-dir/
Switch to the given version of python in directory.
= switch /path/to/python
Switch to the given version of python.
= off
Disable pythonbrew.
= version
Show version.
=== OPTIONS:
= --force
= --build-options
"""
class Pythonbrew(object):
def __init__(self):
self._options = PythonbrewOptions()
def run(self):
cmd = self._options.get_cmd()
try:
f = self.__getattribute__("run_command_%s" % cmd)
except:
print "Unknown command: `%s`. Typo?" % cmd
sys.exit()
f()
def run_command_init(self):
self._makedirs( "%s/pythons" % ROOT )
self._makedirs( "%s/build" % ROOT )
self._makedirs( "%s/dists" % ROOT )
self._makedirs( "%s/etc" % ROOT )
os.system( "echo 'export PATH=%s/bin:%s/pythons/current/bin:${PATH}' > %s/etc/bashrc" % (ROOT, ROOT, ROOT) )
os.system( "echo 'setenv PATH %s/bin:%s/pythons/current/bin:$PATH' > %s/etc/cshrc" % (ROOT, ROOT, ROOT) )
m = re.search( "(t?csh)", os.environ.get("SHELL") )
if m:
shrc = "cshrc"
yourshrc = m.group(1)+"rc"
else:
shrc = yourshrc = "bashrc"
print """
Pythonbrew environment initiated, required directories are created under
"""+ROOT+"""
Well-done! Congratulations! Please add the following line to the end
of your ~/."""+yourshrc+"""
source """+ROOT+"""/etc/"""+shrc+"""
After that, exit this shell, start a new one, and install some fresh
pythons:
pythonbrew install Python-2.6.6
pythonbrew install Python-2.5.5
For further instructions, simply run:
pythonbrew
The default help messages will popup and tell you what to do!
Enjoy pythonbrew at $HOME!!
INSTRUCTION"""
def run_command_install(self):
dist = self._options.get_opt(0)
if not dist:
# Install pythonbrew
executable = os.path.abspath( self._options.get_prog() )
target = "%s/bin/pythonbrew" % ROOT
if os.path.isfile( executable ) and os.path.isfile( target ):
if filecmp.cmp( executable, target ):
print """You are already running the installed pythonbrew:
""" + executable;
sys.exit()
self._makedirs( "%s/bin" % ROOT )
shutil.copy( executable, target )
os.chmod( target, 0755 )
print """The pythonbrew is installed as:
"""+target+"""
You may trash the downloaded """+executable+""" from now on.
Next, if this is the first time you've run pythonbrew installation, run:
"""+target+""" init
And follow the instruction on screen."""
sys.exit()
# Install python
m = re.search( "^Python-(\d\.\d\d?(\.\d\d?)?)$", dist )
if m:
self._install_python(dist, m.group(1))
return
print "Unknown file: `%s`. Typo?" % dist
def _install_python(self, dist, dist_version):
m = re.search( "^Python-(\d\.\d\d?(\.\d\d?)?)$", dist )
if not m:
print "Unknown file: `%s`. Typo?" % dist
sys.exit()
dist_version = m.group(1)
dist_tarball = "%s.tgz" % dist
sys.stdout.write("%s..." % dist_tarball)
sys.stdout.flush()
urllib.urlretrieve( PYTHONDLSITE % (dist_version, dist_tarball),
"%s/dists/%s" % (ROOT, dist_tarball),
self._download_progress )
if os.path.getsize( "%s/dists/%s" % (ROOT, dist_tarball) ) < 1000000: #iffy
print "[ERROR] File not found (probably):%s/dists/%s" % (ROOT, dist_tarball)
sys.exit()
print "[OK]"
build_options = "--prefix=%s/pythons/%s %s" % (ROOT, dist, self._options.build_options())
print "Installing %s into %s/pythons/%s" % (dist, ROOT, dist);
cmd = []
cmd.append( "cd %s/build" % ROOT )
cmd.append( "tar zxf %s/dists/%s" % (ROOT, dist_tarball) )
cmd.append( "cd %s" % dist )
cmd.append( "./configure %s" % (build_options) )
if self._options.force():
cmd.append( "make" )
cmd.append( "make install" )
else:
cmd.append( "make clean" )
cmd.append( "make" )
cmd.append( "make test && make install" )
cmd = ";".join(cmd)
print cmd
try:
retcode = subprocess.call( "%s >> %s/build.log 2>&1" % (cmd, ROOT), shell=True )
except OSError, (e, es):
retcode = -1
if retcode != 0:
print """Installing """+dist+""" failed. See """+ROOT+"""/build.log to see why.
pythonbrew --force install """+dist
sys.exit()
print """Installed """+dist+""" successfully. Run the following command to switch to it.
pythonbrew switch """+dist
def run_command_installed(self):
if os.path.realpath( "%s/pythons/current" % ROOT ) == ROOT:
cur = os.path.realpath("%s/bin/python" % ROOT)
else:
cur = os.path.realpath( "%s/pythons/current" % ROOT )
print "%s (*)" % cur
for d in os.listdir("%s/pythons/" % ROOT):
if d == "current" or cur == "%s/pythons/%s" % (ROOT,d):
continue
print "%s/pythons/%s" % (ROOT, d)
def run_command_switch(self):
dist = self._options.get_opt(0)
distdir = dist
if os.path.isfile( dist ) and os.access( dist, os.X_OK ):
if re.search( ".*python(\d(\.\d)?)?$", dist ):
self._switch_file(dist)
else:
print "Invalid file: `%s`" % dist
return
elif os.path.isdir( dist ):
if os.path.isdir("%s/bin" % dist):
if os.path.isfile("%s/bin/python" % dist):
self._switch_file("%s/bin/python" % dist)
if os.path.isfile("%s/bin/python3" % dist):
self._switch_file("%s/bin/python3" % dist)
return
elif os.path.isfile("%s/python" % dist) and os.access("%s/python" % dist, os.X_OK):
self._switch_file("%s/python" % dist)
return
elif os.path.isfile("%s/python3" % dist) and os.access("%s/python3" % dist, os.X_OK):
self._switch_file("%s/python3" % dist)
return
else:
print "Invalid directory: `%s`" % dist
return
elif not os.path.isdir( "%s/pythons/%s" % (ROOT, dist) ):
print "Unknown switch target: `%s`. Typo?" % dist
return
self._switch_dir( distdir )
def _switch_file(self, dist):
self._unlink( "%s/pythons/current" % ROOT )
self._unlink( "%s/bin/python" % ROOT )
self._clean_switch_symlink()
self._symlink( dist, "%s/bin/python" % ROOT )
self._symlink( ROOT, "%s/pythons/current" % ROOT )
print "Switched to "+dist
def _switch_dir(self, dist):
self._unlink( "%s/pythons/current" % ROOT )
self._unlink( "%s/bin/python" % ROOT )
self._symlink( dist, "%s/pythons/current" % ROOT )
self._clean_switch_symlink()
for root, dirs, files in os.walk("%s/pythons/current/bin/" % ROOT):
for f in files:
self._symlink("%s%s" % (root, f), "%s/bin/%s" % (ROOT, f))
print "Switched to "+dist
def _clean_switch_symlink(self):
for root, dirs, files in os.walk("%s/bin/" % ROOT):
for f in files:
if f == "pythonbrew":
continue
self._unlink("%s%s" % (root, f))
def run_command_off(self):
self._unlink("%s/pythons/current" % ROOT)
self._clean_switch_symlink()
def run_command_version(self):
print VERSION
def _makedirs(self, name):
try:
os.makedirs( name )
except OSError, (e, es):
if errno.EEXIST != e:
raise
def _symlink(self, src, dst):
try:
os.symlink(src, dst)
except:
pass
def _unlink(self, name):
try:
os.unlink( name )
except OSError, (e, es):
if errno.ENOENT != e:
raise
def _download_progress(self, block, blockbytes, maxbytes):
pass
def main():
p = Pythonbrew()
p.run()
if __name__ == "__main__":
main()