Mercurial > hg > carton
annotate carton.py @ 16:c91abbdc871b
* add TODO: dependencies
* take docstring from the module itself
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Fri, 08 Jul 2011 15:55:00 -0700 |
parents | f05e636b7444 |
children | b05f5f1ec26e |
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 | |
15
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
29 "create a virtualenv at %(ENV)s" |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
30 |
0 | 31 import os |
32 import shutil | |
33 import subprocess | |
34 import sys | |
35 import tarfile | |
36 import tempfile | |
37 from optparse import OptionParser | |
38 from StringIO import StringIO | |
39 | |
40 try: | |
41 call = subprocess.check_call | |
42 except AttributeError: | |
43 # old python; boo :( | |
44 call = subprocess.call | |
45 | |
46 # virtualenv name | |
47 ENV='''%(ENV)s''' | |
48 | |
49 # packed files | |
3
75919adb199a
use compression, but it doesnt seem to help much
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
50 VIRTUAL_ENV='''%(VIRTUAL_ENV)s'''.decode('base64').decode('zlib') |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
51 PACKAGE_SOURCES=%(PACKAGE_SOURCES)s |
0 | 52 |
15
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
53 # parse options |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
54 usage = os.path.basename(sys.argv[0]) + ' [options]' |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
55 parser = OptionParser(usage=usage, description=__doc__) |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
56 parser.add_option('--env', dest='env', help="environment name [DEFAULT: " + ENV + "]") |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
57 options, args = parser.parse_args() |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
58 if options.env: |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
59 ENV = options.env |
f05e636b7444
now you can specify the name of the env in the created script
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
60 |
0 | 61 # unpack virtualenv |
62 tempdir = tempfile.mkdtemp() | |
63 buffer = StringIO() | |
64 buffer.write(VIRTUAL_ENV) | |
65 buffer.seek(0) | |
66 tf = tarfile.open(mode='r', fileobj=buffer) | |
67 tf.extractall(tempdir) | |
68 | |
69 # find the virtualenv | |
70 for root, dirs, files in os.walk(tempdir): | |
71 if 'virtualenv.py' in files: | |
72 virtualenv = os.path.join(root, 'virtualenv.py') | |
73 break | |
74 else: | |
75 raise Exception("virtualenv.py not found in " + tempdir) | |
76 print virtualenv | |
77 | |
78 # create the virtualenv | |
79 call([sys.executable, virtualenv, ENV]) | |
80 | |
81 # find the bin/scripts directory | |
82 for i in ('bin', 'Scripts'): | |
83 scripts_dir = os.path.abspath(os.path.join(ENV, i)) | |
84 if os.path.exists(scripts_dir): | |
85 break | |
86 else: | |
87 raise Exception("Scripts directory not found in " + ENV) | |
88 | |
89 # find the virtualenv's python | |
90 for i in ('python', 'python.exe'): | |
91 python = os.path.join(scripts_dir, i) | |
92 if os.path.exists(python): | |
93 break | |
94 else: | |
95 raise Exception("python not found in " + scripts_dir) | |
96 | |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
97 # unpack the sources and setup for development |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
98 srcdir = os.path.join(ENV, 'src') |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
99 os.mkdir(srcdir) |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
100 setup_pys = set() |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
101 for source in PACKAGE_SOURCES: |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
102 source = source.decode('base64').decode('zlib') |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
103 buffer = StringIO() |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
104 buffer.write(source) |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
105 buffer.seek(0) |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
106 tf = tarfile.open(mode='r', fileobj=buffer) |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
107 tf.extractall(srcdir) |
0 | 108 |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
109 # setup sources for development if there are any new setup.py files |
16 | 110 # TODO: ideally this would figure out dependency order for you |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
111 for i in os.listdir(srcdir): |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
112 if i in setup_pys: |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
113 continue |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
114 subdir = os.path.join(srcdir, i) |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
115 if os.path.exists(os.path.join(srcdir, i, 'setup.py')): |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
116 call([python, 'setup.py', 'develop'], cwd=subdir) |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
117 setup_pys.add(i) |
0 | 118 |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
119 # cleanup tempdir # TODO (optionally?) |
0 | 120 # shutil.rmtree(tempdir) |
121 | |
122 # TODO: | |
123 # - add carton to the virtualenv (!) | |
124 # - add virtualenv to the virtualenv (!) | |
125 """ | |
126 | |
127 def isURL(path): | |
128 return path.startswith('http://') or path.startswith('https://') | |
129 | |
130 def main(args=sys.argv[1:]): | |
131 | |
132 # parse CLI arguments | |
133 parser = OptionParser(usage=usage, description=__doc__) | |
134 parser.add_option('-o', dest='outfile', | |
135 help="specify outfile; otherwise it will come from environment_name") | |
136 parser.add_option('--virtualenv', dest='virtualenv', | |
12
542b46ac4e28
fix description more better
Jeff Hammel <jhammel@mozilla.com>
parents:
11
diff
changeset
|
137 help="use this virtualenv URL or file tarball") |
0 | 138 options, args = parser.parse_args(args) |
139 if len(args) < 2: | |
140 parser.print_usage() | |
141 parser.exit() | |
142 environment = args[0] | |
143 if environment.endswith('.py'): | |
144 # stop on .py; will add it in later | |
145 environment = environment[:-3] | |
146 sources = args[1:] | |
147 | |
148 # tar up the sources | |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
149 source_array = [] |
0 | 150 for source in sources: |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
151 buffer = None |
0 | 152 |
153 if isURL(source): | |
14
c474362cf69a
allow fetching of remote tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
154 # remote tarball or resource |
c474362cf69a
allow fetching of remote tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
155 buffer = urllib2.urlopen(source).read() |
0 | 156 else: |
13
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
157 assert os.path.exists(source), "%s does not exist" % source |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
158 |
0 | 159 # local directory or tarball |
13
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
160 if (not os.path.isdir(source)) and tarfile.is_tarfile(source): |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
161 # check for a tarball |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
162 buffer = file(source).read() |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
163 else: |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
164 source_buffer = StringIO() |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
165 source_tar = tarfile.open(mode="w:gz", fileobj=source_buffer) |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
166 source_tar.add(source, arcname=os.path.basename(source)) |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
167 source_tar.close() |
f522620c6a78
now works properly with tarballs
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
168 buffer = source_buffer.getvalue() |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
169 |
0 | 170 # could use git, hg, etc repos. but probably shouldn't |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
171 |
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
172 source_array.append(buffer.encode('zlib').encode('base64')) |
0 | 173 |
174 # tar up virtualenv if not available | |
175 if options.virtualenv: | |
176 if isURL(options.virtualenv): | |
177 globals()['VIRTUAL_ENV'] = urllib2.urlopen(options.virtualenv).read() | |
178 else: | |
179 assert os.path.exists(options.virtualenv) | |
180 if os.path.isdir(options.virtualenv): | |
181 raise NotImplementedError("Hypothetically you should be able to use a local directory or tarball, but I haven't done this yet") | |
182 else: | |
183 # assert a tarfile | |
184 assert tarfile.is_tarfile(options.virtualenv), "%s must be a tar file" % options.virtualenv | |
185 globals()['VIRTUAL_ENV'] = file(options.virtualenv).read() | |
186 else: | |
187 globals()['VIRTUAL_ENV'] = urllib2.urlopen(virtualenv_url).read() | |
188 # TODO: used the below hashed value of VIRTUAL_ENV if set | |
189 # (set that with another file) | |
190 | |
191 # interpolate "template" -> output | |
192 outfile = options.outfile | |
193 if outfile is None: | |
194 outfile = environment + '.py' | |
3
75919adb199a
use compression, but it doesnt seem to help much
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
195 variables = {'VIRTUAL_ENV': VIRTUAL_ENV.encode('zlib').encode('base64'), |
0 | 196 'ENV': environment, |
11
e6a62ba0c24d
now respect the order sources are installed in
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
197 'PACKAGE_SOURCES': repr(source_array)} |
0 | 198 f = file(outfile, 'w') |
199 f.write(template % variables) | |
200 f.close() | |
201 try: | |
202 os.chmod(outfile, 0755) | |
203 except: | |
204 # you probably don't have os.chmod | |
205 pass | |
206 | |
207 VIRTUAL_ENV = """""" | |
208 | |
209 if __name__ == '__main__': | |
210 main() |