Mercurial > hg > carton
view carton.py @ 8:5905459d4ebe
now have a passing if somewhat rudimentary test
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Fri, 08 Jul 2011 11:06:08 -0700 |
parents | 79f332fb3275 |
children | e6a62ba0c24d |
line wrap: on
line source
#!/usr/bin/env python """ make a self-extracting virtualenv from directories or URLs of packages To package up all files in a virtualenvs source directory (e.g.): python path/to/carton.py mozmill mozmill/src/* This will create a self-extracting file, `mozmill.py`, that will unfold a virtualenv """ # imports import os import sys import tarfile import tempfile import urllib2 from optparse import OptionParser from StringIO import StringIO # global variables usage = "%prog [options] environment_name directory|url [...]" virtualenv_url = 'http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.6.1.tar.gz' template = """#!/usr/bin/env python import os import shutil import subprocess import sys import tarfile import tempfile from optparse import OptionParser from StringIO import StringIO try: call = subprocess.check_call except AttributeError: # old python; boo :( call = subprocess.call # virtualenv name ENV='''%(ENV)s''' # packed files VIRTUAL_ENV='''%(VIRTUAL_ENV)s'''.decode('base64').decode('zlib') PACKAGE_SOURCES='''%(PACKAGE_SOURCES)s'''.decode('base64').decode('zlib') # unpack virtualenv tempdir = tempfile.mkdtemp() buffer = StringIO() buffer.write(VIRTUAL_ENV) buffer.seek(0) tf = tarfile.open(mode='r', fileobj=buffer) tf.extractall(tempdir) # find the virtualenv for root, dirs, files in os.walk(tempdir): if 'virtualenv.py' in files: virtualenv = os.path.join(root, 'virtualenv.py') break else: raise Exception("virtualenv.py not found in " + tempdir) print virtualenv # create the virtualenv call([sys.executable, virtualenv, ENV]) # unpack the sources srcdir = os.path.join(ENV, 'src') os.mkdir(srcdir) buffer = StringIO() buffer.write(PACKAGE_SOURCES) buffer.seek(0) tf = tarfile.open(mode='r', fileobj=buffer) tf.extractall(srcdir) # find the bin/scripts directory for i in ('bin', 'Scripts'): scripts_dir = os.path.abspath(os.path.join(ENV, i)) if os.path.exists(scripts_dir): break else: raise Exception("Scripts directory not found in " + ENV) # find the virtualenv's python for i in ('python', 'python.exe'): python = os.path.join(scripts_dir, i) if os.path.exists(python): break else: raise Exception("python not found in " + scripts_dir) # activate the virtualenv #activate = os.path.join(scripts_dir, 'activate_this.py') #assert os.path.exists(activate), activate + " does not exist" #execfile(activate, dict(__file__=activate)) # setup the sources for development for i in os.listdir(srcdir): subdir = os.path.join(srcdir, i) if os.path.exists(os.path.join(srcdir, i, 'setup.py')): call([python, 'setup.py', 'develop'], cwd=subdir) # cleanup tempdir # shutil.rmtree(tempdir) # TODO: # - add carton to the virtualenv (!) # - add virtualenv to the virtualenv (!) """ def isURL(path): return path.startswith('http://') or path.startswith('https://') def main(args=sys.argv[1:]): # parse CLI arguments parser = OptionParser(usage=usage, description=__doc__) parser.add_option('-o', dest='outfile', help="specify outfile; otherwise it will come from environment_name") parser.add_option('--virtualenv', dest='virtualenv', help="use virtualenv URL") options, args = parser.parse_args(args) if len(args) < 2: parser.print_usage() parser.exit() environment = args[0] if environment.endswith('.py'): # stop on .py; will add it in later environment = environment[:-3] sources = args[1:] # tar up the sources source_buffer = StringIO() sources_tar = tarfile.open(mode="w:gz", fileobj=source_buffer) for source in sources: if isURL(source): # remote tarball raise NotImplementedError else: # local directory or tarball sources_tar.add(source, arcname=os.path.basename(source)) # could use git, hg, etc repos. but probably shouldn't sources_tar.close() # tar up virtualenv if not available if options.virtualenv: if isURL(options.virtualenv): globals()['VIRTUAL_ENV'] = urllib2.urlopen(options.virtualenv).read() else: assert os.path.exists(options.virtualenv) if os.path.isdir(options.virtualenv): raise NotImplementedError("Hypothetically you should be able to use a local directory or tarball, but I haven't done this yet") else: # assert a tarfile assert tarfile.is_tarfile(options.virtualenv), "%s must be a tar file" % options.virtualenv globals()['VIRTUAL_ENV'] = file(options.virtualenv).read() else: globals()['VIRTUAL_ENV'] = urllib2.urlopen(virtualenv_url).read() # TODO: used the below hashed value of VIRTUAL_ENV if set # (set that with another file) # interpolate "template" -> output outfile = options.outfile if outfile is None: outfile = environment + '.py' variables = {'VIRTUAL_ENV': VIRTUAL_ENV.encode('zlib').encode('base64'), 'ENV': environment, 'PACKAGE_SOURCES': source_buffer.getvalue().encode('zlib').encode('base64')} f = file(outfile, 'w') f.write(template % variables) f.close() try: os.chmod(outfile, 0755) except: # you probably don't have os.chmod pass VIRTUAL_ENV = """""" if __name__ == '__main__': main()