Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/pip/commands/zip.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 from __future__ import absolute_import | |
2 | |
3 import sys | |
4 import re | |
5 import fnmatch | |
6 import logging | |
7 import os | |
8 import shutil | |
9 import warnings | |
10 import zipfile | |
11 | |
12 from pip.utils import display_path, backup_dir, rmtree | |
13 from pip.utils.deprecation import RemovedInPip7Warning | |
14 from pip.utils.logging import indent_log | |
15 from pip.exceptions import InstallationError | |
16 from pip.basecommand import Command | |
17 | |
18 | |
19 logger = logging.getLogger(__name__) | |
20 | |
21 | |
22 class ZipCommand(Command): | |
23 """Zip individual packages.""" | |
24 name = 'zip' | |
25 usage = """ | |
26 %prog [options] <package> ...""" | |
27 summary = 'DEPRECATED. Zip individual packages.' | |
28 | |
29 def __init__(self, *args, **kw): | |
30 super(ZipCommand, self).__init__(*args, **kw) | |
31 if self.name == 'zip': | |
32 self.cmd_opts.add_option( | |
33 '--unzip', | |
34 action='store_true', | |
35 dest='unzip', | |
36 help='Unzip (rather than zip) a package.') | |
37 else: | |
38 self.cmd_opts.add_option( | |
39 '--zip', | |
40 action='store_false', | |
41 dest='unzip', | |
42 default=True, | |
43 help='Zip (rather than unzip) a package.') | |
44 self.cmd_opts.add_option( | |
45 '--no-pyc', | |
46 action='store_true', | |
47 dest='no_pyc', | |
48 help=( | |
49 'Do not include .pyc files in zip files (useful on Google App ' | |
50 'Engine).'), | |
51 ) | |
52 self.cmd_opts.add_option( | |
53 '-l', '--list', | |
54 action='store_true', | |
55 dest='list', | |
56 help='List the packages available, and their zip status.') | |
57 self.cmd_opts.add_option( | |
58 '--sort-files', | |
59 action='store_true', | |
60 dest='sort_files', | |
61 help=('With --list, sort packages according to how many files they' | |
62 ' contain.'), | |
63 ) | |
64 self.cmd_opts.add_option( | |
65 '--path', | |
66 action='append', | |
67 dest='paths', | |
68 help=('Restrict operations to the given paths (may include ' | |
69 'wildcards).'), | |
70 ) | |
71 self.cmd_opts.add_option( | |
72 '-n', '--simulate', | |
73 action='store_true', | |
74 help='Do not actually perform the zip/unzip operation.') | |
75 | |
76 self.parser.insert_option_group(0, self.cmd_opts) | |
77 | |
78 def paths(self): | |
79 """All the entries of sys.path, possibly restricted by --path""" | |
80 if not self.select_paths: | |
81 return sys.path | |
82 result = [] | |
83 match_any = set() | |
84 for path in sys.path: | |
85 path = os.path.normcase(os.path.abspath(path)) | |
86 for match in self.select_paths: | |
87 match = os.path.normcase(os.path.abspath(match)) | |
88 if '*' in match: | |
89 if re.search(fnmatch.translate(match + '*'), path): | |
90 result.append(path) | |
91 match_any.add(match) | |
92 break | |
93 else: | |
94 if path.startswith(match): | |
95 result.append(path) | |
96 match_any.add(match) | |
97 break | |
98 else: | |
99 logger.debug( | |
100 "Skipping path %s because it doesn't match %s", | |
101 path, | |
102 ', '.join(self.select_paths), | |
103 ) | |
104 for match in self.select_paths: | |
105 if match not in match_any and '*' not in match: | |
106 result.append(match) | |
107 logger.debug( | |
108 "Adding path %s because it doesn't match " | |
109 "anything already on sys.path", | |
110 match, | |
111 ) | |
112 return result | |
113 | |
114 def run(self, options, args): | |
115 | |
116 warnings.warn( | |
117 "'pip zip' and 'pip unzip` are deprecated, and will be removed in " | |
118 "a future release.", | |
119 RemovedInPip7Warning, | |
120 ) | |
121 | |
122 self.select_paths = options.paths | |
123 self.simulate = options.simulate | |
124 if options.list: | |
125 return self.list(options, args) | |
126 if not args: | |
127 raise InstallationError( | |
128 'You must give at least one package to zip or unzip') | |
129 packages = [] | |
130 for arg in args: | |
131 module_name, filename = self.find_package(arg) | |
132 if options.unzip and os.path.isdir(filename): | |
133 raise InstallationError( | |
134 'The module %s (in %s) is not a zip file; cannot be ' | |
135 'unzipped' % (module_name, filename) | |
136 ) | |
137 elif not options.unzip and not os.path.isdir(filename): | |
138 raise InstallationError( | |
139 'The module %s (in %s) is not a directory; cannot be ' | |
140 'zipped' % (module_name, filename) | |
141 ) | |
142 packages.append((module_name, filename)) | |
143 last_status = None | |
144 for module_name, filename in packages: | |
145 if options.unzip: | |
146 last_status = self.unzip_package(module_name, filename) | |
147 else: | |
148 last_status = self.zip_package( | |
149 module_name, filename, options.no_pyc | |
150 ) | |
151 return last_status | |
152 | |
153 def unzip_package(self, module_name, filename): | |
154 zip_filename = os.path.dirname(filename) | |
155 if (not os.path.isfile(zip_filename) and | |
156 zipfile.is_zipfile(zip_filename)): | |
157 raise InstallationError( | |
158 'Module %s (in %s) isn\'t located in a zip file in %s' | |
159 % (module_name, filename, zip_filename)) | |
160 package_path = os.path.dirname(zip_filename) | |
161 if package_path not in self.paths(): | |
162 logger.warning( | |
163 'Unpacking %s into %s, but %s is not on sys.path', | |
164 display_path(zip_filename), | |
165 display_path(package_path), | |
166 display_path(package_path), | |
167 ) | |
168 logger.info( | |
169 'Unzipping %s (in %s)', module_name, display_path(zip_filename), | |
170 ) | |
171 if self.simulate: | |
172 logger.info( | |
173 'Skipping remaining operations because of --simulate' | |
174 ) | |
175 return | |
176 | |
177 with indent_log(): | |
178 # FIXME: this should be undoable: | |
179 zip = zipfile.ZipFile(zip_filename) | |
180 to_save = [] | |
181 for info in zip.infolist(): | |
182 name = info.filename | |
183 if name.startswith(module_name + os.path.sep): | |
184 content = zip.read(name) | |
185 dest = os.path.join(package_path, name) | |
186 if not os.path.exists(os.path.dirname(dest)): | |
187 os.makedirs(os.path.dirname(dest)) | |
188 if not content and dest.endswith(os.path.sep): | |
189 if not os.path.exists(dest): | |
190 os.makedirs(dest) | |
191 else: | |
192 with open(dest, 'wb') as f: | |
193 f.write(content) | |
194 else: | |
195 to_save.append((name, zip.read(name))) | |
196 zip.close() | |
197 if not to_save: | |
198 logger.debug( | |
199 'Removing now-empty zip file %s', | |
200 display_path(zip_filename) | |
201 ) | |
202 os.unlink(zip_filename) | |
203 self.remove_filename_from_pth(zip_filename) | |
204 else: | |
205 logger.debug( | |
206 'Removing entries in %s/ from zip file %s', | |
207 module_name, | |
208 display_path(zip_filename), | |
209 ) | |
210 zip = zipfile.ZipFile(zip_filename, 'w') | |
211 for name, content in to_save: | |
212 zip.writestr(name, content) | |
213 zip.close() | |
214 | |
215 def zip_package(self, module_name, filename, no_pyc): | |
216 logger.info('Zip %s (in %s)', module_name, display_path(filename)) | |
217 | |
218 orig_filename = filename | |
219 if filename.endswith('.egg'): | |
220 dest_filename = filename | |
221 else: | |
222 dest_filename = filename + '.zip' | |
223 | |
224 with indent_log(): | |
225 # FIXME: I think this needs to be undoable: | |
226 if filename == dest_filename: | |
227 filename = backup_dir(orig_filename) | |
228 logger.info( | |
229 'Moving %s aside to %s', orig_filename, filename, | |
230 ) | |
231 if not self.simulate: | |
232 shutil.move(orig_filename, filename) | |
233 try: | |
234 logger.debug( | |
235 'Creating zip file in %s', display_path(dest_filename), | |
236 ) | |
237 if not self.simulate: | |
238 zip = zipfile.ZipFile(dest_filename, 'w') | |
239 zip.writestr(module_name + '/', '') | |
240 for dirpath, dirnames, filenames in os.walk(filename): | |
241 if no_pyc: | |
242 filenames = [f for f in filenames | |
243 if not f.lower().endswith('.pyc')] | |
244 for fns, is_dir in [ | |
245 (dirnames, True), (filenames, False)]: | |
246 for fn in fns: | |
247 full = os.path.join(dirpath, fn) | |
248 dest = os.path.join( | |
249 module_name, | |
250 dirpath[len(filename):].lstrip( | |
251 os.path.sep | |
252 ), | |
253 fn, | |
254 ) | |
255 if is_dir: | |
256 zip.writestr(dest + '/', '') | |
257 else: | |
258 zip.write(full, dest) | |
259 zip.close() | |
260 logger.debug( | |
261 'Removing old directory %s', display_path(filename), | |
262 ) | |
263 if not self.simulate: | |
264 rmtree(filename) | |
265 except: | |
266 # FIXME: need to do an undo here | |
267 raise | |
268 # FIXME: should also be undone: | |
269 self.add_filename_to_pth(dest_filename) | |
270 | |
271 def remove_filename_from_pth(self, filename): | |
272 for pth in self.pth_files(): | |
273 with open(pth, 'r') as f: | |
274 lines = f.readlines() | |
275 new_lines = [ | |
276 l for l in lines if l.strip() != filename] | |
277 if lines != new_lines: | |
278 logger.debug( | |
279 'Removing reference to %s from .pth file %s', | |
280 display_path(filename), | |
281 display_path(pth), | |
282 ) | |
283 if not [line for line in new_lines if line]: | |
284 logger.debug( | |
285 '%s file would be empty: deleting', display_path(pth) | |
286 ) | |
287 if not self.simulate: | |
288 os.unlink(pth) | |
289 else: | |
290 if not self.simulate: | |
291 with open(pth, 'wb') as f: | |
292 f.writelines(new_lines) | |
293 return | |
294 logger.warning( | |
295 'Cannot find a reference to %s in any .pth file', | |
296 display_path(filename), | |
297 ) | |
298 | |
299 def add_filename_to_pth(self, filename): | |
300 path = os.path.dirname(filename) | |
301 dest = filename + '.pth' | |
302 if path not in self.paths(): | |
303 logger.warning( | |
304 'Adding .pth file %s, but it is not on sys.path', | |
305 display_path(dest), | |
306 ) | |
307 if not self.simulate: | |
308 if os.path.exists(dest): | |
309 with open(dest) as f: | |
310 lines = f.readlines() | |
311 if lines and not lines[-1].endswith('\n'): | |
312 lines[-1] += '\n' | |
313 lines.append(filename + '\n') | |
314 else: | |
315 lines = [filename + '\n'] | |
316 with open(dest, 'wb') as f: | |
317 f.writelines(lines) | |
318 | |
319 def pth_files(self): | |
320 for path in self.paths(): | |
321 if not os.path.exists(path) or not os.path.isdir(path): | |
322 continue | |
323 for filename in os.listdir(path): | |
324 if filename.endswith('.pth'): | |
325 yield os.path.join(path, filename) | |
326 | |
327 def find_package(self, package): | |
328 for path in self.paths(): | |
329 full = os.path.join(path, package) | |
330 if os.path.exists(full): | |
331 return package, full | |
332 if not os.path.isdir(path) and zipfile.is_zipfile(path): | |
333 zip = zipfile.ZipFile(path, 'r') | |
334 try: | |
335 zip.read(os.path.join(package, '__init__.py')) | |
336 except KeyError: | |
337 pass | |
338 else: | |
339 zip.close() | |
340 return package, full | |
341 zip.close() | |
342 # FIXME: need special error for package.py case: | |
343 raise InstallationError( | |
344 'No package with the name %s found' % package) | |
345 | |
346 def list(self, options, args): | |
347 if args: | |
348 raise InstallationError( | |
349 'You cannot give an argument with --list') | |
350 for path in sorted(self.paths()): | |
351 if not os.path.exists(path): | |
352 continue | |
353 basename = os.path.basename(path.rstrip(os.path.sep)) | |
354 if os.path.isfile(path) and zipfile.is_zipfile(path): | |
355 if os.path.dirname(path) not in self.paths(): | |
356 logger.info('Zipped egg: %s', display_path(path)) | |
357 continue | |
358 if (basename != 'site-packages' and | |
359 basename != 'dist-packages' and not | |
360 path.replace('\\', '/').endswith('lib/python')): | |
361 continue | |
362 logger.info('In %s:', display_path(path)) | |
363 | |
364 with indent_log(): | |
365 zipped = [] | |
366 unzipped = [] | |
367 | |
368 for filename in sorted(os.listdir(path)): | |
369 ext = os.path.splitext(filename)[1].lower() | |
370 if ext in ('.pth', '.egg-info', '.egg-link'): | |
371 continue | |
372 if ext == '.py': | |
373 logger.debug( | |
374 'Not displaying %s: not a package', | |
375 display_path(filename) | |
376 ) | |
377 continue | |
378 full = os.path.join(path, filename) | |
379 if os.path.isdir(full): | |
380 unzipped.append((filename, self.count_package(full))) | |
381 elif zipfile.is_zipfile(full): | |
382 zipped.append(filename) | |
383 else: | |
384 logger.debug( | |
385 'Unknown file: %s', display_path(filename), | |
386 ) | |
387 if zipped: | |
388 logger.info('Zipped packages:') | |
389 with indent_log(): | |
390 for filename in zipped: | |
391 logger.info(filename) | |
392 else: | |
393 logger.info('No zipped packages.') | |
394 if unzipped: | |
395 if options.sort_files: | |
396 unzipped.sort(key=lambda x: -x[1]) | |
397 logger.info('Unzipped packages:') | |
398 with indent_log(): | |
399 for filename, count in unzipped: | |
400 logger.info('%s (%i files)', filename, count) | |
401 else: | |
402 logger.info('No unzipped packages.') | |
403 | |
404 def count_package(self, path): | |
405 total = 0 | |
406 for dirpath, dirnames, filenames in os.walk(path): | |
407 filenames = [f for f in filenames | |
408 if not f.lower().endswith('.pyc')] | |
409 total += len(filenames) | |
410 return total |