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