view shasum.py @ 4:67d10529ce88

FIX: "-" filename handling now consistent with Perl shasum
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 04 Dec 2020 12:37:29 +0100
parents 5a6ed622846c
children bbcb225640de
line wrap: on
line source

r"""
:Author:    Franz Glasner
:Copyright: (c) 2020 Franz Glasner.
            All rights reserved.
:License:   BSD 3-Clause "New" or "Revised" License.
            See :ref:`LICENSE <license>` for details.
            If you cannot find LICENSE see
            <https://opensource.org/licenses/BSD-3-Clause>
:ID:        @(#) HGid$

"""

from __future__ import print_function

import argparse
import hashlib
import sys


PY2 = sys.version_info[0] < 3

CHUNK_SIZE = 1024 * 1024 * 1024


def main(argv=None):
    aparser = argparse.ArgumentParser(
        description="Python implementation of shasum",
        fromfile_prefix_chars='@')
    aparser.add_argument(
        "--binary", "-b", action="store_false", dest="text_mode", default=False,
        help="read in binary mode (default)")
    aparser.add_argument(
        "--text", "-t", action="store_true", dest="text_mode", default=False,
        help="read in text mode (not yet supported)")
    aparser.add_argument(
        "files", nargs="*", metavar="FILE")

    opts = aparser.parse_args(args=argv)

    if opts.text_mode:
        print("ERROR: text mode not supported", file=sys.stderr)
        sys.exit(78)   # :manpage:`sysexits(3)` EX_CONFIG
    if not opts.files:
        opts.files.append("-")
    if len(opts.files) == 1 and opts.files[0] == "-":
        if PY2:
            if sys.platform == "win32":
                import os. msvcrt
                msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
            source = sys.stdin
        else:
            source = sys.stdin.buffer
        print(compute_digest(hashlib.sha256, source))
    else:
        for fn in opts.files:
            with open(fn, "rb") as source:
                print(compute_digest(hashlib.sha256, source))


def compute_digest(hashobj, instream):
    """

    :param hashobj: a :mod:`hashlib` compatible hash algorithm type or factory
    :param instream: a bytes input stream to read the data to be hashed from
    :return: the digest in hex form
    :rtype: str

    """
    h = hashobj()
    while True:
        buf = instream.read(CHUNK_SIZE)
        if buf is not None:
            if len(buf) == 0:
                break
            h.update(buf)
    return h.hexdigest()


if __name__ == "__main__":
    sys.exit(main())