From 87d0d7b52f13bdbdea22fe2b435101b6afdacf0e Mon Sep 17 00:00:00 2001 From: utahta Date: Thu, 7 Jul 2011 19:37:30 +0900 Subject: [PATCH 01/30] #21 support ubuntu 11.04(Natty) --- pythonbrew/define.py | 1 + pythonbrew/installer/pythoninstaller.py | 135 ++++++++++-------- .../patches/all/common/patch-setup.py.diff | 47 ++++++ .../patches/all/python25/patch-setup.py.diff | 45 ++++++ 4 files changed, 170 insertions(+), 58 deletions(-) create mode 100644 pythonbrew/patches/all/common/patch-setup.py.diff create mode 100644 pythonbrew/patches/all/python25/patch-setup.py.diff diff --git a/pythonbrew/define.py b/pythonbrew/define.py index 8a51b3f..d46b0e8 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -28,6 +28,7 @@ PATH_SCRIPTS_PYTHONBREW = os.path.join(PATH_SCRIPTS,"pythonbrew") PATH_SCRIPTS_PYTHONBREW_COMMANDS = os.path.join(PATH_SCRIPTS_PYTHONBREW,"commands") PATH_SCRIPTS_PYTHONBREW_INSTALLER = os.path.join(PATH_SCRIPTS_PYTHONBREW,"installer") PATH_PATCHES = os.path.join(ROOT,"patches") +PATH_PATCHES_ALL = os.path.join(PATH_PATCHES,"all") PATH_PATCHES_MACOSX = os.path.join(PATH_PATCHES,"macosx") PATH_PATCHES_MACOSX_PYTHON27 = os.path.join(PATH_PATCHES_MACOSX,"python27") PATH_PATCHES_MACOSX_PYTHON26 = os.path.join(PATH_PATCHES_MACOSX,"python26") diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index 87f31f6..2b52b76 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -10,7 +10,7 @@ from pythonbrew.util import makedirs, symlink, Package, is_url, Link,\ from pythonbrew.define import PATH_BUILD, PATH_DISTS, PATH_PYTHONS,\ ROOT, PATH_LOG, DISTRIBUTE_SETUP_DLSITE,\ PATH_PATCHES_MACOSX_PYTHON25, PATH_PATCHES_MACOSX_PYTHON24,\ - PATH_PATCHES_MACOSX_PYTHON26, PATH_PATCHES_MACOSX_PYTHON27 + PATH_PATCHES_MACOSX_PYTHON26, PATH_PATCHES_MACOSX_PYTHON27, PATH_PATCHES_ALL from pythonbrew.downloader import get_python_version_url, Downloader,\ get_headerinfo_from_url from pythonbrew.log import logger @@ -55,6 +55,7 @@ class PythonInstaller(object): self.options = options self.logfile = os.path.join(PATH_LOG, 'build.log') self.configure_options = '' + self.patches = [] def install(self): if os.path.isdir(self.install_dir): @@ -111,8 +112,40 @@ class PythonInstaller(object): sys.exit(1) def patch(self): - pass - + version = self.pkg.version + if is_python25(version): + patch_dir = os.path.join(PATH_PATCHES_ALL, "python25") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + else: + patch_dir = os.path.join(PATH_PATCHES_ALL, "common") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + self._do_patch() + + def _do_patch(self): + try: + s = Subprocess(log=self.logfile, cwd=self.build_dir) + if self.patches: + logger.info("Patching %s" % self.pkg.name) + for patch in self.patches: + if type(patch) is dict: + for (ed, source) in patch.items(): + s.check_call('ed - %s < %s' % (source, ed)) + else: + s.check_call("patch -p0 < %s" % patch) + except: + logger.error("Failed to patch `%s`" % self.build_dir) + sys.exit(1) + + def _add_patches_to_list(self, patch_dir, patch_files): + for patch in patch_files: + if type(patch) is dict: + for key in patch.keys(): + patch[os.path.join(patch_dir, key)] = patch[key] + del patch[key] + self.patches.append(patch) + else: + self.patches.append(os.path.join(patch_dir, patch)) + def configure(self): s = Subprocess(log=self.logfile, cwd=self.build_dir) s.check_call("./configure --prefix=%s %s %s" % (self.install_dir, self.options.configure, self.configure_options)) @@ -197,58 +230,44 @@ class PythonInstallerMacOSX(PythonInstaller): def patch(self): version = self.pkg.version - try: - s = Subprocess(log=self.logfile, cwd=self.build_dir) - patches = [] - eds = {} - if is_python24(version): - patch_dir = PATH_PATCHES_MACOSX_PYTHON24 - patches = ['patch-configure', 'patch-Makefile.pre.in', - 'patch-Lib-cgi.py.diff', 'patch-Lib-site.py.diff', - 'patch-setup.py.diff', 'patch-Include-pyport.h', - 'patch-Mac-OSX-Makefile.in', 'patch-Mac-OSX-IDLE-Makefile.in', - 'patch-Mac-OSX-PythonLauncher-Makefile.in', 'patch-configure-badcflags.diff', - 'patch-configure-arch_only.diff', 'patch-macosmodule.diff', - 'patch-mactoolboxglue.diff', 'patch-pymactoolbox.diff', - 'patch-gestaltmodule.c.diff'] - elif is_python25(version): - patch_dir = PATH_PATCHES_MACOSX_PYTHON25 - patches = ['patch-Makefile.pre.in.diff', - 'patch-Lib-cgi.py.diff', - 'patch-Lib-distutils-dist.py.diff', - 'patch-setup.py.diff', - 'patch-configure-badcflags.diff', - 'patch-configure-arch_only.diff', - 'patch-64bit.diff', - 'patch-pyconfig.h.in.diff', - 'patch-gestaltmodule.c.diff'] - eds = {'_localemodule.c.ed': 'Modules/_localemodule.c', - 'locale.py.ed': 'Lib/locale.py'} - elif is_python26(version): - patch_dir = PATH_PATCHES_MACOSX_PYTHON26 - patches = ['patch-Lib-cgi.py.diff', - 'patch-Lib-distutils-dist.py.diff', - 'patch-Mac-IDLE-Makefile.in.diff', - 'patch-Mac-Makefile.in.diff', - 'patch-Mac-PythonLauncher-Makefile.in.diff', - 'patch-Mac-Tools-Doc-setup.py.diff', - 'patch-setup.py-db46.diff', - 'patch-Lib-ctypes-macholib-dyld.py.diff', - 'patch-setup_no_tkinter.py.diff'] - eds = {'_localemodule.c.ed': 'Modules/_localemodule.c', - 'locale.py.ed': 'Lib/locale.py'} - elif is_python27(version): - patch_dir = PATH_PATCHES_MACOSX_PYTHON27 - patches = ['patch-Modules-posixmodule.diff'] - - if patches or eds: - logger.info("Patching %s" % self.pkg.name) - for patch in patches: - s.check_call("patch -p0 < %s" % os.path.join(patch_dir, patch)) - for (ed, source) in eds.items(): - ed = os.path.join(patch_dir, ed) - s.check_call('ed - %s < %s' % (source, ed)) - except: - logger.error("Failed to patch `%s`" % self.build_dir) - sys.exit(1) - + if is_python24(version): + patch_dir = PATH_PATCHES_MACOSX_PYTHON24 + self._add_patches_to_list(patch_dir, ['patch-configure', 'patch-Makefile.pre.in', + 'patch-Lib-cgi.py.diff', 'patch-Lib-site.py.diff', + 'patch-setup.py.diff', 'patch-Include-pyport.h', + 'patch-Mac-OSX-Makefile.in', 'patch-Mac-OSX-IDLE-Makefile.in', + 'patch-Mac-OSX-PythonLauncher-Makefile.in', 'patch-configure-badcflags.diff', + 'patch-configure-arch_only.diff', 'patch-macosmodule.diff', + 'patch-mactoolboxglue.diff', 'patch-pymactoolbox.diff', + 'patch-gestaltmodule.c.diff']) + elif is_python25(version): + patch_dir = PATH_PATCHES_MACOSX_PYTHON25 + self._add_patches_to_list(patch_dir, ['patch-Makefile.pre.in.diff', + 'patch-Lib-cgi.py.diff', + 'patch-Lib-distutils-dist.py.diff', + 'patch-setup.py.diff', + 'patch-configure-badcflags.diff', + 'patch-configure-arch_only.diff', + 'patch-64bit.diff', + 'patch-pyconfig.h.in.diff', + 'patch-gestaltmodule.c.diff', + {'_localemodule.c.ed': 'Modules/_localemodule.c'}, + {'locale.py.ed': 'Lib/locale.py'}]) + elif is_python26(version): + patch_dir = PATH_PATCHES_MACOSX_PYTHON26 + self._add_patches_to_list(patch_dir, ['patch-Lib-cgi.py.diff', + 'patch-Lib-distutils-dist.py.diff', + 'patch-Mac-IDLE-Makefile.in.diff', + 'patch-Mac-Makefile.in.diff', + 'patch-Mac-PythonLauncher-Makefile.in.diff', + 'patch-Mac-Tools-Doc-setup.py.diff', + 'patch-setup.py-db46.diff', + 'patch-Lib-ctypes-macholib-dyld.py.diff', + 'patch-setup_no_tkinter.py.diff', + {'_localemodule.c.ed': 'Modules/_localemodule.c'}, + {'locale.py.ed': 'Lib/locale.py'}]) + elif is_python27(version): + patch_dir = PATH_PATCHES_MACOSX_PYTHON27 + self._add_patches_to_list(patch_dir, ['patch-Modules-posixmodule.diff']) + + self._do_patch() diff --git a/pythonbrew/patches/all/common/patch-setup.py.diff b/pythonbrew/patches/all/common/patch-setup.py.diff new file mode 100644 index 0000000..b2998bc --- /dev/null +++ b/pythonbrew/patches/all/common/patch-setup.py.diff @@ -0,0 +1,47 @@ + +# HG changeset patch +# User Barry Warsaw +# Date 1302190091 14400 +# Node ID bd0f73a9538e05f526feaf05821e68bdcff498fa +# Parent 2e4cdaffe493e879fb5367a4aa454491de451137 +Backport for Python 2.7 of issue 11715 support for building Python on +multiarch Debian/Ubuntu. + +diff --git a/setup.py b/setup.py +--- setup.py.orig ++++ setup.py +@@ -345,10 +345,33 @@ class PyBuildExt(build_ext): + return platform + return sys.platform + ++ def add_multiarch_paths(self): ++ # Debian/Ubuntu multiarch support. ++ # https://wiki.ubuntu.com/MultiarchSpec ++ if not find_executable('dpkg-architecture'): ++ return ++ tmpfile = os.path.join(self.build_temp, 'multiarch') ++ if not os.path.exists(self.build_temp): ++ os.makedirs(self.build_temp) ++ ret = os.system( ++ 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % ++ tmpfile) ++ try: ++ if ret >> 8 == 0: ++ with open(tmpfile) as fp: ++ multiarch_path_component = fp.readline().strip() ++ add_dir_to_list(self.compiler.library_dirs, ++ '/usr/lib/' + multiarch_path_component) ++ add_dir_to_list(self.compiler.include_dirs, ++ '/usr/include/' + multiarch_path_component) ++ finally: ++ os.unlink(tmpfile) ++ + def detect_modules(self): + # Ensure that /usr/local is always used + add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') ++ self.add_multiarch_paths() + + # Add paths specified in the environment variables LDFLAGS and + # CPPFLAGS for header and library files. + diff --git a/pythonbrew/patches/all/python25/patch-setup.py.diff b/pythonbrew/patches/all/python25/patch-setup.py.diff new file mode 100644 index 0000000..ffe4b0d --- /dev/null +++ b/pythonbrew/patches/all/python25/patch-setup.py.diff @@ -0,0 +1,45 @@ +--- setup.py.orig 2011-07-07 19:19:43.800122463 +0900 ++++ setup.py 2011-07-07 19:25:04.548416377 +0900 +@@ -13,6 +13,7 @@ + from distutils.command.build_ext import build_ext + from distutils.command.install import install + from distutils.command.install_lib import install_lib ++from distutils.spawn import find_executable + + # This global variable is used to hold the list of modules to be disabled. + disabled_module_list = [] +@@ -242,10 +243,34 @@ + return platform + return sys.platform + ++ def add_multiarch_paths(self): ++ # Debian/Ubuntu multiarch support. ++ # https://wiki.ubuntu.com/MultiarchSpec ++ if not find_executable('dpkg-architecture'): ++ return ++ tmpfile = os.path.join(self.build_temp, 'multiarch') ++ if not os.path.exists(self.build_temp): ++ os.makedirs(self.build_temp) ++ ret = os.system( ++ 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % ++ tmpfile) ++ try: ++ if ret >> 8 == 0: ++ fp = open(tmpfile) ++ multiarch_path_component = fp.readline().strip() ++ fp.close() ++ add_dir_to_list(self.compiler.library_dirs, ++ '/usr/lib/' + multiarch_path_component) ++ add_dir_to_list(self.compiler.include_dirs, ++ '/usr/include/' + multiarch_path_component) ++ finally: ++ os.unlink(tmpfile) ++ + def detect_modules(self): + # Ensure that /usr/local is always used + add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') ++ self.add_multiarch_paths() + + # Add paths specified in the environment variables LDFLAGS and + # CPPFLAGS for header and library files. From 8a1032b08c14988c00dead6434068972c0f1128d Mon Sep 17 00:00:00 2001 From: utahta Date: Thu, 7 Jul 2011 20:39:19 +0900 Subject: [PATCH 02/30] #21 support ubuntu 11.04(Natty) --- pythonbrew/installer/pythoninstaller.py | 20 ++++++++- .../patches/all/python30/patch-setup.py.diff | 44 +++++++++++++++++++ .../patches/all/python32/patch-setup.py.diff | 38 ++++++++++++++++ pythonbrew/util.py | 9 ++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 pythonbrew/patches/all/python30/patch-setup.py.diff create mode 100644 pythonbrew/patches/all/python32/patch-setup.py.diff diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index 2b52b76..4e2e7cb 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -6,7 +6,7 @@ from pythonbrew.util import makedirs, symlink, Package, is_url, Link,\ unlink, is_html, Subprocess, rm_r,\ is_python25, is_python24, is_python26, is_python27,\ unpack_downloadfile, is_archive_file, path_to_fileurl, is_file,\ - fileurl_to_path + fileurl_to_path, is_python30, is_python31, is_python32 from pythonbrew.define import PATH_BUILD, PATH_DISTS, PATH_PYTHONS,\ ROOT, PATH_LOG, DISTRIBUTE_SETUP_DLSITE,\ PATH_PATCHES_MACOSX_PYTHON25, PATH_PATCHES_MACOSX_PYTHON24,\ @@ -113,12 +113,28 @@ class PythonInstaller(object): def patch(self): version = self.pkg.version + # ubuntu 11.04(Natty) if is_python25(version): patch_dir = os.path.join(PATH_PATCHES_ALL, "python25") self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) - else: + elif is_python26(version): patch_dir = os.path.join(PATH_PATCHES_ALL, "common") self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + elif is_python27(version): + if version < '2.7.2': + patch_dir = os.path.join(PATH_PATCHES_ALL, "common") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + elif is_python30(version): + patch_dir = os.path.join(PATH_PATCHES_ALL, "python30") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + elif is_python31(version): + if version < '3.1.4': + patch_dir = os.path.join(PATH_PATCHES_ALL, "common") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + elif is_python32(version): + if version == '3.2': + patch_dir = os.path.join(PATH_PATCHES_ALL, "python32") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) self._do_patch() def _do_patch(self): diff --git a/pythonbrew/patches/all/python30/patch-setup.py.diff b/pythonbrew/patches/all/python30/patch-setup.py.diff new file mode 100644 index 0000000..8f1a177 --- /dev/null +++ b/pythonbrew/patches/all/python30/patch-setup.py.diff @@ -0,0 +1,44 @@ +--- setup.py.orig 2011-07-07 19:41:48.610196111 +0900 ++++ setup.py 2011-07-07 19:46:44.986310031 +0900 +@@ -14,6 +14,7 @@ + from distutils.command.build_ext import build_ext + from distutils.command.install import install + from distutils.command.install_lib import install_lib ++from distutils.spawn import find_executable + + # This global variable is used to hold the list of modules to be disabled. + disabled_module_list = [] +@@ -308,10 +309,33 @@ + return platform + return sys.platform + ++ def add_multiarch_paths(self): ++ # Debian/Ubuntu multiarch support. ++ # https://wiki.ubuntu.com/MultiarchSpec ++ if not find_executable('dpkg-architecture'): ++ return ++ tmpfile = os.path.join(self.build_temp, 'multiarch') ++ if not os.path.exists(self.build_temp): ++ os.makedirs(self.build_temp) ++ ret = os.system( ++ 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % ++ tmpfile) ++ try: ++ if ret >> 8 == 0: ++ with open(tmpfile) as fp: ++ multiarch_path_component = fp.readline().strip() ++ add_dir_to_list(self.compiler.library_dirs, ++ '/usr/lib/' + multiarch_path_component) ++ add_dir_to_list(self.compiler.include_dirs, ++ '/usr/include/' + multiarch_path_component) ++ finally: ++ os.unlink(tmpfile) ++ + def detect_modules(self): + # Ensure that /usr/local is always used + add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') ++ self.add_multiarch_paths() + + # Add paths specified in the environment variables LDFLAGS and + # CPPFLAGS for header and library files. diff --git a/pythonbrew/patches/all/python32/patch-setup.py.diff b/pythonbrew/patches/all/python32/patch-setup.py.diff new file mode 100644 index 0000000..f4c361e --- /dev/null +++ b/pythonbrew/patches/all/python32/patch-setup.py.diff @@ -0,0 +1,38 @@ +--- setup.py.orig 2011-07-07 20:26:15.000000000 +0900 ++++ setup.py 2011-07-07 20:29:28.735543350 +0900 +@@ -370,12 +370,35 @@ + return platform + return sys.platform + ++ def add_multiarch_paths(self): ++ # Debian/Ubuntu multiarch support. ++ # https://wiki.ubuntu.com/MultiarchSpec ++ if not find_executable('dpkg-architecture'): ++ return ++ tmpfile = os.path.join(self.build_temp, 'multiarch') ++ if not os.path.exists(self.build_temp): ++ os.makedirs(self.build_temp) ++ ret = os.system( ++ 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % ++ tmpfile) ++ try: ++ if ret >> 8 == 0: ++ with open(tmpfile) as fp: ++ multiarch_path_component = fp.readline().strip() ++ add_dir_to_list(self.compiler.library_dirs, ++ '/usr/lib/' + multiarch_path_component) ++ add_dir_to_list(self.compiler.include_dirs, ++ '/usr/include/' + multiarch_path_component) ++ finally: ++ os.unlink(tmpfile) ++ + def detect_modules(self): + # Ensure that /usr/local is always used, but the local build + # directories (i.e. '.' and 'Include') must be first. See issue + # 10520. + add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') ++ self.add_multiarch_paths() + + # Add paths specified in the environment variables LDFLAGS and + # CPPFLAGS for header and library files. diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 50e7ed3..79780d3 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -77,6 +77,15 @@ def is_python26(version): def is_python27(version): return version >= '2.7' and version < '2.8' +def is_python30(version): + return version >= '3.0' and version < '3.1' + +def is_python31(version): + return version >= '3.1' and version < '3.2' + +def is_python32(version): + return version >= '3.2' and version < '3.3' + def makedirs(path): try: os.makedirs(path) From f410b1d1d8ffc090d9b4f2b903586ab679b99cd1 Mon Sep 17 00:00:00 2001 From: utahta Date: Fri, 8 Jul 2011 19:25:18 +0900 Subject: [PATCH 03/30] update --- pythonbrew/installer/pythoninstaller.py | 5 ++- .../patches/all/python24/patch-setup.py.diff | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 pythonbrew/patches/all/python24/patch-setup.py.diff diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index 4e2e7cb..4575df4 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -114,7 +114,10 @@ class PythonInstaller(object): def patch(self): version = self.pkg.version # ubuntu 11.04(Natty) - if is_python25(version): + if is_python24(version): + patch_dir = os.path.join(PATH_PATCHES_ALL, "python24") + self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) + elif is_python25(version): patch_dir = os.path.join(PATH_PATCHES_ALL, "python25") self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) elif is_python26(version): diff --git a/pythonbrew/patches/all/python24/patch-setup.py.diff b/pythonbrew/patches/all/python24/patch-setup.py.diff new file mode 100644 index 0000000..ffe4b0d --- /dev/null +++ b/pythonbrew/patches/all/python24/patch-setup.py.diff @@ -0,0 +1,45 @@ +--- setup.py.orig 2011-07-07 19:19:43.800122463 +0900 ++++ setup.py 2011-07-07 19:25:04.548416377 +0900 +@@ -13,6 +13,7 @@ + from distutils.command.build_ext import build_ext + from distutils.command.install import install + from distutils.command.install_lib import install_lib ++from distutils.spawn import find_executable + + # This global variable is used to hold the list of modules to be disabled. + disabled_module_list = [] +@@ -242,10 +243,34 @@ + return platform + return sys.platform + ++ def add_multiarch_paths(self): ++ # Debian/Ubuntu multiarch support. ++ # https://wiki.ubuntu.com/MultiarchSpec ++ if not find_executable('dpkg-architecture'): ++ return ++ tmpfile = os.path.join(self.build_temp, 'multiarch') ++ if not os.path.exists(self.build_temp): ++ os.makedirs(self.build_temp) ++ ret = os.system( ++ 'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % ++ tmpfile) ++ try: ++ if ret >> 8 == 0: ++ fp = open(tmpfile) ++ multiarch_path_component = fp.readline().strip() ++ fp.close() ++ add_dir_to_list(self.compiler.library_dirs, ++ '/usr/lib/' + multiarch_path_component) ++ add_dir_to_list(self.compiler.include_dirs, ++ '/usr/include/' + multiarch_path_component) ++ finally: ++ os.unlink(tmpfile) ++ + def detect_modules(self): + # Ensure that /usr/local is always used + add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') ++ self.add_multiarch_paths() + + # Add paths specified in the environment variables LDFLAGS and + # CPPFLAGS for header and library files. From 6cb6cc60576e70ef01dbc1b6c385da66a7e2c1a5 Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 10 Jul 2011 20:49:00 +0900 Subject: [PATCH 04/30] update 0.8 --- ChangeLog | 17 ++- PKG-INFO | 174 +++++++++++++++++++++++- README.rst | 80 +++++------ pythonbrew/commands/clean.py | 11 +- pythonbrew/commands/cleanup.py | 19 +++ pythonbrew/commands/install.py | 26 +++- pythonbrew/commands/py.py | 8 +- pythonbrew/commands/update.py | 34 +++-- pythonbrew/curl.py | 6 +- pythonbrew/define.py | 5 +- pythonbrew/downloader.py | 13 +- pythonbrew/etc/config.cfg | 3 +- pythonbrew/installer/__init__.py | 4 +- pythonbrew/installer/pythoninstaller.py | 116 ++++++++-------- pythonbrew/util.py | 118 ++++++++++------ tests/test_01_update.py | 5 +- tests/test_04_install.py | 2 + tests/test_11_clean.py | 4 - tests/test_11_cleanup.py | 4 + 19 files changed, 447 insertions(+), 202 deletions(-) mode change 120000 => 100644 PKG-INFO create mode 100644 pythonbrew/commands/cleanup.py delete mode 100644 tests/test_11_clean.py create mode 100644 tests/test_11_cleanup.py diff --git a/ChangeLog b/ChangeLog index fd09df0..b6e3837 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,20 @@ +* 0.8 + - Fixed issue #21 Added Ubuntu 11.04(Natty) support + - Fixed issue #24 non-framework python27 now defines environ properly. Thanks npinto. + - Fixed issue #27 Cleanup of OS X python build flags + - Fixed issue #28 Describe the 'symlink' command better. Thanks tgs. + - Fixed issue #30 py command does not accept arguments with a space + - Fixed bug: `pythonbrew off` need not have removed the symlink in bin directory + - Added --no-test option to the install command + - Added --verbose option to the install command + - `pythonbrew clean` has been renamed. Added `pythonbrew cleanup` instead. + * 0.7.3 - - Improved symlink command. - - support python3 + - Improved symlink command + - Added python3 support * 0.7.2 - - Bug fixed. + - Bug fixed * 0.7.1 - Enable parallel make option (--jobs). diff --git a/PKG-INFO b/PKG-INFO deleted file mode 120000 index 92cacd2..0000000 --- a/PKG-INFO +++ /dev/null @@ -1 +0,0 @@ -README.rst \ No newline at end of file diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..d061329 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,173 @@ +Overview +======== + +pythonbrew is a program to automate the building and installation of Python in the users HOME. + +pythonbrew is inspired by `perlbrew `_ and `rvm `_. + +Installation +============ + +The recommended way to download and install pythonbrew is to run these statements in your shell:: + + curl -kLO http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install + chmod +x pythonbrew-install + ./pythonbrew-install + +or more simply like this:: + + curl -kL http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install | bash + +After that, pythonbrew installs itself to ~/.pythonbrew, and you should follow the instruction on screen to setup your .bashrc 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 + +Usage +===== + +pythonbrew command [options] + +Install some pythons:: + + pythonbrew install 2.6.6 + pythonbrew install --force 2.6.6 + pythonbrew install --configure="CC=gcc_4.1" 2.6.6 + pythonbrew install --no-setuptools 2.6.6 + pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.6.6.tgz + pythonbrew install file:///path/to/Python-2.6.6.tgz + pythonbrew install /path/to/Python-2.6.6.tgz + pythonbrew install 2.5.5 2.6.6 + +Permanently use the specified python as default:: + + pythonbrew switch 2.6.6 + pythonbrew switch 2.5.5 + +Use the specified python in current shell:: + + pythonbrew use 2.6.6 + +Runs a named python file against specified and/or all pythons:: + + pythonbrew py test.py + pythonbrew py -v test.py # Show running python version + pythonbrew py -p 2.6.6 -p 3.1.2 test.py # Use the specified pythons + +List the installed pythons:: + + pythonbrew list + +List the available install pythons:: + + pythonbrew list -k + +Uninstall the specified python:: + + pythonbrew uninstall 2.6.6 + pythonbrew uninstall 2.5.5 2.6.6 + +Remove stale source folders and archives:: + + pythonbrew clean + +Upgrades pythonbrew to the latest version:: + + pythonbrew update + +Disable pythonbrew:: + + pythonbrew off + +Create/Remove a symbolic link to python:: + + pythonbrew symlink # Create a symbolic link, like "py2.5.5" + pythonbrew symlink -p 2.5.5 + pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory + pythonbrew symlink -r # Remove a symbolic link + +Show version:: + + pythonbrew version + +COMMANDS +======== + +install + Build and install the given version of python. + + Setuptools and pip is automatically installed. + + options: --force, --no-setuptools, --configure and --as. + +switch + Permanently use the specified python as default. + +use + Use the specified python in current shell. + +py + Runs a named python file against specified and/or all pythons. + +list + List the installed all pythons. + +list -k + List the available install pythons. + +uninstall + Uninstall the given version of python. + +clean + Remove stale source folders and archives. + +update + Upgrades pythonbrew to the latest version. + +off + Disable pythonbrew. + +version + Show version. + +Options +======= + +\-f | --force + Force installation of a python. (skip `make test`) + +\-C | --configure + Custom configure options. + +\-n | --no-setuptools + Skip installation of setuptools. + +\--as + Install a python under an alias. + +LICENCE +======= + +The MIT License + +Copyright (c) <2010-2011> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.rst b/README.rst index fd9c14b..881912e 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ Overview ======== -pythonbrew is a program to automate the building and installation of Python in the users HOME. +pythonbrew is a program to automate the building and installation of Python in the users $HOME. pythonbrew is inspired by `perlbrew `_ and `rvm `_. @@ -10,20 +10,16 @@ Installation The recommended way to download and install pythonbrew is to run these statements in your shell:: - curl -kLO http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install - chmod +x pythonbrew-install - ./pythonbrew-install - -or more simply like this:: - - curl -kL http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install | bash + curl -kL http://xrl.us/pythonbrewinstall | bash After that, pythonbrew installs itself to ~/.pythonbrew, and you should follow the instruction on screen to setup your .bashrc 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 + curl -kLO http://xrl.us/pythonbrewinstall + chmod +x pythonbrewinstall + ./pythonbrewinstall Usage ===== @@ -32,50 +28,54 @@ pythonbrew command [options] Install some pythons:: - pythonbrew install 2.6.6 - pythonbrew install --force 2.6.6 - pythonbrew install --configure="CC=gcc_4.1" 2.6.6 - pythonbrew install --no-setuptools 2.6.6 - pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.6.6.tgz - pythonbrew install file:///path/to/Python-2.6.6.tgz - pythonbrew install /path/to/Python-2.6.6.tgz - pythonbrew install 2.5.5 2.6.6 + pythonbrew install 2.7.2 + pythonbrew install --verbose 2.7.2 + pythonbrew install --force 2.7.2 + pythonbrew install --no-test 2.7.2 + pythonbrew install --configure="CC=gcc_4.1" 2.7.2 + pythonbrew install --no-setuptools 2.7.2 + pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.7.2.tgz + pythonbrew install /path/to/Python-2.7.2.tgz + pythonbrew install /path/to/Python-2.7.2 + pythonbrew install 2.7.2 3.2 -Permanently use the specified python as default:: +Permanently use the specified python:: - pythonbrew switch 2.6.6 - pythonbrew switch 2.5.5 + pythonbrew switch 2.7.2 + pythonbrew switch 3.2 Use the specified python in current shell:: - pythonbrew use 2.6.6 + pythonbrew use 2.7.2 Runs a named python file against specified and/or all pythons:: pythonbrew py test.py pythonbrew py -v test.py # Show running python version - pythonbrew py -p 2.6.6 -p 3.1.2 test.py # Use the specified pythons + pythonbrew py -p 2.7.2 -p 3.2 test.py # Use the specified pythons List the installed pythons:: pythonbrew list -List the available install pythons:: +List the available installation pythons:: pythonbrew list -k Uninstall the specified python:: - pythonbrew uninstall 2.6.6 - pythonbrew uninstall 2.5.5 2.6.6 + pythonbrew uninstall 2.7.2 + pythonbrew uninstall 2.7.2 3.2 Remove stale source folders and archives:: - pythonbrew clean + pythonbrew cleanup Upgrades pythonbrew to the latest version:: pythonbrew update + pythonbrew update --master + pythonbrew update --develop Disable pythonbrew:: @@ -83,8 +83,8 @@ Disable pythonbrew:: Create/Remove a symbolic link to python (in a directory on your $PATH):: - pythonbrew symlink # Create a symbolic link, like "py2.5.5", for each installed version - pythonbrew symlink -p 2.5.5 + pythonbrew symlink # Create a symbolic link, like "py2.7.2", for each installed version + pythonbrew symlink -p 2.7.2 pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory pythonbrew symlink -r # Remove a symbolic link @@ -97,10 +97,7 @@ COMMANDS install Build and install the given version of python. - - Setuptools and pip is automatically installed. - - options: --force, --no-setuptools, --configure and --as. + Install setuptools and pip automatically. switch Permanently use the specified python as default. @@ -120,7 +117,7 @@ list -k uninstall Uninstall the given version of python. -clean +cleanup Remove stale source folders and archives. update @@ -131,21 +128,10 @@ off version Show version. + +See more details below:: -Options -======= - -\-f | --force - Force installation of a python. (skip `make test`) - -\-C | --configure - Custom configure options. - -\-n | --no-setuptools - Skip installation of setuptools. - -\--as - Install a python under an alias. + `pythonbrew help ` LICENCE ======= diff --git a/pythonbrew/commands/clean.py b/pythonbrew/commands/clean.py index 99aed07..c967e76 100644 --- a/pythonbrew/commands/clean.py +++ b/pythonbrew/commands/clean.py @@ -1,7 +1,5 @@ -import os from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_BUILD, PATH_DISTS -from pythonbrew.util import rm_r +from pythonbrew.log import logger class CleanCommand(Command): name = "clean" @@ -9,11 +7,6 @@ class CleanCommand(Command): summary = "Remove stale source folders and archives" def run_command(self, options, args): - self._clean(PATH_BUILD) - self._clean(PATH_DISTS) + logger.info('\nDEPRECATION WARNING: `pythonbrew clean` has been renamed. Please run `pythonbrew cleanup` instead.\n') - def _clean(self, root): - for dir in os.listdir(root): - rm_r(os.path.join(root, dir)) - CleanCommand() diff --git a/pythonbrew/commands/cleanup.py b/pythonbrew/commands/cleanup.py new file mode 100644 index 0000000..2de8c48 --- /dev/null +++ b/pythonbrew/commands/cleanup.py @@ -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 CleanupCommand(Command): + name = "cleanup" + usage = "%prog" + summary = "Remove stale source folders and archives" + + def run_command(self, options, args): + self._cleanup(PATH_BUILD) + self._cleanup(PATH_DISTS) + + def _cleanup(self, root): + for dir in os.listdir(root): + rm_r(os.path.join(root, dir)) + +CleanupCommand() diff --git a/pythonbrew/commands/install.py b/pythonbrew/commands/install.py index edbb013..34e6877 100644 --- a/pythonbrew/commands/install.py +++ b/pythonbrew/commands/install.py @@ -2,7 +2,7 @@ from pythonbrew.basecommand import Command from pythonbrew.log import logger from pythonbrew.installer.pythoninstaller import PythonInstaller,\ PythonInstallerMacOSX -from pythonbrew.util import is_macosx_snowleopard +from pythonbrew.util import is_macosx from pythonbrew.exceptions import UnknownVersionException,\ AlreadyInstalledException, NotSupportedVersionException @@ -18,7 +18,21 @@ class InstallCommand(Command): dest="force", action="store_true", default=False, - help="Force install of python.(skip make test)" + help="Force installation of python." + ) + self.parser.add_option( + "-n", "--no-test", + dest="no_test", + action="store_true", + default=False, + help="Skip `make test`." + ) + self.parser.add_option( + "-v", "--verbose", + dest="verbose", + action="store_true", + default=False, + help="Display log information on the console." ) self.parser.add_option( "-C", "--configure", @@ -28,11 +42,11 @@ class InstallCommand(Command): help="Options passed directly to configure." ) self.parser.add_option( - "-n", "--no-setuptools", + "--no-setuptools", dest="no_setuptools", action="store_true", default=False, - help="Skip install of setuptools." + help="Skip installation of setuptools." ) self.parser.add_option( "--as", @@ -50,10 +64,10 @@ class InstallCommand(Command): def run_command(self, options, args): if args: - # Install pythons + # installing python for arg in args: try: - if is_macosx_snowleopard(): + if is_macosx(): p = PythonInstallerMacOSX(arg, options) else: p = PythonInstaller(arg, options) diff --git a/pythonbrew/commands/py.py b/pythonbrew/commands/py.py index ca11af9..9390dca 100644 --- a/pythonbrew/commands/py.py +++ b/pythonbrew/commands/py.py @@ -1,10 +1,10 @@ import os import sys +import subprocess from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS from pythonbrew.util import Package from pythonbrew.log import logger -from subprocess import Popen class PyCommand(Command): name = "py" @@ -40,13 +40,11 @@ class PyCommand(Command): logger.info('*** %s ***' % d) path = os.path.join(PATH_PYTHONS, d, 'bin', args[0]) if os.path.isfile(path) and os.access(path, os.X_OK): - p = Popen([path] + args[1:]) - p.wait() + subprocess.call([path] + args[1:]) else: path = os.path.join(PATH_PYTHONS, d, 'bin', 'python') if os.path.isfile(path) and os.access(path, os.X_OK): - p = Popen([path] + args) - p.wait() + subprocess.call([path] + args) else: logger.info('%s: No such file or directory.' % path) diff --git a/pythonbrew/commands/update.py b/pythonbrew/commands/update.py index d342224..f9d760a 100644 --- a/pythonbrew/commands/update.py +++ b/pythonbrew/commands/update.py @@ -6,7 +6,7 @@ from pythonbrew.define import PATH_DISTS, VERSION, ROOT,\ from pythonbrew.log import logger from pythonbrew.downloader import Downloader, get_pythonbrew_update_url,\ get_stable_version, get_headerinfo_from_url -from pythonbrew.util import rm_r, unpack_downloadfile, Link, is_gzip, Subprocess +from pythonbrew.util import rm_r, extract_downloadfile, Link, is_gzip, Subprocess class UpdateCommand(Command): name = "update" @@ -16,11 +16,18 @@ class UpdateCommand(Command): def __init__(self): super(UpdateCommand, self).__init__() self.parser.add_option( - '--head', - dest='head', + '--master', + dest='master', action='store_true', default=False, - help='Update the pythonbrew to the github version.' + help='Update the pythonbrew to the `master` branch on github.' + ) + self.parser.add_option( + '--develop', + dest='develop', + action='store_true', + default=False, + help='Update the pythonbrew to the `develop` branch on github.' ) self.parser.add_option( '--config', @@ -61,9 +68,10 @@ class UpdateCommand(Command): logger.info("The config.cfg has been updated.") def _update_pythonbrew(self, options, args): - # pythonbrew update - if options.head: - version = 'head' + if options.master: + version = 'master' + elif options.develop: + version = 'develop' else: version = get_stable_version() # check for version @@ -77,10 +85,10 @@ class UpdateCommand(Command): sys.exit(1) headinfo = get_headerinfo_from_url(download_url) content_type = headinfo['content-type'] - # head is only for gzip. - if not options.head and not is_gzip(content_type, Link(download_url).filename): - logger.error("Invalid content-type: `%s`" % content_type) - sys.exit(1) + if not options.master and not options.develop: + if not is_gzip(content_type, Link(download_url).filename): + logger.error("content type should be gzip. content-type:`%s`" % content_type) + sys.exit(1) filename = "pythonbrew-%s" % version distname = "%s.tgz" % filename @@ -94,13 +102,13 @@ class UpdateCommand(Command): extract_dir = os.path.join(PATH_BUILD, filename) rm_r(extract_dir) - if not unpack_downloadfile(content_type, download_file, extract_dir): + if not extract_downloadfile(content_type, download_file, extract_dir): sys.exit(1) try: logger.info("Installing %s into %s" % (extract_dir, ROOT)) s = Subprocess() - s.check_call('%s %s/pythonbrew_install.py --upgrade' % (sys.executable, extract_dir)) + s.check_call([sys.executable, os.path.join(extract_dir,'pythonbrew_install.py'), '--upgrade']) except: logger.error("Failed to update pythonbrew.") sys.exit(1) diff --git a/pythonbrew/curl.py b/pythonbrew/curl.py index 62bccba..719639c 100644 --- a/pythonbrew/curl.py +++ b/pythonbrew/curl.py @@ -3,7 +3,7 @@ import re import subprocess from subprocess import Popen, PIPE from pythonbrew.log import logger -from pythonbrew.util import u +from pythonbrew.util import to_str class Curl(object): def __init__(self): @@ -26,11 +26,11 @@ class Curl(object): raise respinfo = {} for line in p.stdout: - line = u(line.strip()) + line = to_str(line.strip()) if re.match('^HTTP.*? 200 OK$', line): break for line in p.stdout: - line = u(line.strip()).split(":", 1) + line = to_str(line.strip()).split(":", 1) if len(line) == 2: respinfo[line[0].strip().lower()] = line[1].strip() return respinfo diff --git a/pythonbrew/define.py b/pythonbrew/define.py index d46b0e8..593d2a7 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -6,7 +6,7 @@ except: import configparser as ConfigParser # pythonbrew version -VERSION = "0.7.3" +VERSION = "0.8" # pythonbrew root path ROOT = os.environ.get("PYTHONBREW_ROOT") @@ -54,7 +54,8 @@ def _get_or_default(section, option, default=''): DISTRIBUTE_SETUP_DLSITE = _get_or_default('distribute', 'url') # pythonbrew download -PYTHONBREW_UPDATE_URL_HEAD = _get_or_default('pythonbrew', 'head') +PYTHONBREW_UPDATE_URL_MASTER = _get_or_default('pythonbrew', 'master') +PYTHONBREW_UPDATE_URL_DEVELOP = _get_or_default('pythonbrew', 'develop') PYTHONBREW_UPDATE_URL_PYPI = _get_or_default('pythonbrew', 'pypi') PYTHONBREW_UPDATE_URL_CONFIG = _get_or_default('pythonbrew', 'config') diff --git a/pythonbrew/downloader.py b/pythonbrew/downloader.py index f5266a1..ee21c02 100644 --- a/pythonbrew/downloader.py +++ b/pythonbrew/downloader.py @@ -1,8 +1,9 @@ from pythonbrew.define import PYTHON_VERSION_URL, PYTHONBREW_STABLE_VERSION_URL, \ - PYTHONBREW_UPDATE_URL_PYPI, PYTHONBREW_UPDATE_URL_HEAD + PYTHONBREW_UPDATE_URL_PYPI, PYTHONBREW_UPDATE_URL_MASTER,\ + PYTHONBREW_UPDATE_URL_DEVELOP from pythonbrew.log import logger from pythonbrew.curl import Curl -from pythonbrew.util import u +from pythonbrew.util import to_str def get_headerinfo_from_url(url): c = Curl() @@ -10,7 +11,7 @@ def get_headerinfo_from_url(url): def get_stable_version(): c = Curl() - return u(c.read(PYTHONBREW_STABLE_VERSION_URL).strip()) + return to_str(c.read(PYTHONBREW_STABLE_VERSION_URL).strip()) class Downloader(object): def download(self, msg, url, path): @@ -19,8 +20,10 @@ class Downloader(object): c.fetch(url, path) def get_pythonbrew_update_url(version): - if version == "head": - return PYTHONBREW_UPDATE_URL_HEAD + if version == "master": + return PYTHONBREW_UPDATE_URL_MASTER + elif version == 'develop': + return PYTHONBREW_UPDATE_URL_DEVELOP else: return PYTHONBREW_UPDATE_URL_PYPI % (version) diff --git a/pythonbrew/etc/config.cfg b/pythonbrew/etc/config.cfg index cf6ec26..dbdc698 100644 --- a/pythonbrew/etc/config.cfg +++ b/pythonbrew/etc/config.cfg @@ -2,7 +2,8 @@ url = http://python-distribute.org/distribute_setup.py [pythonbrew] -head = https://github.com/utahta/pythonbrew/tarball/master +master = https://github.com/utahta/pythonbrew/tarball/master +develop = https://github.com/utahta/pythonbrew/tarball/develop pypi = http://pypi.python.org/packages/source/p/pythonbrew/pythonbrew-%%s.tar.gz stable-version = https://github.com/utahta/pythonbrew/raw/master/stable-version.txt config = https://github.com/utahta/pythonbrew/raw/master/pythonbrew/etc/config.cfg diff --git a/pythonbrew/installer/__init__.py b/pythonbrew/installer/__init__.py index 2cbc24e..f4362e4 100644 --- a/pythonbrew/installer/__init__.py +++ b/pythonbrew/installer/__init__.py @@ -20,8 +20,8 @@ Please add the following line to the end of your ~/.%(yourshrc)s After that, exit this shell, start a new one, and install some fresh pythons: - pythonbrew install 2.6.6 - pythonbrew install 2.5.5 + pythonbrew install 2.7.2 + pythonbrew install 3.2 For further instructions, run: diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index 4575df4..50a6a77 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -5,8 +5,9 @@ import mimetypes from pythonbrew.util import makedirs, symlink, Package, is_url, Link,\ unlink, is_html, Subprocess, rm_r,\ is_python25, is_python24, is_python26, is_python27,\ - unpack_downloadfile, is_archive_file, path_to_fileurl, is_file,\ - fileurl_to_path, is_python30, is_python31, is_python32 + extract_downloadfile, is_archive_file, path_to_fileurl, is_file,\ + fileurl_to_path, is_python30, is_python31, is_python32,\ + get_macosx_deployment_target from pythonbrew.define import PATH_BUILD, PATH_DISTS, PATH_PYTHONS,\ ROOT, PATH_LOG, DISTRIBUTE_SETUP_DLSITE,\ PATH_PATCHES_MACOSX_PYTHON25, PATH_PATCHES_MACOSX_PYTHON24,\ @@ -22,15 +23,13 @@ class PythonInstaller(object): """ def __init__(self, arg, options): - if is_url(arg): - name = arg - elif is_archive_file(arg): + if is_archive_file(arg): name = path_to_fileurl(arg) elif os.path.isdir(arg): name = path_to_fileurl(arg) else: name = arg - + if is_url(name): self.download_url = name filename = Link(self.download_url).filename @@ -46,12 +45,23 @@ class PythonInstaller(object): self.install_dir = os.path.join(PATH_PYTHONS, pkg.name) self.build_dir = os.path.join(PATH_BUILD, pkg.name) self.download_file = os.path.join(PATH_DISTS, filename) + + # cleanup + if os.path.isdir(self.build_dir): + shutil.rmtree(self.build_dir) + + # get content type. if is_file(self.download_url): path = fileurl_to_path(self.download_url) self.content_type = mimetypes.guess_type(path)[0] else: headerinfo = get_headerinfo_from_url(self.download_url) self.content_type = headerinfo['content-type'] + if is_html(self.content_type): + # note: maybe got 404 or 503 http status code. + logger.error("Invalid content-type: `%s`" % self.content_type) + return + self.options = options self.logfile = os.path.join(PATH_LOG, 'build.log') self.configure_options = '' @@ -61,11 +71,9 @@ class PythonInstaller(object): if os.path.isdir(self.install_dir): logger.info("You are already installed `%s`" % self.pkg.name) raise AlreadyInstalledException - self.download_unpack() - 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("") + self.download_and_extract() + logger.info("\nThis could take a while. You can run the following command on another shell to track the status:") + logger.info(" tail -f %s\n" % self.logfile) self.patch() logger.info("Installing %s into %s" % (self.pkg.name, self.install_dir)) try: @@ -82,38 +90,32 @@ class PythonInstaller(object): logger.info("Installed %(pkgname)s successfully. Run the following command to switch to %(pkgname)s." % {"pkgname":self.pkg.name}) logger.info(" pythonbrew switch %s" % self.pkg.alias) - - def download_unpack(self): - content_type = self.content_type - if is_html(content_type): - logger.error("Invalid content-type: `%s`" % content_type) - sys.exit(1) + + def download_and_extract(self): if is_file(self.download_url): path = fileurl_to_path(self.download_url) if os.path.isdir(path): logger.info('Copying %s into %s' % (path, self.build_dir)) - if os.path.isdir(self.build_dir): - shutil.rmtree(self.build_dir) shutil.copytree(path, self.build_dir) return if os.path.isfile(self.download_file): logger.info("Use the previously fetched %s" % (self.download_file)) else: - msg = Link(self.download_url).show_msg + base_url = Link(self.download_url).base_url try: dl = Downloader() - dl.download(msg, self.download_url, self.download_file) + dl.download(base_url, self.download_url, self.download_file) except: unlink(self.download_file) logger.info("\nInterrupt to abort. `%s`" % (self.download_url)) sys.exit(1) - # unpack - if not unpack_downloadfile(self.content_type, self.download_file, self.build_dir): + # extracting + if not extract_downloadfile(self.content_type, self.download_file, self.build_dir): sys.exit(1) def patch(self): version = self.pkg.version - # ubuntu 11.04(Natty) + # for ubuntu 11.04(Natty) if is_python24(version): patch_dir = os.path.join(PATH_PATCHES_ALL, "python24") self._add_patches_to_list(patch_dir, ['patch-setup.py.diff']) @@ -142,15 +144,15 @@ class PythonInstaller(object): def _do_patch(self): try: - s = Subprocess(log=self.logfile, cwd=self.build_dir) + s = Subprocess(log=self.logfile, cwd=self.build_dir, verbose=self.options.verbose) if self.patches: logger.info("Patching %s" % self.pkg.name) for patch in self.patches: if type(patch) is dict: for (ed, source) in patch.items(): - s.check_call('ed - %s < %s' % (source, ed)) + s.shell('ed - %s < %s' % (source, ed)) else: - s.check_call("patch -p0 < %s" % patch) + s.shell("patch -p0 < %s" % patch) except: logger.error("Failed to patch `%s`" % self.build_dir) sys.exit(1) @@ -158,32 +160,35 @@ class PythonInstaller(object): def _add_patches_to_list(self, patch_dir, patch_files): for patch in patch_files: if type(patch) is dict: - for key in patch.keys(): - patch[os.path.join(patch_dir, key)] = patch[key] - del patch[key] + tmp = patch + patch = {} + for key in tmp.keys(): + patch[os.path.join(patch_dir, key)] = tmp[key] self.patches.append(patch) else: self.patches.append(os.path.join(patch_dir, patch)) def configure(self): - s = Subprocess(log=self.logfile, cwd=self.build_dir) + s = Subprocess(log=self.logfile, cwd=self.build_dir, verbose=self.options.verbose) s.check_call("./configure --prefix=%s %s %s" % (self.install_dir, self.options.configure, self.configure_options)) def make(self): jobs = self.options.jobs make = ((jobs > 0 and 'make -j%s' % jobs) or 'make') - s = Subprocess(log=self.logfile, cwd=self.build_dir) - if self.options.force: - s.check_call(make) - else: - s.check_call(make) - s.check_call("make test") + s = Subprocess(log=self.logfile, cwd=self.build_dir, verbose=self.options.verbose) + s.check_call(make) + if not self.options.no_test: + if self.options.force: + # note: ignore tests failure error. + s.call("make test") + else: + s.check_call("make test") def make_install(self): version = self.pkg.version if version == "1.5.2" or version == "1.6.1": makedirs(self.install_dir) - s = Subprocess(log=self.logfile, cwd=self.build_dir) + s = Subprocess(log=self.logfile, cwd=self.build_dir, verbose=self.options.verbose) s.check_call("make install") def symlink(self): @@ -201,7 +206,7 @@ class PythonInstaller(object): options = self.options pkgname = self.pkg.name if options.no_setuptools: - logger.info("Skip installation setuptools.") + logger.info("Skip installation of setuptools.") return download_url = DISTRIBUTE_SETUP_DLSITE filename = Link(download_url).filename @@ -213,41 +218,40 @@ class PythonInstaller(object): install_dir = os.path.join(PATH_PYTHONS, pkgname) path_python = os.path.join(install_dir,"bin","python") try: - s = Subprocess(log=self.logfile, cwd=PATH_DISTS) + s = Subprocess(log=self.logfile, cwd=PATH_DISTS, verbose=self.options.verbose) logger.info("Installing distribute into %s" % install_dir) - s.check_call("%s %s" % (path_python, filename)) - # Using easy_install install pip + s.check_call([path_python, filename]) + # installing pip easy_install = os.path.join(install_dir, 'bin', 'easy_install') if os.path.isfile(easy_install): logger.info("Installing pip into %s" % install_dir) - s.check_call("%s pip" % (easy_install)) + s.check_call([easy_install, 'pip']) except: logger.error("Failed to install setuptools. See %s/build.log to see why." % (ROOT)) - logger.info("Skip install setuptools.") + logger.info("Skip installation of setuptools.") class PythonInstallerMacOSX(PythonInstaller): - """Python installer for MacOSX SnowLeopard + """Python installer for MacOSX """ def __init__(self, arg, options): super(PythonInstallerMacOSX, self).__init__(arg, options) - version = self.pkg.version + # check for version + version = self.pkg.version if version < '2.6' and (version != '2.4.6' and version < '2.5.5'): logger.info("`%s` is not supported on MacOSX Snow Leopard" % self.pkg.name) raise NotSupportedVersionException # set configure options - if is_python24(version): - self.configure_options = '--with-universal-archs="intel" MACOSX_DEPLOYMENT_TARGET=10.6 CPPFLAGS="-D__DARWIN_UNIX03"' - elif is_python25(version): - self.configure_options = '--with-universal-archs="intel" MACOSX_DEPLOYMENT_TARGET=10.6 CPPFLAGS="-D_DARWIN_C_SOURCE"' - elif is_python26(version): - self.configure_options = '--with-universal-archs="intel" --enable-universalsdk=/ MACOSX_DEPLOYMENT_TARGET=10.6' - elif is_python27(version): - self.configure_options = '--with-universal-archs="intel" --enable-universalsdk=/ MACOSX_DEPLOYMENT_TARGET=10.6' - else: - self.configure_options = '--with-universal-archs="intel" --enable-universalsdk=/ MACOSX_DEPLOYMENT_TARGET=10.6' + target = get_macosx_deployment_target() + if target: + self.configure_options = 'MACOSX_DEPLOYMENT_TARGET=%s' % target + # note: skip `make test` to avoid hanging test_threading. + if is_python25(version) or is_python24(version): + self.options.no_test = True + def patch(self): + # note: want an interface to the source patching functionality. like a patchperl. version = self.pkg.version if is_python24(version): patch_dir = PATH_PATCHES_MACOSX_PYTHON24 diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 79780d3..45dadfe 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -1,17 +1,17 @@ import os +import sys import errno import shutil -import subprocess import re import posixpath import tarfile import platform import urllib -from subprocess import PIPE, Popen -from pythonbrew.define import PATH_BIN, PATH_PYTHONS, PATH_ETC_CURRENT +import subprocess +import shlex +from pythonbrew.define import PATH_BIN, PATH_ETC_CURRENT from pythonbrew.exceptions import ShellCommandException from pythonbrew.log import logger -import sys def size_format(b): kb = 1000 @@ -61,9 +61,15 @@ def is_gzip(content_type, filename): return True return False -def is_macosx_snowleopard(): +def is_macosx(): mac_ver = platform.mac_ver()[0] - return mac_ver >= '10.6' and mac_ver < '10.7' + return mac_ver >= '10.6' + +def get_macosx_deployment_target(): + m = re.search('^([0-9]+\.[0-9]+)', platform.mac_ver()[0]) + if m: + return m.group(1) + return None def is_python24(version): return version >= '2.4' and version < '2.5' @@ -116,12 +122,6 @@ def rm_r(path): 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) set_current_path(PATH_BIN) def split_leading_dir(path): @@ -151,7 +151,7 @@ def has_leading_dir(paths): def untar_file(filename, location): if not os.path.exists(location): - makedirs(location) + os.makedirs(location) if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): mode = 'r:gz' elif filename.lower().endswith('.bz2') or filename.lower().endswith('.tbz'): @@ -195,12 +195,15 @@ def untar_file(filename, location): shutil.copyfileobj(fp, destfp) finally: destfp.close() - os.chmod(path, member.mode) fp.close() + # note: configure ...etc + os.chmod(path, member.mode) + # note: the file timestamps should be such that asdl_c.py is not invoked. + os.utime(path, (member.mtime, member.mtime)) finally: tar.close() -def unpack_downloadfile(content_type, download_file, target_dir): +def extract_downloadfile(content_type, download_file, target_dir): logger.info("Extracting %s into %s" % (os.path.basename(download_file), target_dir)) if is_gzip(content_type, download_file): untar_file(download_file, target_dir) @@ -210,12 +213,10 @@ def unpack_downloadfile(content_type, download_file, target_dir): return True def get_current_python_path(): - p = Popen('command -v python', stdout=PIPE, shell=True) - p.wait() - if p.returncode == 0: - return p.stdout.read().strip() - else: - return None + """return: python path or '' + """ + p = subprocess.Popen(['command', '-v', 'python'], stdout=subprocess.PIPE) + return p.communicate()[0].strip() def set_current_path(path): fp = open(PATH_ETC_CURRENT, 'w') @@ -234,40 +235,71 @@ def fileurl_to_path(url): url = '/' + url[len('file:'):].lstrip('/') return urllib.unquote(url) -def u(val): - """to unicode - """ +def to_str(val): try: - # for python3 - if type(val) == bytes: + # python3 + if type(val) is bytes: return val.decode() except: - if type(val) == str: - return val.decode("utf-8") - return val + if type(val) is unicode: + return val.encode("utf-8") + return val + +def is_str(val): + try: + # python2 + return isinstance(val, basestring) + except: + # python3 + return isinstance(val, str) + return False class Subprocess(object): - def __init__(self, log=None, shell=True, cwd=None, print_cmd=False): + def __init__(self, log=None, cwd=None, verbose=False, debug=False): self._log = log - self._shell = shell self._cwd = cwd - self._print_cmd = print_cmd + self._verbose = verbose + self._debug = debug 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: + def shell(self, cmd): + if self._debug: 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 ShellCommandException('Failed to `%s` command' % cmd) + if self._verbose: + cmd = "(%s) 2>&1 | tee '%s'" % (cmd, self._log) + else: + cmd = "(%s) >> '%s' 2>&1" % (cmd, self._log) + returncode = subprocess.call(cmd, shell=True, cwd=self._cwd) + if returncode: + raise ShellCommandException('%s: failed to `%s`' % (returncode, cmd)) + + def call(self, cmd): + if is_str(cmd): + cmd = shlex.split(cmd) + if self._debug: + logger.info(cmd) + + fp = ((self._log and open(self._log, 'a')) or None) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self._cwd) + while p.returncode is None: + p.poll() + line = to_str(p.stdout.readline()) + if self._verbose: + logger.info(line.strip()) + if fp: + fp.write(line) + fp.flush() + if fp: + fp.close() + return p.returncode + + def check_call(self, cmd): + returncode = self.call(cmd) + if returncode: + raise ShellCommandException('%s: failed to `%s`' % (returncode, cmd)) class Package(object): def __init__(self, name, alias=None): @@ -302,7 +334,7 @@ class Link(object): return name @property - def show_msg(self): + def base_url(self): return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0]) diff --git a/tests/test_01_update.py b/tests/test_01_update.py index 99e0f5f..328a86a 100644 --- a/tests/test_01_update.py +++ b/tests/test_01_update.py @@ -1,5 +1,6 @@ class UpdateOptions(object): - head = False + master = False + develop = False config = False force = False @@ -7,4 +8,4 @@ def test_update(): from pythonbrew.commands.update import UpdateCommand c = UpdateCommand() c.run_command(UpdateOptions(), None) - + \ No newline at end of file diff --git a/tests/test_04_install.py b/tests/test_04_install.py index f54e26f..e033ebe 100644 --- a/tests/test_04_install.py +++ b/tests/test_04_install.py @@ -2,6 +2,8 @@ from tests import TESTPY_VERSION class InstallOptions(object): force = True + no_test = False + verbose = False configure = "" no_setuptools = False alias = None diff --git a/tests/test_11_clean.py b/tests/test_11_clean.py deleted file mode 100644 index 7823339..0000000 --- a/tests/test_11_clean.py +++ /dev/null @@ -1,4 +0,0 @@ -def test_clean(): - from pythonbrew.commands.clean import CleanCommand - c = CleanCommand() - c.run_command(None, None) diff --git a/tests/test_11_cleanup.py b/tests/test_11_cleanup.py new file mode 100644 index 0000000..3549334 --- /dev/null +++ b/tests/test_11_cleanup.py @@ -0,0 +1,4 @@ +def test_clean(): + from pythonbrew.commands.cleanup import CleanupCommand + c = CleanupCommand() + c.run_command(None, None) From f9bcb606380bdaae75f18977cbe3d2dc0e94c09e Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 10 Jul 2011 20:51:27 +0900 Subject: [PATCH 05/30] update readme --- PKG-INFO | 82 ++++++++++++++++++++++-------------------------------- README.rst | 2 +- 2 files changed, 35 insertions(+), 49 deletions(-) diff --git a/PKG-INFO b/PKG-INFO index d061329..6ade579 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,7 +1,7 @@ Overview ======== -pythonbrew is a program to automate the building and installation of Python in the users HOME. +pythonbrew is a program to automate the building and installation of Python in the users $HOME. pythonbrew is inspired by `perlbrew `_ and `rvm `_. @@ -10,20 +10,16 @@ Installation The recommended way to download and install pythonbrew is to run these statements in your shell:: - curl -kLO http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install - chmod +x pythonbrew-install - ./pythonbrew-install - -or more simply like this:: - - curl -kL http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install | bash + curl -kL http://xrl.us/pythonbrewinstall | bash After that, pythonbrew installs itself to ~/.pythonbrew, and you should follow the instruction on screen to setup your .bashrc 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 + curl -kLO http://xrl.us/pythonbrewinstall + chmod +x pythonbrewinstall + ./pythonbrewinstall Usage ===== @@ -32,59 +28,63 @@ pythonbrew command [options] Install some pythons:: - pythonbrew install 2.6.6 - pythonbrew install --force 2.6.6 - pythonbrew install --configure="CC=gcc_4.1" 2.6.6 - pythonbrew install --no-setuptools 2.6.6 - pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.6.6.tgz - pythonbrew install file:///path/to/Python-2.6.6.tgz - pythonbrew install /path/to/Python-2.6.6.tgz - pythonbrew install 2.5.5 2.6.6 + pythonbrew install 2.7.2 + pythonbrew install --verbose 2.7.2 + pythonbrew install --force 2.7.2 + pythonbrew install --no-test 2.7.2 + pythonbrew install --configure="CC=gcc_4.1" 2.7.2 + pythonbrew install --no-setuptools 2.7.2 + pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.7.2.tgz + pythonbrew install /path/to/Python-2.7.2.tgz + pythonbrew install /path/to/Python-2.7.2 + pythonbrew install 2.7.2 3.2 -Permanently use the specified python as default:: +Permanently use the specified python:: - pythonbrew switch 2.6.6 - pythonbrew switch 2.5.5 + pythonbrew switch 2.7.2 + pythonbrew switch 3.2 Use the specified python in current shell:: - pythonbrew use 2.6.6 + pythonbrew use 2.7.2 Runs a named python file against specified and/or all pythons:: pythonbrew py test.py pythonbrew py -v test.py # Show running python version - pythonbrew py -p 2.6.6 -p 3.1.2 test.py # Use the specified pythons + pythonbrew py -p 2.7.2 -p 3.2 test.py # Use the specified pythons List the installed pythons:: pythonbrew list -List the available install pythons:: +List the available installation pythons:: pythonbrew list -k Uninstall the specified python:: - pythonbrew uninstall 2.6.6 - pythonbrew uninstall 2.5.5 2.6.6 + pythonbrew uninstall 2.7.2 + pythonbrew uninstall 2.7.2 3.2 Remove stale source folders and archives:: - pythonbrew clean + pythonbrew cleanup Upgrades pythonbrew to the latest version:: pythonbrew update + pythonbrew update --master + pythonbrew update --develop Disable pythonbrew:: pythonbrew off -Create/Remove a symbolic link to python:: +Create/Remove a symbolic link to python (in a directory on your $PATH):: - pythonbrew symlink # Create a symbolic link, like "py2.5.5" - pythonbrew symlink -p 2.5.5 + pythonbrew symlink # Create a symbolic link, like "py2.7.2", for each installed version + pythonbrew symlink -p 2.7.2 pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory pythonbrew symlink -r # Remove a symbolic link @@ -97,10 +97,7 @@ COMMANDS install Build and install the given version of python. - - Setuptools and pip is automatically installed. - - options: --force, --no-setuptools, --configure and --as. + Install setuptools and pip automatically. switch Permanently use the specified python as default. @@ -120,7 +117,7 @@ list -k uninstall Uninstall the given version of python. -clean +cleanup Remove stale source folders and archives. update @@ -131,21 +128,10 @@ off version Show version. + +See more details below:: -Options -======= - -\-f | --force - Force installation of a python. (skip `make test`) - -\-C | --configure - Custom configure options. - -\-n | --no-setuptools - Skip installation of setuptools. - -\--as - Install a python under an alias. + pythonbrew help LICENCE ======= diff --git a/README.rst b/README.rst index 881912e..6ade579 100644 --- a/README.rst +++ b/README.rst @@ -131,7 +131,7 @@ version See more details below:: - `pythonbrew help ` + pythonbrew help LICENCE ======= From 2469c1a7af193ccdecb46bccbd4f5a37406a4943 Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 10 Jul 2011 21:17:05 +0900 Subject: [PATCH 06/30] update --- pythonbrew/__init__.py | 5 +++++ pythonbrew/commands/clean.py | 12 ------------ pythonbrew/commands/help.py | 2 +- pythonbrew/util.py | 4 ++-- 4 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 pythonbrew/commands/clean.py diff --git a/pythonbrew/__init__.py b/pythonbrew/__init__.py index 5e2f4d8..e09793c 100644 --- a/pythonbrew/__init__.py +++ b/pythonbrew/__init__.py @@ -1,6 +1,7 @@ import sys from pythonbrew.basecommand import command_dict, load_all_commands from pythonbrew.baseparser import parser +from pythonbrew.log import logger def main(): options, args = parser.parse_args(sys.argv[1:]) @@ -12,6 +13,10 @@ def main(): load_all_commands() command = args[0].lower() if command not in command_dict: + if command == 'clean': + # note: for some time + logger.info('\nDEPRECATION WARNING: `pythonbrew clean` has been renamed. Please run `pythonbrew cleanup` instead.\n') + return parser.error("Unknown command: `%s`" % command) return command = command_dict[command] diff --git a/pythonbrew/commands/clean.py b/pythonbrew/commands/clean.py deleted file mode 100644 index c967e76..0000000 --- a/pythonbrew/commands/clean.py +++ /dev/null @@ -1,12 +0,0 @@ -from pythonbrew.basecommand import Command -from pythonbrew.log import logger - -class CleanCommand(Command): - name = "clean" - usage = "%prog" - summary = "Remove stale source folders and archives" - - def run_command(self, options, args): - logger.info('\nDEPRECATION WARNING: `pythonbrew clean` has been renamed. Please run `pythonbrew cleanup` instead.\n') - -CleanCommand() diff --git a/pythonbrew/commands/help.py b/pythonbrew/commands/help.py index a3dda2a..7256ae4 100644 --- a/pythonbrew/commands/help.py +++ b/pythonbrew/commands/help.py @@ -22,6 +22,6 @@ class HelpCommand(Command): for command in commands: logger.info(" %s: %s" % (command.name, command.summary)) logger.info("\nFurther Instructions:") - logger.info(" http://github.com/utahta/pythonbrew") + logger.info(" https://github.com/utahta/pythonbrew") HelpCommand() diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 45dadfe..457e936 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -215,8 +215,8 @@ def extract_downloadfile(content_type, download_file, target_dir): def get_current_python_path(): """return: python path or '' """ - p = subprocess.Popen(['command', '-v', 'python'], stdout=subprocess.PIPE) - return p.communicate()[0].strip() + p = subprocess.Popen('command -v python', stdout=subprocess.PIPE, shell=True) + return to_str(p.communicate()[0].strip()) def set_current_path(path): fp = open(PATH_ETC_CURRENT, 'w') From f09e32372da5a4fbf2aa3e41127062d4eb656d23 Mon Sep 17 00:00:00 2001 From: utahta Date: Mon, 11 Jul 2011 00:01:20 +0900 Subject: [PATCH 07/30] update --- tests/test_04_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_04_install.py b/tests/test_04_install.py index e033ebe..6d0cd17 100644 --- a/tests/test_04_install.py +++ b/tests/test_04_install.py @@ -2,7 +2,7 @@ from tests import TESTPY_VERSION class InstallOptions(object): force = True - no_test = False + no_test = True verbose = False configure = "" no_setuptools = False From aec7d769b18b77e44ff3c235bcb8d85cad390b83 Mon Sep 17 00:00:00 2001 From: utahta Date: Mon, 11 Jul 2011 19:03:37 +0900 Subject: [PATCH 08/30] bug fix --- pythonbrew/util.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 457e936..1530777 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -9,6 +9,7 @@ import platform import urllib import subprocess import shlex +import select from pythonbrew.define import PATH_BIN, PATH_ETC_CURRENT from pythonbrew.exceptions import ShellCommandException from pythonbrew.log import logger @@ -254,6 +255,16 @@ def is_str(val): return isinstance(val, str) return False +def bltin_any(iter): + try: + return any(iter) + except: + # python2.4 + for it in iter: + if it: + return True + return False + class Subprocess(object): def __init__(self, log=None, cwd=None, verbose=False, debug=False): self._log = log @@ -285,13 +296,16 @@ class Subprocess(object): fp = ((self._log and open(self._log, 'a')) or None) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self._cwd) while p.returncode is None: + while bltin_any(select.select([p.stdout], [], [])): + line = to_str(p.stdout.readline()) + if not line: + break + if self._verbose: + logger.info(line.strip()) + if fp: + fp.write(line) + fp.flush() p.poll() - line = to_str(p.stdout.readline()) - if self._verbose: - logger.info(line.strip()) - if fp: - fp.write(line) - fp.flush() if fp: fp.close() return p.returncode From 1db87055fda3ab5be164770ad2300151c6946583 Mon Sep 17 00:00:00 2001 From: utahta Date: Mon, 18 Jul 2011 22:31:13 +0900 Subject: [PATCH 09/30] Added buildout command --- .gitignore | 1 + pythonbrew/commands/buildout.py | 56 +++++++++++++++++++++++++++++++++ pythonbrew/define.py | 3 ++ pythonbrew/etc/config.cfg | 3 ++ 4 files changed, 63 insertions(+) create mode 100644 pythonbrew/commands/buildout.py diff --git a/.gitignore b/.gitignore index 1e2444e..1306759 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ pythonbrew.egg-info dist __pycache__ +*.swp diff --git a/pythonbrew/commands/buildout.py b/pythonbrew/commands/buildout.py new file mode 100644 index 0000000..bf81a40 --- /dev/null +++ b/pythonbrew/commands/buildout.py @@ -0,0 +1,56 @@ +import os +import sys +import subprocess +from pythonbrew.basecommand import Command +from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE, PATH_DISTS +from pythonbrew.util import Package, get_current_python_path, Link +from pythonbrew.log import logger +from pythonbrew.downloader import Downloader + +class BuildoutCommand(Command): + name = "buildout" + usage = "%prog" + summary = "Runs the buildout against specified or currently use python" + + def __init__(self): + super(BuildoutCommand, self).__init__() + self.parser.add_option( + "-p", "--python", + dest="python", + default=None, + help="Use the specified version of python.", + metavar='VERSION' + ) + self.parser.disable_interspersed_args() + + def run_command(self, options, args): + if options.python: + python = Package(options.python).name + python = os.path.join(PATH_PYTHONS, python, 'bin', 'python') + if not os.path.isfile(python): + logger.info('%s is not installed.' % options.python) + sys.exit(1) + else: + python = get_current_python_path() + logger.info('Using %s' % python) + + # Download bootstrap.py + download_url = BOOTSTRAP_DLSITE + filename = Link(download_url).filename + bootstrap = os.path.join(PATH_DISTS, filename) + try: + d = Downloader() + d.download(filename, download_url, bootstrap) + except: + logger.error("Failed to download. `%s`" % download_url) + sys.exit(1) + + # Using bootstrap.py + if subprocess.call([python, bootstrap, '-d']): + logger.error('Failed to bootstrap.') + sys.exit(1) + + # Using buildout + subprocess.call(['./bin/buildout']) + +BuildoutCommand() diff --git a/pythonbrew/define.py b/pythonbrew/define.py index 593d2a7..761d829 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -53,6 +53,9 @@ def _get_or_default(section, option, default=''): # setuptools download DISTRIBUTE_SETUP_DLSITE = _get_or_default('distribute', 'url') +# buildout bootstrap download +BOOTSTRAP_DLSITE = _get_or_default('bootstrap', 'url') + # pythonbrew download PYTHONBREW_UPDATE_URL_MASTER = _get_or_default('pythonbrew', 'master') PYTHONBREW_UPDATE_URL_DEVELOP = _get_or_default('pythonbrew', 'develop') diff --git a/pythonbrew/etc/config.cfg b/pythonbrew/etc/config.cfg index dbdc698..1a16836 100644 --- a/pythonbrew/etc/config.cfg +++ b/pythonbrew/etc/config.cfg @@ -1,6 +1,9 @@ [distribute] url = http://python-distribute.org/distribute_setup.py +[bootstrap] +url = http://svn.zope.org/*checkout*/zc.buildout/trunk/bootstrap/bootstrap.py + [pythonbrew] master = https://github.com/utahta/pythonbrew/tarball/master develop = https://github.com/utahta/pythonbrew/tarball/develop From 219ad1745996e7f8fe4ece57255d7f2bc8acd3c1 Mon Sep 17 00:00:00 2001 From: utahta Date: Tue, 19 Jul 2011 23:17:29 +0900 Subject: [PATCH 10/30] update --- pythonbrew/commands/buildout.py | 19 +++-- pythonbrew/commands/list.py | 6 +- pythonbrew/commands/switch.py | 7 +- pythonbrew/commands/uninstall.py | 7 +- pythonbrew/commands/venv.py | 84 +++++++++++++++++++ pythonbrew/util.py | 26 +++--- tests/__init__.py | 5 +- tests/test_00_install_pythonbrew.py | 3 - .../{test_01_update.py => test_00_update.py} | 0 tests/{test_02_help.py => test_01_help.py} | 0 ...{test_03_version.py => test_02_version.py} | 0 ...{test_04_install.py => test_03_install.py} | 0 .../{test_05_switch.py => test_04_switch.py} | 0 tests/{test_06_use.py => test_05_use.py} | 0 tests/{test_07_off.py => test_06_off.py} | 0 tests/{test_08_list.py => test_07_list.py} | 0 tests/{test_09_py.py => test_08_py.py} | 5 +- tests/test_09_buildout.py | 31 +++++++ 18 files changed, 157 insertions(+), 36 deletions(-) create mode 100644 pythonbrew/commands/venv.py delete mode 100644 tests/test_00_install_pythonbrew.py rename tests/{test_01_update.py => test_00_update.py} (100%) rename tests/{test_02_help.py => test_01_help.py} (100%) rename tests/{test_03_version.py => test_02_version.py} (100%) rename tests/{test_04_install.py => test_03_install.py} (100%) rename tests/{test_05_switch.py => test_04_switch.py} (100%) rename tests/{test_06_use.py => test_05_use.py} (100%) rename tests/{test_07_off.py => test_06_off.py} (100%) rename tests/{test_08_list.py => test_07_list.py} (100%) rename tests/{test_09_py.py => test_08_py.py} (76%) create mode 100644 tests/test_09_buildout.py diff --git a/pythonbrew/commands/buildout.py b/pythonbrew/commands/buildout.py index bf81a40..879db36 100644 --- a/pythonbrew/commands/buildout.py +++ b/pythonbrew/commands/buildout.py @@ -3,7 +3,7 @@ import sys import subprocess from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE, PATH_DISTS -from pythonbrew.util import Package, get_current_python_path, Link +from pythonbrew.util import Package, get_current_use_pkgname, Link, is_installed from pythonbrew.log import logger from pythonbrew.downloader import Downloader @@ -21,18 +21,19 @@ class BuildoutCommand(Command): help="Use the specified version of python.", metavar='VERSION' ) - self.parser.disable_interspersed_args() def run_command(self, options, args): if options.python: - python = Package(options.python).name - python = os.path.join(PATH_PYTHONS, python, 'bin', 'python') - if not os.path.isfile(python): - logger.info('%s is not installed.' % options.python) - sys.exit(1) + pkgname = Package(options.python).name else: - python = get_current_python_path() - logger.info('Using %s' % python) + pkgname = get_current_use_pkgname() + if not is_installed(pkgname): + logger.info('%s is not installed.' % pkgname) + sys.exit(1) + logger.info('Using %s' % pkgname) + + # build a path + python = os.path.join(PATH_PYTHONS, pkgname, 'bin', 'python') # Download bootstrap.py download_url = BOOTSTRAP_DLSITE diff --git a/pythonbrew/commands/list.py b/pythonbrew/commands/list.py index 1c9f76d..f0e3ccc 100644 --- a/pythonbrew/commands/list.py +++ b/pythonbrew/commands/list.py @@ -3,7 +3,7 @@ import re from pythonbrew.basecommand import Command from pythonbrew.define import PYTHON_VERSION_URL, LATEST_VERSIONS_OF_PYTHON,\ PATH_PYTHONS -from pythonbrew.util import Package, get_current_python_path +from pythonbrew.util import Package, get_current_use_pkgname from pythonbrew.log import logger class ListCommand(Command): @@ -36,9 +36,9 @@ class ListCommand(Command): def installed(self, options, args): logger.info('# installed pythons') - cur = get_current_python_path() + cur = get_current_use_pkgname() for d in sorted(os.listdir(PATH_PYTHONS)): - if cur and os.path.samefile(cur, os.path.join(PATH_PYTHONS, d, 'bin','python')): + if cur and cur == d: logger.info('%s (*)' % d) cur = None else: diff --git a/pythonbrew/commands/switch.py b/pythonbrew/commands/switch.py index 2fcfc29..d25e5c5 100644 --- a/pythonbrew/commands/switch.py +++ b/pythonbrew/commands/switch.py @@ -2,7 +2,7 @@ import os import sys from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS, PATH_BIN -from pythonbrew.util import Package, set_current_path +from pythonbrew.util import Package, set_current_path, is_installed from pythonbrew.log import logger class SwitchCommand(Command): @@ -16,11 +16,10 @@ class SwitchCommand(Command): sys.exit(1) pkg = Package(args[0]) pkgname = pkg.name - pkgdir = os.path.join(PATH_PYTHONS, pkgname) - if not os.path.isdir(pkgdir): + if not is_installed(pkgname): logger.info("`%s` is not installed." % pkgname) sys.exit(1) - pkgbin = os.path.join(pkgdir,'bin') + pkgbin = os.path.join(PATH_PYTHONS,pkgname,'bin') set_current_path('%s:%s' % (PATH_BIN, pkgbin)) diff --git a/pythonbrew/commands/uninstall.py b/pythonbrew/commands/uninstall.py index 19f506d..2659bec 100644 --- a/pythonbrew/commands/uninstall.py +++ b/pythonbrew/commands/uninstall.py @@ -1,7 +1,8 @@ import os from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS, PATH_BIN -from pythonbrew.util import off, rm_r, Package, get_current_python_path, unlink +from pythonbrew.util import off, rm_r, Package, get_current_use_pkgname, unlink,\ + is_installed from pythonbrew.log import logger class UninstallCommand(Command): @@ -16,10 +17,10 @@ class UninstallCommand(Command): pkg = Package(arg) pkgname = pkg.name pkgpath = os.path.join(PATH_PYTHONS, pkgname) - if not os.path.isdir(pkgpath): + if not is_installed(pkgname): logger.info("`%s` is not installed." % pkgname) continue - if get_current_python_path() == os.path.join(pkgpath,'bin','python'): + if get_current_use_pkgname() == pkgname: off() for d in os.listdir(PATH_BIN): # remove symlink diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py new file mode 100644 index 0000000..df174b3 --- /dev/null +++ b/pythonbrew/commands/venv.py @@ -0,0 +1,84 @@ +import os +import sys +import subprocess +from pythonbrew.basecommand import Command +from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE, PATH_DISTS +from pythonbrew.util import Package, get_current_use_pkgname, Link +from pythonbrew.log import logger +from pythonbrew.downloader import Downloader + +class VenvCommand(Command): + name = "venv" + usage = "%prog [create|use|delete|list] [project]" + summary = "Create isolated python environments" + + def __init__(self): + super(VenvCommand, self).__init__() + self.parser.add_option( + "-p", "--python", + dest="python", + default=None, + help="Use the specified version of python.", + metavar='VERSION' + ) + + def run_command(self, options, args): + if not args: + logger.error('Unrecognized command line argument: argument not found.') + sys.exit(1) + cmd = args[0] + if not cmd in ('create', 'use', 'delete', 'list'): + logger.error('%s command not found.' % cmd) + sys.exit(1) + + # Decide which version of python to use. + if options.python: + pkgname = Package(options.python).name + else: + pkgname = get_current_use_pkgname() + logger.info('Using %s' % pkgname) + + if cmd == 'create': + self._create(args[1:]) + elif cmd == 'use': + self._use(args[1]) + elif cmd == 'delete': + self._delete(args[1:]) + elif cmd == 'list': + self._list() + + # Download bootstrap.py +# download_url = BOOTSTRAP_DLSITE +# filename = Link(download_url).filename +# bootstrap = os.path.join(PATH_DISTS, filename) +# try: +# d = Downloader() +# d.download(filename, download_url, bootstrap) +# except: +# logger.error("Failed to download. `%s`" % download_url) +# sys.exit(1) +# +# # Using bootstrap.py +# if subprocess.call([python, bootstrap, '-d']): +# logger.error('Failed to bootstrap.') +# sys.exit(1) +# +# # Using buildout +# subprocess.call(['./bin/buildout']) + + def _create(self, projects): + """Create python environment""" + for proj in projects: + print proj + + def _use(self, project): + print project + + def _delete(self, projects): + for proj in projects: + print proj + + def _list(self): + print 'list' + +VenvCommand() diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 1530777..ab6b661 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -10,7 +10,7 @@ import urllib import subprocess import shlex import select -from pythonbrew.define import PATH_BIN, PATH_ETC_CURRENT +from pythonbrew.define import PATH_BIN, PATH_ETC_CURRENT, PATH_PYTHONS from pythonbrew.exceptions import ShellCommandException from pythonbrew.log import logger @@ -94,12 +94,8 @@ def is_python32(version): return version >= '3.2' and version < '3.3' def makedirs(path): - try: + if not os.path.exists(path): os.makedirs(path) - except OSError: - e = sys.exc_info()[1] - if errno.EEXIST != e.errno: - raise def symlink(src, dst): try: @@ -213,12 +209,22 @@ def extract_downloadfile(content_type, download_file, target_dir): return False return True -def get_current_python_path(): - """return: python path or '' - """ +def get_current_use_pkgname(): + """return: Python- or None""" p = subprocess.Popen('command -v python', stdout=subprocess.PIPE, shell=True) - return to_str(p.communicate()[0].strip()) + path = to_str(p.communicate()[0].strip()) + for d in sorted(os.listdir(PATH_PYTHONS)): + if path and os.path.samefile(path, os.path.join(PATH_PYTHONS, d, 'bin','python')): + return d + return None +def is_installed(name): + pkgname = Package(name).name + pkgdir = os.path.join(PATH_PYTHONS, pkgname) + if not os.path.isdir(pkgdir): + return False + return True + def set_current_path(path): fp = open(PATH_ETC_CURRENT, 'w') fp.write('PATH_PYTHONBREW="%s"\n' % (path)) diff --git a/tests/__init__.py b/tests/__init__.py index e6eeae9..2e311ed 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,17 +2,16 @@ import os import shutil PYTHONBREW_ROOT = '/tmp/pythonbrew.test' -TESTPY_FILE = '/tmp/pythonbrew_test.py' TESTPY_VERSION = ['2.4.6', '2.5.5', '2.6.6', '3.2'] def cleanall(): if os.path.isdir(PYTHONBREW_ROOT): shutil.rmtree(PYTHONBREW_ROOT) - if os.path.isfile(TESTPY_FILE): - os.remove(TESTPY_FILE) def setup(): os.environ['PYTHONBREW_ROOT'] = PYTHONBREW_ROOT cleanall() + from pythonbrew.installer import install_pythonbrew + install_pythonbrew() def teardown(): cleanall() diff --git a/tests/test_00_install_pythonbrew.py b/tests/test_00_install_pythonbrew.py deleted file mode 100644 index 30d0471..0000000 --- a/tests/test_00_install_pythonbrew.py +++ /dev/null @@ -1,3 +0,0 @@ -def test_install_pythonbrew(): - from pythonbrew.installer import install_pythonbrew - install_pythonbrew() \ No newline at end of file diff --git a/tests/test_01_update.py b/tests/test_00_update.py similarity index 100% rename from tests/test_01_update.py rename to tests/test_00_update.py diff --git a/tests/test_02_help.py b/tests/test_01_help.py similarity index 100% rename from tests/test_02_help.py rename to tests/test_01_help.py diff --git a/tests/test_03_version.py b/tests/test_02_version.py similarity index 100% rename from tests/test_03_version.py rename to tests/test_02_version.py diff --git a/tests/test_04_install.py b/tests/test_03_install.py similarity index 100% rename from tests/test_04_install.py rename to tests/test_03_install.py diff --git a/tests/test_05_switch.py b/tests/test_04_switch.py similarity index 100% rename from tests/test_05_switch.py rename to tests/test_04_switch.py diff --git a/tests/test_06_use.py b/tests/test_05_use.py similarity index 100% rename from tests/test_06_use.py rename to tests/test_05_use.py diff --git a/tests/test_07_off.py b/tests/test_06_off.py similarity index 100% rename from tests/test_07_off.py rename to tests/test_06_off.py diff --git a/tests/test_08_list.py b/tests/test_07_list.py similarity index 100% rename from tests/test_08_list.py rename to tests/test_07_list.py diff --git a/tests/test_09_py.py b/tests/test_08_py.py similarity index 76% rename from tests/test_09_py.py rename to tests/test_08_py.py index 77a0705..07031e6 100644 --- a/tests/test_09_py.py +++ b/tests/test_08_py.py @@ -1,4 +1,7 @@ -from tests import TESTPY_FILE +from tests import PYTHONBREW_ROOT +import os + +TESTPY_FILE = os.path.join(PYTHONBREW_ROOT, 'etc', 'testfile.py') class PyOptions(object): pythons = [] diff --git a/tests/test_09_buildout.py b/tests/test_09_buildout.py new file mode 100644 index 0000000..221757a --- /dev/null +++ b/tests/test_09_buildout.py @@ -0,0 +1,31 @@ +from tests import PYTHONBREW_ROOT +import os + +BUILDOUT_DIR = os.path.join(PYTHONBREW_ROOT, 'etc', 'buildout') +BUILDOUT_CONF = os.path.join(BUILDOUT_DIR, 'buildout.cfg') + +def _create_buildout_cfg(): + if not os.path.isdir(BUILDOUT_DIR): + os.makedirs(BUILDOUT_DIR) + fp = open(BUILDOUT_CONF, 'w') + fp.write("""[buildout] +parts = test +develop = + +[test] +recipe = +eggs =""") + fp.close() + +class BuildoutOptions(object): + python = '2.6.6' + +def test_buildout(): + from pythonbrew.commands.buildout import BuildoutCommand + + # Runs the buildout + _create_buildout_cfg() + os.chdir(BUILDOUT_DIR) + c = BuildoutCommand() + c.run_command(BuildoutOptions(), []) + \ No newline at end of file From ef4ff756308759d6c251561c5018fd495e1f35bd Mon Sep 17 00:00:00 2001 From: utahta Date: Wed, 20 Jul 2011 00:08:01 +0900 Subject: [PATCH 11/30] update --- README.rst | 17 ++++++++++++++--- pythonbrew/commands/buildout.py | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 6ade579..faf463c 100644 --- a/README.rst +++ b/README.rst @@ -51,7 +51,7 @@ Use the specified python in current shell:: Runs a named python file against specified and/or all pythons:: pythonbrew py test.py - pythonbrew py -v test.py # Show running python version + pythonbrew py -v test.py # Show verbose output pythonbrew py -p 2.7.2 -p 3.2 test.py # Use the specified pythons List the installed pythons:: @@ -88,6 +88,11 @@ Create/Remove a symbolic link to python (in a directory on your $PATH):: pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory pythonbrew symlink -r # Remove a symbolic link +Runs the buildout with specified or current using python:: + + pythonbrew buildout + pythonbrew buildout -p 2.6.6 + Show version:: pythonbrew version @@ -125,11 +130,17 @@ update off Disable pythonbrew. - + +symlink + Create/Remove a symbolic link to python (in a directory on your $PATH) + +buildout + Runs the buildout with specified or current using python. + version Show version. -See more details below:: +See more details below: pythonbrew help diff --git a/pythonbrew/commands/buildout.py b/pythonbrew/commands/buildout.py index 879db36..94cdfdd 100644 --- a/pythonbrew/commands/buildout.py +++ b/pythonbrew/commands/buildout.py @@ -10,7 +10,7 @@ from pythonbrew.downloader import Downloader class BuildoutCommand(Command): name = "buildout" usage = "%prog" - summary = "Runs the buildout against specified or currently use python" + summary = "Runs the buildout with specified or current using python" def __init__(self): super(BuildoutCommand, self).__init__() From b4a6674fba437d706abf15c53235a6a1a8ee550c Mon Sep 17 00:00:00 2001 From: utahta Date: Thu, 21 Jul 2011 02:14:41 +0900 Subject: [PATCH 12/30] Added venv command --- ChangeLog | 2 +- PKG-INFO | 27 +++++- README.rst | 10 +++ pythonbrew/commands/buildout.py | 4 +- pythonbrew/commands/list.py | 10 +-- pythonbrew/commands/uninstall.py | 4 +- pythonbrew/commands/venv.py | 93 ++++++++++----------- pythonbrew/define.py | 2 + pythonbrew/etc/bashrc | 37 ++++++++ pythonbrew/installer/pythonbrewinstaller.py | 3 +- pythonbrew/util.py | 9 +- 11 files changed, 133 insertions(+), 68 deletions(-) diff --git a/ChangeLog b/ChangeLog index b6e3837..dcc3575 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,7 +7,7 @@ - Fixed bug: `pythonbrew off` need not have removed the symlink in bin directory - Added --no-test option to the install command - Added --verbose option to the install command - - `pythonbrew clean` has been renamed. Added `pythonbrew cleanup` instead. + - `pythonbrew clean` has been removed. Added `pythonbrew cleanup` instead. * 0.7.3 - Improved symlink command diff --git a/PKG-INFO b/PKG-INFO index 6ade579..a074e0c 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -51,7 +51,7 @@ Use the specified python in current shell:: Runs a named python file against specified and/or all pythons:: pythonbrew py test.py - pythonbrew py -v test.py # Show running python version + pythonbrew py -v test.py # Show verbose output pythonbrew py -p 2.7.2 -p 3.2 test.py # Use the specified pythons List the installed pythons:: @@ -88,6 +88,18 @@ Create/Remove a symbolic link to python (in a directory on your $PATH):: pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory pythonbrew symlink -r # Remove a symbolic link +Runs the buildout with specified or current using python:: + + pythonbrew buildout + pythonbrew buildout -p 2.6.6 + +Create isolated python environments:: + + pythonbrew venv create proj1 + pythonbrew venv list + pythonbrew venv use proj1 + pythonbrew venv delete proj1 + Show version:: pythonbrew version @@ -125,11 +137,20 @@ update off Disable pythonbrew. - + +symlink + Create/Remove a symbolic link to python (in a directory on your $PATH) + +buildout + Runs the buildout with specified or current using python. + +venv + Create isolated python environments. + version Show version. -See more details below:: +See more details below: pythonbrew help diff --git a/README.rst b/README.rst index faf463c..a074e0c 100644 --- a/README.rst +++ b/README.rst @@ -93,6 +93,13 @@ Runs the buildout with specified or current using python:: pythonbrew buildout pythonbrew buildout -p 2.6.6 +Create isolated python environments:: + + pythonbrew venv create proj1 + pythonbrew venv list + pythonbrew venv use proj1 + pythonbrew venv delete proj1 + Show version:: pythonbrew version @@ -137,6 +144,9 @@ symlink buildout Runs the buildout with specified or current using python. +venv + Create isolated python environments. + version Show version. diff --git a/pythonbrew/commands/buildout.py b/pythonbrew/commands/buildout.py index 94cdfdd..81ef50a 100644 --- a/pythonbrew/commands/buildout.py +++ b/pythonbrew/commands/buildout.py @@ -3,7 +3,7 @@ import sys import subprocess from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE, PATH_DISTS -from pythonbrew.util import Package, get_current_use_pkgname, Link, is_installed +from pythonbrew.util import Package, get_using_python_pkgname, Link, is_installed from pythonbrew.log import logger from pythonbrew.downloader import Downloader @@ -26,7 +26,7 @@ class BuildoutCommand(Command): if options.python: pkgname = Package(options.python).name else: - pkgname = get_current_use_pkgname() + pkgname = get_using_python_pkgname() if not is_installed(pkgname): logger.info('%s is not installed.' % pkgname) sys.exit(1) diff --git a/pythonbrew/commands/list.py b/pythonbrew/commands/list.py index f0e3ccc..d9fb902 100644 --- a/pythonbrew/commands/list.py +++ b/pythonbrew/commands/list.py @@ -3,7 +3,8 @@ import re from pythonbrew.basecommand import Command from pythonbrew.define import PYTHON_VERSION_URL, LATEST_VERSIONS_OF_PYTHON,\ PATH_PYTHONS -from pythonbrew.util import Package, get_current_use_pkgname +from pythonbrew.util import Package, get_using_python_pkgname,\ + get_using_python_path from pythonbrew.log import logger class ListCommand(Command): @@ -36,15 +37,14 @@ class ListCommand(Command): def installed(self, options, args): logger.info('# installed pythons') - cur = get_current_use_pkgname() + cur = get_using_python_pkgname() for d in sorted(os.listdir(PATH_PYTHONS)): if cur and cur == d: logger.info('%s (*)' % d) - cur = None else: logger.info('%s' % d) - if cur: - logger.info('%s (*)' % cur) + if not cur: + logger.info('%s (*)' % get_using_python_path()) def available_install(self, options, args): logger.info('# available install pythons') diff --git a/pythonbrew/commands/uninstall.py b/pythonbrew/commands/uninstall.py index 2659bec..0a79e8c 100644 --- a/pythonbrew/commands/uninstall.py +++ b/pythonbrew/commands/uninstall.py @@ -1,7 +1,7 @@ import os from pythonbrew.basecommand import Command from pythonbrew.define import PATH_PYTHONS, PATH_BIN -from pythonbrew.util import off, rm_r, Package, get_current_use_pkgname, unlink,\ +from pythonbrew.util import off, rm_r, Package, get_using_python_pkgname, unlink,\ is_installed from pythonbrew.log import logger @@ -20,7 +20,7 @@ class UninstallCommand(Command): if not is_installed(pkgname): logger.info("`%s` is not installed." % pkgname) continue - if get_current_use_pkgname() == pkgname: + if get_using_python_pkgname() == pkgname: off() for d in os.listdir(PATH_BIN): # remove symlink diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index df174b3..9fb0ab7 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -1,11 +1,10 @@ import os import sys -import subprocess from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE, PATH_DISTS -from pythonbrew.util import Package, get_current_use_pkgname, Link +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.log import logger -from pythonbrew.downloader import Downloader class VenvCommand(Command): name = "venv" @@ -24,61 +23,53 @@ class VenvCommand(Command): def run_command(self, options, args): if not args: - logger.error('Unrecognized command line argument: argument not found.') - sys.exit(1) + logger.error('Unrecognized command line argument: ( see: \'pythonbrew help venv\' )') + sys.exit(1) cmd = args[0] if not cmd in ('create', 'use', 'delete', 'list'): - logger.error('%s command not found.' % cmd) + logger.error('Unrecognized command line argument: ( see: \'pythonbrew help venv\' )') sys.exit(1) - # Decide which version of python to use. if options.python: pkgname = Package(options.python).name else: - pkgname = get_current_use_pkgname() - logger.info('Using %s' % pkgname) + pkgname = get_using_python_pkgname() + if not is_installed(pkgname): + logger.error("%s is not installed." % pkgname) + sys.exit(1) + pkg_dir = os.path.join(PATH_PYTHONS, pkgname) + pkg_bin_dir = os.path.join(pkg_dir, 'bin') - if cmd == 'create': - self._create(args[1:]) - elif cmd == 'use': - self._use(args[1]) - elif cmd == 'delete': - self._delete(args[1:]) + self._pkg_bin_dir = pkg_bin_dir + self._venv_dir = os.path.join(PATH_VENVS, pkgname) + + # check python package name + if not pkgname: + logger.error('Can not create virtual environment before using a python. Try \'pythonbrew switch \'.') + sys.exit(1) + + # 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) + s = Subprocess(verbose=True) + s.shell('%s %s %s' % (os.path.join(pkg_bin_dir,'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': - self._list() - - # Download bootstrap.py -# download_url = BOOTSTRAP_DLSITE -# filename = Link(download_url).filename -# bootstrap = os.path.join(PATH_DISTS, filename) -# try: -# d = Downloader() -# d.download(filename, download_url, bootstrap) -# except: -# logger.error("Failed to download. `%s`" % download_url) -# sys.exit(1) -# -# # Using bootstrap.py -# if subprocess.call([python, bootstrap, '-d']): -# logger.error('Failed to bootstrap.') -# sys.exit(1) -# -# # Using buildout -# subprocess.call(['./bin/buildout']) - - def _create(self, projects): - """Create python environment""" - for proj in projects: - print proj - - def _use(self, project): - print project - - def _delete(self, projects): - for proj in projects: - print proj - - def _list(self): - print 'list' + logger.info('# virtualenv for %s (found in %s)' % (pkgname, self._venv_dir)) + + def _init(self): + 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.close() VenvCommand() diff --git a/pythonbrew/define.py b/pythonbrew/define.py index 761d829..5258694 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -23,6 +23,7 @@ PATH_DISTS = os.path.join(ROOT,"dists") PATH_ETC = os.path.join(ROOT,"etc") PATH_BIN = os.path.join(ROOT,"bin") PATH_LOG = os.path.join(ROOT,"log") +PATH_VENVS = os.path.join(ROOT, "venvs") PATH_SCRIPTS = os.path.join(ROOT,"scripts") PATH_SCRIPTS_PYTHONBREW = os.path.join(PATH_SCRIPTS,"pythonbrew") PATH_SCRIPTS_PYTHONBREW_COMMANDS = os.path.join(PATH_SCRIPTS_PYTHONBREW,"commands") @@ -40,6 +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') # read config.cfg config = ConfigParser.SafeConfigParser() diff --git a/pythonbrew/etc/bashrc b/pythonbrew/etc/bashrc index 6639033..8963f66 100644 --- a/pythonbrew/etc/bashrc +++ b/pythonbrew/etc/bashrc @@ -61,6 +61,42 @@ __pythonbrew_update() [[ $? == 0 ]] && __pythonbrew_reload } +__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 + fi +} + __pythonbrew_find_command() { command_name="" @@ -84,6 +120,7 @@ pythonbrew() switch) __pythonbrew_switch "$@" ;; off) __pythonbrew_off "$@" ;; update) __pythonbrew_update "$@" ;; + venv) __pythonbrew_venv "$@" ;; *) command pythonbrew "$@" ;; esac builtin hash -r diff --git a/pythonbrew/installer/pythonbrewinstaller.py b/pythonbrew/installer/pythonbrewinstaller.py index bc17bc3..14c23bc 100644 --- a/pythonbrew/installer/pythonbrewinstaller.py +++ b/pythonbrew/installer/pythonbrewinstaller.py @@ -7,7 +7,7 @@ from pythonbrew.define import PATH_BUILD, PATH_BIN, PATH_DISTS, PATH_PYTHONS,\ PATH_ETC, PATH_SCRIPTS, PATH_SCRIPTS_PYTHONBREW,\ PATH_SCRIPTS_PYTHONBREW_COMMANDS, PATH_BIN_PYTHONBREW,\ ROOT, PATH_LOG, PATH_PATCHES, PATH_ETC_CONFIG,\ - PATH_SCRIPTS_PYTHONBREW_INSTALLER + PATH_SCRIPTS_PYTHONBREW_INSTALLER, PATH_VENVS import stat class PythonbrewInstaller(object): @@ -22,6 +22,7 @@ class PythonbrewInstaller(object): makedirs(PATH_ETC) makedirs(PATH_BIN) makedirs(PATH_LOG) + makedirs(PATH_VENVS) # create script directories rm_r(PATH_SCRIPTS) diff --git a/pythonbrew/util.py b/pythonbrew/util.py index ab6b661..9bba392 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -209,10 +209,13 @@ def extract_downloadfile(content_type, download_file, target_dir): return False return True -def get_current_use_pkgname(): - """return: Python- or None""" +def get_using_python_path(): p = subprocess.Popen('command -v python', stdout=subprocess.PIPE, shell=True) - path = to_str(p.communicate()[0].strip()) + return to_str(p.communicate()[0].strip()) + +def get_using_python_pkgname(): + """return: Python- or None""" + path = get_using_python_path() for d in sorted(os.listdir(PATH_PYTHONS)): if path and os.path.samefile(path, os.path.join(PATH_PYTHONS, d, 'bin','python')): return d From 4aa62201c7f13f1212911308d19236b1be6ef790 Mon Sep 17 00:00:00 2001 From: utahta Date: Thu, 21 Jul 2011 02:22:00 +0900 Subject: [PATCH 13/30] update venv command --- pythonbrew/commands/venv.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index 9fb0ab7..25a0bce 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -32,22 +32,20 @@ class VenvCommand(Command): if options.python: pkgname = Package(options.python).name + if not is_installed(pkgname): + logger.error('%s is not installed.' % pkgname) + sys.exit(1) else: pkgname = get_using_python_pkgname() - if not is_installed(pkgname): - logger.error("%s is not installed." % pkgname) - sys.exit(1) + if not pkgname: + logger.error('Can not create virtual environment before using a python. Try \'pythonbrew install \'.') + 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) - # check python package name - if not pkgname: - logger.error('Can not create virtual environment before using a python. Try \'pythonbrew switch \'.') - sys.exit(1) - # 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'))): From 9fbc3273cfa7efe5c0de5485977c42e09eaa531a Mon Sep 17 00:00:00 2001 From: utahta Date: Fri, 22 Jul 2011 01:56:01 +0900 Subject: [PATCH 14/30] update venv command --- pythonbrew/commands/uninstall.py | 4 +- pythonbrew/commands/venv.py | 139 ++++++++++++++---- pythonbrew/define.py | 2 +- pythonbrew/etc/bashrc | 33 +---- pythonbrew/util.py | 4 + tests/test_10_venv.py | 11 ++ ...t_10_uninstall.py => test_11_uninstall.py} | 0 ...{test_11_cleanup.py => test_12_cleanup.py} | 0 8 files changed, 135 insertions(+), 58 deletions(-) create mode 100644 tests/test_10_venv.py rename tests/{test_10_uninstall.py => test_11_uninstall.py} (100%) rename tests/{test_11_cleanup.py => test_12_cleanup.py} (100%) 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 From 07828a266d9f956025cb8909b7b24e818482f06d Mon Sep 17 00:00:00 2001 From: utahta Date: Fri, 22 Jul 2011 18:38:20 +0900 Subject: [PATCH 15/30] update --- ChangeLog | 4 ++++ PKG-INFO | 6 +++--- README.rst | 6 +++--- pythonbrew/define.py | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index dcc3575..f61a9d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +* 0.9 + - Added `buildout` command. + - Added `venv` command. + * 0.8 - Fixed issue #21 Added Ubuntu 11.04(Natty) support - Fixed issue #24 non-framework python27 now defines environ properly. Thanks npinto. diff --git a/PKG-INFO b/PKG-INFO index a074e0c..832c59a 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -95,10 +95,10 @@ Runs the buildout with specified or current using python:: Create isolated python environments:: - pythonbrew venv create proj1 + pythonbrew venv create proj pythonbrew venv list - pythonbrew venv use proj1 - pythonbrew venv delete proj1 + pythonbrew venv use proj + pythonbrew venv delete proj Show version:: diff --git a/README.rst b/README.rst index a074e0c..832c59a 100644 --- a/README.rst +++ b/README.rst @@ -95,10 +95,10 @@ Runs the buildout with specified or current using python:: Create isolated python environments:: - pythonbrew venv create proj1 + pythonbrew venv create proj pythonbrew venv list - pythonbrew venv use proj1 - pythonbrew venv delete proj1 + pythonbrew venv use proj + pythonbrew venv delete proj Show version:: diff --git a/pythonbrew/define.py b/pythonbrew/define.py index 4b3551c..bf4dee5 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -6,7 +6,7 @@ except: import configparser as ConfigParser # pythonbrew version -VERSION = "0.8" +VERSION = "0.9" # pythonbrew root path ROOT = os.environ.get("PYTHONBREW_ROOT") From 704321f040c2f08978391051725210ce60333220 Mon Sep 17 00:00:00 2001 From: Chris Ledet Date: Fri, 22 Jul 2011 10:34:00 -0400 Subject: [PATCH 16/30] updated README --- README.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e872a7e..a4de515 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,11 @@ The recommended way to download and install pythonbrew is to run these statement curl -kL http://xrl.us/pythonbrewinstall | bash -After that, pythonbrew installs itself to ~/.pythonbrew, and you should follow the instruction on screen to setup your .bashrc to put it in your PATH. +After that, pythonbrew installs itself to ~/.pythonbrew. + +Please add the following line to the end of your ~/.bashrc + + [[ -s $HOME/.pythonbrew/etc/bashrc ]] && source $HOME/.pythonbrew/etc/bashrc If you need to install pythonbrew into somewhere else, you can do that by setting a PYTHONBREW_ROOT environment variable:: From 483b49984caea1616d23643f3322654da036f5fc Mon Sep 17 00:00:00 2001 From: Chris Ledet Date: Fri, 22 Jul 2011 07:35:05 -0700 Subject: [PATCH 17/30] updated README with corrected rst syntax --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a4de515..26b7f44 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ The recommended way to download and install pythonbrew is to run these statement After that, pythonbrew installs itself to ~/.pythonbrew. -Please add the following line to the end of your ~/.bashrc +Please add the following line to the end of your ~/.bashrc:: [[ -s $HOME/.pythonbrew/etc/bashrc ]] && source $HOME/.pythonbrew/etc/bashrc From 12b392a98c1ffdea02abbae8801605732a51269f Mon Sep 17 00:00:00 2001 From: utahta Date: Sat, 23 Jul 2011 16:31:37 +0900 Subject: [PATCH 18/30] fixed #34 #35 --- PKG-INFO | 45 ++++++++++++++++++++++++--------------------- README.rst | 4 ++-- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/PKG-INFO b/PKG-INFO index 9b02dc7..8276229 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -97,7 +97,7 @@ Runs the buildout with specified or current using python:: pythonbrew buildout pythonbrew buildout -p 2.6.6 -Create isolated python environments:: +Create isolated python environments (uses virtualenv and virtualenvwrapper):: pythonbrew venv create proj pythonbrew venv list @@ -149,7 +149,7 @@ buildout Runs the buildout with specified or current using python. venv - Create isolated python environments. + Create isolated python environments (uses virtualenv and virtualenvwrapper) version Show version. @@ -157,27 +157,30 @@ version See more details below `pythonbrew help ` -LICENCE -======= +Changelog +========= -The MIT License +0.9 (2011-07-21) +---------------- -Copyright (c) <2010-2011> +- Add `venv` command (virtualenv and virtualenvwrapper supported) +- Add `buildout` command. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +0.8 (2011-07-10) +---------------- -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +- Fixed issue #21 Added Ubuntu 11.04(Natty) support +- Fixed issue #24 non-framework python27 now defines environ properly. Thanks npinto. +- Fixed issue #27 Cleanup of OS X python build flags +- Fixed issue #28 Describe the 'symlink' command better. Thanks tgs. +- Fixed issue #30 py command does not accept arguments with a space +- Fixed bug: `pythonbrew off` need not have removed the symlink in bin directory +- Added --no-test option to the install command +- Added --verbose option to the install command +- `pythonbrew clean` has been removed. Added `pythonbrew cleanup` instead. + +More +---- + +see the `pythonbrew/Changelog `_ -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/README.rst b/README.rst index 9b02dc7..68e9b7b 100644 --- a/README.rst +++ b/README.rst @@ -97,7 +97,7 @@ Runs the buildout with specified or current using python:: pythonbrew buildout pythonbrew buildout -p 2.6.6 -Create isolated python environments:: +Create isolated python environments (uses virtualenv and virtualenvwrapper):: pythonbrew venv create proj pythonbrew venv list @@ -149,7 +149,7 @@ buildout Runs the buildout with specified or current using python. venv - Create isolated python environments. + Create isolated python environments (uses virtualenv and virtualenvwrapper) version Show version. From 04f4cd15b3367d16da15997585c865c773d8f83b Mon Sep 17 00:00:00 2001 From: utahta Date: Sat, 6 Aug 2011 23:56:31 +0900 Subject: [PATCH 19/30] Improve venv command, log and bashrc --- pythonbrew/__init__.py | 2 +- pythonbrew/commands/buildout.py | 6 +- pythonbrew/commands/help.py | 8 +- pythonbrew/commands/install.py | 36 ++--- pythonbrew/commands/list.py | 19 +-- pythonbrew/commands/py.py | 6 +- pythonbrew/commands/switch.py | 8 +- pythonbrew/commands/symlink.py | 2 +- pythonbrew/commands/uninstall.py | 2 +- pythonbrew/commands/update.py | 2 +- pythonbrew/commands/use.py | 13 +- pythonbrew/commands/venv.py | 168 ++++++++++---------- pythonbrew/commands/version.py | 2 +- pythonbrew/curl.py | 2 +- pythonbrew/define.py | 27 +++- pythonbrew/etc/bashrc | 44 +++-- pythonbrew/etc/config.cfg | 3 + pythonbrew/installer/__init__.py | 4 +- pythonbrew/installer/pythonbrewinstaller.py | 3 +- pythonbrew/installer/pythoninstaller.py | 14 +- pythonbrew/log.py | 70 ++++---- pythonbrew/util.py | 19 ++- tests/test_10_venv.py | 10 ++ 23 files changed, 257 insertions(+), 213 deletions(-) diff --git a/pythonbrew/__init__.py b/pythonbrew/__init__.py index e09793c..d190d8c 100644 --- a/pythonbrew/__init__.py +++ b/pythonbrew/__init__.py @@ -15,7 +15,7 @@ def main(): if command not in command_dict: if command == 'clean': # note: for some time - logger.info('\nDEPRECATION WARNING: `pythonbrew clean` has been renamed. Please run `pythonbrew cleanup` instead.\n') + logger.log('\nDEPRECATION WARNING: `pythonbrew clean` has been renamed. Please run `pythonbrew cleanup` instead.\n') return parser.error("Unknown command: `%s`" % command) return diff --git a/pythonbrew/commands/buildout.py b/pythonbrew/commands/buildout.py index 81ef50a..5d08ffe 100644 --- a/pythonbrew/commands/buildout.py +++ b/pythonbrew/commands/buildout.py @@ -28,7 +28,7 @@ class BuildoutCommand(Command): else: pkgname = get_using_python_pkgname() if not is_installed(pkgname): - logger.info('%s is not installed.' % pkgname) + logger.error('`%s` is not installed.' % pkgname) sys.exit(1) logger.info('Using %s' % pkgname) @@ -46,12 +46,12 @@ class BuildoutCommand(Command): logger.error("Failed to download. `%s`" % download_url) sys.exit(1) - # Using bootstrap.py + # call bootstrap.py if subprocess.call([python, bootstrap, '-d']): logger.error('Failed to bootstrap.') sys.exit(1) - # Using buildout + # call buildout subprocess.call(['./bin/buildout']) BuildoutCommand() diff --git a/pythonbrew/commands/help.py b/pythonbrew/commands/help.py index 7256ae4..7e9d8a3 100644 --- a/pythonbrew/commands/help.py +++ b/pythonbrew/commands/help.py @@ -17,11 +17,11 @@ class HelpCommand(Command): command.parser.print_help() return parser.print_help() - logger.info("\nCommands available:") + logger.log("\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(" https://github.com/utahta/pythonbrew") + logger.log(" %s: %s" % (command.name, command.summary)) + logger.log("\nFurther Instructions:") + logger.log(" https://github.com/utahta/pythonbrew") HelpCommand() diff --git a/pythonbrew/commands/install.py b/pythonbrew/commands/install.py index 34e6877..2a67c2c 100644 --- a/pythonbrew/commands/install.py +++ b/pythonbrew/commands/install.py @@ -1,5 +1,5 @@ +import sys from pythonbrew.basecommand import Command -from pythonbrew.log import logger from pythonbrew.installer.pythoninstaller import PythonInstaller,\ PythonInstallerMacOSX from pythonbrew.util import is_macosx @@ -63,22 +63,22 @@ class InstallCommand(Command): ) def run_command(self, options, args): - if args: - # installing python - for arg in args: - try: - if is_macosx(): - p = PythonInstallerMacOSX(arg, options) - else: - p = PythonInstaller(arg, options) - p.install() - except UnknownVersionException: - continue - except AlreadyInstalledException: - continue - except NotSupportedVersionException: - continue - else: - logger.info("Unknown python version.") + if not args: + self.parser.print_help() + sys.exit(1) + # installing python + for arg in args: + try: + if is_macosx(): + p = PythonInstallerMacOSX(arg, options) + else: + p = PythonInstaller(arg, options) + p.install() + except UnknownVersionException: + continue + except AlreadyInstalledException: + continue + except NotSupportedVersionException: + continue InstallCommand() diff --git a/pythonbrew/commands/list.py b/pythonbrew/commands/list.py index d9fb902..ab4293d 100644 --- a/pythonbrew/commands/list.py +++ b/pythonbrew/commands/list.py @@ -3,8 +3,7 @@ import re from pythonbrew.basecommand import Command from pythonbrew.define import PYTHON_VERSION_URL, LATEST_VERSIONS_OF_PYTHON,\ PATH_PYTHONS -from pythonbrew.util import Package, get_using_python_pkgname,\ - get_using_python_path +from pythonbrew.util import Package, get_using_python_pkgname from pythonbrew.log import logger class ListCommand(Command): @@ -36,18 +35,16 @@ class ListCommand(Command): self.installed(options, args) def installed(self, options, args): - logger.info('# installed pythons') + logger.log("# pythonbrew pythons") cur = get_using_python_pkgname() for d in sorted(os.listdir(PATH_PYTHONS)): if cur and cur == d: - logger.info('%s (*)' % d) + logger.log(' %s (*)' % d) else: - logger.info('%s' % d) - if not cur: - logger.info('%s (*)' % get_using_python_path()) + logger.log(' %s' % d) def available_install(self, options, args): - logger.info('# available install pythons') + logger.log('# Pythons') if args: pkg = Package(args[0]) _re = re.compile(r"%s" % pkg.name) @@ -57,12 +54,12 @@ class ListCommand(Command): pkgs.append(pkgname) if pkgs: for pkgname in pkgs: - logger.info("%s" % pkgname) + logger.log("%s" % pkgname) else: - logger.info("Python version not found. `%s`" % pkg.name) + logger.error("Python version not found. `%s`" % pkg.name) else: for pkgname in self._get_packages_name(options): - logger.info("%s" % pkgname) + logger.log("%s" % pkgname) def _get_packages_name(self, options): return ["Python-%s" % version for version in sorted(PYTHON_VERSION_URL.keys()) diff --git a/pythonbrew/commands/py.py b/pythonbrew/commands/py.py index 9390dca..102cb79 100644 --- a/pythonbrew/commands/py.py +++ b/pythonbrew/commands/py.py @@ -32,12 +32,12 @@ class PyCommand(Command): def run_command(self, options, args): if not args: - logger.info("Unrecognized command line argument: argument not found.") + self.parser.print_help() sys.exit(1) pythons = self._get_pythons(options.pythons) for d in pythons: if options.verbose: - logger.info('*** %s ***' % d) + logger.info('`%s` running...' % d) path = os.path.join(PATH_PYTHONS, d, 'bin', args[0]) if os.path.isfile(path) and os.access(path, os.X_OK): subprocess.call([path] + args[1:]) @@ -46,7 +46,7 @@ class PyCommand(Command): if os.path.isfile(path) and os.access(path, os.X_OK): subprocess.call([path] + args) else: - logger.info('%s: No such file or directory.' % path) + logger.error('%s: No such file or directory.' % path) def _get_pythons(self, _pythons): pythons = [Package(p).name for p in _pythons] diff --git a/pythonbrew/commands/switch.py b/pythonbrew/commands/switch.py index d25e5c5..34e25be 100644 --- a/pythonbrew/commands/switch.py +++ b/pythonbrew/commands/switch.py @@ -1,7 +1,7 @@ import os import sys from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, PATH_BIN +from pythonbrew.define import PATH_PYTHONS from pythonbrew.util import Package, set_current_path, is_installed from pythonbrew.log import logger @@ -12,16 +12,16 @@ class SwitchCommand(Command): def run_command(self, options, args): if not args: - logger.info("Unrecognized command line argument: argument not found.") + self.parser.print_help() sys.exit(1) pkg = Package(args[0]) pkgname = pkg.name if not is_installed(pkgname): - logger.info("`%s` is not installed." % pkgname) + logger.error("`%s` is not installed." % pkgname) sys.exit(1) pkgbin = os.path.join(PATH_PYTHONS,pkgname,'bin') - set_current_path('%s:%s' % (PATH_BIN, pkgbin)) + set_current_path(pkgbin) logger.info("Switched to %s" % pkgname) diff --git a/pythonbrew/commands/symlink.py b/pythonbrew/commands/symlink.py index 5e35d72..5d51193 100644 --- a/pythonbrew/commands/symlink.py +++ b/pythonbrew/commands/symlink.py @@ -75,7 +75,7 @@ class SymlinkCommand(Command): if os.path.isfile(src): symlink(src, dst) else: - logger.info("%s: File not found" % src) + logger.error("%s: File not found" % src) def _get_pythons(self, _pythons): """Get the installed python versions list. diff --git a/pythonbrew/commands/uninstall.py b/pythonbrew/commands/uninstall.py index d04e53c..0699224 100644 --- a/pythonbrew/commands/uninstall.py +++ b/pythonbrew/commands/uninstall.py @@ -19,7 +19,7 @@ class UninstallCommand(Command): 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) + logger.error("`%s` is not installed." % pkgname) continue if get_using_python_pkgname() == pkgname: off() diff --git a/pythonbrew/commands/update.py b/pythonbrew/commands/update.py index f9d760a..b49d27d 100644 --- a/pythonbrew/commands/update.py +++ b/pythonbrew/commands/update.py @@ -65,7 +65,7 @@ class UpdateCommand(Command): except: logger.error("Failed to download. `%s`" % download_url) sys.exit(1) - logger.info("The config.cfg has been updated.") + logger.log("The config.cfg has been updated.") def _update_pythonbrew(self, options, args): if options.master: diff --git a/pythonbrew/commands/use.py b/pythonbrew/commands/use.py index 0b7c200..be1ea86 100644 --- a/pythonbrew/commands/use.py +++ b/pythonbrew/commands/use.py @@ -1,7 +1,7 @@ import os import sys from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, PATH_BIN, PATH_ETC_TEMP +from pythonbrew.define import PATH_PYTHONS, PATH_HOME_ETC_TEMP from pythonbrew.util import Package from pythonbrew.log import logger @@ -12,24 +12,23 @@ class UseCommand(Command): def run_command(self, options, args): if not args: - logger.info("Unrecognized command line argument: argument not found.") + self.parser.print_help() sys.exit(1) pkg = Package(args[0]) pkgname = pkg.name pkgdir = os.path.join(PATH_PYTHONS, pkgname) if not os.path.isdir(pkgdir): - logger.info("`%s` is not installed." % pkgname) + logger.error("`%s` is not installed." % pkgname) sys.exit(1) pkgbin = os.path.join(pkgdir,'bin') - self._set_temp('%s:%s' % (PATH_BIN, pkgbin)) + self._set_temp(pkgbin) logger.info("Using `%s`" % pkgname) def _set_temp(self, path): - fp = open(PATH_ETC_TEMP, 'w') - fp.write('PATH_PYTHONBREW="%s"\n' % (path)) + fp = open(PATH_HOME_ETC_TEMP, 'w') + fp.write('PATH_PYTHONBREW_TEMP="%s"\n' % (path)) fp.close() - UseCommand() diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index 8ac4e4f..c289936 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -1,10 +1,13 @@ import os import sys from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, PATH_VENVS, PATH_ETC_VENV -from pythonbrew.util import Subprocess, Package,\ - is_installed, get_installed_pythons_pkgname, get_using_python_pkgname +from pythonbrew.define import PATH_PYTHONS, PATH_VENVS, PATH_HOME_ETC_VENV,\ + PATH_ETC, VIRTUALENV_DLSITE, PATH_DISTS +from pythonbrew.util import Package, \ + is_installed, get_installed_pythons_pkgname, get_using_python_pkgname,\ + untar_file from pythonbrew.log import logger +from pythonbrew.downloader import Downloader class VenvCommand(Command): name = "venv" @@ -26,38 +29,30 @@ class VenvCommand(Command): 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 -""" - + self.parser.add_option( + "-n", "--no-site-packages", + dest="no_site_packages", + action='store_true', + default=False, + help="Don't give access to the global site-packages dir to the virtual environment.", + ) + self._venv_dir = os.path.join(PATH_ETC, 'virtualenv') + self._venv = os.path.join(self._venv_dir, 'virtualenv.py') + def run_command(self, options, args): if not args: - logger.error('Unrecognized command line argument: ( see: \'pythonbrew help venv\' )') + self.parser.print_help() sys.exit(1) cmd = args[0] - if not cmd in ('create', 'delete', 'use', 'list'): - logger.error('Unrecognized command line argument: ( see: \'pythonbrew help venv\' )') + if not cmd in ('init', 'create', 'delete', 'use', 'list'): + self.parser.print_help() 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') + # initialize? + if cmd == 'init': + self.run_command_init() + return # target python interpreter if options.python: @@ -66,92 +61,97 @@ source %(venv_sh)s logger.error('%s is not installed.' % pkgname) sys.exit(1) else: + # check using python under pythonbrew pkgname = get_using_python_pkgname() if not pkgname: - logger.error('Can not use venv command before using a python. Try \'pythonbrew switch \'.') + logger.error('Can not use venv command before switching a python. Try \'pythonbrew switch \'.') sys.exit(1) 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') + self._py = os.path.join(PATH_PYTHONS, pkgname, 'bin', 'python') - # has virtualenv & virtualenvwrapper? - 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(venv_bin,'pip'), 'install', 'virtualenvwrapper')) + # is already installed virtualenv? + if not os.path.exists(self._venv): + self.run_command_init() # Create a shell script - try: - self.__getattribute__('run_command_%s' % cmd)(options, args) - except: - logger.error('`%s` command not found.' % cmd) + self.__getattribute__('run_command_%s' % cmd)(options, args) + + def run_command_init(self): + if os.path.exists(self._venv): + logger.info('venv command is already initialized.') + return + if not os.access(PATH_DISTS, os.W_OK): + logger.error("Can not write to %s: Permission denied." % PATH_DISTS) sys.exit(1) + d = Downloader() + download_file = os.path.join(PATH_DISTS, 'virtualenv.tar.gz') + d.download('virtualenv.tar.gz', VIRTUALENV_DLSITE, download_file) + logger.info('Extracting virtualenv into %s' % self._venv_dir) + untar_file(download_file, self._venv_dir) 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}] + virtualenv_options = '' + if options.no_site_packages: + virtualenv_options += '--no-site-packages' + + print 'in create' + output = [] 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}) + target_dir = os.path.join(self._workon_home, arg) + output.append("""\ +echo '# Create `%(arg)s` environment into %(workon_home)s' +%(py)s %(venv)s -p '%(target_py)s' %(options)s '%(target_dir)s' +""" % {'arg': arg, 'workon_home': self._workon_home, 'py': self._py, 'venv': self._venv, 'target_py': self._target_py, 'options': virtualenv_options, 'target_dir': target_dir}) 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}] + output = [] 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)) + target_dir = os.path.join(self._workon_home, arg) + if not os.path.isdir(target_dir): + logger.error('%s already does not exist.' % target_dir) + else: + output.append("""\ +echo '# Delete `%(arg)s` environment in %(workon_home)s' +rm -rf '%(target_dir)s' +""" % {'arg': arg, 'workon_home': self._workon_home, 'target_dir': target_dir}) + if output: + 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)' + + activate = os.path.join(self._workon_home, args[1], 'bin', 'activate') + if not os.path.exists(activate): + logger.error('`%s` environment already does not exist. Try `pythonbrew venv create %s`.' % (args[1], args[1])) + sys.exit(1) + + self._write("""\ +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]}) - +source '%(activate)s' +""" % {'arg': args[1], 'workon_home': self._workon_home, 'activate': activate}) + 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)) + logger.log("# virtualenv for %(pkgname)s (found in %(workon_home)s)" % {'pkgname': pkgname, 'workon_home': workon_home}) + if os.path.isdir(workon_home): + for d in sorted(os.listdir(workon_home)): + logger.log(d) 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}) + logger.log("# virtualenv for %(pkgname)s (found in %(workon_home)s)" % {'pkgname': self._pkgname, 'workon_home': self._workon_home}) + if os.path.isdir(self._workon_home): + for d in sorted(os.listdir(self._workon_home)): + logger.log(d) def _write(self, src): - fp = open(PATH_ETC_VENV, 'w') + fp = open(PATH_HOME_ETC_VENV, 'w') fp.write(src) fp.close() diff --git a/pythonbrew/commands/version.py b/pythonbrew/commands/version.py index 2144123..5be8a62 100644 --- a/pythonbrew/commands/version.py +++ b/pythonbrew/commands/version.py @@ -8,6 +8,6 @@ class VersionCommand(Command): summary = "Show version" def run_command(self, options, args): - logger.info(VERSION) + logger.log(VERSION) VersionCommand() diff --git a/pythonbrew/curl.py b/pythonbrew/curl.py index 719639c..14b05c3 100644 --- a/pythonbrew/curl.py +++ b/pythonbrew/curl.py @@ -9,7 +9,7 @@ class Curl(object): def __init__(self): returncode = subprocess.call("command -v curl > /dev/null", shell=True) if returncode: - logger.info("pythonbrew required curl. curl was not found in your path.") + logger.log("pythonbrew required curl. curl was not found in your path.") sys.exit(1) def read(self, url): diff --git a/pythonbrew/define.py b/pythonbrew/define.py index bf4dee5..5589615 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -8,14 +8,15 @@ except: # pythonbrew version VERSION = "0.9" +# pythonbrew installer root path +INSTALLER_ROOT = os.path.dirname(os.path.abspath(__file__)) + +# Root # pythonbrew root path ROOT = os.environ.get("PYTHONBREW_ROOT") if not ROOT: ROOT = os.path.join(os.environ["HOME"],".pythonbrew") -# pythonbrew installer root path -INSTALLER_ROOT = os.path.dirname(os.path.abspath(__file__)) - # directories PATH_PYTHONS = os.path.join(ROOT,"pythons") PATH_BUILD = os.path.join(ROOT,"build") @@ -38,10 +39,21 @@ PATH_PATCHES_MACOSX_PYTHON24 = os.path.join(PATH_PATCHES_MACOSX,"python24") # files 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.run') + +# Home +# pythonbrew home path +PATH_HOME = os.environ.get('PYTHONBREW_HOME') +if not PATH_HOME: + PATH_HOME = os.path.join(os.environ["HOME"],".pythonbrew") + +# directories +PATH_HOME_ETC = os.path.join(PATH_HOME, 'etc') + +# files +PATH_HOME_ETC_VENV = os.path.join(PATH_HOME_ETC, 'venv.run') +PATH_HOME_ETC_CURRENT = os.path.join(PATH_HOME_ETC,'current') +PATH_HOME_ETC_TEMP = os.path.join(PATH_HOME_ETC,'temp') # read config.cfg config = ConfigParser.SafeConfigParser() @@ -58,6 +70,9 @@ DISTRIBUTE_SETUP_DLSITE = _get_or_default('distribute', 'url') # buildout bootstrap download BOOTSTRAP_DLSITE = _get_or_default('bootstrap', 'url') +# virtualenv download +VIRTUALENV_DLSITE = _get_or_default('virtualenv', 'url') + # pythonbrew download PYTHONBREW_UPDATE_URL_MASTER = _get_or_default('pythonbrew', 'master') PYTHONBREW_UPDATE_URL_DEVELOP = _get_or_default('pythonbrew', 'develop') diff --git a/pythonbrew/etc/bashrc b/pythonbrew/etc/bashrc index 82b73c4..e6e7e02 100644 --- a/pythonbrew/etc/bashrc +++ b/pythonbrew/etc/bashrc @@ -1,6 +1,20 @@ -PATH_ROOT="@ROOT@" +# settings +PATH_ROOT="$PYTHONBREW_ROOT" +if [ -z "${PATH_ROOT}" ] ; then + PATH_ROOT="$HOME/.pythonbrew" +fi PATH_ETC="$PATH_ROOT/etc" +PATH_HOME="$PYTHONBREW_HOME" +if [ -z "${PATH_HOME}" ] ; then + PATH_HOME="$HOME/.pythonbrew" +fi +PATH_HOME_ETC="$PATH_HOME/etc" + +# exec +pythonbrew="$PATH_ROOT/bin/pythonbrew" + +# functions __pythonbrew_set_default() { PATH_PYTHONBREW="$PATH_ROOT/bin" @@ -14,8 +28,9 @@ __pythonbrew_set_path() __pythonbrew_set_temp_path() { - if [[ -s "$PATH_ETC/temp" ]] ; then - source "$PATH_ETC/temp" + if [[ -s "$PATH_HOME_ETC/temp" ]] ; then + source "$PATH_HOME_ETC/temp" + PATH_PYTHONBREW="$PATH_ROOT/bin:$PATH_PYTHONBREW_TEMP" else __pythonbrew_set_default fi @@ -24,8 +39,9 @@ __pythonbrew_set_temp_path() __pythonbrew_set_current_path() { - if [[ -s "$PATH_ETC/current" ]] ; then - source "$PATH_ETC/current" + if [[ -s "$PATH_HOME_ETC/current" ]] ; then + source "$PATH_HOME_ETC/current" + PATH_PYTHONBREW="$PATH_ROOT/bin:$PATH_PYTHONBREW_CURRENT" else __pythonbrew_set_default fi @@ -39,35 +55,35 @@ __pythonbrew_reload() __pythonbrew_use() { - command pythonbrew "$@" + $pythonbrew "$@" [[ $? == 0 ]] && __pythonbrew_set_temp_path } __pythonbrew_switch() { - command pythonbrew "$@" + $pythonbrew "$@" [[ $? == 0 ]] && __pythonbrew_set_current_path } __pythonbrew_off() { - command pythonbrew "$@" + $pythonbrew "$@" [[ $? == 0 ]] && __pythonbrew_set_current_path } __pythonbrew_update() { - command pythonbrew "$@" + $pythonbrew "$@" [[ $? == 0 ]] && __pythonbrew_reload } __pythonbrew_venv() { - command pythonbrew "$@" + $pythonbrew "$@" if [[ $? == 0 ]] ; then - if [[ -s "$PATH_ETC/venv.run" ]] ; then - source "$PATH_ETC/venv.run" - cat /dev/null > "$PATH_ETC/venv.run" + if [[ -s "$PATH_HOME_ETC/venv.run" ]] ; then + source "$PATH_HOME_ETC/venv.run" + cat /dev/null > "$PATH_HOME_ETC/venv.run" fi fi } @@ -96,7 +112,7 @@ pythonbrew() off) __pythonbrew_off "$@" ;; update) __pythonbrew_update "$@" ;; venv) __pythonbrew_venv "$@" ;; - *) command pythonbrew "$@" ;; + *) $pythonbrew "$@" ;; esac builtin hash -r } diff --git a/pythonbrew/etc/config.cfg b/pythonbrew/etc/config.cfg index 1a16836..3f057a4 100644 --- a/pythonbrew/etc/config.cfg +++ b/pythonbrew/etc/config.cfg @@ -4,6 +4,9 @@ url = http://python-distribute.org/distribute_setup.py [bootstrap] url = http://svn.zope.org/*checkout*/zc.buildout/trunk/bootstrap/bootstrap.py +[virtualenv] +url = http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.6.4.tar.gz + [pythonbrew] master = https://github.com/utahta/pythonbrew/tarball/master develop = https://github.com/utahta/pythonbrew/tarball/develop diff --git a/pythonbrew/installer/__init__.py b/pythonbrew/installer/__init__.py index f4362e4..8ff349d 100644 --- a/pythonbrew/installer/__init__.py +++ b/pythonbrew/installer/__init__.py @@ -4,9 +4,9 @@ from pythonbrew.define import INSTALLER_ROOT, ROOT, PATH_ETC def install_pythonbrew(): PythonbrewInstaller().install(INSTALLER_ROOT) - # pythonbrew is only for bash + # for bash shrc = yourshrc = "bashrc" - logger.info(""" + logger.log(""" Well-done! Congratulations! The pythonbrew is installed as: diff --git a/pythonbrew/installer/pythonbrewinstaller.py b/pythonbrew/installer/pythonbrewinstaller.py index 14c23bc..f8dd398 100644 --- a/pythonbrew/installer/pythonbrewinstaller.py +++ b/pythonbrew/installer/pythonbrewinstaller.py @@ -7,7 +7,7 @@ from pythonbrew.define import PATH_BUILD, PATH_BIN, PATH_DISTS, PATH_PYTHONS,\ PATH_ETC, PATH_SCRIPTS, PATH_SCRIPTS_PYTHONBREW,\ PATH_SCRIPTS_PYTHONBREW_COMMANDS, PATH_BIN_PYTHONBREW,\ ROOT, PATH_LOG, PATH_PATCHES, PATH_ETC_CONFIG,\ - PATH_SCRIPTS_PYTHONBREW_INSTALLER, PATH_VENVS + PATH_SCRIPTS_PYTHONBREW_INSTALLER, PATH_VENVS, PATH_HOME_ETC import stat class PythonbrewInstaller(object): @@ -23,6 +23,7 @@ class PythonbrewInstaller(object): makedirs(PATH_BIN) makedirs(PATH_LOG) makedirs(PATH_VENVS) + makedirs(PATH_HOME_ETC) # create script directories rm_r(PATH_SCRIPTS) diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index 50a6a77..fbe89e8 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -38,7 +38,7 @@ class PythonInstaller(object): pkg = Package(name, options.alias) self.download_url = get_python_version_url(pkg.version) if not self.download_url: - logger.info("Unknown python version: `%s`" % pkg.name) + logger.error("Unknown python version: `%s`" % pkg.name) raise UnknownVersionException filename = Link(self.download_url).filename self.pkg = pkg @@ -83,11 +83,11 @@ class PythonInstaller(object): except: rm_r(self.install_dir) logger.error("Failed to install %s. See %s to see why." % (self.pkg.name, self.logfile)) - logger.info(" pythonbrew install --force %s" % self.pkg.version) + logger.log(" pythonbrew install --force %s" % self.pkg.version) sys.exit(1) self.symlink() self.install_setuptools() - logger.info("Installed %(pkgname)s successfully. Run the following command to switch to %(pkgname)s." + logger.info("\nInstalled %(pkgname)s successfully. Run the following command to switch to %(pkgname)s." % {"pkgname":self.pkg.name}) logger.info(" pythonbrew switch %s" % self.pkg.alias) @@ -107,7 +107,7 @@ class PythonInstaller(object): dl.download(base_url, self.download_url, self.download_file) except: unlink(self.download_file) - logger.info("\nInterrupt to abort. `%s`" % (self.download_url)) + logger.log("\nInterrupt to abort. `%s`" % (self.download_url)) sys.exit(1) # extracting if not extract_downloadfile(self.content_type, self.download_file, self.build_dir): @@ -206,7 +206,7 @@ class PythonInstaller(object): options = self.options pkgname = self.pkg.name if options.no_setuptools: - logger.info("Skip installation of setuptools.") + logger.log("Skip installation of setuptools.") return download_url = DISTRIBUTE_SETUP_DLSITE filename = Link(download_url).filename @@ -228,7 +228,7 @@ class PythonInstaller(object): s.check_call([easy_install, 'pip']) except: logger.error("Failed to install setuptools. See %s/build.log to see why." % (ROOT)) - logger.info("Skip installation of setuptools.") + logger.log("Skip installation of setuptools.") class PythonInstallerMacOSX(PythonInstaller): """Python installer for MacOSX @@ -239,7 +239,7 @@ class PythonInstallerMacOSX(PythonInstaller): # check for version version = self.pkg.version if version < '2.6' and (version != '2.4.6' and version < '2.5.5'): - logger.info("`%s` is not supported on MacOSX Snow Leopard" % self.pkg.name) + logger.error("`%s` is not supported on MacOSX Snow Leopard" % self.pkg.name) raise NotSupportedVersionException # set configure options target = get_macosx_deployment_target() diff --git a/pythonbrew/log.py b/pythonbrew/log.py index 3ddf3cd..8b55939 100644 --- a/pythonbrew/log.py +++ b/pythonbrew/log.py @@ -1,43 +1,43 @@ import sys -import logging -class LoggerInfo(object): - def log(self, level, msg, *arg, **keys): - sys.stdout.write("%s\n" % msg) - -class LoggerError(object): - def log(self, level, msg, *arg, **keys): - sys.stderr.write("ERROR: %s\n" % msg) - -class Logger(object): +class Color(object): + DEBUG = '\033[35m' + INFO = '\033[32m' + ERROR = '\033[31m' + ENDC = '\033[0m' - DEBUG = logging.DEBUG - INFO = logging.INFO - ERROR = logging.ERROR + @classmethod + def _deco(cls, msg, color): + return '%s%s%s' % (color, msg, cls.ENDC) - def __init__(self): - self._consumers = [] - consumer = LoggerInfo() - self.add_consumer(Logger.INFO, consumer) + @classmethod + def debug(cls, msg): + return cls._deco(msg, cls.DEBUG) + @classmethod + def info(cls, msg): + return cls._deco(msg, cls.INFO) + @classmethod + def error(cls, msg): + return cls._deco(msg, cls.ERROR) + +class Logger(object): + def debug(self, msg): + self._stdout(Color.debug("DEBUG: %s\n" % msg)) + + def log(self, msg): + self._stdout("%s\n" % (msg)) + + def info(self, msg): + self._stdout(Color.info('%s\n' % msg)) - consumer = LoggerError() - 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): + self._stderr(Color.error("ERROR: %s\n" % msg)) - 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)) + def _stdout(self, msg): + sys.stdout.write(msg) + sys.stdout.flush() + def _stderr(self, msg): + sys.stderr.write(msg) + sys.stderr.flush() logger = Logger() diff --git a/pythonbrew/util.py b/pythonbrew/util.py index a29ae85..11f6e3d 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -10,7 +10,7 @@ import urllib import subprocess import shlex import select -from pythonbrew.define import PATH_BIN, PATH_ETC_CURRENT, PATH_PYTHONS +from pythonbrew.define import PATH_BIN, PATH_HOME_ETC_CURRENT, PATH_PYTHONS from pythonbrew.exceptions import ShellCommandException from pythonbrew.log import logger @@ -209,10 +209,13 @@ def extract_downloadfile(content_type, download_file, target_dir): return False return True -def get_using_python_path(): - p = subprocess.Popen('command -v python', stdout=subprocess.PIPE, shell=True) +def get_command_path(command): + p = subprocess.Popen('command -v %s' % command, stdout=subprocess.PIPE, shell=True) return to_str(p.communicate()[0].strip()) +def get_using_python_path(): + return get_command_path('python') + def get_using_python_pkgname(): """return: Python- or None""" path = get_using_python_path() @@ -233,8 +236,8 @@ def is_installed(name): return True def set_current_path(path): - fp = open(PATH_ETC_CURRENT, 'w') - fp.write('PATH_PYTHONBREW="%s"\n' % (path)) + fp = open(PATH_HOME_ETC_CURRENT, 'w') + fp.write('PATH_PYTHONBREW_CURRENT="%s"\n' % (path)) fp.close() def path_to_fileurl(path): @@ -290,7 +293,7 @@ class Subprocess(object): def shell(self, cmd): if self._debug: - logger.info(cmd) + logger.log(cmd) if self._log: if self._verbose: cmd = "(%s) 2>&1 | tee '%s'" % (cmd, self._log) @@ -304,7 +307,7 @@ class Subprocess(object): if is_str(cmd): cmd = shlex.split(cmd) if self._debug: - logger.info(cmd) + logger.log(cmd) fp = ((self._log and open(self._log, 'a')) or None) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self._cwd) @@ -314,7 +317,7 @@ class Subprocess(object): if not line: break if self._verbose: - logger.info(line.strip()) + logger.log(line.strip()) if fp: fp.write(line) fp.flush() diff --git a/tests/test_10_venv.py b/tests/test_10_venv.py index eb5f352..639ca11 100644 --- a/tests/test_10_venv.py +++ b/tests/test_10_venv.py @@ -1,11 +1,21 @@ class VenvOptions(object): python = '2.6.6' all = False + no_site_packages = False def test_venv(): + import os from pythonbrew.commands.venv import VenvCommand + from pythonbrew.util import Subprocess + from pythonbrew.define import PATH_HOME_ETC_VENV + s = Subprocess() c = VenvCommand() + c.run_command(VenvOptions(), ['init']) c.run_command(VenvOptions(), ['create', 'aaa']) + s.shell('source %s' % PATH_HOME_ETC_VENV) c.run_command(VenvOptions(), ['list']) c.run_command(VenvOptions(), ['use', 'aaa']) c.run_command(VenvOptions(), ['delete', 'aaa']) + s.shell('source %s' % PATH_HOME_ETC_VENV) + # finish + os.unlink(PATH_HOME_ETC_VENV) From 10255295287af6b9b88bb6971f83d040e309a0af Mon Sep 17 00:00:00 2001 From: utahta Date: Sat, 6 Aug 2011 23:58:47 +0900 Subject: [PATCH 20/30] update readme --- PKG-INFO | 4 ++-- README.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PKG-INFO b/PKG-INFO index 8276229..4cd025e 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -97,7 +97,7 @@ Runs the buildout with specified or current using python:: pythonbrew buildout pythonbrew buildout -p 2.6.6 -Create isolated python environments (uses virtualenv and virtualenvwrapper):: +Create isolated python environments (uses virtualenv):: pythonbrew venv create proj pythonbrew venv list @@ -149,7 +149,7 @@ buildout Runs the buildout with specified or current using python. venv - Create isolated python environments (uses virtualenv and virtualenvwrapper) + Create isolated python environments (uses virtualenv) version Show version. diff --git a/README.rst b/README.rst index 68e9b7b..8c240ae 100644 --- a/README.rst +++ b/README.rst @@ -97,7 +97,7 @@ Runs the buildout with specified or current using python:: pythonbrew buildout pythonbrew buildout -p 2.6.6 -Create isolated python environments (uses virtualenv and virtualenvwrapper):: +Create isolated python environments (uses virtualenv):: pythonbrew venv create proj pythonbrew venv list @@ -149,7 +149,7 @@ buildout Runs the buildout with specified or current using python. venv - Create isolated python environments (uses virtualenv and virtualenvwrapper) + Create isolated python environments (uses virtualenv) version Show version. From 4ef2954bd6bfdacb65af339707b7be9a367f0240 Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 00:08:37 +0900 Subject: [PATCH 21/30] bug fix --- pythonbrew/commands/venv.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index c289936..a45ca1d 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -143,12 +143,14 @@ source '%(activate)s' logger.log("# virtualenv for %(pkgname)s (found in %(workon_home)s)" % {'pkgname': pkgname, 'workon_home': workon_home}) if os.path.isdir(workon_home): for d in sorted(os.listdir(workon_home)): - logger.log(d) + if os.path.isdir(d): + logger.log(d) else: logger.log("# virtualenv for %(pkgname)s (found in %(workon_home)s)" % {'pkgname': self._pkgname, 'workon_home': self._workon_home}) if os.path.isdir(self._workon_home): for d in sorted(os.listdir(self._workon_home)): - logger.log(d) + if os.path.isdir(d): + logger.log(d) def _write(self, src): fp = open(PATH_HOME_ETC_VENV, 'w') From 90face7065015737ba604392dd86b92ae6c1fc12 Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 00:11:23 +0900 Subject: [PATCH 22/30] bug fix --- pythonbrew/commands/venv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index a45ca1d..27e61db 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -143,13 +143,13 @@ source '%(activate)s' logger.log("# virtualenv for %(pkgname)s (found in %(workon_home)s)" % {'pkgname': pkgname, 'workon_home': workon_home}) if os.path.isdir(workon_home): for d in sorted(os.listdir(workon_home)): - if os.path.isdir(d): + if os.path.isdir(os.path.join(workon_home, d)): logger.log(d) else: logger.log("# virtualenv for %(pkgname)s (found in %(workon_home)s)" % {'pkgname': self._pkgname, 'workon_home': self._workon_home}) if os.path.isdir(self._workon_home): for d in sorted(os.listdir(self._workon_home)): - if os.path.isdir(d): + if os.path.isdir(os.path.join(self._workon_home, d)): logger.log(d) def _write(self, src): From 7b2fa2f0ebb909a0129e2bf0b2c926ecc251c3af Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 00:39:13 +0900 Subject: [PATCH 23/30] Improve symlink command --- pythonbrew/commands/symlink.py | 34 ++++++++++++++++++++++++++++++++-- pythonbrew/commands/venv.py | 1 - 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/pythonbrew/commands/symlink.py b/pythonbrew/commands/symlink.py index 5d51193..54d19c6 100644 --- a/pythonbrew/commands/symlink.py +++ b/pythonbrew/commands/symlink.py @@ -1,7 +1,9 @@ import os +import sys from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, PATH_BIN -from pythonbrew.util import Package, symlink, unlink +from pythonbrew.define import PATH_PYTHONS, PATH_BIN, PATH_VENVS +from pythonbrew.util import Package, symlink, unlink, get_using_python_pkgname,\ + is_installed from pythonbrew.log import logger class SymlinkCommand(Command): @@ -32,6 +34,12 @@ class SymlinkCommand(Command): default=None, help="Use as default the specified python version." ) + self.parser.add_option( + "-v", "--venv", + dest="venv", + default=None, + help="Use the virtual environment python." + ) def run_command(self, options, args): if options.default: @@ -43,6 +51,28 @@ class SymlinkCommand(Command): self._symlink(bin, bin, pkgname) else: self._symlink('python', 'py', pkgname) + elif options.venv: + if options.pythons: + pkgname = Package(options.pythons[0]).name + else: + pkgname = get_using_python_pkgname() + if not is_installed(pkgname): + logger.error('`%s` is not installed.') + sys.exit(1) + + venv_pkgdir = os.path.join(PATH_VENVS, pkgname) + venv_dir = os.path.join(venv_pkgdir, options.venv) + if not os.path.isdir(venv_dir): + logger.error("`%s` environment not found in %s." % (options.venv, venv_pkgdir)) + sys.exit(1) + pkg = Package(pkgname) + if args: + bin = args[0] + dstbin = '%s%s-%s' % (bin, pkg.version, options.venv) + self._symlink(bin, dstbin, pkgname) + else: + dstbin = 'py%s-%s' % (pkg.version, options.venv) + self._symlink('python', dstbin, pkgname) else: pythons = self._get_pythons(options.pythons) for pkgname in pythons: diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index 27e61db..f4a6318 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -96,7 +96,6 @@ class VenvCommand(Command): if options.no_site_packages: virtualenv_options += '--no-site-packages' - print 'in create' output = [] for arg in args[1:]: target_dir = os.path.join(self._workon_home, arg) From 4993f466e98c1fb0cd1d12db00298d87db443c02 Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 03:48:38 +0900 Subject: [PATCH 24/30] add systemwide install support --- pythonbrew-install | 23 +++++++--- pythonbrew/commands/venv.py | 30 ++++++------- pythonbrew/etc/bashrc | 18 ++++++-- pythonbrew/installer/__init__.py | 30 ++++++++++++- pythonbrew/installer/pythonbrewinstaller.py | 50 +++++++++++++++++---- pythonbrew_install.py | 13 +++++- 6 files changed, 126 insertions(+), 38 deletions(-) diff --git a/pythonbrew-install b/pythonbrew-install index f918d47..70594c1 100755 --- a/pythonbrew-install +++ b/pythonbrew-install @@ -66,16 +66,23 @@ if [[ $PYTHON_FOUND != '1' ]] ; then exit fi -ROOT="$HOME/.pythonbrew" -if [[ -n $PYTHONBREW_ROOT ]] ; then - ROOT=$PYTHONBREW_ROOT +systemwide_install=0 +if [[ -n "$PYTHONBREW_ROOT" ]] ; then + ROOT="$PYTHONBREW_ROOT" +else + if (( UID == 0 )) ; then + systemwide_install=1 + ROOT="/usr/local/pythonbrew" + else + ROOT="$HOME/.pythonbrew" + fi fi PATH_DISTS="$ROOT/dists" STABLE_VERSION=`curl -skL https://github.com/utahta/pythonbrew/raw/master/stable-version.txt` STABLE_VERSION=`trim $STABLE_VERSION` -if [[ $STABLE_VERSION = "" ]] ; then - echo 'Could not get stable-version of pythonbrew.' +if [[ -z "$STABLE_VERSION" ]] ; then + echo 'Can not get stable-version of pythonbrew.' exit 1 fi TEMP_FILE="pythonbrew-$STABLE_VERSION" @@ -93,7 +100,11 @@ echo "Extracting $PATH_DISTS/$TEMP_TARBALL" builtin cd $PATH_DISTS ; tar zxf $TEMP_TARBALL echo "Installing pythonbrew into $ROOT" -$PYTHON $PATH_DISTS/$TEMP_FILE/pythonbrew_install.py +if (( systemwide_install == 1 )) ; then + PYTHONBREW_ROOT="$ROOT" $PYTHON $PATH_DISTS/$TEMP_FILE/pythonbrew_install.py --systemwide +else + $PYTHON $PATH_DISTS/$TEMP_FILE/pythonbrew_install.py +fi if [[ $? == 1 ]] ; then echo "Failed to install pythonbrew." exit diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index f4a6318..bd8e32e 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -5,7 +5,7 @@ from pythonbrew.define import PATH_PYTHONS, PATH_VENVS, PATH_HOME_ETC_VENV,\ PATH_ETC, VIRTUALENV_DLSITE, PATH_DISTS from pythonbrew.util import Package, \ is_installed, get_installed_pythons_pkgname, get_using_python_pkgname,\ - untar_file + untar_file, Subprocess, rm_r from pythonbrew.log import logger from pythonbrew.downloader import Downloader @@ -92,32 +92,30 @@ class VenvCommand(Command): untar_file(download_file, self._venv_dir) def run_command_create(self, options, args): - virtualenv_options = '' + virtualenv_options = [] if options.no_site_packages: - virtualenv_options += '--no-site-packages' + virtualenv_options.append('--no-site-packages') - output = [] for arg in args[1:]: target_dir = os.path.join(self._workon_home, arg) - output.append("""\ -echo '# Create `%(arg)s` environment into %(workon_home)s' -%(py)s %(venv)s -p '%(target_py)s' %(options)s '%(target_dir)s' -""" % {'arg': arg, 'workon_home': self._workon_home, 'py': self._py, 'venv': self._venv, 'target_py': self._target_py, 'options': virtualenv_options, 'target_dir': target_dir}) - self._write(''.join(output)) + logger.log("# Create `%s` environment into %s" % (arg, self._workon_home)) + # make command + cmd = [self._py, self._venv, '-p', self._target_py] + cmd.extend(virtualenv_options) + cmd.append(target_dir) + # create environment + s = Subprocess(verbose=True) + s.call(cmd) def run_command_delete(self, options, args): - output = [] for arg in args[1:]: target_dir = os.path.join(self._workon_home, arg) if not os.path.isdir(target_dir): logger.error('%s already does not exist.' % target_dir) else: - output.append("""\ -echo '# Delete `%(arg)s` environment in %(workon_home)s' -rm -rf '%(target_dir)s' -""" % {'arg': arg, 'workon_home': self._workon_home, 'target_dir': target_dir}) - if output: - self._write(''.join(output)) + logger.log('# Delete `%s` environment in %s' % (arg, self._workon_home)) + # make command + rm_r(target_dir) def run_command_use(self, options, args): if len(args) < 2: diff --git a/pythonbrew/etc/bashrc b/pythonbrew/etc/bashrc index e6e7e02..da65b41 100644 --- a/pythonbrew/etc/bashrc +++ b/pythonbrew/etc/bashrc @@ -11,8 +11,8 @@ if [ -z "${PATH_HOME}" ] ; then fi PATH_HOME_ETC="$PATH_HOME/etc" -# exec -pythonbrew="$PATH_ROOT/bin/pythonbrew" +# py file +PY_PYTHONBREW="$PATH_ROOT/bin/pythonbrew" # functions __pythonbrew_set_default() @@ -103,7 +103,7 @@ __pythonbrew_find_command() done } -pythonbrew() +__pythonbrew_run() { __pythonbrew_find_command "$@" case $command_name in @@ -117,10 +117,22 @@ pythonbrew() builtin hash -r } +pythonbrew() +{ + pythonbrew=$PY_PYTHONBREW + __pythonbrew_run "$@" +} + pybrew() { pythonbrew "$@" } +sudopybrew() +{ + pythonbrew="sudo PYTHONBREW_ROOT=$PATH_ROOT $PY_PYTHONBREW" + __pythonbrew_run "$@" +} + # main __pythonbrew_set_current_path diff --git a/pythonbrew/installer/__init__.py b/pythonbrew/installer/__init__.py index 8ff349d..0a22bee 100644 --- a/pythonbrew/installer/__init__.py +++ b/pythonbrew/installer/__init__.py @@ -3,7 +3,7 @@ from pythonbrew.log import logger from pythonbrew.define import INSTALLER_ROOT, ROOT, PATH_ETC def install_pythonbrew(): - PythonbrewInstaller().install(INSTALLER_ROOT) + PythonbrewInstaller.install(INSTALLER_ROOT) # for bash shrc = yourshrc = "bashrc" logger.log(""" @@ -33,4 +33,30 @@ Enjoy pythonbrew at %(ROOT)s!! """ % {'ROOT':ROOT, 'yourshrc':yourshrc, 'shrc':shrc, 'PATH_ETC':PATH_ETC}) def upgrade_pythonbrew(): - PythonbrewInstaller().install(INSTALLER_ROOT) + PythonbrewInstaller.install(INSTALLER_ROOT) + +def systemwide_pythonbrew(): + PythonbrewInstaller.install(INSTALLER_ROOT) + PythonbrewInstaller.systemwide_install() + logger.log(""" +Well-done! Congratulations! + +The pythonbrew is installed as: + + %(ROOT)s + +After that, exit this shell, start a new one, and install some fresh +pythons: + + pythonbrew install 2.7.2 + pythonbrew install 3.2 + +For further instructions, run: + + pythonbrew help + +The default help messages will popup and tell you what to do! + +Enjoy pythonbrew at %(ROOT)s!! +""" % {'ROOT':ROOT}) + \ No newline at end of file diff --git a/pythonbrew/installer/pythonbrewinstaller.py b/pythonbrew/installer/pythonbrewinstaller.py index f8dd398..ab6e824 100644 --- a/pythonbrew/installer/pythonbrewinstaller.py +++ b/pythonbrew/installer/pythonbrewinstaller.py @@ -6,15 +6,16 @@ from pythonbrew.util import makedirs, rm_r from pythonbrew.define import PATH_BUILD, PATH_BIN, PATH_DISTS, PATH_PYTHONS,\ PATH_ETC, PATH_SCRIPTS, PATH_SCRIPTS_PYTHONBREW,\ PATH_SCRIPTS_PYTHONBREW_COMMANDS, PATH_BIN_PYTHONBREW,\ - ROOT, PATH_LOG, PATH_PATCHES, PATH_ETC_CONFIG,\ - PATH_SCRIPTS_PYTHONBREW_INSTALLER, PATH_VENVS, PATH_HOME_ETC + PATH_LOG, PATH_PATCHES, PATH_ETC_CONFIG,\ + PATH_SCRIPTS_PYTHONBREW_INSTALLER, PATH_VENVS, PATH_HOME_ETC, ROOT import stat class PythonbrewInstaller(object): """pythonbrew installer: """ - def install(self, installer_root): + @staticmethod + def install(installer_root): # create directories makedirs(PATH_PYTHONS) makedirs(PATH_BUILD) @@ -62,12 +63,43 @@ if __name__ == "__main__": os.chmod(PATH_BIN_PYTHONBREW, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH) # create a bashrc for pythonbrew - fp = open(os.path.join(PATH_ETC,'bashrc'), 'w') - for line in open(os.path.join(installer_root,'etc','bashrc')): - line = line.replace('@ROOT@', ROOT) - fp.write(line) - fp.close() + shutil.copy(os.path.join(installer_root,'etc','bashrc'), os.path.join(PATH_ETC,'bashrc')) # copy config.cfg shutil.copy(os.path.join(installer_root,'etc','config.cfg'), PATH_ETC_CONFIG) - + + @staticmethod + def systemwide_install(): + profile = """\ +#begin-pythonbrew +if [ -n "${BASH_VERSION:-}" -o -n "${ZSH_VERSION:-}" ] ; then + export PYTHONBREW_ROOT=%(root)s + source "${PYTHONBREW_ROOT}/etc/bashrc" +fi +#end-pythonbrew +""" % {'root': ROOT} + + if os.path.isdir('/etc/profile.d'): + fp = open('/etc/profile.d/pythonbrew.sh', 'w') + fp.write(profile) + fp.close() + elif os.path.isfile('/etc/profile'): + output = [] + is_copy = True + fp = open('/etc/profile', 'r') + for line in fp: + if line.startswith('#begin-pythonbrew'): + is_copy = False + continue + elif line.startswith('#end-pythonbrew'): + is_copy = True + continue + if is_copy: + output.append(line) + fp.close() + output.append(profile) + + fp = open('/etc/profile', 'w') + fp.write(''.join(output)) + fp.close() + diff --git a/pythonbrew_install.py b/pythonbrew_install.py index 0f78ffd..13075c2 100644 --- a/pythonbrew_install.py +++ b/pythonbrew_install.py @@ -1,4 +1,4 @@ -from pythonbrew.installer import install_pythonbrew, upgrade_pythonbrew +from pythonbrew.installer import install_pythonbrew, upgrade_pythonbrew, systemwide_pythonbrew from optparse import OptionParser if __name__ == "__main__": parser = OptionParser() @@ -9,8 +9,17 @@ if __name__ == "__main__": default=False, help="Upgrade." ) + parser.add_option( + '--systemwide', + dest="systemwide", + action="store_true", + default=False, + help="systemwide install." + ) (opt, arg) = parser.parse_args() - if opt.upgrade: + if opt.systemwide: + systemwide_pythonbrew() + elif opt.upgrade: upgrade_pythonbrew() else: install_pythonbrew() From bc219fcebe9fd2eecde8e4257bba844c21d4a24a Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 12:58:54 +0900 Subject: [PATCH 25/30] bug fix --- pythonbrew/__init__.py | 12 ++++++++---- pythonbrew/commands/buildout.py | 7 ++++--- pythonbrew/commands/list.py | 2 +- pythonbrew/commands/symlink.py | 4 ++-- pythonbrew/commands/update.py | 2 +- pythonbrew/commands/venv.py | 2 +- pythonbrew/curl.py | 7 ++++--- pythonbrew/etc/bashrc | 2 +- pythonbrew/exceptions.py | 4 +++- pythonbrew/installer/pythoninstaller.py | 4 ++-- pythonbrew/util.py | 7 +++++++ 11 files changed, 34 insertions(+), 19 deletions(-) diff --git a/pythonbrew/__init__.py b/pythonbrew/__init__.py index d190d8c..9eec705 100644 --- a/pythonbrew/__init__.py +++ b/pythonbrew/__init__.py @@ -1,7 +1,14 @@ import sys +import os from pythonbrew.basecommand import command_dict, load_all_commands from pythonbrew.baseparser import parser from pythonbrew.log import logger +from pythonbrew.define import PATH_HOME_ETC +from pythonbrew.util import makedirs + +def init_home(): + if not os.path.isdir(PATH_HOME_ETC): + makedirs(PATH_HOME_ETC) def main(): options, args = parser.parse_args(sys.argv[1:]) @@ -10,13 +17,10 @@ def main(): if not args: args = ['help'] # as default + init_home() load_all_commands() command = args[0].lower() if command not in command_dict: - if command == 'clean': - # note: for some time - logger.log('\nDEPRECATION WARNING: `pythonbrew clean` has been renamed. Please run `pythonbrew cleanup` instead.\n') - return parser.error("Unknown command: `%s`" % command) return command = command_dict[command] diff --git a/pythonbrew/commands/buildout.py b/pythonbrew/commands/buildout.py index 5d08ffe..1c29574 100644 --- a/pythonbrew/commands/buildout.py +++ b/pythonbrew/commands/buildout.py @@ -2,7 +2,7 @@ import os import sys import subprocess from pythonbrew.basecommand import Command -from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE, PATH_DISTS +from pythonbrew.define import PATH_PYTHONS, BOOTSTRAP_DLSITE from pythonbrew.util import Package, get_using_python_pkgname, Link, is_installed from pythonbrew.log import logger from pythonbrew.downloader import Downloader @@ -38,12 +38,13 @@ class BuildoutCommand(Command): # Download bootstrap.py download_url = BOOTSTRAP_DLSITE filename = Link(download_url).filename - bootstrap = os.path.join(PATH_DISTS, filename) + bootstrap = os.path.join(os.getcwd(), filename) # fetching into current directory try: d = Downloader() d.download(filename, download_url, bootstrap) except: - logger.error("Failed to download. `%s`" % download_url) + e = sys.exc_info()[1] + logger.error("%s" % (e)) sys.exit(1) # call bootstrap.py diff --git a/pythonbrew/commands/list.py b/pythonbrew/commands/list.py index ab4293d..91dfa6f 100644 --- a/pythonbrew/commands/list.py +++ b/pythonbrew/commands/list.py @@ -56,7 +56,7 @@ class ListCommand(Command): for pkgname in pkgs: logger.log("%s" % pkgname) else: - logger.error("Python version not found. `%s`" % pkg.name) + logger.error("`%s` was not found." % pkg.name) else: for pkgname in self._get_packages_name(options): logger.log("%s" % pkgname) diff --git a/pythonbrew/commands/symlink.py b/pythonbrew/commands/symlink.py index 54d19c6..f87da05 100644 --- a/pythonbrew/commands/symlink.py +++ b/pythonbrew/commands/symlink.py @@ -63,7 +63,7 @@ class SymlinkCommand(Command): venv_pkgdir = os.path.join(PATH_VENVS, pkgname) venv_dir = os.path.join(venv_pkgdir, options.venv) if not os.path.isdir(venv_dir): - logger.error("`%s` environment not found in %s." % (options.venv, venv_pkgdir)) + logger.error("`%s` environment was not found in %s." % (options.venv, venv_pkgdir)) sys.exit(1) pkg = Package(pkgname) if args: @@ -105,7 +105,7 @@ class SymlinkCommand(Command): if os.path.isfile(src): symlink(src, dst) else: - logger.error("%s: File not found" % src) + logger.error("%s was not found in your path." % src) def _get_pythons(self, _pythons): """Get the installed python versions list. diff --git a/pythonbrew/commands/update.py b/pythonbrew/commands/update.py index b49d27d..6a3e4a4 100644 --- a/pythonbrew/commands/update.py +++ b/pythonbrew/commands/update.py @@ -81,7 +81,7 @@ class UpdateCommand(Command): download_url = get_pythonbrew_update_url(version) if not download_url: - logger.error("`%s` of pythonbrew not found." % version) + logger.error("`pythonbrew-%s` was not found in pypi." % version) sys.exit(1) headinfo = get_headerinfo_from_url(download_url) content_type = headinfo['content-type'] diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index bd8e32e..f01664e 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -83,7 +83,7 @@ class VenvCommand(Command): logger.info('venv command is already initialized.') return if not os.access(PATH_DISTS, os.W_OK): - logger.error("Can not write to %s: Permission denied." % PATH_DISTS) + logger.error("Can not initialize venv command: Permission denied.") sys.exit(1) d = Downloader() download_file = os.path.join(PATH_DISTS, 'virtualenv.tar.gz') diff --git a/pythonbrew/curl.py b/pythonbrew/curl.py index 14b05c3..00e5790 100644 --- a/pythonbrew/curl.py +++ b/pythonbrew/curl.py @@ -4,6 +4,7 @@ import subprocess from subprocess import Popen, PIPE from pythonbrew.log import logger from pythonbrew.util import to_str +from pythonbrew.exceptions import CurlFetchException class Curl(object): def __init__(self): @@ -16,14 +17,14 @@ class Curl(object): p = Popen("curl -skL %s" % url, stdout=PIPE, shell=True) p.wait() if p.returncode: - raise + raise Exception('Failed to read.') return p.stdout.read() def readheader(self, url): p = Popen("curl --head -skL %s" % url, stdout=PIPE, shell=True) p.wait() if p.returncode: - raise + raise Exception('Failed to readheader.') respinfo = {} for line in p.stdout: line = to_str(line.strip()) @@ -39,4 +40,4 @@ class Curl(object): p = Popen("curl -# -kL %s -o %s" % (url, filename), shell=True) p.wait() if p.returncode: - raise + raise CurlFetchException('Failed to fetch.') diff --git a/pythonbrew/etc/bashrc b/pythonbrew/etc/bashrc index da65b41..8944e1e 100644 --- a/pythonbrew/etc/bashrc +++ b/pythonbrew/etc/bashrc @@ -130,7 +130,7 @@ pybrew() sudopybrew() { - pythonbrew="sudo PYTHONBREW_ROOT=$PATH_ROOT $PY_PYTHONBREW" + pythonbrew="sudo PYTHONBREW_ROOT=$PATH_ROOT PATH=$PATH_PYTHONBREW:$PATH_WITHOUT_PYTHONBREW $PY_PYTHONBREW" __pythonbrew_run "$@" } diff --git a/pythonbrew/exceptions.py b/pythonbrew/exceptions.py index fd6cee9..69036f1 100644 --- a/pythonbrew/exceptions.py +++ b/pythonbrew/exceptions.py @@ -11,4 +11,6 @@ class AlreadyInstalledException(Exception): """General exception during installing""" class NotSupportedVersionException(Exception): """General exception during installing""" - \ No newline at end of file + +class CurlFetchException(Exception): + """Exception curl during fetching""" diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index fbe89e8..46f8182 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -107,7 +107,7 @@ class PythonInstaller(object): dl.download(base_url, self.download_url, self.download_file) except: unlink(self.download_file) - logger.log("\nInterrupt to abort. `%s`" % (self.download_url)) + logger.error("\n%s" % (sys.exc_info()[1])) sys.exit(1) # extracting if not extract_downloadfile(self.content_type, self.download_file, self.build_dir): @@ -154,7 +154,7 @@ class PythonInstaller(object): else: s.shell("patch -p0 < %s" % patch) except: - logger.error("Failed to patch `%s`" % self.build_dir) + logger.error("Failed to patch `%s`.\n%s" % (self.build_dir, sys.exc_info()[1])) sys.exit(1) def _add_patches_to_list(self, patch_dir, patch_files): diff --git a/pythonbrew/util.py b/pythonbrew/util.py index 11f6e3d..61b42f1 100644 --- a/pythonbrew/util.py +++ b/pythonbrew/util.py @@ -271,6 +271,11 @@ def is_str(val): return isinstance(val, str) return False +def is_sequence(val): + if is_str(val): + return False + return (hasattr(val, "__getitem__") or hasattr(val, "__iter__")) + def bltin_any(iter): try: return any(iter) @@ -294,6 +299,8 @@ class Subprocess(object): def shell(self, cmd): if self._debug: logger.log(cmd) + if is_sequence(cmd): + cmd = ''.join(cmd) if self._log: if self._verbose: cmd = "(%s) 2>&1 | tee '%s'" % (cmd, self._log) From bfdccb5051440f597037e192d65d1e72517d2bac Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 15:36:46 +0900 Subject: [PATCH 26/30] improve venv --- pythonbrew/commands/venv.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index f01664e..b2f4169 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -92,13 +92,17 @@ class VenvCommand(Command): untar_file(download_file, self._venv_dir) def run_command_create(self, options, args): + if not os.access(PATH_VENVS, os.W_OK): + logger.error("Can not create a virtuale environment in %s.\nPermission denied." % PATH_VENVS) + sys.exit(1) + virtualenv_options = [] if options.no_site_packages: virtualenv_options.append('--no-site-packages') for arg in args[1:]: target_dir = os.path.join(self._workon_home, arg) - logger.log("# Create `%s` environment into %s" % (arg, self._workon_home)) + logger.info("Create `%s` environment into %s" % (arg, self._workon_home)) # make command cmd = [self._py, self._venv, '-p', self._target_py] cmd.extend(virtualenv_options) @@ -113,7 +117,10 @@ class VenvCommand(Command): if not os.path.isdir(target_dir): logger.error('%s already does not exist.' % target_dir) else: - logger.log('# Delete `%s` environment in %s' % (arg, self._workon_home)) + if not os.access(target_dir, os.W_OK): + logger.error("Can not delete %s.\nPermission denied." % target_dir) + continue + logger.info('Delete `%s` environment in %s' % (arg, self._workon_home)) # make command rm_r(target_dir) From 212460fd6de12ba6296b04b48cc915232fd23e5b Mon Sep 17 00:00:00 2001 From: utahta Date: Sun, 7 Aug 2011 15:56:04 +0900 Subject: [PATCH 27/30] update --- pythonbrew/commands/venv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pythonbrew/commands/venv.py b/pythonbrew/commands/venv.py index b2f4169..00ea77c 100644 --- a/pythonbrew/commands/venv.py +++ b/pythonbrew/commands/venv.py @@ -102,7 +102,7 @@ class VenvCommand(Command): for arg in args[1:]: target_dir = os.path.join(self._workon_home, arg) - logger.info("Create `%s` environment into %s" % (arg, self._workon_home)) + logger.info("Creating `%s` environment into %s" % (arg, self._workon_home)) # make command cmd = [self._py, self._venv, '-p', self._target_py] cmd.extend(virtualenv_options) @@ -120,7 +120,7 @@ class VenvCommand(Command): if not os.access(target_dir, os.W_OK): logger.error("Can not delete %s.\nPermission denied." % target_dir) continue - logger.info('Delete `%s` environment in %s' % (arg, self._workon_home)) + logger.info('Deleting `%s` environment in %s' % (arg, self._workon_home)) # make command rm_r(target_dir) From df91a87b2471484c265948e0e58e968903636dee Mon Sep 17 00:00:00 2001 From: utahta Date: Mon, 8 Aug 2011 02:44:08 +0900 Subject: [PATCH 28/30] update 0.10 --- ChangeLog | 5 +++++ PKG-INFO | 24 +++++++++++++++++++-- README.rst | 13 +++++++++++ pythonbrew/define.py | 2 +- pythonbrew/installer/pythonbrewinstaller.py | 4 ++++ pythonbrew/installer/pythoninstaller.py | 2 +- stable-version.txt | 2 +- 7 files changed, 47 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f61a9d6..d44a530 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +* 0.10 + - Added systemwide install support. (issue #31) + - Fixed issue #41 Handle venv binary with the symlink command. + - Improved `venv` command (without virtualenvwrapper) + * 0.9 - Added `buildout` command. - Added `venv` command. diff --git a/PKG-INFO b/PKG-INFO index 4cd025e..9add08d 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -25,6 +25,17 @@ If you need to install pythonbrew into somewhere else, you can do that by settin chmod +x pythonbrewinstall ./pythonbrewinstall +For Systemwide(Multi-User) installation +--------------------------------------- + +If the install script is run as root, pythonbrew will automatically install into /usr/local/pythonbrew. + +The pythonbrew.bashrc will be automatically configured for every user on the system if you install as root. + +After installation, where you would normally use `sudo`, non-root users will need to use `sudopybrew`:: + + sudopybrew install -n -v -j2 2.7.2 + Usage ===== @@ -91,6 +102,7 @@ Create/Remove a symbolic link to python (in a directory on your $PATH):: pythonbrew symlink -p 2.7.2 pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory pythonbrew symlink -r # Remove a symbolic link + pythonbrew symlink -v foo # Create a symbolic link to the specified virtual environment python in bin directory Runs the buildout with specified or current using python:: @@ -99,6 +111,7 @@ Runs the buildout with specified or current using python:: Create isolated python environments (uses virtualenv):: + pythonbrew venv init pythonbrew venv create proj pythonbrew venv list pythonbrew venv use proj @@ -160,11 +173,18 @@ See more details below Changelog ========= +0.10 (2011-08-08) +----------------- + +- Added systemwide install support. (issue #31) +- Fixed issue #41 Handle venv binary with the symlink command. +- Improved `venv` command (without virtualenvwrapper) + 0.9 (2011-07-21) ---------------- -- Add `venv` command (virtualenv and virtualenvwrapper supported) -- Add `buildout` command. +- Added `venv` command (uses virtualenv and virtualenvwrapper) +- Added `buildout` command. 0.8 (2011-07-10) ---------------- diff --git a/README.rst b/README.rst index 8c240ae..0c66401 100644 --- a/README.rst +++ b/README.rst @@ -25,6 +25,17 @@ If you need to install pythonbrew into somewhere else, you can do that by settin chmod +x pythonbrewinstall ./pythonbrewinstall +For Systemwide(Multi-User) installation +--------------------------------------- + +If the install script is run as root, pythonbrew will automatically install into /usr/local/pythonbrew. + +The pythonbrew function will be automatically configured for every user on the system if you install as root. + +After installation, where you would normally use `sudo`, non-root users will need to use `sudopybrew`:: + + sudopybrew install -n -v -j2 2.7.2 + Usage ===== @@ -91,6 +102,7 @@ Create/Remove a symbolic link to python (in a directory on your $PATH):: pythonbrew symlink -p 2.7.2 pythonbrew symlink pip # Create a symbolic link to the specified script in bin directory pythonbrew symlink -r # Remove a symbolic link + pythonbrew symlink -v foo # Create a symbolic link to the specified virtual environment python in bin directory Runs the buildout with specified or current using python:: @@ -99,6 +111,7 @@ Runs the buildout with specified or current using python:: Create isolated python environments (uses virtualenv):: + pythonbrew venv init pythonbrew venv create proj pythonbrew venv list pythonbrew venv use proj diff --git a/pythonbrew/define.py b/pythonbrew/define.py index 5589615..a8ab362 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -6,7 +6,7 @@ except: import configparser as ConfigParser # pythonbrew version -VERSION = "0.9" +VERSION = "0.10" # pythonbrew installer root path INSTALLER_ROOT = os.path.dirname(os.path.abspath(__file__)) diff --git a/pythonbrew/installer/pythonbrewinstaller.py b/pythonbrew/installer/pythonbrewinstaller.py index ab6e824..eb44c1e 100644 --- a/pythonbrew/installer/pythonbrewinstaller.py +++ b/pythonbrew/installer/pythonbrewinstaller.py @@ -9,6 +9,7 @@ from pythonbrew.define import PATH_BUILD, PATH_BIN, PATH_DISTS, PATH_PYTHONS,\ PATH_LOG, PATH_PATCHES, PATH_ETC_CONFIG,\ PATH_SCRIPTS_PYTHONBREW_INSTALLER, PATH_VENVS, PATH_HOME_ETC, ROOT import stat +import time class PythonbrewInstaller(object): """pythonbrew installer: @@ -84,6 +85,9 @@ fi fp.write(profile) fp.close() elif os.path.isfile('/etc/profile'): + # create backup + shutil.copy('/etc/profile', '/tmp/profile.pythonbrew.%s' % int(time.time())) + output = [] is_copy = True fp = open('/etc/profile', 'r') diff --git a/pythonbrew/installer/pythoninstaller.py b/pythonbrew/installer/pythoninstaller.py index 46f8182..eaaacc6 100644 --- a/pythonbrew/installer/pythoninstaller.py +++ b/pythonbrew/installer/pythoninstaller.py @@ -107,7 +107,7 @@ class PythonInstaller(object): dl.download(base_url, self.download_url, self.download_file) except: unlink(self.download_file) - logger.error("\n%s" % (sys.exc_info()[1])) + logger.error("Failed to download.\n%s" % (sys.exc_info()[1])) sys.exit(1) # extracting if not extract_downloadfile(self.content_type, self.download_file, self.build_dir): diff --git a/stable-version.txt b/stable-version.txt index d893d08..688abaa 100644 --- a/stable-version.txt +++ b/stable-version.txt @@ -1 +1 @@ -0.9 \ No newline at end of file +0.10 \ No newline at end of file From 0112a39aff35cbc694e02f9a7db489d9b379bfec Mon Sep 17 00:00:00 2001 From: utahta Date: Mon, 8 Aug 2011 02:45:29 +0900 Subject: [PATCH 29/30] update --- PKG-INFO | 2 +- README.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PKG-INFO b/PKG-INFO index 9add08d..3369289 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -30,7 +30,7 @@ For Systemwide(Multi-User) installation If the install script is run as root, pythonbrew will automatically install into /usr/local/pythonbrew. -The pythonbrew.bashrc will be automatically configured for every user on the system if you install as root. +The pythonbrew will be automatically configured for every user on the system if you install as root. After installation, where you would normally use `sudo`, non-root users will need to use `sudopybrew`:: diff --git a/README.rst b/README.rst index 0c66401..8c5cb50 100644 --- a/README.rst +++ b/README.rst @@ -30,7 +30,7 @@ For Systemwide(Multi-User) installation If the install script is run as root, pythonbrew will automatically install into /usr/local/pythonbrew. -The pythonbrew function will be automatically configured for every user on the system if you install as root. +The pythonbrew will be automatically configured for every user on the system if you install as root. After installation, where you would normally use `sudo`, non-root users will need to use `sudopybrew`:: From 630d525f6a65be4b89374e6887e473ca0426e3ab Mon Sep 17 00:00:00 2001 From: utahta Date: Mon, 8 Aug 2011 03:04:42 +0900 Subject: [PATCH 30/30] 0.10 -> 1.0 --- ChangeLog | 2 +- PKG-INFO | 4 ++-- pythonbrew/define.py | 2 +- setup.py | 4 ++++ stable-version.txt | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index d44a530..3ea73bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -* 0.10 +* 1.0 - Added systemwide install support. (issue #31) - Fixed issue #41 Handle venv binary with the symlink command. - Improved `venv` command (without virtualenvwrapper) diff --git a/PKG-INFO b/PKG-INFO index 3369289..81ebabb 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -173,8 +173,8 @@ See more details below Changelog ========= -0.10 (2011-08-08) ------------------ +1.0 (2011-08-08) +---------------- - Added systemwide install support. (issue #31) - Fixed issue #41 Handle venv binary with the symlink command. diff --git a/pythonbrew/define.py b/pythonbrew/define.py index a8ab362..4174c7b 100644 --- a/pythonbrew/define.py +++ b/pythonbrew/define.py @@ -6,7 +6,7 @@ except: import configparser as ConfigParser # pythonbrew version -VERSION = "0.10" +VERSION = "1.0" # pythonbrew installer root path INSTALLER_ROOT = os.path.dirname(os.path.abspath(__file__)) diff --git a/setup.py b/setup.py index 41b91d3..08bed4c 100755 --- a/setup.py +++ b/setup.py @@ -17,6 +17,10 @@ setup(name='pythonbrew', 'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.1', + 'Programming Language :: Python :: 3.2', ], keywords='pythonbrew pip easy_install distutils setuptools virtualenv', author='utahta', diff --git a/stable-version.txt b/stable-version.txt index 688abaa..9f8e9b6 100644 --- a/stable-version.txt +++ b/stable-version.txt @@ -1 +1 @@ -0.10 \ No newline at end of file +1.0 \ No newline at end of file