Commits

Stan Seibert committed 7bc9416

Major update to shrinkwrap so that it adds new keyword arguments to setup(),
installs build dependencies before installing the package, and also records
the installation of the package in the usual setuptools manner.

  • Participants
  • Parent commits e6b49b6

Comments (0)

Files changed (2)

 
 setup(
     name='shrinkwrap',
-    version='0.2',
+    version='0.3',
     author='Stan Seibert',
     author_email='stan@mtrr.org',
     packages=['shrinkwrap'],
     license='LICENSE.txt',
     description='Helper modules for making wrapper packages around non-Python code.',
     long_description=open('README.txt').read(),
+    entry_points = {
+        "distutils.setup_keywords": [
+            "shrinkwrap_source_url = shrinkwrap.install:assert_string",
+            "shrinkwrap_source_dir = shrinkwrap.install:assert_string",
+            "shrinkwrap_installer = shrinkwrap.install:validate_installer_option",
+            "shrinkwrap_requires = setuptools.dist:assert_string_list",
+        ],
+    },
     cmdclass = {'install': install},
 )

shrinkwrap/install.py

 import tarfile
 import subprocess
-from setuptools import Command
+from setuptools.command import install as _install
 from distutils import log
 import os
 import multiprocessing
 import platform
+import collections
+
+def assert_string(dist, attr, value):
+    '''Verify that value is a string'''
+    if not isinstance(value, str):
+        raise DistutilsSetupError(
+            "%r must be a string value (got %r)" % (attr,value)
+        )
+
+
+def validate_installer_option(dist, attr, value):
+    '''Verify that value is either an allowed string or a callable function'''
+    if callable(value):
+        return # OK
+    elif isinstance(value, str) and value in install_functions:
+        return # OK
+    else:
+        raise DistutilsSetupError(
+            "%r must be a callable function or valid string option (got %r)" % (attr,value)
+        )
 
 
 class CommandError(Exception):
         Exception.__init__(self, message)
 
 
-class ShrinkwrapInstall(Command):
+class ShrinkwrapInstall(_install.install):
     '''Base class for a setup.py "install" command that wraps a generic tarball installation.'''
 
-    description = "install package"
-    user_options = [('single-version-externally-managed', None, ''),
-                    ('record=', None, ''),
-                    ('install-headers=', None, '')]
+    
 
     def initialize_options(self):
-        self.single_version_externally_managed = True
-        self.record = None
-        self.install_headers = None
+        _install.install.initialize_options(self)
 
     def finalize_options(self):
-        pass
+        _install.install.finalize_options(self)
 
     def download_url(self, url, saveto=None):
         '''Downloads a file.  If no saveto is specified, the basename of
         with open(fullpath, 'w') as f:
             f.write(contents)
 
+#### Main command interface ####
+
+    def run(self):
+        '''Base implementation of the run command that install dependencies in
+        before allowing installation to continue.
+
+        Do not override this method, but instead override the install() method.
+        '''
+        # Install dependencies
+        build_deps = getattr(self.distribution, 'shrinkwrap_requires', None)
+        if build_deps is None:
+            build_deps = []
+        for dep in build_deps:
+            self.shell('pip install '+dep)
+
+        # Do the install process for this package
+        installer = self.distribution.shrinkwrap_installer
+        if installer in install_functions:
+            installer = install_functions[installer]
+
+        installer(self)
+
+        # Now finish up and register installation
+        _install.install.run(self)
+
+
     #### Useful properties ####
 
     @property
         return os.path.join(self.virtualenv, 'lib', 'python%s.%s' % platform.python_version_tuple()[:2], 'config')
 
 
-class AutoconfInstall(ShrinkwrapInstall):
-    '''Convenience class that automates the installation of a standard autoconf/configure-based
-    package.  Just set the version and source_url class attributes.  If the source directory
-    in the tar file is not the basename of the source url with .tar.gz/bz2 removed, 
-    also set the build_dir class attribute.'''
+def autoconf_install(self):
+    source_url = self.distribution.shrinkwrap_source_url
+    source_dir = getattr(self.distribution, 'shrinkwrap_source_dir', None)
 
-    def run(self):
-        self.download_and_unpack_tarball(self.source_url)
-        if not hasattr(self, 'build_dir'):
-            # Remove .tar or .gz or .bz2 if present
-            basename, ext = os.path.splitext(os.path.basename(self.source_url))
-            while ext in ['.gz', '.bz2', '.tar']:
-                basename, ext = os.path.splitext(basename)
-            # Went one too far, now back up, ext could also be empty
-            basename = basename + ext
-            self.build_dir = basename
+    self.download_and_unpack_tarball(source_url)
+    if source_dir is None:
+        # Remove .tar or .gz or .bz2 if present
+        basename, ext = os.path.splitext(os.path.basename(source_url))
+        while ext in ['.gz', '.bz2', '.tar']:
+            basename, ext = os.path.splitext(basename)
+        # Went one too far, now back up, ext could also be empty
+        basename = basename + ext
+        source_dir = basename
 
-        os.chdir(self.build_dir)
-        self.shell('./configure --prefix=' + self.virtualenv)
-        self.make(extra_opts=['install'])
+    os.chdir(source_dir)
+    self.shell('./configure --prefix=' + self.virtualenv)
+    self.make(extra_opts=['install'])
+
+
+install_functions = { 'autoconf' : autoconf_install }