hash.py 1.7 KB
Newer Older
Sartika Aritonang committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
# The following comment should be removed at some point in the future.
# mypy: disallow-untyped-defs=False

from __future__ import absolute_import

import hashlib
import logging
import sys

from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR
from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES
from pip._internal.utils.misc import read_chunks, write_output

logger = logging.getLogger(__name__)


class HashCommand(Command):
    """
    Compute a hash of a local package archive.

    These can be used with --hash in a requirements file to do repeatable
    installs.
    """

    usage = '%prog [options] <file> ...'
    ignore_require_venv = True

    def __init__(self, *args, **kw):
        super(HashCommand, self).__init__(*args, **kw)
        self.cmd_opts.add_option(
            '-a', '--algorithm',
            dest='algorithm',
            choices=STRONG_HASHES,
            action='store',
            default=FAVORITE_HASH,
            help='The hash algorithm to use: one of {}'.format(
                 ', '.join(STRONG_HASHES)))
        self.parser.insert_option_group(0, self.cmd_opts)

    def run(self, options, args):
        if not args:
            self.parser.print_usage(sys.stderr)
            return ERROR

        algorithm = options.algorithm
        for path in args:
            write_output('%s:\n--hash=%s:%s',
                         path, algorithm, _hash_of_file(path, algorithm))


def _hash_of_file(path, algorithm):
    """Return the hash digest of a file."""
    with open(path, 'rb') as archive:
        hash = hashlib.new(algorithm)
        for chunk in read_chunks(archive):
            hash.update(chunk)
    return hash.hexdigest()