2019-04-08 19:00:09 +02:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import textwrap
|
|
|
|
|
|
|
|
from pip._internal.cli.base_command import Command
|
2019-10-08 05:03:03 +02:00
|
|
|
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
|
|
|
from pip._internal.exceptions import CommandError, PipError
|
2019-04-08 19:00:09 +02:00
|
|
|
from pip._internal.utils.filesystem import find_files
|
2019-10-08 05:03:03 +02:00
|
|
|
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
|
|
|
|
|
|
|
if MYPY_CHECK_RUNNING:
|
|
|
|
from optparse import Values
|
|
|
|
from typing import Any, List
|
|
|
|
|
2019-04-08 19:00:09 +02:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class CacheCommand(Command):
|
2019-10-08 05:59:30 +02:00
|
|
|
"""
|
|
|
|
Inspect and manage pip's caches.
|
2019-10-08 05:03:03 +02:00
|
|
|
|
|
|
|
Subcommands:
|
|
|
|
|
2019-10-08 05:59:30 +02:00
|
|
|
info:
|
|
|
|
Show information about the caches.
|
|
|
|
list:
|
|
|
|
List filenames of packages stored in the cache.
|
|
|
|
remove:
|
|
|
|
Remove one or more package from the cache.
|
|
|
|
purge:
|
|
|
|
Remove all items from the cache.
|
2019-10-08 05:03:03 +02:00
|
|
|
|
|
|
|
<pattern> can be a glob expression or a package name.
|
2019-04-08 19:00:09 +02:00
|
|
|
"""
|
2019-10-08 05:50:47 +02:00
|
|
|
|
2019-04-08 19:00:09 +02:00
|
|
|
usage = """
|
2019-10-08 05:03:03 +02:00
|
|
|
%prog info
|
|
|
|
%prog list [name]
|
|
|
|
%prog remove <pattern>
|
|
|
|
%prog purge
|
|
|
|
"""
|
2019-04-08 19:00:09 +02:00
|
|
|
|
|
|
|
def __init__(self, *args, **kw):
|
2019-10-08 05:03:03 +02:00
|
|
|
# type: (*Any, **Any) -> None
|
2019-04-08 19:00:09 +02:00
|
|
|
super(CacheCommand, self).__init__(*args, **kw)
|
|
|
|
|
|
|
|
def run(self, options, args):
|
2019-10-08 05:03:03 +02:00
|
|
|
# type: (Values, List[Any]) -> int
|
|
|
|
handlers = {
|
|
|
|
"info": self.get_cache_info,
|
|
|
|
"list": self.list_cache_items,
|
|
|
|
"remove": self.remove_cache_items,
|
|
|
|
"purge": self.purge_cache,
|
|
|
|
}
|
|
|
|
|
|
|
|
# Determine action
|
|
|
|
if not args or args[0] not in handlers:
|
|
|
|
logger.error("Need an action ({}) to perform.".format(
|
|
|
|
", ".join(sorted(handlers)))
|
|
|
|
)
|
|
|
|
return ERROR
|
|
|
|
|
|
|
|
action = args[0]
|
|
|
|
|
|
|
|
# Error handling happens here, not in the action-handlers.
|
|
|
|
try:
|
|
|
|
handlers[action](options, args[1:])
|
|
|
|
except PipError as e:
|
|
|
|
logger.error(e.args[0])
|
|
|
|
return ERROR
|
|
|
|
|
|
|
|
return SUCCESS
|
|
|
|
|
|
|
|
def get_cache_info(self, options, args):
|
|
|
|
# type: (Values, List[Any]) -> None
|
2019-10-08 05:50:47 +02:00
|
|
|
num_packages = len(self._find_wheels(options, '*'))
|
|
|
|
|
2019-10-10 02:00:34 +02:00
|
|
|
message = textwrap.dedent("""
|
2019-04-08 19:00:09 +02:00
|
|
|
Cache info:
|
2019-10-10 02:00:34 +02:00
|
|
|
Location: {location}
|
|
|
|
Packages: {package_count}
|
|
|
|
""").format(
|
2019-10-10 11:42:28 +02:00
|
|
|
location=self._wheels_cache_dir(options),
|
2019-10-10 02:00:34 +02:00
|
|
|
package_count=num_packages,
|
|
|
|
).strip()
|
|
|
|
|
|
|
|
logger.info(message)
|
2019-04-08 19:00:09 +02:00
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
def list_cache_items(self, options, args):
|
|
|
|
# type: (Values, List[Any]) -> None
|
2019-10-10 01:58:23 +02:00
|
|
|
if len(args) > 1:
|
|
|
|
raise CommandError('Too many arguments')
|
|
|
|
|
|
|
|
if args:
|
2019-04-08 19:00:09 +02:00
|
|
|
pattern = args[0]
|
|
|
|
else:
|
|
|
|
pattern = '*'
|
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
files = self._find_wheels(options, pattern)
|
2019-10-08 05:50:47 +02:00
|
|
|
wheels = sorted(set(map(lambda f: os.path.basename(f), files)))
|
2019-04-08 19:00:09 +02:00
|
|
|
|
|
|
|
if not wheels:
|
|
|
|
logger.info('Nothing is currently cached.')
|
|
|
|
return
|
|
|
|
|
|
|
|
result = 'Current cache contents:\n'
|
|
|
|
for wheel in wheels:
|
|
|
|
result += ' - %s\n' % wheel
|
|
|
|
logger.info(result.strip())
|
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
def remove_cache_items(self, options, args):
|
|
|
|
# type: (Values, List[Any]) -> None
|
2019-10-10 01:58:23 +02:00
|
|
|
if len(args) > 1:
|
|
|
|
raise CommandError('Too many arguments')
|
|
|
|
|
2019-04-08 19:00:09 +02:00
|
|
|
if not args:
|
|
|
|
raise CommandError('Please provide a pattern')
|
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
files = self._find_wheels(options, args[0])
|
2019-04-08 19:00:09 +02:00
|
|
|
if not files:
|
|
|
|
raise CommandError('No matching packages')
|
|
|
|
|
|
|
|
for filename in files:
|
|
|
|
os.unlink(filename)
|
|
|
|
logger.debug('Removed %s', filename)
|
|
|
|
logger.info('Removed %s files', len(files))
|
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
def purge_cache(self, options, args):
|
|
|
|
# type: (Values, List[Any]) -> None
|
2019-10-10 01:58:23 +02:00
|
|
|
if args:
|
|
|
|
raise CommandError('Too many arguments')
|
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
return self.remove_cache_items(options, ['*'])
|
2019-04-08 19:00:09 +02:00
|
|
|
|
2019-10-10 11:42:28 +02:00
|
|
|
def _wheels_cache_dir(self, options):
|
2019-10-10 11:51:06 +02:00
|
|
|
# type: (Values) -> str
|
2019-10-10 11:42:28 +02:00
|
|
|
return os.path.join(options.cache_dir, 'wheels')
|
|
|
|
|
2019-10-08 05:03:03 +02:00
|
|
|
def _find_wheels(self, options, pattern):
|
|
|
|
# type: (Values, str) -> List[str]
|
2019-10-10 11:42:28 +02:00
|
|
|
wheel_dir = self._wheels_cache_dir(options)
|
2019-10-10 11:27:51 +02:00
|
|
|
return find_files(wheel_dir, pattern + '*.whl')
|