update 0.5

This commit is contained in:
utahta
2010-11-13 03:25:56 +09:00
parent 640fb13834
commit 3f455e161b
26 changed files with 969 additions and 1423 deletions
+8
View File
@@ -0,0 +1,8 @@
* 0.5
- This version is incompatible with the 0.4 or less.
- Split the file.
- Added pythonbrew-install script.
- Added pybrew script. This is a symbolic pythonbrew.
- Rename `search` to `list`.
- Removed `init`.
- Added syntax that `pythonbrew command <VERSION>`
+17 -31
View File
@@ -13,48 +13,42 @@ Following python version is required to use pythonbrew:
The recommended way to download and install pythonbrew is to run these statements in your shell.::
curl -LO http://github.com/utahta/pythonbrew/raw/master/pythonbrew
chmod +x pythonbrew
./pythonbrew install
curl -LO http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install
chmod +x pythonbrew-install
./pythonbrew-install
After that, pythonbrew installs itself to ~/python/pythonbrew/bin, and you should follow the instruction on screen to setup your .bashrc or .cshrc to put it in your PATH.
After that, pythonbrew installs itself to ~/.pythonbrew/bin, and you should follow the instruction on screen to setup your .bashrc or .cshrc to put it in your PATH.
If you need to install pythonbrew into somewhere else, you can do that by setting a PYTHONBREW_ROOT environment variable.::
export PYTHONBREW_ROOT=/path/to/pythonbrew
./pythonbrew install
./pythonbrew-install
Usage
=====
pythonbrew command [options]
Initialize::
pythonbrew init
Install some Pythons::
pythonbrew install Python-3.1.2
pythonbrew install Python-2.6.6
pythonbrew install 2.6.6
pythonbrew install Python-2.5.5
pythonbrew install --configure="CC=gcc_4.1" Python-2.6.6
pythonbrew install --no-setuptools Python-2.6.6
pythonbrew install http://www.python.org/ftp/python/2.6.6/Python-2.6.6.tgz
pythonbrew install /path/to/Python-2.6.6.tgz
Switch python in the $PATH::
pythonbrew switch Python-2.6.6
pythonbrew switch /path/to/python
pythonbrew switch 2.6.6
pythonbrew switch Python-2.5.5
Search python packages::
List the available install versions of Python::
pythonbrew search Python-2.6
pythonbrew search Python-3
pythonbrew list 2.6
pythonbrew list 3.0
Uninstall some Pythons::
pythonbrew uninstall Python-2.6.6
pythonbrew uninstall 2.6.6
Remove stale source folders and archives::
@@ -75,12 +69,7 @@ Show 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>
install <version>
Build and install the given version of Python.
Setuptools and pip is automatically installed.
@@ -90,14 +79,11 @@ install Python-<version>
installed
List the installed versions of python.
switch Python-<version>
switch <version>
Switch to the given version.
switch /path/to/python
Switch to the given version of python.
search Python-<version>
Search Python packages.
list <version>
List the available install version of python.
uninstall Python-<version>
Uninstall the given version of python.
-696
View File
@@ -1,696 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
import os
import sys
import urllib
import errno
import re
import shutil
import filecmp
import subprocess
import tempfile
from HTMLParser import HTMLParser
from optparse import OptionParser
VERSION = "0.4"
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"
DISTRIBUTE_SETUP_DLSITE = "http://python-distribute.org/distribute_setup.py"
PYTHONBREW_DLSITE = "http://github.com/utahta/pythonbrew/raw/master/pythonbrew"
PATH_PYTHONS = "%s/pythons" % ROOT
PATH_BUILD = "%s/build" % ROOT
PATH_DISTS = "%s/dists" % ROOT
PATH_ETC = "%s/etc" % ROOT
PATH_BIN = "%s/bin" % ROOT
parser = OptionParser(usage="%prog COMMAND [OPTIONS]",
version=VERSION,
add_help_option=False)
parser.add_option(
'-h', '--help',
dest='help',
action='store_true',
help='Show help')
parser.disable_interspersed_args()
command_dict = {}
def add_command(command):
command_dict[command.name] = command
#----------------------------------------------------
# exception
#----------------------------------------------------
class BuildingException(Exception):
"""General exception during building"""
#----------------------------------------------------
# util
#----------------------------------------------------
def size_format(b):
kb = 1000
mb = kb*kb
b = float(b)
if b >= mb:
return "%.1fMb" % (b/mb)
if b >= kb:
return "%.1fKb" % (b/kb)
return "%.0fbytes" % (b)
def is_url(name):
if ':' not in name:
return False
scheme = name.split(':', 1)[0].lower()
return scheme in ['http', 'https', 'file', 'ftp']
def splitext(name):
base, ext = os.path.splitext(name)
if base.lower().endswith('.tar'):
ext = base[-4:] + ext
base = base[:-4]
return base, ext
def is_archive_file(name):
ext = splitext(name)[1].lower()
archives = ('.zip', '.tar.gz', '.tar.bz2', '.tgz', '.tar')
if ext in archives:
return True
return False
def makedirs(path):
try:
os.makedirs(path)
except OSError, (e, es):
if errno.EEXIST != e:
raise
def symlink(src, dst):
try:
os.symlink(src, dst)
except:
pass
def unlink(path):
try:
os.unlink(path)
except OSError, (e, es):
if errno.ENOENT != e:
raise
def rm_r(path):
"""like rm -r command."""
if os.path.isdir(path):
shutil.rmtree(path)
else:
unlink(path)
def off():
for root, dirs, files in os.walk(PATH_BIN):
for f in files:
if f == "pythonbrew":
continue
unlink("%s/%s" % (root, f))
unlink("%s/current" % PATH_PYTHONS)
def copy_myself(path):
(fd, src) = tempfile.mkstemp()
fp = file(path, "r")
line = fp.readline()
if line.startswith("#!"):
os.write(fd, "#!%s\n" % os.path.realpath(sys.executable))
else:
os.write(fd, line)
os.write(fd, fp.read())
os.close(fd)
fp.close()
dist = "%s/pythonbrew" % PATH_BIN
if os.path.isfile(src) and os.path.isfile(dist):
if filecmp.cmp(src, dist):
unlink(src)
return (False, dist)
makedirs(PATH_BIN)
shutil.copy(src, dist)
os.chmod(dist, 0755)
unlink(src)
return (True, dist)
#----------------------------------------------------
# classes
#----------------------------------------------------
class Downloader(object):
def __init__(self):
self._msg = ""
self._last_msg = ""
self._bytes = 0.0
def download(self, msg, url, path):
self._msg = msg
self._bytes = 0
urllib.urlretrieve(url, path, self._download_progress)
print " downloaded."
def _download_progress(self, block, blockbytes, maxbytes):
self._bytes += float(blockbytes)
if self._bytes >= maxbytes:
self._bytes = maxbytes
percent = (self._bytes / maxbytes) * 100
max_size = size_format(maxbytes)
now_size = size_format(self._bytes)
now_msg = "\rDownloading %s (%s): %3i%% %s" % (self._msg, max_size, percent, now_size)
padding = " " * (len(self._last_msg) - len(now_msg))
sys.stdout.write("%s%s" % (now_msg, padding))
sys.stdout.flush()
self._last_msg = now_msg
class Subprocess(object):
def __init__(self, log=None, shell=False, cwd=None, print_cmd=True):
self._log = log
self._shell = shell
self._cwd = cwd
self._print_cmd = print_cmd
def chdir(self, cwd):
self._cwd = cwd
def check_call(self, cmd, shell=None, cwd=None):
if shell:
self._shell = shell
if cwd:
self._cwd = cwd
if self._print_cmd:
print cmd
if self._log:
cmd = "(%s) >> '%s' 2>&1" % (cmd, self._log)
retcode = subprocess.call(cmd, shell=self._shell, cwd=self._cwd)
if retcode != 0:
raise BuildingException()
class PythonVersionParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self._versions = []
self._re = re.compile("^(\d+\.\d+(\..*)?)/$")
def handle_starttag(self, tag, attrs):
if tag == "a":
attrs = dict(attrs)
if "href" in attrs:
m = self._re.search(attrs["href"])
if m:
self._versions.append(m.group(1))
def get_sorted_versions(self):
return sorted(self._versions)
class PythonPackages(object):
def __init__(self):
parser = PythonVersionParser()
fp = urllib.urlopen("http://www.python.org/ftp/python/")
parser.feed(fp.read())
fp.close()
parser.close()
self._versions = parser.get_sorted_versions()
def has_version(self, version):
return version in self._versions
def get_packages(self):
return ["Python-%s" % v for v in self._versions]
#----------------------------------------------------
# commands
#----------------------------------------------------
class Command(object):
name = None
usage = None
summary = ""
def __init__(self):
self.parser = OptionParser(usage=self.usage,
prog='%s %s' % (os.path.basename(sys.argv[0]), self.name))
def run(self, args):
options, args = self.parser.parse_args(args)
self.run_command(options, args[1:])
class HelpCommand(Command):
name = "help"
usage = "%prog [COMMAND]"
summary = "Show available commands"
def run_command(self, options, args):
if args:
command = args[0]
if command not in command_dict:
parser.error("Unknown command: `%s`" % command)
return
command = command_dict[command]
command.parser.print_help()
return
parser.print_help()
print
print "Commands available:"
commands = [command_dict[key] for key in sorted(command_dict.keys())]
for command in commands:
print " %s: %s" % (command.name, command.summary)
print
print "Further Instructions:"
print " http://github.com/utahta/pythonbrew"
class InitCommand(Command):
name = "init"
usage = "%prog"
summary = "Run this once to setup the pythonbrew directory ready for installing pythons into"
def run_command(self, options, args):
makedirs(PATH_PYTHONS)
makedirs(PATH_BUILD)
makedirs(PATH_DISTS)
makedirs(PATH_ETC)
os.system("echo 'export PATH=%s/bin:%s/current/bin:${PATH}' > %s/bashrc" % (ROOT, PATH_PYTHONS, PATH_ETC))
os.system("echo 'setenv PATH %s/bin:%s/current/bin:$PATH' > %s/cshrc" % (ROOT, PATH_PYTHONS, PATH_ETC))
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 """+PATH_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"""
class InstallCommand(Command):
name = "install"
usage = "%prog [OPTIONS] PACKAGE_NAMES"
summary = "Build and install the given version of python"
def __init__(self):
super(InstallCommand, self).__init__()
self.parser.add_option(
"-f", "--force",
dest="force",
action="store_true",
default=False,
help="Force installation of a Python."
)
self.parser.add_option(
"-C", "--configure",
dest="configure",
default="",
metavar="CONFIGURE_OPTIONS",
help="Custom configure options."
)
self.parser.add_option(
"-n", "--no-setuptools",
dest="no_setuptools",
action="store_true",
default=False,
help="Skip installation of setuptools."
)
self._logfile = "%s/build.log" % ROOT
def run_command(self, options, args):
if args:
# Install Python
self._install_python(args[0], options)
else:
# Install pythonbrew
self._install_myself()
def _install_myself(self):
executable = os.path.abspath(sys.argv[0])
(retval, dist) = copy_myself(executable)
if not retval:
print "You are already running the installed latest version of pythonbrew."
print "\n%s" % dist
sys.exit()
print """The pythonbrew is installed as:
"""+dist+"""
You may trash the downloaded """+executable+""" from now on.
Next, if this is the first time you've run pythonbrew installation, run:
"""+dist+""" init
And follow the instruction on screen."""
def _get_package(self, name):
if not os.path.isfile(name) and not os.path.isdir(name):
if is_url(name):
basename = os.path.basename(name)
download_url = name
download_path = "%s/%s" % (PATH_DISTS, basename)
else:
m = re.search("^Python-(\d+\.\d+(\..*)?)$", name)
if not m:
print "Unknown package: `%s`" % name
sys.exit(1)
if os.path.isdir("%s/%s" % (PATH_PYTHONS, name)):
print "You are already installed `%s`." % name
sys.exit()
dist_version = m.group(1)
pkgs = PythonPackages()
if not pkgs.has_version(dist_version):
print "Package not found: `%s`" % name
sys.exit(1)
basename = "%s.tgz" % name
download_url = PYTHONDLSITE % (dist_version, basename)
download_path = "%s/%s" % (PATH_DISTS, basename)
if os.path.isfile(download_path):
print "Use the previously fetched %s" % (download_path)
else:
try:
dl = Downloader()
dl.download(
basename,
download_url,
download_path
)
except:
unlink(download_path)
print "\nInterrupt to abort. `%s`" % (download_url)
sys.exit(1)
# iffy
if os.path.getsize(download_path) < 1000000:
print "Failed to download. (maybe not stable version of python) `%s`" % (download_url)
unlink(download_path)
sys.exit(1)
else:
if is_archive_file(name):
basename = os.path.basename(name)
print "Copy the archive file %s to %s/%s" % (name, PATH_DISTS, basename)
shutil.copy(name, "%s/%s" % (PATH_DISTS, basename))
else:
print "Invalid file. `%s`" % name
sys.exit(1)
return basename
def _get_uncompress_command(self, basename):
distpath = "%s/%s" % (PATH_DISTS, basename)
if os.path.isfile(distpath):
ext = splitext(basename)[1]
if ext == ".tar.gz" or ext == ".tgz":
return "tar zxf %s" % (distpath)
elif ext == ".tar.bz2":
return "tar jxf %s" % (distpath)
elif ext == ".tar":
return "tar xf %s" % (distpath)
elif ext == ".zip":
return "unzip %s" % (distpath)
elif os.path.isdir(distpath):
return "mv %s %s/%s" % (distpath, PATH_BUILD, basename)
else:
print "File not found. `%s`" % (basename)
return ""
def _install_python(self, dist, options):
basename = self._get_package(dist)
pkgname = splitext(basename)[0]
install_dir = "%s/%s" % (PATH_PYTHONS, pkgname)
configure = "--prefix=%s %s" % (install_dir, options.configure)
print "Installing %s into %s" % (pkgname, install_dir);
print """This could take a while. You can run the following command on another shell to track the status:
tail -f %s
""" % (self._logfile)
try:
s = Subprocess(log=self._logfile, shell=True, cwd=PATH_BUILD)
s.check_call(self._get_uncompress_command(basename))
s.chdir("%s/%s" % (PATH_BUILD, pkgname))
s.check_call("./configure %s" % (configure))
if options.force:
s.check_call("make")
s.check_call("make install")
else:
s.check_call("make")
s.check_call("make test")
s.check_call("make install")
except:
print """Installing %(pkgname)s failed. See %(ROOT)s/build.log to see why.
pythonbrew install --force %(pkgname)s""" % {"pkgname":pkgname, "ROOT":ROOT}
sys.exit(1)
# install setuptools
self._install_setuptools(pkgname, options.no_setuptools)
print """
Installed %(pkgname)s successfully. Run the following command to switch to it.
pythonbrew switch %(pkgname)s""" % {"pkgname":pkgname}
def _install_setuptools(self, pkgname, no_setuptools):
if no_setuptools:
print "Skip installation setuptools."
return
if re.match("^Python-3.*", pkgname):
is_python3 = True
else:
is_python3 = False
download_url = DISTRIBUTE_SETUP_DLSITE
basename = os.path.basename(download_url)
dl = Downloader()
dl.download(basename, download_url, "%s/%s" % (PATH_DISTS, basename))
if is_python3:
if os.path.isfile("%s/%s/bin/python3" % (PATH_PYTHONS, pkgname)):
pyexec = "%s/%s/bin/python3" % (PATH_PYTHONS, pkgname)
elif os.path.isfile("%s/%s/bin/python3.0" % (PATH_PYTHONS, pkgname)):
pyexec = "%s/%s/bin/python3.0" % (PATH_PYTHONS, pkgname)
else:
print "Python3 binary not found. `%s/%s`" % (PATH_PYTHONS, pkgname)
return
else:
pyexec = "%s/%s/bin/python" % (PATH_PYTHONS, pkgname)
try:
s = Subprocess(log=self._logfile, shell=True, cwd=PATH_DISTS)
s.check_call("%s %s" % (pyexec, basename))
if os.path.isfile("%s/%s/bin/easy_install" % (PATH_PYTHONS, pkgname)) and not is_python3:
s.check_call("%s/%s/bin/easy_install pip" % (PATH_PYTHONS, pkgname), cwd=None)
except:
print "Installing setuptools failed. See %s/build.log to see why." % (ROOT)
sys.exit(1)
class InstalledCommand(Command):
name = "installed"
usage = "%prog"
summary = "List the installed versions of python"
def run_command(self, options, args):
if not os.path.islink("%s/current" % PATH_PYTHONS):
cur = os.path.realpath("%s/bin/python" % ROOT)
print "%s (*)" % cur
elif os.path.islink("%s/current" % PATH_PYTHONS):
cur = os.path.basename(os.path.realpath("%s/current" % PATH_PYTHONS))
else:
cur = ""
for d in sorted(os.listdir("%s/" % PATH_PYTHONS)):
if d == "current":
continue
if cur == d:
print "%s (*)" % cur
else:
print "%s" % (d)
class SwitchCommand(Command):
name = "switch"
usage = "%prog PACKAGE"
summary = "Switch to the given version"
def run_command(self, options, args):
if args:
dist = args[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 "`%s` is not python binary." % dist
return
elif not os.path.isdir( "%s/%s" % (PATH_PYTHONS, dist) ):
print "`%s` is not installed." % dist
return
self._switch_dir( distdir )
def _switch_file(self, dist):
off()
symlink(dist, "%s/python" % PATH_BIN)
print "Switched to "+dist
def _switch_dir(self, dist):
off()
symlink(dist, "%s/current" % PATH_PYTHONS)
for root, dirs, files in os.walk("%s/current/bin/" % PATH_PYTHONS):
for f in files:
symlink("%s%s" % (root, f), "%s/%s" % (PATH_BIN, f))
break
# I want better code
if not os.path.isfile("%s/python" % PATH_BIN):
if os.path.isfile("%s/python3" % PATH_BIN):
symlink(os.path.realpath("%s/python3" % PATH_BIN), "%s/python" % PATH_BIN)
elif os.path.isfile("%s/python3.0" % PATH_BIN):
symlink(os.path.realpath("%s/python3.0" % PATH_BIN), "%s/python" % PATH_BIN)
print "Switched to "+dist
class OffCommand(Command):
name = "off"
usage = "%prog"
summary = "Disable pythonbrew"
def run_command(self, options, args):
off()
class VersionCommand(Command):
name = "version"
usage = "%prog"
summary = "Show version"
def run_command(self, options, args):
print VERSION
class SearchCommand(Command):
name = "search"
usage = "%prog Python-<VERSION>"
summary = "Search Python packages"
def run_command(self, options, args):
pkgs = PythonPackages()
if args:
pattern = args[0]
_re = re.compile(r"%s" % pattern)
pkgnames = []
for pkgname in pkgs.get_packages():
if _re.match(pkgname):
pkgnames.append(pkgname)
if pkgnames:
for pkgname in pkgnames:
print pkgname
else:
print "Package not found. `%s`" % pattern
else:
for pkgname in pkgs.get_packages():
print pkgname
class UninstallCommand(Command):
name = "uninstall"
usage = "%prog Python-<VERSION>"
summary = "Uninstall the given version of python"
def run_command(self, options, args):
if args:
pkgname = args[0]
pkgpath = "%s/%s" % (PATH_PYTHONS, pkgname)
if not os.path.isdir(pkgpath):
print "%s is not installed." % pkgname
sys.exit(1)
if os.path.islink("%s/current" % PATH_PYTHONS):
curpath = os.path.realpath("%s/current" % PATH_PYTHONS)
if pkgpath == curpath:
off()
rm_r(pkgpath)
else:
self.parser.print_help()
class CleanCommand(Command):
name = "clean"
usage = "%prog"
summary = "Remove stale source folders and archives"
def run_command(self, options, args):
self._clean(PATH_BUILD)
self._clean(PATH_DISTS)
def _clean(self, root):
for dir in os.listdir(root):
rm_r("%s/%s" % (root, dir))
class UpdateCommand(Command):
name = "update"
usage = "%prog"
summary = "Upgrades pythonbrew to the latest version"
def run_command(self, options, args):
download_url = PYTHONBREW_DLSITE
basename = os.path.basename(download_url)
download_path = "%s/%s" % (PATH_DISTS, basename)
try:
d = Downloader()
d.download(basename, download_url, download_path)
except:
print "Failed to download. `%s`" % download_url
sys.exit(1)
(retval, dist) = copy_myself(download_path)
if not retval:
print "You are already running the installed latest version of pythonbrew."
print "\n%s" % dist
sys.exit()
print "The pythonbrew has been updated."
class Pythonbrew(object):
def run(self):
options, args = parser.parse_args(sys.argv[1:])
if options.help and not args:
args = ["help"]
if not args:
parser.error('You must give a command (use "pythonbrew help" to see a list of commands)')
return
add_command(HelpCommand())
add_command(InitCommand())
add_command(InstallCommand())
add_command(InstalledCommand())
add_command(SwitchCommand())
add_command(OffCommand())
add_command(VersionCommand())
add_command(SearchCommand())
add_command(UninstallCommand())
add_command(CleanCommand())
add_command(UpdateCommand())
command = args[0].lower()
if command not in command_dict:
parser.error("Unknown command: `%s`" % command)
return
command = command_dict[command]
command.run(args)
def main():
p = Pythonbrew()
p.run()
if __name__ == "__main__":
main()
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env bash
PYTHON=`command -v python`
usage()
{
printf "
Usage:
${0} [options]
options:
--python : Python interpreter.
"
}
parse_arguments()
{
for arg do
val=`echo "$arg" | sed -e "s;--[^=]*=;;"`
case "$arg" in
--python=*) PYTHON="$val" ;;
--help) usage ;;
*) echo "Can't find the option. :$arg";;
esac
done
}
parse_arguments $@
if [[ ! -x $PYTHON ]] ; then
echo "I think $PYTHON is not Python interpreter."
exit
fi
PYTHON_VERSION=`$PYTHON -V 2>&1`
PYTHON_VERSION=${PYTHON_VERSION/"Python "/""}
PYTHON_VERSION_S=`echo $PYTHON_VERSION | sed -e "s/\(^[[:digit:]]\{1,\}.[[:digit:]]\{1,\}\).*/\1/"`
if [[ $PYTHON_VERSION_S != "2.4" ]] && [[ $PYTHON_VERSION_S != "2.5" ]] && [[ $PYTHON_VERSION_S != "2.6" ]] ; then
printf "Python's version is $PYTHON_VERSION_S:
2.4 <= python < 3.0 is required.
"
exit
fi
ROOT="$HOME/.pythonbrew"
if [[ -n $PYTHONBREW_ROOT ]] ; then
ROOT=$PYTHONBREW_ROOT
fi
PATH_DISTS="$ROOT/dists"
PATH_ETC="$ROOT/etc"
mkdir -p $PATH_DISTS
rm -rf $PATH_DISTS/pythonbrew.tar.gz
rm -rf $PATH_DISTS/utahta-pythonbrew*
TEMP_TARBALL="pythonbrew.tar.gz"
DOWNLOAD_URL="http://github.com/utahta/pythonbrew/tarball/master"
echo "Downloading $DOWNLOAD_URL"
builtin cd $PATH_DISTS ; curl -L $DOWNLOAD_URL -o "$TEMP_TARBALL" > /dev/null 2>&1
echo "Extracting $PATH_DISTS/$TEMP_TARBALL"
builtin cd $PATH_DISTS ; tar zxf $TEMP_TARBALL
TEMP_FILE=`ls $PATH_DISTS | grep utahta-pythonbrew`
echo "Installing pythonbrew into $ROOT"
$PYTHON $PATH_DISTS/$TEMP_FILE/pythonbrew_install.py
if [[ $? == 1 ]] ; then
echo "Failed to install pythonbrew."
exit
fi
case $SHELL in
*tcsh)
shrc="cshrc"
yourshrc="tcshrc"
;;
*csh)
shrc="cshrc"
yourshrc=$shrc
;;
*)
shrc="bashrc"
yourshrc=$shrc
;;
esac
printf "
The pythonbrew is installed as:
$ROOT/bin/pythonbrew
You may trash the downloaded $0 from now on.
Pythonbrew environment initiated, required directories are created under
$ROOT
Well-done! Congratulations! Please add the following line to the end
of your ~/.$yourshrc
source $PATH_ETC/$shrc
After that, exit this shell, start a new one, and install some fresh
pythons:
pythonbrew install 2.6.6
pythonbrew install 2.5.5
For further instructions, run:
pythonbrew help
The default help messages will popup and tell you what to do!
Enjoy pythonbrew at $ROOT!!
"
-696
View File
@@ -1,696 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
import os
import sys
import urllib
import errno
import re
import shutil
import filecmp
import subprocess
import tempfile
from HTMLParser import HTMLParser
from optparse import OptionParser
VERSION = "0.4"
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"
DISTRIBUTE_SETUP_DLSITE = "http://python-distribute.org/distribute_setup.py"
PYTHONBREW_DLSITE = "http://github.com/utahta/pythonbrew/raw/master/pythonbrew"
PATH_PYTHONS = "%s/pythons" % ROOT
PATH_BUILD = "%s/build" % ROOT
PATH_DISTS = "%s/dists" % ROOT
PATH_ETC = "%s/etc" % ROOT
PATH_BIN = "%s/bin" % ROOT
parser = OptionParser(usage="%prog COMMAND [OPTIONS]",
version=VERSION,
add_help_option=False)
parser.add_option(
'-h', '--help',
dest='help',
action='store_true',
help='Show help')
parser.disable_interspersed_args()
command_dict = {}
def add_command(command):
command_dict[command.name] = command
#----------------------------------------------------
# exception
#----------------------------------------------------
class BuildingException(Exception):
"""General exception during building"""
#----------------------------------------------------
# util
#----------------------------------------------------
def size_format(b):
kb = 1000
mb = kb*kb
b = float(b)
if b >= mb:
return "%.1fMb" % (b/mb)
if b >= kb:
return "%.1fKb" % (b/kb)
return "%.0fbytes" % (b)
def is_url(name):
if ':' not in name:
return False
scheme = name.split(':', 1)[0].lower()
return scheme in ['http', 'https', 'file', 'ftp']
def splitext(name):
base, ext = os.path.splitext(name)
if base.lower().endswith('.tar'):
ext = base[-4:] + ext
base = base[:-4]
return base, ext
def is_archive_file(name):
ext = splitext(name)[1].lower()
archives = ('.zip', '.tar.gz', '.tar.bz2', '.tgz', '.tar')
if ext in archives:
return True
return False
def makedirs(path):
try:
os.makedirs(path)
except OSError, (e, es):
if errno.EEXIST != e:
raise
def symlink(src, dst):
try:
os.symlink(src, dst)
except:
pass
def unlink(path):
try:
os.unlink(path)
except OSError, (e, es):
if errno.ENOENT != e:
raise
def rm_r(path):
"""like rm -r command."""
if os.path.isdir(path):
shutil.rmtree(path)
else:
unlink(path)
def off():
for root, dirs, files in os.walk(PATH_BIN):
for f in files:
if f == "pythonbrew":
continue
unlink("%s/%s" % (root, f))
unlink("%s/current" % PATH_PYTHONS)
def copy_myself(path):
(fd, src) = tempfile.mkstemp()
fp = file(path, "r")
line = fp.readline()
if line.startswith("#!"):
os.write(fd, "#!%s\n" % os.path.realpath(sys.executable))
else:
os.write(fd, line)
os.write(fd, fp.read())
os.close(fd)
fp.close()
dist = "%s/pythonbrew" % PATH_BIN
if os.path.isfile(src) and os.path.isfile(dist):
if filecmp.cmp(src, dist):
unlink(src)
return (False, dist)
makedirs(PATH_BIN)
shutil.copy(src, dist)
os.chmod(dist, 0755)
unlink(src)
return (True, dist)
#----------------------------------------------------
# classes
#----------------------------------------------------
class Downloader(object):
def __init__(self):
self._msg = ""
self._last_msg = ""
self._bytes = 0.0
def download(self, msg, url, path):
self._msg = msg
self._bytes = 0
urllib.urlretrieve(url, path, self._download_progress)
print " downloaded."
def _download_progress(self, block, blockbytes, maxbytes):
self._bytes += float(blockbytes)
if self._bytes >= maxbytes:
self._bytes = maxbytes
percent = (self._bytes / maxbytes) * 100
max_size = size_format(maxbytes)
now_size = size_format(self._bytes)
now_msg = "\rDownloading %s (%s): %3i%% %s" % (self._msg, max_size, percent, now_size)
padding = " " * (len(self._last_msg) - len(now_msg))
sys.stdout.write("%s%s" % (now_msg, padding))
sys.stdout.flush()
self._last_msg = now_msg
class Subprocess(object):
def __init__(self, log=None, shell=False, cwd=None, print_cmd=True):
self._log = log
self._shell = shell
self._cwd = cwd
self._print_cmd = print_cmd
def chdir(self, cwd):
self._cwd = cwd
def check_call(self, cmd, shell=None, cwd=None):
if shell:
self._shell = shell
if cwd:
self._cwd = cwd
if self._print_cmd:
print cmd
if self._log:
cmd = "(%s) >> '%s' 2>&1" % (cmd, self._log)
retcode = subprocess.call(cmd, shell=self._shell, cwd=self._cwd)
if retcode != 0:
raise BuildingException()
class PythonVersionParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self._versions = []
self._re = re.compile("^(\d+\.\d+(\..*)?)/$")
def handle_starttag(self, tag, attrs):
if tag == "a":
attrs = dict(attrs)
if "href" in attrs:
m = self._re.search(attrs["href"])
if m:
self._versions.append(m.group(1))
def get_sorted_versions(self):
return sorted(self._versions)
class PythonPackages(object):
def __init__(self):
parser = PythonVersionParser()
fp = urllib.urlopen("http://www.python.org/ftp/python/")
parser.feed(fp.read())
fp.close()
parser.close()
self._versions = parser.get_sorted_versions()
def has_version(self, version):
return version in self._versions
def get_packages(self):
return ["Python-%s" % v for v in self._versions]
#----------------------------------------------------
# commands
#----------------------------------------------------
class Command(object):
name = None
usage = None
summary = ""
def __init__(self):
self.parser = OptionParser(usage=self.usage,
prog='%s %s' % (os.path.basename(sys.argv[0]), self.name))
def run(self, args):
options, args = self.parser.parse_args(args)
self.run_command(options, args[1:])
class HelpCommand(Command):
name = "help"
usage = "%prog [COMMAND]"
summary = "Show available commands"
def run_command(self, options, args):
if args:
command = args[0]
if command not in command_dict:
parser.error("Unknown command: `%s`" % command)
return
command = command_dict[command]
command.parser.print_help()
return
parser.print_help()
print
print "Commands available:"
commands = [command_dict[key] for key in sorted(command_dict.keys())]
for command in commands:
print " %s: %s" % (command.name, command.summary)
print
print "Further Instructions:"
print " http://github.com/utahta/pythonbrew"
class InitCommand(Command):
name = "init"
usage = "%prog"
summary = "Run this once to setup the pythonbrew directory ready for installing pythons into"
def run_command(self, options, args):
makedirs(PATH_PYTHONS)
makedirs(PATH_BUILD)
makedirs(PATH_DISTS)
makedirs(PATH_ETC)
os.system("echo 'export PATH=%s/bin:%s/current/bin:${PATH}' > %s/bashrc" % (ROOT, PATH_PYTHONS, PATH_ETC))
os.system("echo 'setenv PATH %s/bin:%s/current/bin:$PATH' > %s/cshrc" % (ROOT, PATH_PYTHONS, PATH_ETC))
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 """+PATH_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"""
class InstallCommand(Command):
name = "install"
usage = "%prog [OPTIONS] PACKAGE_NAMES"
summary = "Build and install the given version of python"
def __init__(self):
super(InstallCommand, self).__init__()
self.parser.add_option(
"-f", "--force",
dest="force",
action="store_true",
default=False,
help="Force installation of a Python."
)
self.parser.add_option(
"-C", "--configure",
dest="configure",
default="",
metavar="CONFIGURE_OPTIONS",
help="Custom configure options."
)
self.parser.add_option(
"-n", "--no-setuptools",
dest="no_setuptools",
action="store_true",
default=False,
help="Skip installation of setuptools."
)
self._logfile = "%s/build.log" % ROOT
def run_command(self, options, args):
if args:
# Install Python
self._install_python(args[0], options)
else:
# Install pythonbrew
self._install_myself()
def _install_myself(self):
executable = os.path.abspath(sys.argv[0])
(retval, dist) = copy_myself(executable)
if not retval:
print "You are already running the installed latest version of pythonbrew."
print "\n%s" % dist
sys.exit()
print """The pythonbrew is installed as:
"""+dist+"""
You may trash the downloaded """+executable+""" from now on.
Next, if this is the first time you've run pythonbrew installation, run:
"""+dist+""" init
And follow the instruction on screen."""
def _get_package(self, name):
if not os.path.isfile(name) and not os.path.isdir(name):
if is_url(name):
basename = os.path.basename(name)
download_url = name
download_path = "%s/%s" % (PATH_DISTS, basename)
else:
m = re.search("^Python-(\d+\.\d+(\..*)?)$", name)
if not m:
print "Unknown package: `%s`" % name
sys.exit(1)
if os.path.isdir("%s/%s" % (PATH_PYTHONS, name)):
print "You are already installed `%s`." % name
sys.exit()
dist_version = m.group(1)
pkgs = PythonPackages()
if not pkgs.has_version(dist_version):
print "Package not found: `%s`" % name
sys.exit(1)
basename = "%s.tgz" % name
download_url = PYTHONDLSITE % (dist_version, basename)
download_path = "%s/%s" % (PATH_DISTS, basename)
if os.path.isfile(download_path):
print "Use the previously fetched %s" % (download_path)
else:
try:
dl = Downloader()
dl.download(
basename,
download_url,
download_path
)
except:
unlink(download_path)
print "\nInterrupt to abort. `%s`" % (download_url)
sys.exit(1)
# iffy
if os.path.getsize(download_path) < 1000000:
print "Failed to download. (maybe not stable version of python) `%s`" % (download_url)
unlink(download_path)
sys.exit(1)
else:
if is_archive_file(name):
basename = os.path.basename(name)
print "Copy the archive file %s to %s/%s" % (name, PATH_DISTS, basename)
shutil.copy(name, "%s/%s" % (PATH_DISTS, basename))
else:
print "Invalid file. `%s`" % name
sys.exit(1)
return basename
def _get_uncompress_command(self, basename):
distpath = "%s/%s" % (PATH_DISTS, basename)
if os.path.isfile(distpath):
ext = splitext(basename)[1]
if ext == ".tar.gz" or ext == ".tgz":
return "tar zxf %s" % (distpath)
elif ext == ".tar.bz2":
return "tar jxf %s" % (distpath)
elif ext == ".tar":
return "tar xf %s" % (distpath)
elif ext == ".zip":
return "unzip %s" % (distpath)
elif os.path.isdir(distpath):
return "mv %s %s/%s" % (distpath, PATH_BUILD, basename)
else:
print "File not found. `%s`" % (basename)
return ""
def _install_python(self, dist, options):
basename = self._get_package(dist)
pkgname = splitext(basename)[0]
install_dir = "%s/%s" % (PATH_PYTHONS, pkgname)
configure = "--prefix=%s %s" % (install_dir, options.configure)
print "Installing %s into %s" % (pkgname, install_dir);
print """This could take a while. You can run the following command on another shell to track the status:
tail -f %s
""" % (self._logfile)
try:
s = Subprocess(log=self._logfile, shell=True, cwd=PATH_BUILD)
s.check_call(self._get_uncompress_command(basename))
s.chdir("%s/%s" % (PATH_BUILD, pkgname))
s.check_call("./configure %s" % (configure))
if options.force:
s.check_call("make")
s.check_call("make install")
else:
s.check_call("make")
s.check_call("make test")
s.check_call("make install")
except:
print """Installing %(pkgname)s failed. See %(ROOT)s/build.log to see why.
pythonbrew install --force %(pkgname)s""" % {"pkgname":pkgname, "ROOT":ROOT}
sys.exit(1)
# install setuptools
self._install_setuptools(pkgname, options.no_setuptools)
print """
Installed %(pkgname)s successfully. Run the following command to switch to it.
pythonbrew switch %(pkgname)s""" % {"pkgname":pkgname}
def _install_setuptools(self, pkgname, no_setuptools):
if no_setuptools:
print "Skip installation setuptools."
return
if re.match("^Python-3.*", pkgname):
is_python3 = True
else:
is_python3 = False
download_url = DISTRIBUTE_SETUP_DLSITE
basename = os.path.basename(download_url)
dl = Downloader()
dl.download(basename, download_url, "%s/%s" % (PATH_DISTS, basename))
if is_python3:
if os.path.isfile("%s/%s/bin/python3" % (PATH_PYTHONS, pkgname)):
pyexec = "%s/%s/bin/python3" % (PATH_PYTHONS, pkgname)
elif os.path.isfile("%s/%s/bin/python3.0" % (PATH_PYTHONS, pkgname)):
pyexec = "%s/%s/bin/python3.0" % (PATH_PYTHONS, pkgname)
else:
print "Python3 binary not found. `%s/%s`" % (PATH_PYTHONS, pkgname)
return
else:
pyexec = "%s/%s/bin/python" % (PATH_PYTHONS, pkgname)
try:
s = Subprocess(log=self._logfile, shell=True, cwd=PATH_DISTS)
s.check_call("%s %s" % (pyexec, basename))
if os.path.isfile("%s/%s/bin/easy_install" % (PATH_PYTHONS, pkgname)) and not is_python3:
s.check_call("%s/%s/bin/easy_install pip" % (PATH_PYTHONS, pkgname), cwd=None)
except:
print "Installing setuptools failed. See %s/build.log to see why." % (ROOT)
sys.exit(1)
class InstalledCommand(Command):
name = "installed"
usage = "%prog"
summary = "List the installed versions of python"
def run_command(self, options, args):
if not os.path.islink("%s/current" % PATH_PYTHONS):
cur = os.path.realpath("%s/bin/python" % ROOT)
print "%s (*)" % cur
elif os.path.islink("%s/current" % PATH_PYTHONS):
cur = os.path.basename(os.path.realpath("%s/current" % PATH_PYTHONS))
else:
cur = ""
for d in sorted(os.listdir("%s/" % PATH_PYTHONS)):
if d == "current":
continue
if cur == d:
print "%s (*)" % cur
else:
print "%s" % (d)
class SwitchCommand(Command):
name = "switch"
usage = "%prog PACKAGE"
summary = "Switch to the given version"
def run_command(self, options, args):
if args:
dist = args[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 "`%s` is not python binary." % dist
return
elif not os.path.isdir( "%s/%s" % (PATH_PYTHONS, dist) ):
print "`%s` is not installed." % dist
return
self._switch_dir( distdir )
def _switch_file(self, dist):
off()
symlink(dist, "%s/python" % PATH_BIN)
print "Switched to "+dist
def _switch_dir(self, dist):
off()
symlink(dist, "%s/current" % PATH_PYTHONS)
for root, dirs, files in os.walk("%s/current/bin/" % PATH_PYTHONS):
for f in files:
symlink("%s%s" % (root, f), "%s/%s" % (PATH_BIN, f))
break
# I want better code
if not os.path.isfile("%s/python" % PATH_BIN):
if os.path.isfile("%s/python3" % PATH_BIN):
symlink(os.path.realpath("%s/python3" % PATH_BIN), "%s/python" % PATH_BIN)
elif os.path.isfile("%s/python3.0" % PATH_BIN):
symlink(os.path.realpath("%s/python3.0" % PATH_BIN), "%s/python" % PATH_BIN)
print "Switched to "+dist
class OffCommand(Command):
name = "off"
usage = "%prog"
summary = "Disable pythonbrew"
def run_command(self, options, args):
off()
class VersionCommand(Command):
name = "version"
usage = "%prog"
summary = "Show version"
def run_command(self, options, args):
print VERSION
class SearchCommand(Command):
name = "search"
usage = "%prog Python-<VERSION>"
summary = "Search Python packages"
def run_command(self, options, args):
pkgs = PythonPackages()
if args:
pattern = args[0]
_re = re.compile(r"%s" % pattern)
pkgnames = []
for pkgname in pkgs.get_packages():
if _re.match(pkgname):
pkgnames.append(pkgname)
if pkgnames:
for pkgname in pkgnames:
print pkgname
else:
print "Package not found. `%s`" % pattern
else:
for pkgname in pkgs.get_packages():
print pkgname
class UninstallCommand(Command):
name = "uninstall"
usage = "%prog Python-<VERSION>"
summary = "Uninstall the given version of python"
def run_command(self, options, args):
if args:
pkgname = args[0]
pkgpath = "%s/%s" % (PATH_PYTHONS, pkgname)
if not os.path.isdir(pkgpath):
print "%s is not installed." % pkgname
sys.exit(1)
if os.path.islink("%s/current" % PATH_PYTHONS):
curpath = os.path.realpath("%s/current" % PATH_PYTHONS)
if pkgpath == curpath:
off()
rm_r(pkgpath)
else:
self.parser.print_help()
class CleanCommand(Command):
name = "clean"
usage = "%prog"
summary = "Remove stale source folders and archives"
def run_command(self, options, args):
self._clean(PATH_BUILD)
self._clean(PATH_DISTS)
def _clean(self, root):
for dir in os.listdir(root):
rm_r("%s/%s" % (root, dir))
class UpdateCommand(Command):
name = "update"
usage = "%prog"
summary = "Upgrades pythonbrew to the latest version"
def run_command(self, options, args):
download_url = PYTHONBREW_DLSITE
basename = os.path.basename(download_url)
download_path = "%s/%s" % (PATH_DISTS, basename)
try:
d = Downloader()
d.download(basename, download_url, download_path)
except:
print "Failed to download. `%s`" % download_url
sys.exit(1)
(retval, dist) = copy_myself(download_path)
if not retval:
print "You are already running the installed latest version of pythonbrew."
print "\n%s" % dist
sys.exit()
print "The pythonbrew has been updated."
class Pythonbrew(object):
def run(self):
options, args = parser.parse_args(sys.argv[1:])
if options.help and not args:
args = ["help"]
if not args:
parser.error('You must give a command (use "pythonbrew help" to see a list of commands)')
return
add_command(HelpCommand())
add_command(InitCommand())
add_command(InstallCommand())
add_command(InstalledCommand())
add_command(SwitchCommand())
add_command(OffCommand())
add_command(VersionCommand())
add_command(SearchCommand())
add_command(UninstallCommand())
add_command(CleanCommand())
add_command(UpdateCommand())
command = args[0].lower()
if command not in command_dict:
parser.error("Unknown command: `%s`" % command)
return
command = command_dict[command]
command.run(args)
def main():
p = Pythonbrew()
p.run()
if __name__ == "__main__":
main()
+19
View File
@@ -0,0 +1,19 @@
import sys
from pythonbrew.basecommand import command_dict, load_all_commands
from pythonbrew.baseparser import parser
def main():
options, args = parser.parse_args(sys.argv[1:])
if options.help and not args:
args = ["help"]
if not args:
parser.error('You must give a command (use "pythonbrew help" to see a list of commands)')
return
load_all_commands()
command = args[0].lower()
if command not in command_dict:
parser.error("Unknown command: `%s`" % command)
return
command = command_dict[command]
command.run(args)
+38
View File
@@ -0,0 +1,38 @@
import os
import sys
import re
from optparse import OptionParser
from pythonbrew import commands
from pythonbrew.define import PATH_BIN_PYTHONBREW
command_dict = {}
class Command(object):
name = None
usage = None
summary = ""
def __init__(self):
self.parser = OptionParser(usage=self.usage,
prog='%s %s' % (PATH_BIN_PYTHONBREW, self.name))
command_dict[self.name] = self
def run(self, args):
options, args = self.parser.parse_args(args)
self.run_command(options, args[1:])
def load_command(name):
full_name = 'pythonbrew.commands.%s' % name
if full_name in sys.modules:
return
try:
__import__(full_name)
except ImportError:
pass
def load_all_commands():
for name in command_names():
load_command(name)
def command_names():
return [path[:-3] for path in os.listdir(commands.__path__[0]) if not re.match("(__init__\.py$|.*\.pyc$)", path)]
+13
View File
@@ -0,0 +1,13 @@
from optparse import OptionParser
from pythonbrew.define import VERSION, PATH_BIN_PYTHONBREW
parser = OptionParser(usage="%prog COMMAND [OPTIONS]",
prog=PATH_BIN_PYTHONBREW,
version=VERSION,
add_help_option=False)
parser.add_option(
'-h', '--help',
dest='help',
action='store_true',
help='Show help')
parser.disable_interspersed_args()
View File
+19
View File
@@ -0,0 +1,19 @@
import os
from pythonbrew.basecommand import Command
from pythonbrew.define import PATH_BUILD, PATH_DISTS
from pythonbrew.util import rm_r
class CleanCommand(Command):
name = "clean"
usage = "%prog"
summary = "Remove stale source folders and archives"
def run_command(self, options, args):
self._clean(PATH_BUILD)
self._clean(PATH_DISTS)
def _clean(self, root):
for dir in os.listdir(root):
rm_r("%s/%s" % (root, dir))
CleanCommand()
+27
View File
@@ -0,0 +1,27 @@
from pythonbrew.basecommand import Command, command_dict
from pythonbrew.baseparser import parser
from pythonbrew.log import logger
class HelpCommand(Command):
name = "help"
usage = "%prog [COMMAND]"
summary = "Show available commands"
def run_command(self, options, args):
if args:
command = args[0]
if command not in command_dict:
parser.error("Unknown command: `%s`" % command)
return
command = command_dict[command]
command.parser.print_help()
return
parser.print_help()
logger.info("\nCommands available:")
commands = [command_dict[key] for key in sorted(command_dict.keys())]
for command in commands:
logger.info(" %s: %s" % (command.name, command.summary))
logger.info("\nFurther Instructions:")
logger.info(" http://github.com/utahta/pythonbrew")
HelpCommand()
+184
View File
@@ -0,0 +1,184 @@
import os
import sys
import re
import shutil
from pythonbrew.basecommand import Command
from pythonbrew.util import unlink, splitext, Subprocess, Package, makedirs,\
rm_r
from pythonbrew.define import ROOT, PATH_PYTHONS, PATH_DISTS, PATH_BUILD, PATH_LOG, DISTRIBUTE_SETUP_DLSITE
from pythonbrew.log import logger
from pythonbrew.downloader import get_python_package_url, Downloader
class InstallCommand(Command):
name = "install"
usage = "%prog [OPTIONS] VERSION"
summary = "Build and install the given version of python"
def __init__(self):
super(InstallCommand, self).__init__()
self.parser.add_option(
"-f", "--force",
dest="force",
action="store_true",
default=False,
help="Force installation of a Python."
)
self.parser.add_option(
"-C", "--configure",
dest="configure",
default="",
metavar="CONFIGURE_OPTIONS",
help="Custom configure options."
)
self.parser.add_option(
"-n", "--no-setuptools",
dest="no_setuptools",
action="store_true",
default=False,
help="Skip installation of setuptools."
)
self._logfile = "%s/build.log" % PATH_LOG
def run_command(self, options, args):
if args:
# Install Python
self._install_python(args[0], options)
else:
logger.error("Package not found.")
def _install_python(self, dist, options):
pkg = Package(dist)
distname = self._download_package(pkg)
pkgname = pkg.name
version = pkg.version
install_dir = "%s/%s" % (PATH_PYTHONS, pkgname)
configure = "--prefix=%s %s" % (install_dir, options.configure)
logger.info("")
logger.info("This could take a while. You can run the following command on another shell to track the status:")
logger.info(" tail -f %s" % self._logfile)
logger.info("")
try:
s = Subprocess(log=self._logfile, shell=True, cwd=PATH_BUILD, print_cmd=False)
logger.info("Extracting %s" % distname)
s.check_call(self._get_uncompress_command(distname))
logger.info("Installing %s into %s" % (pkgname, install_dir))
s.chdir("%s/%s" % (PATH_BUILD, pkgname))
s.check_call("./configure %s" % (configure))
if options.force:
s.check_call("make")
else:
s.check_call("make")
s.check_call("make test")
if version == "1.5.2" or version == "1.6.1":
makedirs(install_dir)
s.check_call("make install")
except:
rm_r(install_dir)
logger.error("""Failed to install %(pkgname)s. See %(ROOT)s/build.log to see why.
pythonbrew install --force %(version)s""" % {"pkgname":pkgname, "ROOT":ROOT, "version":version})
sys.exit(1)
# install setuptools
self._install_setuptools(pkgname, options.no_setuptools)
logger.info("""
Installed %(pkgname)s successfully. Run the following command to switch to %(pkgname)s.
pythonbrew switch %(version)s""" % {"pkgname":pkgname, "version":version})
def _download_package(self, pkg):
pkgname = pkg.name
version = pkg.version
if os.path.isdir("%s/%s" % (PATH_PYTHONS, pkgname)):
logger.error("You are already installed `%s`." % pkgname)
sys.exit(1)
download_url = get_python_package_url(version)
if not download_url:
logger.error("Unknown package: `%s`" % pkgname)
sys.exit(1)
distname = os.path.basename(download_url)
download_path = "%s/%s" % (PATH_DISTS, distname)
if os.path.isfile(download_path):
logger.info("Use the previously fetched %s" % (download_path))
else:
try:
dl = Downloader()
dl.download(
distname,
download_url,
download_path
)
except:
unlink(download_path)
logger.info("\nInterrupt to abort. `%s`" % (download_url))
sys.exit(1)
# iffy
if os.path.getsize(download_path) < 1000000:
logger.error("Failed to download. `%s`" % (download_url))
unlink(download_path)
sys.exit(1)
return distname
def _get_uncompress_command(self, basename):
distpath = "%s/%s" % (PATH_DISTS, basename)
if os.path.isfile(distpath):
ext = splitext(basename)[1]
if ext == ".tar.gz" or ext == ".tgz":
return "tar zxf %s" % (distpath)
elif ext == ".tar.bz2":
return "tar jxf %s" % (distpath)
elif ext == ".tar":
return "tar xf %s" % (distpath)
elif ext == ".zip":
return "unzip %s" % (distpath)
elif os.path.isdir(distpath):
return "mv %s %s/%s" % (distpath, PATH_BUILD, basename)
else:
logger.error("File not found. `%s`" % (basename))
return ""
def _install_setuptools(self, pkgname, no_setuptools):
if no_setuptools:
logger.info("Skip installation setuptools.")
return
if re.match("^Python-3.*", pkgname):
is_python3 = True
else:
is_python3 = False
download_url = DISTRIBUTE_SETUP_DLSITE
basename = os.path.basename(download_url)
dl = Downloader()
dl.download(basename, download_url, "%s/%s" % (PATH_DISTS, basename))
install_dir = "%s/%s" % (PATH_PYTHONS, pkgname)
if is_python3:
if os.path.isfile("%s/bin/python3" % (install_dir)):
pyexec = "%s/bin/python3" % (install_dir)
elif os.path.isfile("%s/bin/python3.0" % (install_dir)):
pyexec = "%s/bin/python3.0" % (install_dir)
else:
logger.error("Python3 binary not found. `%s`" % (install_dir))
return
else:
pyexec = "%s/bin/python" % (install_dir)
try:
s = Subprocess(log=self._logfile, shell=True, cwd=PATH_DISTS, print_cmd=False)
logger.info("Installing distribute into %s" % install_dir)
s.check_call("%s %s" % (pyexec, basename))
if os.path.isfile("%s/bin/easy_install" % (install_dir)) and not is_python3:
logger.info("Installing pip into %s" % install_dir)
s.check_call("%s/bin/easy_install pip" % (install_dir), cwd=None)
except:
logger.error("Failed to install setuptools. See %s/build.log to see why." % (ROOT))
logger.info("Skip install setuptools.")
InstallCommand()
+26
View File
@@ -0,0 +1,26 @@
import os
from pythonbrew.basecommand import Command
from pythonbrew.define import PATH_PYTHONS
from pythonbrew.log import logger
import sys
class InstalledCommand(Command):
name = "installed"
usage = "%prog"
summary = "List the installed versions of python"
def run_command(self, options, args):
cur = ""
if not os.path.islink("%s/current" % PATH_PYTHONS):
logger.info("%s (*)" % sys.executable)
elif os.path.islink("%s/current" % PATH_PYTHONS):
cur = os.path.basename(os.path.realpath("%s/current" % PATH_PYTHONS))
for d in sorted(os.listdir("%s/" % PATH_PYTHONS)):
if d == "current":
continue
if cur == d:
logger.info("%s (*)" % cur)
else:
logger.info("%s" % (d))
InstalledCommand()
+34
View File
@@ -0,0 +1,34 @@
import re
from pythonbrew.basecommand import Command
from pythonbrew.define import PYTHON_PACKAGE_URL
from pythonbrew.util import Package
from pythonbrew.log import logger
class ListCommand(Command):
name = "list"
usage = "%prog [VERSION]"
summary = "List the available install version of python"
def run_command(self, options, args):
if args:
pkg = Package(args[0])
_re = re.compile(r"%s" % pkg.name)
pkgs = []
for pkgname in self._get_packages_name():
if _re.match(pkgname):
pkgs.append(pkgname)
if pkgs:
logger.info("Pythons:")
for pkgname in pkgs:
logger.info(" %s" % pkgname)
else:
print "Package not found. `%s`" % pkg.name
else:
logger.info("Pythons:")
for pkgname in self._get_packages_name():
logger.info(" %s" % pkgname)
def _get_packages_name(self):
return ["Python-%s" % version for version in sorted(PYTHON_PACKAGE_URL.keys())]
ListCommand()
+12
View File
@@ -0,0 +1,12 @@
from pythonbrew.basecommand import Command
from pythonbrew.util import off
class OffCommand(Command):
name = "off"
usage = "%prog"
summary = "Disable pythonbrew"
def run_command(self, options, args):
off()
OffCommand()
+41
View File
@@ -0,0 +1,41 @@
import os
import sys
import re
from pythonbrew.basecommand import Command
from pythonbrew.define import PATH_PYTHONS, PATH_BIN
from pythonbrew.util import off, symlink, Package
from pythonbrew.log import logger
class SwitchCommand(Command):
name = "switch"
usage = "%prog VERSION"
summary = "Switch to the given version"
def run_command(self, options, args):
if not args:
logger.error("Unrecognized command line argument: argument not found.")
sys.exit(1)
pkg = Package(args[0])
pkgname = pkg.name
pkgdir = "%s/%s" % (PATH_PYTHONS, pkgname)
if not os.path.isdir(pkgdir):
logger.error("`%s` is not installed." % pkgname)
sys.exit(1)
self._switch_dir(pkgdir)
logger.info("Switched to %s" % pkgname)
def _switch_dir(self, pkgdir):
off()
symlink(pkgdir, "%s/current" % PATH_PYTHONS)
for root, dirs, files in os.walk("%s/current/bin/" % PATH_PYTHONS):
for f in files:
symlink("%s%s" % (root, f), "%s/%s" % (PATH_BIN, f))
break
# I want better code
if not os.path.isfile("%s/python" % PATH_BIN):
if os.path.isfile("%s/python3" % PATH_BIN):
symlink(os.path.realpath("%s/python3" % PATH_BIN), "%s/python" % PATH_BIN)
elif os.path.isfile("%s/python3.0" % PATH_BIN):
symlink(os.path.realpath("%s/python3.0" % PATH_BIN), "%s/python" % PATH_BIN)
SwitchCommand()
+29
View File
@@ -0,0 +1,29 @@
import os
import sys
from pythonbrew.basecommand import Command
from pythonbrew.define import PATH_PYTHONS
from pythonbrew.util import off, rm_r, Package
from pythonbrew.log import logger
class UninstallCommand(Command):
name = "uninstall"
usage = "%prog VERSION"
summary = "Uninstall the given version of python"
def run_command(self, options, args):
if args:
pkg = Package(args[0])
pkgname = pkg.name
pkgpath = "%s/%s" % (PATH_PYTHONS, pkgname)
if not os.path.isdir(pkgpath):
logger.error("`%s` is not installed." % pkgname)
sys.exit(1)
if os.path.islink("%s/current" % PATH_PYTHONS):
curpath = os.path.realpath("%s/current" % PATH_PYTHONS)
if pkgpath == curpath:
off()
rm_r(pkgpath)
else:
self.parser.print_help()
UninstallCommand()
+64
View File
@@ -0,0 +1,64 @@
import os
import sys
import re
from pythonbrew.basecommand import Command
from pythonbrew.define import PATH_DISTS, VERSION, PYTHONBREW_DIRNAME, ROOT
from pythonbrew.log import logger
from pythonbrew.downloader import Downloader, get_pythonbrew_update_url
from pythonbrew.util import Subprocess, rm_r
class UpdateCommand(Command):
name = "update"
usage = "%prog"
summary = "Upgrades pythonbrew to the latest version"
def run_command(self, options, args):
version = "head"
if args:
version = args[0]
# check for latest version
if version == VERSION:
logger.info("You are already running the installed latest version of pythonbrew.")
sys.exit()
download_url = get_pythonbrew_update_url(version)
if not download_url:
logger.error("`%s` of pythonbrew not found." % version)
sys.exit(1)
distname = "pythonbrew.tgz"
download_path = "%s/%s" % (PATH_DISTS, distname)
try:
d = Downloader()
d.download(distname, download_url, download_path)
except:
logger.error("Failed to download. `%s`" % download_url)
sys.exit(1)
_re = re.compile("^%s.*" % PYTHONBREW_DIRNAME)
for name in os.listdir(PATH_DISTS):
if _re.match(name):
rm_r("%s/%s" % (PATH_DISTS, name))
try:
s = Subprocess(shell=True, cwd=PATH_DISTS, print_cmd=False)
logger.info("Extracting %s" % download_path)
s.check_call("tar zxf %s" % download_path)
except:
logger.error("Failed to update pythonbrew.")
sys.exit(1)
for name in os.listdir(PATH_DISTS):
if _re.match(name):
try:
installer_path = "%s/%s" % (PATH_DISTS, name)
s = Subprocess(shell=True, cwd=PATH_DISTS, print_cmd=False)
logger.info("Installing %s into %s" % (installer_path, ROOT))
s.check_call("%s %s/pythonbrew_install.py" % (sys.executable, installer_path))
except:
logger.error("Failed to update pythonbrew.")
sys.exit(1)
break
logger.info("The pythonbrew has been updated.")
UpdateCommand()
+13
View File
@@ -0,0 +1,13 @@
from pythonbrew.basecommand import Command
from pythonbrew.define import VERSION
from pythonbrew.log import logger
class VersionCommand(Command):
name = "version"
usage = "%prog"
summary = "Show version"
def run_command(self, options, args):
logger.info(VERSION)
VersionCommand()
+56
View File
@@ -0,0 +1,56 @@
import os
VERSION = "0.5"
if os.environ.has_key("PYTHONBREW_ROOT"):
ROOT = os.environ["PYTHONBREW_ROOT"]
else:
ROOT = "%s/.pythonbrew" % os.environ["HOME"]
INSTALLER_ROOT = os.path.dirname(os.path.abspath(__file__))
PATH_PYTHONS = "%s/pythons" % ROOT
PATH_BUILD = "%s/build" % ROOT
PATH_DISTS = "%s/dists" % ROOT
PATH_ETC = "%s/etc" % ROOT
PATH_BIN = "%s/bin" % ROOT
PATH_LOG = "%s/log" % ROOT
PATH_SCRIPTS = "%s/scripts" % ROOT
PATH_SCRIPTS_PYTHONBREW = "%s/pythonbrew" % PATH_SCRIPTS
PATH_SCRIPTS_PYTHONBREW_COMMANDS = "%s/commands" % PATH_SCRIPTS_PYTHONBREW
# file path
PATH_BIN_PYTHONBREW = "%s/pythonbrew" % PATH_BIN
PATH_BIN_PYBREW = "%s/pybrew" % PATH_BIN # pybrew is symlink as pythonbrew
# download setuptools url
DISTRIBUTE_SETUP_DLSITE = "http://python-distribute.org/distribute_setup.py"
# download pythonbrew url
PYTHONBREW_UPDATE_URL = {
"head": "http://github.com/utahta/pythonbrew/tarball/master"
}
PYTHONBREW_DIRNAME = "utahta-pythonbrew"
# download Python package url
PYTHON_PACKAGE_URL = {}
PYTHON_PACKAGE_URL["1.5.2"] = "http://www.python.org/ftp/python/src/py152.tgz"
PYTHON_PACKAGE_URL["1.6.1"] = "http://www.python.org/download/releases/1.6.1/Python-1.6.1.tar.gz"
_PYTHON_PACKAGE_VERSIONS = [
"2.0", "2.0.1",
"2.1", "2.1.1", "2.1.2", "2.1.3",
"2.2", "2.2.1", "2.2.2", "2.2.3",
"2.3", "2.3.1", "2.3.2", "2.3.4", "2.3.5", "2.3.6", "2.3.7",
"2.4", "2.4.1", "2.4.2", "2.4.3", "2.4.4", "2.4.5", "2.4.6",
"2.5", "2.5.1", "2.5.2", "2.5.3", "2.5.4", "2.5.5",
"2.6", "2.6.1", "2.6.2", "2.6.3", "2.6.4", "2.6.5", "2.6.6",
"2.7",
"3.0", "3.0.1",
"3.1", "3.1.1", "3.1.2",
]
for version in _PYTHON_PACKAGE_VERSIONS:
PYTHON_PACKAGE_URL[version] = "http://www.python.org/ftp/python/%s/Python-%s.tgz" % (version, version)
del _PYTHON_PACKAGE_VERSIONS
PYTHON_PACKAGE_URL["3.2a1"] = "http://www.python.org/ftp/python/3.2/Python-3.2a1.tgz"
PYTHON_PACKAGE_URL["3.2a2"] = "http://www.python.org/ftp/python/3.2/Python-3.2a2.tgz"
+39
View File
@@ -0,0 +1,39 @@
import sys
import urllib
from pythonbrew.util import size_format
from pythonbrew.define import PYTHON_PACKAGE_URL, PYTHONBREW_UPDATE_URL
class Downloader(object):
def __init__(self):
self._msg = ""
self._last_msg = ""
self._bytes = 0.0
def download(self, msg, url, path):
self._msg = msg
self._bytes = 0
urllib.urlretrieve(url, path, self._download_progress)
print " downloaded."
def _download_progress(self, block, blockbytes, maxbytes):
self._bytes += float(blockbytes)
if self._bytes >= maxbytes:
self._bytes = maxbytes
percent = (self._bytes / maxbytes) * 100
max_size = size_format(maxbytes)
now_size = size_format(self._bytes)
now_msg = "\rDownloading %s (%s): %3i%% %s" % (self._msg, max_size, percent, now_size)
padding = " " * (len(self._last_msg) - len(now_msg))
sys.stdout.write("%s%s" % (now_msg, padding))
sys.stdout.flush()
self._last_msg = now_msg
def get_pythonbrew_update_url(version):
if PYTHONBREW_UPDATE_URL.has_key(version):
return PYTHONBREW_UPDATE_URL[version]
return None
def get_python_package_url(version):
if PYTHON_PACKAGE_URL.has_key(version):
return PYTHON_PACKAGE_URL[version]
return None
+3
View File
@@ -0,0 +1,3 @@
class BuildingException(Exception):
"""General exception during building"""
+46
View File
@@ -0,0 +1,46 @@
import os
import sys
import glob
import shutil
from pythonbrew.util import makedirs, symlink
from pythonbrew.define import PATH_BUILD, PATH_BIN, PATH_DISTS, PATH_PYTHONS,\
PATH_ETC, PATH_SCRIPTS, PATH_SCRIPTS_PYTHONBREW,\
PATH_SCRIPTS_PYTHONBREW_COMMANDS, INSTALLER_ROOT, PATH_BIN_PYTHONBREW,\
PATH_BIN_PYBREW, ROOT, PATH_LOG
def install_pythonbrew():
makedirs(PATH_PYTHONS)
makedirs(PATH_BUILD)
makedirs(PATH_DISTS)
makedirs(PATH_ETC)
makedirs(PATH_BIN)
makedirs(PATH_LOG)
makedirs(PATH_SCRIPTS)
makedirs(PATH_SCRIPTS_PYTHONBREW)
makedirs(PATH_SCRIPTS_PYTHONBREW_COMMANDS)
for path in glob.glob("%s/*.py" % INSTALLER_ROOT):
shutil.copy(path, PATH_SCRIPTS_PYTHONBREW)
for path in glob.glob("%s/commands/*.py" % INSTALLER_ROOT):
shutil.copy(path, PATH_SCRIPTS_PYTHONBREW_COMMANDS)
fp = open("%s/pythonbrew.py" % PATH_SCRIPTS, "w")
fp.write("""import pythonbrew
if __name__ == "__main__":
pythonbrew.main()
""")
fp.close()
fp = open(PATH_BIN_PYTHONBREW, "w")
fp.write("""#!/usr/bin/env bash
%s %s/pythonbrew.py $@
""" % (sys.executable, PATH_SCRIPTS))
fp.close()
os.chmod(PATH_BIN_PYTHONBREW, 0755)
symlink(PATH_BIN_PYTHONBREW, PATH_BIN_PYBREW) # pyb as pythonbrew
os.system("echo 'export PATH=%s/bin:%s/current/bin:${PATH}' > %s/bashrc" % (ROOT, PATH_PYTHONS, PATH_ETC))
os.system("echo 'setenv PATH %s/bin:%s/current/bin:$PATH' > %s/cshrc" % (ROOT, PATH_PYTHONS, PATH_ETC))
+43
View File
@@ -0,0 +1,43 @@
import sys
import logging
class Logger(object):
DEBUG = logging.DEBUG
INFO = logging.INFO
ERROR = logging.ERROR
def __init__(self):
self._consumers = []
consumer = logging.getLogger('info')
consumer.setLevel(Logger.INFO)
hdlr = logging.StreamHandler(sys.stdout)
hdlr.setFormatter(logging.Formatter("%(message)s"))
consumer.addHandler(hdlr)
self.add_consumer(Logger.INFO, consumer)
consumer = logging.getLogger('error')
consumer.setLevel(Logger.ERROR)
hdlr = logging.StreamHandler(sys.stderr)
hdlr.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
consumer.addHandler(hdlr)
self.add_consumer(Logger.ERROR, consumer)
def debug(self, msg, *args, **keys):
self._log(Logger.DEBUG, msg, *args, **keys)
def info(self, msg, *args, **keys):
self._log(Logger.INFO, msg, *args, **keys)
def error(self, msg, *args, **keys):
self._log(Logger.ERROR, msg, *args, **keys)
def _log(self, level, msg, *args, **keys):
for (consumer_level, consumer) in self._consumers:
if level == consumer_level:
consumer.log(level, msg, *args, **keys)
def add_consumer(self, level, consumer):
self._consumers.append((level, consumer))
logger = Logger()
+111
View File
@@ -0,0 +1,111 @@
import os
import sys
import errno
import shutil
import urllib
import subprocess
import re
from pythonbrew.define import PATH_BIN, PATH_PYTHONS
from pythonbrew.exceptions import BuildingException
from pythonbrew.log import logger
def size_format(b):
kb = 1000
mb = kb*kb
b = float(b)
if b >= mb:
return "%.1fMb" % (b/mb)
if b >= kb:
return "%.1fKb" % (b/kb)
return "%.0fbytes" % (b)
def is_url(name):
if ':' not in name:
return False
scheme = name.split(':', 1)[0].lower()
return scheme in ['http', 'https', 'file', 'ftp']
def splitext(name):
base, ext = os.path.splitext(name)
if base.lower().endswith('.tar'):
ext = base[-4:] + ext
base = base[:-4]
return base, ext
def is_archive_file(name):
ext = splitext(name)[1].lower()
archives = ('.zip', '.tar.gz', '.tar.bz2', '.tgz', '.tar')
if ext in archives:
return True
return False
def makedirs(path):
try:
os.makedirs(path)
except OSError, (e, es):
if errno.EEXIST != e:
raise
def symlink(src, dst):
try:
os.symlink(src, dst)
except:
pass
def unlink(path):
try:
os.unlink(path)
except OSError, (e, es):
if errno.ENOENT != e:
raise
def rm_r(path):
"""like rm -r command."""
if os.path.isdir(path):
shutil.rmtree(path)
else:
unlink(path)
def off():
for root, dirs, files in os.walk(PATH_BIN):
for f in files:
if f == "pythonbrew" or f == "pybrew":
continue
unlink("%s/%s" % (root, f))
unlink("%s/current" % PATH_PYTHONS)
class Subprocess(object):
def __init__(self, log=None, shell=False, cwd=None, print_cmd=True):
self._log = log
self._shell = shell
self._cwd = cwd
self._print_cmd = print_cmd
def chdir(self, cwd):
self._cwd = cwd
def check_call(self, cmd, shell=None, cwd=None):
if shell:
self._shell = shell
if cwd:
self._cwd = cwd
if self._print_cmd:
logger.info(cmd)
if self._log:
cmd = "(%s) >> '%s' 2>&1" % (cmd, self._log)
retcode = subprocess.call(cmd, shell=self._shell, cwd=self._cwd)
if retcode != 0:
raise BuildingException()
class Package(object):
def __init__(self, name):
self.name = None
self.version = None
m = re.search("^Python-(.*)$", name)
if m:
self.name = name
self.version = m.group(1)
else:
self.name = "Python-%s" % name
self.version = name
+3
View File
@@ -0,0 +1,3 @@
from pythonbrew.installer import install_pythonbrew
if __name__ == "__main__":
install_pythonbrew()