Mercurial > hg > carton
annotate 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 |
rev | line source |
---|---|
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 | |
3
75919adb199a
use compression, but it doesnt seem to help much
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
48 VIRTUAL_ENV='''%(VIRTUAL_ENV)s'''.decode('base64').decode('zlib') |
75919adb199a
use compression, but it doesnt seem to help much
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
49 PACKAGE_SOURCES='''%(PACKAGE_SOURCES)s'''.decode('base64').decode('zlib') |
0 | 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 source_buffer = StringIO() | |
138 sources_tar = tarfile.open(mode="w:gz", fileobj=source_buffer) | |
139 for source in sources: | |
140 | |
141 if isURL(source): | |
142 # remote tarball | |
143 raise NotImplementedError | |
144 else: | |
145 # local directory or tarball | |
146 sources_tar.add(source, arcname=os.path.basename(source)) | |
147 # could use git, hg, etc repos. but probably shouldn't | |
148 sources_tar.close() | |
149 | |
150 # tar up virtualenv if not available | |
151 if options.virtualenv: | |
152 if isURL(options.virtualenv): | |
153 globals()['VIRTUAL_ENV'] = urllib2.urlopen(options.virtualenv).read() | |
154 else: | |
155 assert os.path.exists(options.virtualenv) | |
156 if os.path.isdir(options.virtualenv): | |
157 raise NotImplementedError("Hypothetically you should be able to use a local directory or tarball, but I haven't done this yet") | |
158 else: | |
159 # assert a tarfile | |
160 assert tarfile.is_tarfile(options.virtualenv), "%s must be a tar file" % options.virtualenv | |
161 globals()['VIRTUAL_ENV'] = file(options.virtualenv).read() | |
162 else: | |
163 globals()['VIRTUAL_ENV'] = urllib2.urlopen(virtualenv_url).read() | |
164 # TODO: used the below hashed value of VIRTUAL_ENV if set | |
165 # (set that with another file) | |
166 | |
167 # interpolate "template" -> output | |
168 outfile = options.outfile | |
169 if outfile is None: | |
170 outfile = environment + '.py' | |
3
75919adb199a
use compression, but it doesnt seem to help much
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
171 variables = {'VIRTUAL_ENV': VIRTUAL_ENV.encode('zlib').encode('base64'), |
0 | 172 'ENV': environment, |
3
75919adb199a
use compression, but it doesnt seem to help much
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
173 'PACKAGE_SOURCES': source_buffer.getvalue().encode('zlib').encode('base64')} |
0 | 174 f = file(outfile, 'w') |
175 f.write(template % variables) | |
176 f.close() | |
177 try: | |
178 os.chmod(outfile, 0755) | |
179 except: | |
180 # you probably don't have os.chmod | |
181 pass | |
182 | |
183 VIRTUAL_ENV = """""" | |
184 | |
185 if __name__ == '__main__': | |
186 main() |