diff --git a/pythonbrew/commands/uninstall.py b/pythonbrew/commands/uninstall.py index 0a79e8c..d04e53c 100644 --- a/pythonbrew/commands/uninstall.py +++ b/pythonbrew/commands/uninstall.py @@ -1,6 +1,6 @@ import os from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, PATH_BIN +from pythonbrew.define import PATH_PYTHONS, PATH_BIN, PATH_VENVS from pythonbrew.util import off, rm_r, Package, get_using_python_pkgname, unlink,\ is_installed from pythonbrew.log import logger @@ -17,6 +17,7 @@ class UninstallCommand(Command): pkg = Package(arg) pkgname = pkg.name pkgpath = os.path.join(PATH_PYTHONS, pkgname) + venvpath = os.path.join(PATH_VENVS, pkgname) if not is_installed(pkgname): logger.info("`%s` is not installed." % pkgname) continue @@ -31,6 +32,7 @@ class UninstallCommand(Command): if os.path.isfile(tgtpath) and os.path.samefile(path, tgtpath): unlink(path) rm_r(pkgpath) + rm_r(venvpath) else: self.parser.print_help() diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index 25a0bce..8ac4e4f 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -2,8 +2,8 @@ import os import sys from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS, PATH_VENVS, PATH_ETC_VENV -from pythonbrew.util import get_using_python_pkgname, Subprocess, Package,\ - is_installed +from pythonbrew.util import Subprocess, Package,\ + is_installed, get_installed_pythons_pkgname, get_using_python_pkgname from pythonbrew.log import logger class VenvCommand(Command): @@ -20,16 +20,46 @@ class VenvCommand(Command): help="Use the specified version of python.", metavar='VERSION' ) + self.parser.add_option( + "-a", "--all", + dest="all", + action='store_true', + default=False, + help="Show the all python environments.", + metavar='VERSION' + ) + self.template_env = """export VIRTUALENVWRAPPER_PYTHON=%(venv_py)s +export VIRTUALENVWRAPPER_VIRTUALENV=%(venv_venv)s +export WORKON_HOME=%(workon_home)s +export VIRTUALENVWRAPPER_HOOK_DIR=%(workon_home)s +export VIRTUALENVWRAPPER_LOG_DIR=%(workon_home)s +source %(venv_sh)s +""" def run_command(self, options, args): if not args: logger.error('Unrecognized command line argument: ( see: \'pythonbrew help venv\' )') sys.exit(1) cmd = args[0] - if not cmd in ('create', 'use', 'delete', 'list'): + if not cmd in ('create', 'delete', 'use', 'list'): logger.error('Unrecognized command line argument: ( see: \'pythonbrew help venv\' )') sys.exit(1) + # find python2 + venv_pkgname = None + for pkgname in reversed(get_installed_pythons_pkgname()): + # virtualenvwrapper require Python2 + venv_pkgver = Package(pkgname).version + if venv_pkgver >= '2.4' and venv_pkgver < '3': + venv_pkgname = pkgname + break + if not venv_pkgname: + logger.error('Can not create virtual environment before installing a python2. Try \'pythonbrew install \'.') + sys.exit(1) + venv_dir = os.path.join(PATH_PYTHONS, venv_pkgname) + venv_bin = os.path.join(venv_dir, 'bin') + + # target python interpreter if options.python: pkgname = Package(options.python).name if not is_installed(pkgname): @@ -38,36 +68,91 @@ class VenvCommand(Command): else: pkgname = get_using_python_pkgname() if not pkgname: - logger.error('Can not create virtual environment before using a python. Try \'pythonbrew install \'.') + logger.error('Can not use venv command before using a python. Try \'pythonbrew switch \'.') sys.exit(1) - pkg_dir = os.path.join(PATH_PYTHONS, pkgname) - pkg_bin_dir = os.path.join(pkg_dir, 'bin') - - self._pkg_bin_dir = pkg_bin_dir - self._venv_dir = os.path.join(PATH_VENVS, pkgname) + self._pkgname = pkgname + self._target_py = os.path.join(PATH_PYTHONS, pkgname, 'bin', 'python') + self._workon_home = os.path.join(PATH_VENVS, pkgname) + self._venv_py = os.path.join(venv_bin, 'python') + self._venv_venv = os.path.join(venv_bin, 'virtualenv') + self._venv_sh = os.path.join(venv_bin, 'virtualenvwrapper.sh') # has virtualenv & virtualenvwrapper? - if(not os.path.exists(os.path.join(pkg_bin_dir, 'virtualenvwrapper.sh')) or - not os.path.exists(os.path.join(pkg_bin_dir, 'virtualenv'))): - logger.info('Installing virtualenv into %s' % pkg_dir) + if not self._venv_venv or not self._venv_sh: + logger.info('Installing virtualenv into %s' % venv_dir) s = Subprocess(verbose=True) - s.shell('%s %s %s' % (os.path.join(pkg_bin_dir,'pip'), 'install', 'virtualenvwrapper')) + s.shell('%s %s %s' % (os.path.join(venv_bin,'pip'), 'install', 'virtualenvwrapper')) - # Initialize virtualenv - self._init() - - # check - if cmd == 'use': - if len(args) < 2: - logger.error("Unrecognized command line argument: ( 'pythonbrew venv use ' )") - sys.exit(1) - elif cmd == 'list': - logger.info('# virtualenv for %s (found in %s)' % (pkgname, self._venv_dir)) + # Create a shell script + try: + self.__getattribute__('run_command_%s' % cmd)(options, args) + except: + logger.error('`%s` command not found.' % cmd) + sys.exit(1) - def _init(self): + def run_command_create(self, options, args): + output = [self.template_env % {'venv_py': self._venv_py, + 'venv_venv': self._venv_venv, + 'workon_home': self._workon_home, + 'venv_sh': self._venv_sh}] + for arg in args[1:]: + output.append("""echo '# Create `%(arg)s` environment into %(workon_home)s' +mkvirtualenv -p '%(target_py)s' '%(arg)s' +""" % {'arg': arg, + 'workon_home': self._workon_home, + 'target_py': self._target_py}) + self._write(''.join(output)) + + def run_command_delete(self, options, args): + output = [self.template_env % {'venv_py': self._venv_py, + 'venv_venv': self._venv_venv, + 'workon_home': self._workon_home, + 'venv_sh': self._venv_sh}] + for arg in args[1:]: + output.append("""echo '# Delete `%(arg)s` environment in %(workon_home)s' +rmvirtualenv '%(arg)s' +""" % {'arg': arg, + 'workon_home': self._workon_home}) + self._write(''.join(output)) + + def run_command_use(self, options, args): + if len(args) < 2: + logger.error("Unrecognized command line argument: ( 'pythonbrew venv use ' )") + sys.exit(1) + template = self.template_env + """echo '# Using `%(arg)s` environment (found in %(workon_home)s)' +echo '# To leave an environment, simply run `deactivate`' +workon '%(arg)s' +""" + self._write(template % {'venv_py': self._venv_py, + 'venv_venv': self._venv_venv, + 'workon_home': self._workon_home, + 'venv_sh': self._venv_sh, + 'arg': args[1]}) + + def run_command_list(self, options, args): + template = self.template_env + """echo '# virtualenv for %(pkgname)s (found in %(workon_home)s)' +workon +""" + if options.all: + output = [] + for pkgname in get_installed_pythons_pkgname(): + workon_home = os.path.join(PATH_VENVS, pkgname) + output.append(template % {'venv_py': self._venv_py, + 'venv_venv': self._venv_venv, + 'workon_home': workon_home, + 'venv_sh': self._venv_sh, + 'pkgname': pkgname}) + self._write(''.join(output)) + else: + self._write(template % {'venv_py': self._venv_py, + 'venv_venv': self._venv_venv, + 'workon_home': self._workon_home, + 'venv_sh': self._venv_sh, + 'pkgname': self._pkgname}) + + def _write(self, src): fp = open(PATH_ETC_VENV, 'w') - fp.write("VIRTUALENVWRAPPER_PYTHON=%s\n" % os.path.join(self._pkg_bin_dir, 'python')) - fp.write("WORKON_HOME=%s" % self._venv_dir) + fp.write(src) fp.close() - + VenvCommand() diff --git a/pythonbrew/define.py b/pythonbrew/define.py index 5258694..4b3551c 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -41,7 +41,7 @@ PATH_BIN_PYTHONBREW = os.path.join(PATH_BIN,'pythonbrew') PATH_ETC_CURRENT = os.path.join(PATH_ETC,'current') PATH_ETC_TEMP = os.path.join(PATH_ETC,'temp') PATH_ETC_CONFIG = os.path.join(PATH_ETC,'config.cfg') -PATH_ETC_VENV = os.path.join(PATH_ETC, 'venv') +PATH_ETC_VENV = os.path.join(PATH_ETC, 'venv.run') # read config.cfg config = ConfigParser.SafeConfigParser() diff --git a/pythonbrew/etc/bashrc b/pythonbrew/etc/bashrc index 8963f66..82b73c4 100644 --- a/pythonbrew/etc/bashrc +++ b/pythonbrew/etc/bashrc @@ -65,35 +65,10 @@ __pythonbrew_venv() { command pythonbrew "$@" if [[ $? == 0 ]] ; then - source "$PATH_ETC/venv" - args=() - for arg in "$@" ; do - if [[ $param_skip = 1 ]] ; then - param_skip=0 - continue - fi - case $arg in - -p) param_skip=1 ; continue ;; - --python) param_skip=1 ; continue ;; - esac - args=("${args[@]}" $arg) - done - for arg in ${args[@]} ; do - case $arg in - create) - for proj in ${args[@]:2} ; do - mkvirtualenv $proj - done - ;; - delete) - for proj in ${args[@]:2} ; do - rmvirtualenv $proj - done - ;; - use) workon ${args[2]} ;; - list) workon ;; - esac - done + if [[ -s "$PATH_ETC/venv.run" ]] ; then + source "$PATH_ETC/venv.run" + cat /dev/null > "$PATH_ETC/venv.run" + fi fi } diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 9bba392..a29ae85 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -221,6 +221,10 @@ def get_using_python_pkgname(): return d return None +def get_installed_pythons_pkgname(): + """Get the installed python versions list.""" + return [d for d in sorted(os.listdir(PATH_PYTHONS))] + def is_installed(name): pkgname = Package(name).name pkgdir = os.path.join(PATH_PYTHONS, pkgname) diff --git a/tests/test_10_venv.py b/tests/test_10_venv.py new file mode 100644 index 0000000..eb5f352 --- /dev/null +++ b/tests/test_10_venv.py @@ -0,0 +1,11 @@ +class VenvOptions(object): + python = '2.6.6' + all = False + +def test_venv(): + from pythonbrew.commands.venv import VenvCommand + c = VenvCommand() + c.run_command(VenvOptions(), ['create', 'aaa']) + c.run_command(VenvOptions(), ['list']) + c.run_command(VenvOptions(), ['use', 'aaa']) + c.run_command(VenvOptions(), ['delete', 'aaa']) diff --git a/tests/test_10_uninstall.py b/tests/test_11_uninstall.py similarity index 100% rename from tests/test_10_uninstall.py rename to tests/test_11_uninstall.py diff --git a/tests/test_11_cleanup.py b/tests/test_12_cleanup.py similarity index 100% rename from tests/test_11_cleanup.py rename to tests/test_12_cleanup.py