diff --git a/pythonbrew b/pythonbrew deleted file mode 100755 index b324365..0000000 --- a/pythonbrew +++ /dev/null @@ -1,595 +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 -from HTMLParser import HTMLParser -from optparse import OptionParser - -VERSION = "0.3" -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" - -PATH_PYTHONS = "%s/pythons" % ROOT -PATH_BUILD = "%s/build" % ROOT -PATH_DISTS = "%s/dists" % ROOT -PATH_ETC = "%s/etc" % 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(name): - try: - os.makedirs(name) - except OSError, (e,es): - if errno.EEXIST != e: - raise - -def symlink(src, dst): - try: - os.symlink(src, dst) - except: - pass - -def unlink(name): - try: - os.unlink(name) - except OSError, (e,es): - if errno.ENOENT != e: - raise - -def clean_switch_symlink(): - for root, dirs, files in os.walk("%s/bin/" % ROOT): - for f in files: - if f == "pythonbrew": - continue - unlink("%s%s" % (root, f)) - -#---------------------------------------------------- -# 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( - "-b", "--build-options", - dest="build_options", - default="", - help="Set 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 - executable = os.path.abspath(sys.argv[0]) - 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; - return - 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.""" - - 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) - 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: - os.remove(download_path) - print "\nInterrupt to abort. `%s`" % (download_url) - sys.exit(1) - # iffy - if os.path.getsize(download_path) < 1000000: - print "Invalid file downloaded. (maybe 404 not found?) `%s`" % (download_url) - os.remove(download_path) - sys.exit(1) - else: - if os.path.isfile(name): - basename = os.path.basename(name) - print "Copy the file %s to %s/%s" % (name, PATH_DISTS, basename) - shutil.copy(name, "%s/%s" % (PATH_DISTS, basename)) - elif os.path.isdir(name): - basename = name - print "Copy the directory %s to %s/%s" % (name, PATH_DISTS, basename) - shutil.copytree(name, "%s/%s" % (PATH_DISTS, basename)) - else: - print "Unknown object. `%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 "Unknown object. `%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) - build_options = "--prefix=%s %s" % (install_dir, options.build_options) - 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" % (build_options)) - 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 ez_setup - self._install_ez_setup(pkgname, options.no_setuptools) - print """Installed """+pkgname+""" successfully. Run the following command to switch to it. - - pythonbrew switch """+pkgname - - def _install_ez_setup(self, pydist, no_setuptools): - if no_setuptools: - print "Skip installation setuptools." - return - basename = os.path.basename(EZSETUPDLSITE) - - dl = Downloader() - dl.download(basename, EZSETUPDLSITE, "%s/%s" % (PATH_DISTS, basename)) - - os.system("%s/%s/bin/python %s/%s" % (PATH_PYTHONS, pydist, PATH_DISTS, basename)) - if os.path.isfile("%s/%s/bin/easy_install" % (PATH_PYTHONS, pydist)): - os.system("%s/%s/bin/easy_install pip" % (PATH_PYTHONS, pydist)) - -class InstalledCommand(Command): - name = "installed" - usage = "%prog" - summary = "List the installed versions of python" - - def run_command(self, options, args): - if os.path.islink("%s/current" % PATH_PYTHONS): - if os.path.realpath("%s/current" % PATH_PYTHONS) == ROOT: - cur = os.path.realpath("%s/bin/python" % ROOT) - else: - cur = os.path.basename(os.path.realpath("%s/current" % PATH_PYTHONS)) - print "%s (*)" % cur - else: - cur = "" - for d in os.listdir("%s/" % PATH_PYTHONS): - if d == "current" or cur == "%s" % (d): - continue - 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 "Invalid binary: `%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/%s" % (PATH_PYTHONS, dist) ): - print "Unknown package: `%s`" % dist - return - self._switch_dir( distdir ) - - def _switch_file(self, dist): - unlink("%s/current" % PATH_PYTHONS) - unlink("%s/bin/python" % ROOT) - clean_switch_symlink() - symlink(dist, "%s/bin/python" % ROOT) - symlink(ROOT, "%s/current" % PATH_PYTHONS) - print "Switched to "+dist - - def _switch_dir(self, dist): - unlink("%s/current" % PATH_PYTHONS) - unlink("%s/bin/python" % ROOT) - symlink(dist, "%s/current" % PATH_PYTHONS) - clean_switch_symlink() - for root, dirs, files in os.walk("%s/pythons/current/bin/" % ROOT): - for f in files: - symlink("%s%s" % (root, f), "%s/bin/%s" % (ROOT, f)) - print "Switched to "+dist - -class OffCommand(Command): - name = "off" - usage = "%prog" - summary = "Disable pythonbrew" - - def run_command(self, options, args): - unlink("%s/current" % PATH_PYTHONS) - clean_switch_symlink() - -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-]" - 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 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()) - - 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() diff --git a/pythonbrew b/pythonbrew new file mode 120000 index 0000000..505b4fc --- /dev/null +++ b/pythonbrew @@ -0,0 +1 @@ +pythonbrew.py \ No newline at end of file diff --git a/pythonbrew.py b/pythonbrew.py new file mode 100755 index 0000000..b324365 --- /dev/null +++ b/pythonbrew.py @@ -0,0 +1,595 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +import os +import sys +import urllib +import errno +import re +import shutil +import filecmp +import subprocess +from HTMLParser import HTMLParser +from optparse import OptionParser + +VERSION = "0.3" +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" + +PATH_PYTHONS = "%s/pythons" % ROOT +PATH_BUILD = "%s/build" % ROOT +PATH_DISTS = "%s/dists" % ROOT +PATH_ETC = "%s/etc" % 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(name): + try: + os.makedirs(name) + except OSError, (e,es): + if errno.EEXIST != e: + raise + +def symlink(src, dst): + try: + os.symlink(src, dst) + except: + pass + +def unlink(name): + try: + os.unlink(name) + except OSError, (e,es): + if errno.ENOENT != e: + raise + +def clean_switch_symlink(): + for root, dirs, files in os.walk("%s/bin/" % ROOT): + for f in files: + if f == "pythonbrew": + continue + unlink("%s%s" % (root, f)) + +#---------------------------------------------------- +# 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( + "-b", "--build-options", + dest="build_options", + default="", + help="Set 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 + executable = os.path.abspath(sys.argv[0]) + 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; + return + 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.""" + + 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) + 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: + os.remove(download_path) + print "\nInterrupt to abort. `%s`" % (download_url) + sys.exit(1) + # iffy + if os.path.getsize(download_path) < 1000000: + print "Invalid file downloaded. (maybe 404 not found?) `%s`" % (download_url) + os.remove(download_path) + sys.exit(1) + else: + if os.path.isfile(name): + basename = os.path.basename(name) + print "Copy the file %s to %s/%s" % (name, PATH_DISTS, basename) + shutil.copy(name, "%s/%s" % (PATH_DISTS, basename)) + elif os.path.isdir(name): + basename = name + print "Copy the directory %s to %s/%s" % (name, PATH_DISTS, basename) + shutil.copytree(name, "%s/%s" % (PATH_DISTS, basename)) + else: + print "Unknown object. `%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 "Unknown object. `%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) + build_options = "--prefix=%s %s" % (install_dir, options.build_options) + 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" % (build_options)) + 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 ez_setup + self._install_ez_setup(pkgname, options.no_setuptools) + print """Installed """+pkgname+""" successfully. Run the following command to switch to it. + + pythonbrew switch """+pkgname + + def _install_ez_setup(self, pydist, no_setuptools): + if no_setuptools: + print "Skip installation setuptools." + return + basename = os.path.basename(EZSETUPDLSITE) + + dl = Downloader() + dl.download(basename, EZSETUPDLSITE, "%s/%s" % (PATH_DISTS, basename)) + + os.system("%s/%s/bin/python %s/%s" % (PATH_PYTHONS, pydist, PATH_DISTS, basename)) + if os.path.isfile("%s/%s/bin/easy_install" % (PATH_PYTHONS, pydist)): + os.system("%s/%s/bin/easy_install pip" % (PATH_PYTHONS, pydist)) + +class InstalledCommand(Command): + name = "installed" + usage = "%prog" + summary = "List the installed versions of python" + + def run_command(self, options, args): + if os.path.islink("%s/current" % PATH_PYTHONS): + if os.path.realpath("%s/current" % PATH_PYTHONS) == ROOT: + cur = os.path.realpath("%s/bin/python" % ROOT) + else: + cur = os.path.basename(os.path.realpath("%s/current" % PATH_PYTHONS)) + print "%s (*)" % cur + else: + cur = "" + for d in os.listdir("%s/" % PATH_PYTHONS): + if d == "current" or cur == "%s" % (d): + continue + 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 "Invalid binary: `%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/%s" % (PATH_PYTHONS, dist) ): + print "Unknown package: `%s`" % dist + return + self._switch_dir( distdir ) + + def _switch_file(self, dist): + unlink("%s/current" % PATH_PYTHONS) + unlink("%s/bin/python" % ROOT) + clean_switch_symlink() + symlink(dist, "%s/bin/python" % ROOT) + symlink(ROOT, "%s/current" % PATH_PYTHONS) + print "Switched to "+dist + + def _switch_dir(self, dist): + unlink("%s/current" % PATH_PYTHONS) + unlink("%s/bin/python" % ROOT) + symlink(dist, "%s/current" % PATH_PYTHONS) + clean_switch_symlink() + for root, dirs, files in os.walk("%s/pythons/current/bin/" % ROOT): + for f in files: + symlink("%s%s" % (root, f), "%s/bin/%s" % (ROOT, f)) + print "Switched to "+dist + +class OffCommand(Command): + name = "off" + usage = "%prog" + summary = "Disable pythonbrew" + + def run_command(self, options, args): + unlink("%s/current" % PATH_PYTHONS) + clean_switch_symlink() + +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-]" + 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 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()) + + 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() diff --git a/t/dummy.py b/tests/test_dummy.py similarity index 100% rename from t/dummy.py rename to tests/test_dummy.py