view stampit/main.py @ 11:7e538a4b0e79

make directories work like they should
author Jeff Hammel <jhammel@mozilla.com>
date Fri, 23 Apr 2010 09:48:16 -0700
parents f63e51490c61
children fa758b655dcc
line wrap: on
line source

#!/usr/bin/env python
"""
tar up a set of packages and their dependencies in a virtualenv:

<package>-<version>.tar.gz

Example:

mozmill-1.4.1.tar.gz

"""

import os
import shutil
import subprocess
import sys
import tempfile

from optparse import OptionParser, IndentedHelpFormatter, HelpFormatter
from utils import which

def call(*args, **kwargs):
    code = subprocess.call(*args, **kwargs)
    if code:
        sys.exit(code)

class UnformattedDescription(IndentedHelpFormatter):
    def format_description(self, description):
        return description.strip() or ''

def main(args=sys.argv[1:]):

    # XXX this is actually a very long way to work around just getting the
    # tarballs as pip magically does this for you!  ::sigh::
    # not sure of a better/easier way, though
    # should look at the `pip` api and see what's going on there;
    # if pip is already installed, there's probably no need to make the
    # virtualenv at all

    if 'PYTHONHOME' in os.environ:
        del os.environ['PYTHONHOME'] # just make sure this is killed

    # parse options
    usage = '%prog [options] <package> <platform>'
    parser = OptionParser(usage, description=globals()['__doc__'],
                          formatter=UnformattedDescription())
    parser.add_option('-c', '--command',
                      help="command to use on each tarball;  the tarball will be the last argument to the command, or '{}' may be used, find-style, to substittue for the argument")
    parser.add_option('-d', '--directory',
                      help='directory to use as the virtualenv')
    parser.add_option('-o', '--output',
                      help='where to put the tarballs')
    parser.add_option('--clean', default=False, action='store_true',
                      help='remove all directories [BE CAREFUL!]')
    parser.add_option('-q', '--quiet', default=False, action='store_true',
                      help='make less noise')
    parser.add_option('--verbose', default=False, action='store_true',
                      help='more output')
    parser.add_option('--version',
                      help='version of the package to be installed (defaults to the current on the cheeseshop)')
    parser.add_option('--virtualenv',
                      help='path to virtualenv to use')
    options, args = parser.parse_args(args)
    for option in 'virtualenv', 'output', 'directory':
        # expand ~ arguments
        path = getattr(options, option)
        if path is not None:
            if '~' in path:
                path = os.path.expanduser(path)
            setattr(options, option, os.path.abspath(path))
        
    callargs = {}
    if not options.verbose: # suppress output
        callargs = {'stdout': subprocess.PIPE}
    if options.quiet:
        callargs['stderr'] = subprocess.PIPE
    if not args:
        parser.print_help()
        sys.exit(0)

    # locate virtualenv
    if options.virtualenv:
        if not os.path.exists(options.virtualenv):
            parser.error("'%s', specified by --virtualenv, does not exist", options.virtualenv)
    else:
        options.virtualenv = which('virtualenv')
    virtualenv_dir = None
    if options.virtualenv is None:
        hg = which('hg')
        if hg:
            # download virtualenv for them
            virtualenv_src = 'http://bitbucket.org/ianb/virtualenv'
            virtualenv_dir = tempfile.mkdtemp()
            call([hg,  'clone', virtualenv_src, virtualenv_dir], **callargs)
            options.virtualenv = os.path.join(virtualenv_dir, 'virtualenv.py')
        else:
            parser.error("virtualenv cannot be found; please install virtualenv or specify its location with --virtualenv")

    # create a virtualenv
    directory_exists = bool(options.directory and os.path.exists(options.directory))
    if not options.directory:
        options.directory = tempfile.mkdtemp(dir=os.getcwd())
    call([options.virtualenv, '--no-site-packages', options.directory], **callargs)

    # install the packages
    pip = os.path.join(options.directory, 'bin', 'pip')
    command = [ pip, 'install', '--no-install' ]
    command.extend(args)
    call(command, **callargs)

    # make the tarballs
    if not options.output:
        options.output = os.path.join(options.directory, 'dist')
    builddir = os.path.join(options.directory, 'build') # virtualenv creates
    if not os.path.exists(options.output):
        os.mkdir(options.output)
    python = os.path.join(options.directory, 'bin', 'python')
    for package in os.listdir(builddir):
        os.chdir(os.path.join(builddir, package))
        call([python, 'setup.py', 'sdist', '--dist-dir', options.output],
             **callargs)
    tarballs = os.listdir(options.output) # XXX should be just new ones maybe
    quiet = options.quiet or options.command
    if options.quiet:
        if not options.command:
            print '\n'.join([os.path.join(options.output, tarball)
                             for tarball in tarballs])
    else:
        print 'Tarballs are in %s:' % options.output
        print '\n'.join(tarballs)

    # do something with them (optionally)
    if options.command:
        options.command = options.command.strip()
        os.chdir(options.output)
        for tarball in tarballs:
            if '{}' in options.command:
                command = options.command.replace('{}', tarball)
            else:
                command = '%s %s' % (options.command, tarball)
            subprocess.call(command, shell=True)

    # clean up (optionally)
    if options.clean:
        if virtualenv_dir:
            shutil.rmtree(virtualenv_dir)
        if not directory_exists:
            shutil.rmtree(options.directory)

if __name__ == '__main__':
    main()