Merge lp:~jml/pkgme-devportal/entry_point into lp:pkgme-devportal
- entry_point
- Merge into trunk
Proposed by
Jonathan Lange
Status: | Merged |
---|---|
Merged at revision: | 14 |
Proposed branch: | lp:~jml/pkgme-devportal/entry_point |
Merge into: | lp:pkgme-devportal |
Diff against target: |
783 lines (+702/-20) 9 files modified
.bzrignore (+3/-0) MANIFEST.in (+2/-0) bin/guess-deps (+2/-9) bin/guess-executable (+2/-11) devportalbinary/__init__.py (+14/-0) devportalbinary/binary.py (+13/-0) distribute_setup.py (+477/-0) setup.py (+42/-0) setup_helpers.py (+147/-0) |
To merge this branch: | bzr merge lp:~jml/pkgme-devportal/entry_point |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
pkgme binary committers | Pending | ||
Review via email: mp+82399@code.launchpad.net |
Commit message
Description of the change
This makes the binary plugin setup.py-
To post a comment you must log in.
- 16. By Jonathan Lange
-
Export the two other scripts as endpoints.
- 17. By Jonathan Lange
-
Don't think we actually need this.
- 18. By Jonathan Lange
-
Tweaks.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file '.bzrignore' | |||
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 | |||
3 | +++ .bzrignore 2011-11-16 16:53:24 +0000 | |||
4 | @@ -0,0 +1,3 @@ | |||
5 | 1 | build | ||
6 | 2 | dist | ||
7 | 3 | pkgme_binary.egg-info | ||
8 | 0 | 4 | ||
9 | === added file 'MANIFEST.in' | |||
10 | --- MANIFEST.in 1970-01-01 00:00:00 +0000 | |||
11 | +++ MANIFEST.in 2011-11-16 16:53:24 +0000 | |||
12 | @@ -0,0 +1,2 @@ | |||
13 | 1 | include *.py | ||
14 | 2 | graft devportalbinary/backends | ||
15 | 0 | 3 | ||
16 | === modified file 'bin/guess-deps' | |||
17 | --- bin/guess-deps 2011-08-23 17:21:54 +0000 | |||
18 | +++ bin/guess-deps 2011-11-16 16:53:24 +0000 | |||
19 | @@ -4,15 +4,8 @@ | |||
20 | 4 | 4 | ||
21 | 5 | import sys | 5 | import sys |
22 | 6 | 6 | ||
31 | 7 | from devportalbinary.binary import guess_dependencies | 7 | from devportalbinary.binary import print_dependencies |
24 | 8 | |||
25 | 9 | |||
26 | 10 | def main(): | ||
27 | 11 | deps = guess_dependencies('.') | ||
28 | 12 | for dep in deps: | ||
29 | 13 | print dep | ||
30 | 14 | return 0 | ||
32 | 15 | 8 | ||
33 | 16 | 9 | ||
34 | 17 | if __name__ == '__main__': | 10 | if __name__ == '__main__': |
36 | 18 | sys.exit(main()) | 11 | sys.exit(print_dependencies()) |
37 | 19 | 12 | ||
38 | === modified file 'bin/guess-executable' | |||
39 | --- bin/guess-executable 2011-08-23 17:21:54 +0000 | |||
40 | +++ bin/guess-executable 2011-11-16 16:53:24 +0000 | |||
41 | @@ -5,17 +5,8 @@ | |||
42 | 5 | import os | 5 | import os |
43 | 6 | import sys | 6 | import sys |
44 | 7 | 7 | ||
55 | 8 | from devportalbinary.binary import ( | 8 | from devportalbinary.binary import print_executable |
46 | 9 | guess_executable, | ||
47 | 10 | iter_executables, | ||
48 | 11 | ) | ||
49 | 12 | |||
50 | 13 | |||
51 | 14 | def main(): | ||
52 | 15 | cwd = os.getcwd() | ||
53 | 16 | print guess_executable(os.path.dirname(cwd), iter_executables(cwd)) | ||
54 | 17 | return 0 | ||
56 | 18 | 9 | ||
57 | 19 | 10 | ||
58 | 20 | if __name__ == '__main__': | 11 | if __name__ == '__main__': |
60 | 21 | sys.exit(main()) | 12 | sys.exit(print_executable()) |
61 | 22 | 13 | ||
62 | === modified file 'devportalbinary/__init__.py' | |||
63 | --- devportalbinary/__init__.py 2011-08-23 17:21:54 +0000 | |||
64 | +++ devportalbinary/__init__.py 2011-11-16 16:53:24 +0000 | |||
65 | @@ -1,2 +1,16 @@ | |||
66 | 1 | # Copyright 2011 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2011 Canonical Ltd. This software is licensed under the |
67 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
68 | 3 | |||
69 | 4 | from pkg_resources import resource_filename | ||
70 | 5 | |||
71 | 6 | __all__ = [ | ||
72 | 7 | '__version__', | ||
73 | 8 | 'get_backends_path', | ||
74 | 9 | ] | ||
75 | 10 | |||
76 | 11 | |||
77 | 12 | __version__ = '0.0.1' | ||
78 | 13 | |||
79 | 14 | |||
80 | 15 | def get_backends_path(): | ||
81 | 16 | return resource_filename(__name__, 'backends') | ||
82 | 3 | 17 | ||
83 | === modified file 'devportalbinary/binary.py' | |||
84 | --- devportalbinary/binary.py 2011-10-24 22:02:09 +0000 | |||
85 | +++ devportalbinary/binary.py 2011-11-16 16:53:24 +0000 | |||
86 | @@ -279,3 +279,16 @@ | |||
87 | 279 | libraries = get_shared_library_dependencies(binaries, library_finder) | 279 | libraries = get_shared_library_dependencies(binaries, library_finder) |
88 | 280 | deps = libraries_to_deps(libraries, 'i386') | 280 | deps = libraries_to_deps(libraries, 'i386') |
89 | 281 | return deps | 281 | return deps |
90 | 282 | |||
91 | 283 | |||
92 | 284 | def print_dependencies(): | ||
93 | 285 | deps = guess_dependencies('.') | ||
94 | 286 | for dep in deps: | ||
95 | 287 | print dep | ||
96 | 288 | return 0 | ||
97 | 289 | |||
98 | 290 | |||
99 | 291 | def print_executable(): | ||
100 | 292 | cwd = os.getcwd() | ||
101 | 293 | print guess_executable(os.path.dirname(cwd), iter_executables(cwd)) | ||
102 | 294 | return 0 | ||
103 | 282 | 295 | ||
104 | === added file 'distribute_setup.py' | |||
105 | --- distribute_setup.py 1970-01-01 00:00:00 +0000 | |||
106 | +++ distribute_setup.py 2011-11-16 16:53:24 +0000 | |||
107 | @@ -0,0 +1,477 @@ | |||
108 | 1 | #!python | ||
109 | 2 | """Bootstrap distribute installation | ||
110 | 3 | |||
111 | 4 | If you want to use setuptools in your package's setup.py, just include this | ||
112 | 5 | file in the same directory with it, and add this to the top of your setup.py:: | ||
113 | 6 | |||
114 | 7 | from distribute_setup import use_setuptools | ||
115 | 8 | use_setuptools() | ||
116 | 9 | |||
117 | 10 | If you want to require a specific version of setuptools, set a download | ||
118 | 11 | mirror, or use an alternate download directory, you can do so by supplying | ||
119 | 12 | the appropriate options to ``use_setuptools()``. | ||
120 | 13 | |||
121 | 14 | This file can also be run as a script to install or upgrade setuptools. | ||
122 | 15 | """ | ||
123 | 16 | import os | ||
124 | 17 | import sys | ||
125 | 18 | import time | ||
126 | 19 | import fnmatch | ||
127 | 20 | import tempfile | ||
128 | 21 | import tarfile | ||
129 | 22 | from distutils import log | ||
130 | 23 | |||
131 | 24 | try: | ||
132 | 25 | from site import USER_SITE | ||
133 | 26 | except ImportError: | ||
134 | 27 | USER_SITE = None | ||
135 | 28 | |||
136 | 29 | try: | ||
137 | 30 | import subprocess | ||
138 | 31 | |||
139 | 32 | def _python_cmd(*args): | ||
140 | 33 | args = (sys.executable,) + args | ||
141 | 34 | return subprocess.call(args) == 0 | ||
142 | 35 | |||
143 | 36 | except ImportError: | ||
144 | 37 | # will be used for python 2.3 | ||
145 | 38 | def _python_cmd(*args): | ||
146 | 39 | args = (sys.executable,) + args | ||
147 | 40 | # quoting arguments if windows | ||
148 | 41 | if sys.platform == 'win32': | ||
149 | 42 | def quote(arg): | ||
150 | 43 | if ' ' in arg: | ||
151 | 44 | return '"%s"' % arg | ||
152 | 45 | return arg | ||
153 | 46 | args = [quote(arg) for arg in args] | ||
154 | 47 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 | ||
155 | 48 | |||
156 | 49 | DEFAULT_VERSION = "0.6.10" | ||
157 | 50 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" | ||
158 | 51 | SETUPTOOLS_FAKED_VERSION = "0.6c11" | ||
159 | 52 | |||
160 | 53 | SETUPTOOLS_PKG_INFO = """\ | ||
161 | 54 | Metadata-Version: 1.0 | ||
162 | 55 | Name: setuptools | ||
163 | 56 | Version: %s | ||
164 | 57 | Summary: xxxx | ||
165 | 58 | Home-page: xxx | ||
166 | 59 | Author: xxx | ||
167 | 60 | Author-email: xxx | ||
168 | 61 | License: xxx | ||
169 | 62 | Description: xxx | ||
170 | 63 | """ % SETUPTOOLS_FAKED_VERSION | ||
171 | 64 | |||
172 | 65 | |||
173 | 66 | def _install(tarball): | ||
174 | 67 | # extracting the tarball | ||
175 | 68 | tmpdir = tempfile.mkdtemp() | ||
176 | 69 | log.warn('Extracting in %s', tmpdir) | ||
177 | 70 | old_wd = os.getcwd() | ||
178 | 71 | try: | ||
179 | 72 | os.chdir(tmpdir) | ||
180 | 73 | tar = tarfile.open(tarball) | ||
181 | 74 | _extractall(tar) | ||
182 | 75 | tar.close() | ||
183 | 76 | |||
184 | 77 | # going in the directory | ||
185 | 78 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) | ||
186 | 79 | os.chdir(subdir) | ||
187 | 80 | log.warn('Now working in %s', subdir) | ||
188 | 81 | |||
189 | 82 | # installing | ||
190 | 83 | log.warn('Installing Distribute') | ||
191 | 84 | if not _python_cmd('setup.py', 'install'): | ||
192 | 85 | log.warn('Something went wrong during the installation.') | ||
193 | 86 | log.warn('See the error message above.') | ||
194 | 87 | finally: | ||
195 | 88 | os.chdir(old_wd) | ||
196 | 89 | |||
197 | 90 | |||
198 | 91 | def _build_egg(egg, tarball, to_dir): | ||
199 | 92 | # extracting the tarball | ||
200 | 93 | tmpdir = tempfile.mkdtemp() | ||
201 | 94 | log.warn('Extracting in %s', tmpdir) | ||
202 | 95 | old_wd = os.getcwd() | ||
203 | 96 | try: | ||
204 | 97 | os.chdir(tmpdir) | ||
205 | 98 | tar = tarfile.open(tarball) | ||
206 | 99 | _extractall(tar) | ||
207 | 100 | tar.close() | ||
208 | 101 | |||
209 | 102 | # going in the directory | ||
210 | 103 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) | ||
211 | 104 | os.chdir(subdir) | ||
212 | 105 | log.warn('Now working in %s', subdir) | ||
213 | 106 | |||
214 | 107 | # building an egg | ||
215 | 108 | log.warn('Building a Distribute egg in %s', to_dir) | ||
216 | 109 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) | ||
217 | 110 | |||
218 | 111 | finally: | ||
219 | 112 | os.chdir(old_wd) | ||
220 | 113 | # returning the result | ||
221 | 114 | log.warn(egg) | ||
222 | 115 | if not os.path.exists(egg): | ||
223 | 116 | raise IOError('Could not build the egg.') | ||
224 | 117 | |||
225 | 118 | |||
226 | 119 | def _do_download(version, download_base, to_dir, download_delay): | ||
227 | 120 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' | ||
228 | 121 | % (version, sys.version_info[0], sys.version_info[1])) | ||
229 | 122 | if not os.path.exists(egg): | ||
230 | 123 | tarball = download_setuptools(version, download_base, | ||
231 | 124 | to_dir, download_delay) | ||
232 | 125 | _build_egg(egg, tarball, to_dir) | ||
233 | 126 | sys.path.insert(0, egg) | ||
234 | 127 | import setuptools | ||
235 | 128 | setuptools.bootstrap_install_from = egg | ||
236 | 129 | |||
237 | 130 | |||
238 | 131 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, | ||
239 | 132 | to_dir=os.curdir, download_delay=15, no_fake=True): | ||
240 | 133 | # making sure we use the absolute path | ||
241 | 134 | to_dir = os.path.abspath(to_dir) | ||
242 | 135 | was_imported = 'pkg_resources' in sys.modules or \ | ||
243 | 136 | 'setuptools' in sys.modules | ||
244 | 137 | try: | ||
245 | 138 | try: | ||
246 | 139 | import pkg_resources | ||
247 | 140 | if not hasattr(pkg_resources, '_distribute'): | ||
248 | 141 | if not no_fake: | ||
249 | 142 | _fake_setuptools() | ||
250 | 143 | raise ImportError | ||
251 | 144 | except ImportError: | ||
252 | 145 | return _do_download(version, download_base, to_dir, download_delay) | ||
253 | 146 | try: | ||
254 | 147 | pkg_resources.require("distribute>="+version) | ||
255 | 148 | return | ||
256 | 149 | except pkg_resources.VersionConflict: | ||
257 | 150 | e = sys.exc_info()[1] | ||
258 | 151 | if was_imported: | ||
259 | 152 | sys.stderr.write( | ||
260 | 153 | "The required version of distribute (>=%s) is not available,\n" | ||
261 | 154 | "and can't be installed while this script is running. Please\n" | ||
262 | 155 | "install a more recent version first, using\n" | ||
263 | 156 | "'easy_install -U distribute'." | ||
264 | 157 | "\n\n(Currently using %r)\n" % (version, e.args[0])) | ||
265 | 158 | sys.exit(2) | ||
266 | 159 | else: | ||
267 | 160 | del pkg_resources, sys.modules['pkg_resources'] # reload ok | ||
268 | 161 | return _do_download(version, download_base, to_dir, | ||
269 | 162 | download_delay) | ||
270 | 163 | except pkg_resources.DistributionNotFound: | ||
271 | 164 | return _do_download(version, download_base, to_dir, | ||
272 | 165 | download_delay) | ||
273 | 166 | finally: | ||
274 | 167 | if not no_fake: | ||
275 | 168 | _create_fake_setuptools_pkg_info(to_dir) | ||
276 | 169 | |||
277 | 170 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, | ||
278 | 171 | to_dir=os.curdir, delay=15): | ||
279 | 172 | """Download distribute from a specified location and return its filename | ||
280 | 173 | |||
281 | 174 | `version` should be a valid distribute version number that is available | ||
282 | 175 | as an egg for download under the `download_base` URL (which should end | ||
283 | 176 | with a '/'). `to_dir` is the directory where the egg will be downloaded. | ||
284 | 177 | `delay` is the number of seconds to pause before an actual download | ||
285 | 178 | attempt. | ||
286 | 179 | """ | ||
287 | 180 | # making sure we use the absolute path | ||
288 | 181 | to_dir = os.path.abspath(to_dir) | ||
289 | 182 | try: | ||
290 | 183 | from urllib.request import urlopen | ||
291 | 184 | except ImportError: | ||
292 | 185 | from urllib2 import urlopen | ||
293 | 186 | tgz_name = "distribute-%s.tar.gz" % version | ||
294 | 187 | url = download_base + tgz_name | ||
295 | 188 | saveto = os.path.join(to_dir, tgz_name) | ||
296 | 189 | src = dst = None | ||
297 | 190 | if not os.path.exists(saveto): # Avoid repeated downloads | ||
298 | 191 | try: | ||
299 | 192 | log.warn("Downloading %s", url) | ||
300 | 193 | src = urlopen(url) | ||
301 | 194 | # Read/write all in one block, so we don't create a corrupt file | ||
302 | 195 | # if the download is interrupted. | ||
303 | 196 | data = src.read() | ||
304 | 197 | dst = open(saveto, "wb") | ||
305 | 198 | dst.write(data) | ||
306 | 199 | finally: | ||
307 | 200 | if src: | ||
308 | 201 | src.close() | ||
309 | 202 | if dst: | ||
310 | 203 | dst.close() | ||
311 | 204 | return os.path.realpath(saveto) | ||
312 | 205 | |||
313 | 206 | |||
314 | 207 | def _patch_file(path, content): | ||
315 | 208 | """Will backup the file then patch it""" | ||
316 | 209 | existing_content = open(path).read() | ||
317 | 210 | if existing_content == content: | ||
318 | 211 | # already patched | ||
319 | 212 | log.warn('Already patched.') | ||
320 | 213 | return False | ||
321 | 214 | log.warn('Patching...') | ||
322 | 215 | _rename_path(path) | ||
323 | 216 | f = open(path, 'w') | ||
324 | 217 | try: | ||
325 | 218 | f.write(content) | ||
326 | 219 | finally: | ||
327 | 220 | f.close() | ||
328 | 221 | return True | ||
329 | 222 | |||
330 | 223 | |||
331 | 224 | def _same_content(path, content): | ||
332 | 225 | return open(path).read() == content | ||
333 | 226 | |||
334 | 227 | def _no_sandbox(function): | ||
335 | 228 | def __no_sandbox(*args, **kw): | ||
336 | 229 | try: | ||
337 | 230 | from setuptools.sandbox import DirectorySandbox | ||
338 | 231 | def violation(*args): | ||
339 | 232 | pass | ||
340 | 233 | DirectorySandbox._old = DirectorySandbox._violation | ||
341 | 234 | DirectorySandbox._violation = violation | ||
342 | 235 | patched = True | ||
343 | 236 | except ImportError: | ||
344 | 237 | patched = False | ||
345 | 238 | |||
346 | 239 | try: | ||
347 | 240 | return function(*args, **kw) | ||
348 | 241 | finally: | ||
349 | 242 | if patched: | ||
350 | 243 | DirectorySandbox._violation = DirectorySandbox._old | ||
351 | 244 | del DirectorySandbox._old | ||
352 | 245 | |||
353 | 246 | return __no_sandbox | ||
354 | 247 | |||
355 | 248 | @_no_sandbox | ||
356 | 249 | def _rename_path(path): | ||
357 | 250 | new_name = path + '.OLD.%s' % time.time() | ||
358 | 251 | log.warn('Renaming %s into %s', path, new_name) | ||
359 | 252 | os.rename(path, new_name) | ||
360 | 253 | return new_name | ||
361 | 254 | |||
362 | 255 | def _remove_flat_installation(placeholder): | ||
363 | 256 | if not os.path.isdir(placeholder): | ||
364 | 257 | log.warn('Unkown installation at %s', placeholder) | ||
365 | 258 | return False | ||
366 | 259 | found = False | ||
367 | 260 | for file in os.listdir(placeholder): | ||
368 | 261 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'): | ||
369 | 262 | found = True | ||
370 | 263 | break | ||
371 | 264 | if not found: | ||
372 | 265 | log.warn('Could not locate setuptools*.egg-info') | ||
373 | 266 | return | ||
374 | 267 | |||
375 | 268 | log.warn('Removing elements out of the way...') | ||
376 | 269 | pkg_info = os.path.join(placeholder, file) | ||
377 | 270 | if os.path.isdir(pkg_info): | ||
378 | 271 | patched = _patch_egg_dir(pkg_info) | ||
379 | 272 | else: | ||
380 | 273 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) | ||
381 | 274 | |||
382 | 275 | if not patched: | ||
383 | 276 | log.warn('%s already patched.', pkg_info) | ||
384 | 277 | return False | ||
385 | 278 | # now let's move the files out of the way | ||
386 | 279 | for element in ('setuptools', 'pkg_resources.py', 'site.py'): | ||
387 | 280 | element = os.path.join(placeholder, element) | ||
388 | 281 | if os.path.exists(element): | ||
389 | 282 | _rename_path(element) | ||
390 | 283 | else: | ||
391 | 284 | log.warn('Could not find the %s element of the ' | ||
392 | 285 | 'Setuptools distribution', element) | ||
393 | 286 | return True | ||
394 | 287 | |||
395 | 288 | |||
396 | 289 | def _after_install(dist): | ||
397 | 290 | log.warn('After install bootstrap.') | ||
398 | 291 | placeholder = dist.get_command_obj('install').install_purelib | ||
399 | 292 | _create_fake_setuptools_pkg_info(placeholder) | ||
400 | 293 | |||
401 | 294 | @_no_sandbox | ||
402 | 295 | def _create_fake_setuptools_pkg_info(placeholder): | ||
403 | 296 | if not placeholder or not os.path.exists(placeholder): | ||
404 | 297 | log.warn('Could not find the install location') | ||
405 | 298 | return | ||
406 | 299 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) | ||
407 | 300 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \ | ||
408 | 301 | (SETUPTOOLS_FAKED_VERSION, pyver) | ||
409 | 302 | pkg_info = os.path.join(placeholder, setuptools_file) | ||
410 | 303 | if os.path.exists(pkg_info): | ||
411 | 304 | log.warn('%s already exists', pkg_info) | ||
412 | 305 | return | ||
413 | 306 | |||
414 | 307 | log.warn('Creating %s', pkg_info) | ||
415 | 308 | f = open(pkg_info, 'w') | ||
416 | 309 | try: | ||
417 | 310 | f.write(SETUPTOOLS_PKG_INFO) | ||
418 | 311 | finally: | ||
419 | 312 | f.close() | ||
420 | 313 | |||
421 | 314 | pth_file = os.path.join(placeholder, 'setuptools.pth') | ||
422 | 315 | log.warn('Creating %s', pth_file) | ||
423 | 316 | f = open(pth_file, 'w') | ||
424 | 317 | try: | ||
425 | 318 | f.write(os.path.join(os.curdir, setuptools_file)) | ||
426 | 319 | finally: | ||
427 | 320 | f.close() | ||
428 | 321 | |||
429 | 322 | def _patch_egg_dir(path): | ||
430 | 323 | # let's check if it's already patched | ||
431 | 324 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') | ||
432 | 325 | if os.path.exists(pkg_info): | ||
433 | 326 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): | ||
434 | 327 | log.warn('%s already patched.', pkg_info) | ||
435 | 328 | return False | ||
436 | 329 | _rename_path(path) | ||
437 | 330 | os.mkdir(path) | ||
438 | 331 | os.mkdir(os.path.join(path, 'EGG-INFO')) | ||
439 | 332 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') | ||
440 | 333 | f = open(pkg_info, 'w') | ||
441 | 334 | try: | ||
442 | 335 | f.write(SETUPTOOLS_PKG_INFO) | ||
443 | 336 | finally: | ||
444 | 337 | f.close() | ||
445 | 338 | return True | ||
446 | 339 | |||
447 | 340 | |||
448 | 341 | def _before_install(): | ||
449 | 342 | log.warn('Before install bootstrap.') | ||
450 | 343 | _fake_setuptools() | ||
451 | 344 | |||
452 | 345 | |||
453 | 346 | def _under_prefix(location): | ||
454 | 347 | if 'install' not in sys.argv: | ||
455 | 348 | return True | ||
456 | 349 | args = sys.argv[sys.argv.index('install')+1:] | ||
457 | 350 | for index, arg in enumerate(args): | ||
458 | 351 | for option in ('--root', '--prefix'): | ||
459 | 352 | if arg.startswith('%s=' % option): | ||
460 | 353 | top_dir = arg.split('root=')[-1] | ||
461 | 354 | return location.startswith(top_dir) | ||
462 | 355 | elif arg == option: | ||
463 | 356 | if len(args) > index: | ||
464 | 357 | top_dir = args[index+1] | ||
465 | 358 | return location.startswith(top_dir) | ||
466 | 359 | elif option == '--user' and USER_SITE is not None: | ||
467 | 360 | return location.startswith(USER_SITE) | ||
468 | 361 | return True | ||
469 | 362 | |||
470 | 363 | |||
471 | 364 | def _fake_setuptools(): | ||
472 | 365 | log.warn('Scanning installed packages') | ||
473 | 366 | try: | ||
474 | 367 | import pkg_resources | ||
475 | 368 | except ImportError: | ||
476 | 369 | # we're cool | ||
477 | 370 | log.warn('Setuptools or Distribute does not seem to be installed.') | ||
478 | 371 | return | ||
479 | 372 | ws = pkg_resources.working_set | ||
480 | 373 | try: | ||
481 | 374 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', | ||
482 | 375 | replacement=False)) | ||
483 | 376 | except TypeError: | ||
484 | 377 | # old distribute API | ||
485 | 378 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) | ||
486 | 379 | |||
487 | 380 | if setuptools_dist is None: | ||
488 | 381 | log.warn('No setuptools distribution found') | ||
489 | 382 | return | ||
490 | 383 | # detecting if it was already faked | ||
491 | 384 | setuptools_location = setuptools_dist.location | ||
492 | 385 | log.warn('Setuptools installation detected at %s', setuptools_location) | ||
493 | 386 | |||
494 | 387 | # if --root or --preix was provided, and if | ||
495 | 388 | # setuptools is not located in them, we don't patch it | ||
496 | 389 | if not _under_prefix(setuptools_location): | ||
497 | 390 | log.warn('Not patching, --root or --prefix is installing Distribute' | ||
498 | 391 | ' in another location') | ||
499 | 392 | return | ||
500 | 393 | |||
501 | 394 | # let's see if its an egg | ||
502 | 395 | if not setuptools_location.endswith('.egg'): | ||
503 | 396 | log.warn('Non-egg installation') | ||
504 | 397 | res = _remove_flat_installation(setuptools_location) | ||
505 | 398 | if not res: | ||
506 | 399 | return | ||
507 | 400 | else: | ||
508 | 401 | log.warn('Egg installation') | ||
509 | 402 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') | ||
510 | 403 | if (os.path.exists(pkg_info) and | ||
511 | 404 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): | ||
512 | 405 | log.warn('Already patched.') | ||
513 | 406 | return | ||
514 | 407 | log.warn('Patching...') | ||
515 | 408 | # let's create a fake egg replacing setuptools one | ||
516 | 409 | res = _patch_egg_dir(setuptools_location) | ||
517 | 410 | if not res: | ||
518 | 411 | return | ||
519 | 412 | log.warn('Patched done.') | ||
520 | 413 | _relaunch() | ||
521 | 414 | |||
522 | 415 | |||
523 | 416 | def _relaunch(): | ||
524 | 417 | log.warn('Relaunching...') | ||
525 | 418 | # we have to relaunch the process | ||
526 | 419 | args = [sys.executable] + sys.argv | ||
527 | 420 | sys.exit(subprocess.call(args)) | ||
528 | 421 | |||
529 | 422 | |||
530 | 423 | def _extractall(self, path=".", members=None): | ||
531 | 424 | """Extract all members from the archive to the current working | ||
532 | 425 | directory and set owner, modification time and permissions on | ||
533 | 426 | directories afterwards. `path' specifies a different directory | ||
534 | 427 | to extract to. `members' is optional and must be a subset of the | ||
535 | 428 | list returned by getmembers(). | ||
536 | 429 | """ | ||
537 | 430 | import copy | ||
538 | 431 | import operator | ||
539 | 432 | from tarfile import ExtractError | ||
540 | 433 | directories = [] | ||
541 | 434 | |||
542 | 435 | if members is None: | ||
543 | 436 | members = self | ||
544 | 437 | |||
545 | 438 | for tarinfo in members: | ||
546 | 439 | if tarinfo.isdir(): | ||
547 | 440 | # Extract directories with a safe mode. | ||
548 | 441 | directories.append(tarinfo) | ||
549 | 442 | tarinfo = copy.copy(tarinfo) | ||
550 | 443 | tarinfo.mode = 448 # decimal for oct 0700 | ||
551 | 444 | self.extract(tarinfo, path) | ||
552 | 445 | |||
553 | 446 | # Reverse sort directories. | ||
554 | 447 | if sys.version_info < (2, 4): | ||
555 | 448 | def sorter(dir1, dir2): | ||
556 | 449 | return cmp(dir1.name, dir2.name) | ||
557 | 450 | directories.sort(sorter) | ||
558 | 451 | directories.reverse() | ||
559 | 452 | else: | ||
560 | 453 | directories.sort(key=operator.attrgetter('name'), reverse=True) | ||
561 | 454 | |||
562 | 455 | # Set correct owner, mtime and filemode on directories. | ||
563 | 456 | for tarinfo in directories: | ||
564 | 457 | dirpath = os.path.join(path, tarinfo.name) | ||
565 | 458 | try: | ||
566 | 459 | self.chown(tarinfo, dirpath) | ||
567 | 460 | self.utime(tarinfo, dirpath) | ||
568 | 461 | self.chmod(tarinfo, dirpath) | ||
569 | 462 | except ExtractError: | ||
570 | 463 | e = sys.exc_info()[1] | ||
571 | 464 | if self.errorlevel > 1: | ||
572 | 465 | raise | ||
573 | 466 | else: | ||
574 | 467 | self._dbg(1, "tarfile: %s" % e) | ||
575 | 468 | |||
576 | 469 | |||
577 | 470 | def main(argv, version=DEFAULT_VERSION): | ||
578 | 471 | """Install or upgrade setuptools and EasyInstall""" | ||
579 | 472 | tarball = download_setuptools() | ||
580 | 473 | _install(tarball) | ||
581 | 474 | |||
582 | 475 | |||
583 | 476 | if __name__ == '__main__': | ||
584 | 477 | main(sys.argv[1:]) | ||
585 | 0 | 478 | ||
586 | === added file 'setup.py' | |||
587 | --- setup.py 1970-01-01 00:00:00 +0000 | |||
588 | +++ setup.py 2011-11-16 16:53:24 +0000 | |||
589 | @@ -0,0 +1,42 @@ | |||
590 | 1 | # Copyright 2011 Canonical Ltd. This software is licensed under the | ||
591 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
592 | 3 | |||
593 | 4 | import distribute_setup | ||
594 | 5 | distribute_setup.use_setuptools() | ||
595 | 6 | |||
596 | 7 | from setup_helpers import ( | ||
597 | 8 | description, | ||
598 | 9 | get_version, | ||
599 | 10 | ) | ||
600 | 11 | from setuptools import setup, find_packages | ||
601 | 12 | |||
602 | 13 | |||
603 | 14 | __version__ = get_version('devportalbinary/__init__.py') | ||
604 | 15 | |||
605 | 16 | setup( | ||
606 | 17 | name='pkgme-binary', | ||
607 | 18 | version=__version__, | ||
608 | 19 | packages=find_packages(), | ||
609 | 20 | include_package_data=True, | ||
610 | 21 | maintainer='pkgme developers', | ||
611 | 22 | maintainer_email='pkgme-devs@lists.launchpad.net', | ||
612 | 23 | description=description('README'), | ||
613 | 24 | license='AGPLv3', | ||
614 | 25 | url='http://launchpad.net/pkgme-binary', | ||
615 | 26 | download_url='https://launchpad.net/pkgme-binary/+download', | ||
616 | 27 | test_suite='devportalbinary.tests', | ||
617 | 28 | install_requires = [ | ||
618 | 29 | 'bzr', | ||
619 | 30 | 'pkgme', | ||
620 | 31 | ], | ||
621 | 32 | entry_points = { | ||
622 | 33 | 'console_scripts': [ | ||
623 | 34 | 'fetch-symbol-files=devportalbinary.database:main', | ||
624 | 35 | 'guess-executable=devportalbinary.binary:print_executable', | ||
625 | 36 | 'guess-deps=devportalbinary.binary:print_dependencies', | ||
626 | 37 | ], | ||
627 | 38 | 'pkgme.get_backends_path': ['binary=devportalbinary:get_backends_path'], | ||
628 | 39 | }, | ||
629 | 40 | # Auto-conversion to Python 3. | ||
630 | 41 | use_2to3=True, | ||
631 | 42 | ) | ||
632 | 0 | 43 | ||
633 | === added file 'setup_helpers.py' | |||
634 | --- setup_helpers.py 1970-01-01 00:00:00 +0000 | |||
635 | +++ setup_helpers.py 2011-11-16 16:53:24 +0000 | |||
636 | @@ -0,0 +1,147 @@ | |||
637 | 1 | # setup_helper.py - Some utility functions for setup.py authors. | ||
638 | 2 | # | ||
639 | 3 | # Copyright (C) 2009, 2010 by Barry A. Warsaw | ||
640 | 4 | # | ||
641 | 5 | # This program is free software: you can redistribute it and/or modify it | ||
642 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
643 | 7 | # Free Software Foundation, version 3 of the License. | ||
644 | 8 | # | ||
645 | 9 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
646 | 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
647 | 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
648 | 12 | # for more details. | ||
649 | 13 | # | ||
650 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
651 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
652 | 16 | |||
653 | 17 | """setup.py helper functions.""" | ||
654 | 18 | |||
655 | 19 | from __future__ import absolute_import, unicode_literals | ||
656 | 20 | from __future__ import print_function | ||
657 | 21 | |||
658 | 22 | |||
659 | 23 | __metaclass__ = type | ||
660 | 24 | __all__ = [ | ||
661 | 25 | 'description', | ||
662 | 26 | 'find_doctests', | ||
663 | 27 | 'get_version', | ||
664 | 28 | 'long_description', | ||
665 | 29 | 'require_python', | ||
666 | 30 | ] | ||
667 | 31 | |||
668 | 32 | |||
669 | 33 | import os | ||
670 | 34 | import re | ||
671 | 35 | import sys | ||
672 | 36 | |||
673 | 37 | |||
674 | 38 | DEFAULT_VERSION_RE = re.compile(r'(?P<version>\d+\.\d(?:\.\d+)?)') | ||
675 | 39 | NL = '\n' | ||
676 | 40 | |||
677 | 41 | |||
678 | 42 | |||
679 | 0 | 43 | ||
680 | 44 | def require_python(minimum): | ||
681 | 45 | """Require at least a minimum Python version. | ||
682 | 46 | |||
683 | 47 | The version number is expressed in terms of `sys.hexversion`. E.g. to | ||
684 | 48 | require a minimum of Python 2.6, use:: | ||
685 | 49 | |||
686 | 50 | >>> require_python(0x206000f0) | ||
687 | 51 | |||
688 | 52 | :param minimum: Minimum Python version supported. | ||
689 | 53 | :type minimum: integer | ||
690 | 54 | """ | ||
691 | 55 | if sys.hexversion < minimum: | ||
692 | 56 | hversion = hex(minimum)[2:] | ||
693 | 57 | if len(hversion) % 2 != 0: | ||
694 | 58 | hversion = '0' + hversion | ||
695 | 59 | split = list(hversion) | ||
696 | 60 | parts = [] | ||
697 | 61 | while split: | ||
698 | 62 | parts.append(int(''.join((split.pop(0), split.pop(0))), 16)) | ||
699 | 63 | major, minor, micro, release = parts | ||
700 | 64 | if release == 0xf0: | ||
701 | 65 | print('Python {0}.{1}.{2} or better is required'.format( | ||
702 | 66 | major, minor, micro)) | ||
703 | 67 | else: | ||
704 | 68 | print('Python {0}.{1}.{2} ({3}) or better is required'.format( | ||
705 | 69 | major, minor, micro, hex(release)[2:])) | ||
706 | 70 | sys.exit(1) | ||
707 | 71 | |||
708 | 72 | |||
709 | 73 | |||
710 | 1 | 74 | ||
711 | 75 | def get_version(filename, pattern=None): | ||
712 | 76 | """Extract the __version__ from a file without importing it. | ||
713 | 77 | |||
714 | 78 | While you could get the __version__ by importing the module, the very act | ||
715 | 79 | of importing can cause unintended consequences. For example, Distribute's | ||
716 | 80 | automatic 2to3 support will break. Instead, this searches the file for a | ||
717 | 81 | line that starts with __version__, and extract the version number by | ||
718 | 82 | regular expression matching. | ||
719 | 83 | |||
720 | 84 | By default, two or three dot-separated digits are recognized, but by | ||
721 | 85 | passing a pattern parameter, you can recognize just about anything. Use | ||
722 | 86 | the `version` group name to specify the match group. | ||
723 | 87 | |||
724 | 88 | :param filename: The name of the file to search. | ||
725 | 89 | :type filename: string | ||
726 | 90 | :param pattern: Optional alternative regular expression pattern to use. | ||
727 | 91 | :type pattern: string | ||
728 | 92 | :return: The version that was extracted. | ||
729 | 93 | :rtype: string | ||
730 | 94 | """ | ||
731 | 95 | if pattern is None: | ||
732 | 96 | cre = DEFAULT_VERSION_RE | ||
733 | 97 | else: | ||
734 | 98 | cre = re.compile(pattern) | ||
735 | 99 | with open(filename) as fp: | ||
736 | 100 | for line in fp: | ||
737 | 101 | if line.startswith('__version__'): | ||
738 | 102 | mo = cre.search(line) | ||
739 | 103 | assert mo, 'No valid __version__ string found' | ||
740 | 104 | return mo.group('version') | ||
741 | 105 | raise AssertionError('No __version__ assignment found') | ||
742 | 106 | |||
743 | 107 | |||
744 | 108 | |||
745 | 2 | 109 | ||
746 | 110 | def find_doctests(start='.', extension='.txt'): | ||
747 | 111 | """Find separate-file doctests in the package. | ||
748 | 112 | |||
749 | 113 | This is useful for Distribute's automatic 2to3 conversion support. The | ||
750 | 114 | `setup()` keyword argument `convert_2to3_doctests` requires file names, | ||
751 | 115 | which may be difficult to track automatically as you add new doctests. | ||
752 | 116 | |||
753 | 117 | :param start: Directory to start searching in (default is cwd) | ||
754 | 118 | :type start: string | ||
755 | 119 | :param extension: Doctest file extension (default is .txt) | ||
756 | 120 | :type extension: string | ||
757 | 121 | :return: The doctest files found. | ||
758 | 122 | :rtype: list | ||
759 | 123 | """ | ||
760 | 124 | doctests = [] | ||
761 | 125 | for dirpath, dirnames, filenames in os.walk(start): | ||
762 | 126 | doctests.extend(os.path.join(dirpath, filename) | ||
763 | 127 | for filename in filenames | ||
764 | 128 | if filename.endswith(extension)) | ||
765 | 129 | return doctests | ||
766 | 130 | |||
767 | 131 | |||
768 | 132 | |||
769 | 3 | 133 | ||
770 | 134 | def long_description(*filenames): | ||
771 | 135 | """Provide a long description.""" | ||
772 | 136 | res = [] | ||
773 | 137 | for value in filenames: | ||
774 | 138 | if value.endswith('.txt'): | ||
775 | 139 | with open(value) as fp: | ||
776 | 140 | value = fp.read() | ||
777 | 141 | res.append(value) | ||
778 | 142 | if not value.endswith(NL): | ||
779 | 143 | res.append('') | ||
780 | 144 | return NL.join(res) | ||
781 | 145 | |||
782 | 146 | |||
783 | 147 | def description(filename): | ||
784 | 148 | """Provide a short description.""" | ||
785 | 149 | with open(filename) as fp: | ||
786 | 150 | for line in fp: | ||
787 | 151 | return line.strip() |