|
| 1 | +from __future__ import absolute_import |
| 2 | + |
| 3 | +import logging |
| 4 | +import os |
| 5 | +import textwrap |
| 6 | + |
| 7 | +from pip._internal.cli.base_command import Command |
| 8 | +from pip._internal.exceptions import CommandError |
| 9 | +from pip._internal.utils.filesystem import find_files |
| 10 | + |
| 11 | + |
| 12 | +logger = logging.getLogger(__name__) |
| 13 | + |
| 14 | + |
| 15 | +class CacheCommand(Command): |
| 16 | + """ |
| 17 | + Inspect and manage pip's caches. |
| 18 | +
|
| 19 | + Subcommands: |
| 20 | + info: |
| 21 | + Show information about the caches. |
| 22 | + list [name]: |
| 23 | + List filenames of packages stored in the cache. |
| 24 | + remove <pattern>: |
| 25 | + Remove one or more package from the cache. |
| 26 | + `pattern` can be a glob expression or a package name. |
| 27 | + purge: |
| 28 | + Remove all items from the cache. |
| 29 | + """ |
| 30 | + actions = ['info', 'list', 'remove', 'purge'] |
| 31 | + name = 'cache' |
| 32 | + usage = """ |
| 33 | + %prog <command>""" |
| 34 | + summary = "View and manage which packages are available in pip's caches." |
| 35 | + |
| 36 | + def __init__(self, *args, **kw): |
| 37 | + super(CacheCommand, self).__init__(*args, **kw) |
| 38 | + |
| 39 | + def run(self, options, args): |
| 40 | + if not args: |
| 41 | + raise CommandError('Please provide a subcommand.') |
| 42 | + |
| 43 | + if args[0] not in self.actions: |
| 44 | + raise CommandError('Invalid subcommand: %s' % args[0]) |
| 45 | + |
| 46 | + self.wheel_dir = os.path.join(options.cache_dir, 'wheels') |
| 47 | + |
| 48 | + method = getattr(self, 'action_%s' % args[0]) |
| 49 | + return method(options, args[1:]) |
| 50 | + |
| 51 | + def action_info(self, options, args): |
| 52 | + format_args = (options.cache_dir, len(self.find_wheels('*.whl'))) |
| 53 | + result = textwrap.dedent( |
| 54 | + """\ |
| 55 | + Cache info: |
| 56 | + Location: %s |
| 57 | + Packages: %s""" % format_args |
| 58 | + ) |
| 59 | + logger.info(result) |
| 60 | + |
| 61 | + def action_list(self, options, args): |
| 62 | + if args and args[0]: |
| 63 | + pattern = args[0] |
| 64 | + else: |
| 65 | + pattern = '*' |
| 66 | + |
| 67 | + files = self.find_wheels(pattern) |
| 68 | + wheels = map(self._wheel_info, files) |
| 69 | + wheels = sorted(set(wheels)) |
| 70 | + |
| 71 | + if not wheels: |
| 72 | + logger.info('Nothing is currently cached.') |
| 73 | + return |
| 74 | + |
| 75 | + result = 'Current cache contents:\n' |
| 76 | + for wheel in wheels: |
| 77 | + result += ' - %s\n' % wheel |
| 78 | + logger.info(result.strip()) |
| 79 | + |
| 80 | + def action_remove(self, options, args): |
| 81 | + if not args: |
| 82 | + raise CommandError('Please provide a pattern') |
| 83 | + |
| 84 | + files = self.find_wheels(args[0]) |
| 85 | + if not files: |
| 86 | + raise CommandError('No matching packages') |
| 87 | + |
| 88 | + wheels = map(self._wheel_info, files) |
| 89 | + result = 'Removing cached wheels for:\n' |
| 90 | + for wheel in wheels: |
| 91 | + result += '- %s\n' % wheel |
| 92 | + |
| 93 | + for filename in files: |
| 94 | + os.unlink(filename) |
| 95 | + logger.info(result.strip()) |
| 96 | + |
| 97 | + def action_purge(self, options, args): |
| 98 | + return self.action_remove(options, '*') |
| 99 | + |
| 100 | + def _wheel_info(self, path): |
| 101 | + filename = os.path.splitext(os.path.basename(path))[0] |
| 102 | + name, version = filename.split('-')[0:2] |
| 103 | + return '%s-%s' % (name, version) |
| 104 | + |
| 105 | + def find_wheels(self, pattern): |
| 106 | + return find_files(self.wheel_dir, pattern + '-*.whl') |
0 commit comments