0
|
1 #!/usr/bin/env python
|
|
2
|
|
3 """
|
|
4 make a self-extracting virtualenv from directories or URLs
|
|
5 of packages
|
|
6
|
|
7 To package up all files in a virtualenvs source directory (e.g.):
|
|
8
|
|
9 python path/to/carton.py mozmill mozmill/src/*
|
|
10
|
|
11 This will create a self-extracting file, `mozmill.py`, that will unfold
|
|
12 a virtualenv
|
|
13 """
|
|
14
|
|
15 # imports
|
|
16 import os
|
|
17 import sys
|
|
18 import tarfile
|
|
19 import tempfile
|
|
20 import urllib2
|
|
21 from optparse import OptionParser
|
|
22 from StringIO import StringIO
|
|
23
|
|
24 # global variables
|
|
25 usage = "%prog [options] environment_name directory|url [...]"
|
|
26 virtualenv_url = 'http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.6.1.tar.gz'
|
|
27 template = """#!/usr/bin/env python
|
|
28
|
|
29 import os
|
|
30 import shutil
|
|
31 import subprocess
|
|
32 import sys
|
|
33 import tarfile
|
|
34 import tempfile
|
|
35 from optparse import OptionParser
|
|
36 from StringIO import StringIO
|
|
37
|
|
38 try:
|
|
39 call = subprocess.check_call
|
|
40 except AttributeError:
|
|
41 # old python; boo :(
|
|
42 call = subprocess.call
|
|
43
|
|
44 # virtualenv name
|
|
45 ENV='''%(ENV)s'''
|
|
46
|
|
47 # packed files
|
|
48 VIRTUAL_ENV='''%(VIRTUAL_ENV)s'''.decode('base64')
|
|
49 PACKAGE_SOURCES='''%(PACKAGE_SOURCES)s'''.decode('base64')
|
|
50
|
|
51 # unpack virtualenv
|
|
52 tempdir = tempfile.mkdtemp()
|
|
53 buffer = StringIO()
|
|
54 buffer.write(VIRTUAL_ENV)
|
|
55 buffer.seek(0)
|
|
56 tf = tarfile.open(mode='r', fileobj=buffer)
|
|
57 tf.extractall(tempdir)
|
|
58
|
|
59 # find the virtualenv
|
|
60 for root, dirs, files in os.walk(tempdir):
|
|
61 if 'virtualenv.py' in files:
|
|
62 virtualenv = os.path.join(root, 'virtualenv.py')
|
|
63 break
|
|
64 else:
|
|
65 raise Exception("virtualenv.py not found in " + tempdir)
|
|
66 print virtualenv
|
|
67
|
|
68 # create the virtualenv
|
|
69 call([sys.executable, virtualenv, ENV])
|
|
70
|
|
71 # unpack the sources
|
|
72 srcdir = os.path.join(ENV, 'src')
|
|
73 os.mkdir(srcdir)
|
|
74 buffer = StringIO()
|
|
75 buffer.write(PACKAGE_SOURCES)
|
|
76 buffer.seek(0)
|
|
77 tf = tarfile.open(mode='r', fileobj=buffer)
|
|
78 tf.extractall(srcdir)
|
|
79
|
|
80 # find the bin/scripts directory
|
|
81 for i in ('bin', 'Scripts'):
|
|
82 scripts_dir = os.path.abspath(os.path.join(ENV, i))
|
|
83 if os.path.exists(scripts_dir):
|
|
84 break
|
|
85 else:
|
|
86 raise Exception("Scripts directory not found in " + ENV)
|
|
87
|
|
88 # find the virtualenv's python
|
|
89 for i in ('python', 'python.exe'):
|
|
90 python = os.path.join(scripts_dir, i)
|
|
91 if os.path.exists(python):
|
|
92 break
|
|
93 else:
|
|
94 raise Exception("python not found in " + scripts_dir)
|
|
95
|
|
96 # activate the virtualenv
|
|
97 #activate = os.path.join(scripts_dir, 'activate_this.py')
|
|
98 #assert os.path.exists(activate), activate + " does not exist"
|
|
99 #execfile(activate, dict(__file__=activate))
|
|
100
|
|
101 # setup the sources for development
|
|
102 for i in os.listdir(srcdir):
|
|
103 subdir = os.path.join(srcdir, i)
|
|
104 if os.path.exists(os.path.join(srcdir, i, 'setup.py')):
|
|
105 call([python, 'setup.py', 'develop'], cwd=subdir)
|
|
106
|
|
107 # cleanup tempdir
|
|
108 # shutil.rmtree(tempdir)
|
|
109
|
|
110 # TODO:
|
|
111 # - add carton to the virtualenv (!)
|
|
112 # - add virtualenv to the virtualenv (!)
|
|
113 """
|
|
114
|
|
115 def isURL(path):
|
|
116 return path.startswith('http://') or path.startswith('https://')
|
|
117
|
|
118 def main(args=sys.argv[1:]):
|
|
119
|
|
120 # parse CLI arguments
|
|
121 parser = OptionParser(usage=usage, description=__doc__)
|
|
122 parser.add_option('-o', dest='outfile',
|
|
123 help="specify outfile; otherwise it will come from environment_name")
|
|
124 parser.add_option('--virtualenv', dest='virtualenv',
|
|
125 help="use virtualenv URL")
|
|
126 options, args = parser.parse_args(args)
|
|
127 if len(args) < 2:
|
|
128 parser.print_usage()
|
|
129 parser.exit()
|
|
130 environment = args[0]
|
|
131 if environment.endswith('.py'):
|
|
132 # stop on .py; will add it in later
|
|
133 environment = environment[:-3]
|
|
134 sources = args[1:]
|
|
135
|
|
136 # tar up the sources
|
|
137 tempdir = tempfile.mkdtemp()
|
|
138 source_buffer = StringIO()
|
|
139 sources_tar = tarfile.open(mode="w:gz", fileobj=source_buffer)
|
|
140 for source in sources:
|
|
141
|
|
142 if isURL(source):
|
|
143 # remote tarball
|
|
144 raise NotImplementedError
|
|
145 else:
|
|
146 # local directory or tarball
|
|
147 sources_tar.add(source, arcname=os.path.basename(source))
|
|
148 # could use git, hg, etc repos. but probably shouldn't
|
|
149 sources_tar.close()
|
|
150
|
|
151 # tar up virtualenv if not available
|
|
152 if options.virtualenv:
|
|
153 if isURL(options.virtualenv):
|
|
154 globals()['VIRTUAL_ENV'] = urllib2.urlopen(options.virtualenv).read()
|
|
155 else:
|
|
156 assert os.path.exists(options.virtualenv)
|
|
157 if os.path.isdir(options.virtualenv):
|
|
158 raise NotImplementedError("Hypothetically you should be able to use a local directory or tarball, but I haven't done this yet")
|
|
159 else:
|
|
160 # assert a tarfile
|
|
161 assert tarfile.is_tarfile(options.virtualenv), "%s must be a tar file" % options.virtualenv
|
|
162 globals()['VIRTUAL_ENV'] = file(options.virtualenv).read()
|
|
163 else:
|
|
164 globals()['VIRTUAL_ENV'] = urllib2.urlopen(virtualenv_url).read()
|
|
165 # TODO: used the below hashed value of VIRTUAL_ENV if set
|
|
166 # (set that with another file)
|
|
167
|
|
168 # interpolate "template" -> output
|
|
169 outfile = options.outfile
|
|
170 if outfile is None:
|
|
171 outfile = environment + '.py'
|
|
172 variables = {'VIRTUAL_ENV': VIRTUAL_ENV.encode('base64'),
|
|
173 'ENV': environment,
|
|
174 'PACKAGE_SOURCES': source_buffer.getvalue().encode('base64')}
|
|
175 f = file(outfile, 'w')
|
|
176 f.write(template % variables)
|
|
177 f.close()
|
|
178 try:
|
|
179 os.chmod(outfile, 0755)
|
|
180 except:
|
|
181 # you probably don't have os.chmod
|
|
182 pass
|
|
183
|
|
184 VIRTUAL_ENV = """"""
|
|
185
|
|
186 if __name__ == '__main__':
|
|
187 main()
|