diff options
Diffstat (limited to 'build/checksums.py')
-rwxr-xr-x | build/checksums.py | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/build/checksums.py b/build/checksums.py new file mode 100755 index 0000000000..d82c721117 --- /dev/null +++ b/build/checksums.py @@ -0,0 +1,156 @@ +#!/usr/bin/python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from __future__ import with_statement + +from optparse import OptionParser +import hashlib +import logging +import os + +logger = logging.getLogger("checksums.py") + + +def digest_file(filename, digest, chunk_size=131072): + """Produce a checksum for the file specified by 'filename'. 'filename' + is a string path to a file that is opened and read in this function. The + checksum algorithm is specified by 'digest' and is a valid OpenSSL + algorithm. If the digest used is not valid or Python's hashlib doesn't + work, the None object will be returned instead. The size of blocks + that this function will read from the file object it opens based on + 'filename' can be specified by 'chunk_size', which defaults to 1K""" + assert not os.path.isdir(filename), "this function only works with files" + + logger.debug("Creating new %s object" % digest) + h = hashlib.new(digest) + with open(filename, "rb") as f: + while True: + data = f.read(chunk_size) + if not data: + logger.debug("Finished reading in file") + break + h.update(data) + hash = h.hexdigest() + logger.debug("Hash for %s is %s" % (filename, hash)) + return hash + + +def process_files(dirs, output_filename, digests): + """This function takes a list of directory names, 'drs'. It will then + compute the checksum for each of the files in these by by opening the files. + Once each file is read and its checksum is computed, this function + will write the information to the file specified by 'output_filename'. + The path written in the output file will have anything specified by 'strip' + removed from the path. The output file is closed before returning nothing + The algorithm to compute checksums with can be specified by 'digests' + and needs to be a list of valid OpenSSL algorithms. + + The output file is written in the format: + <hash> <algorithm> <filesize> <filepath> + Example: + d1fa09a<snip>e4220 sha1 14250744 firefox-4.0b6pre.en-US.mac64.dmg + """ + + if os.path.exists(output_filename): + logger.debug('Overwriting existing checksums file "%s"' % output_filename) + else: + logger.debug('Creating a new checksums file "%s"' % output_filename) + with open(output_filename, "w+") as output: + for d in dirs: + for root, dirs, files in os.walk(d): + for f in files: + full = os.path.join(root, f) + rel = os.path.relpath(full, d) + + for digest in digests: + hash = digest_file(full, digest) + + output.write( + "%s %s %s %s\n" % (hash, digest, os.path.getsize(full), rel) + ) + + +def setup_logging(level=logging.DEBUG): + """This function sets up the logging module using a speficiable logging + module logging level. The default log level is DEBUG. + + The output is in the format: + <level> - <message> + Example: + DEBUG - Finished reading in file""" + + logger = logging.getLogger("checksums.py") + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + handler.setLevel(level) + formatter = logging.Formatter("%(levelname)s - %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + + +def main(): + """This is a main function that parses arguments, sets up logging + and generates a checksum file""" + # Parse command line arguments + parser = OptionParser() + parser.add_option( + "-d", + "--digest", + help="checksum algorithm to use", + action="append", + dest="digests", + ) + parser.add_option( + "-o", + "--output", + help="output file to use", + action="store", + dest="outfile", + default="checksums", + ) + parser.add_option( + "-v", + "--verbose", + help="Be noisy (takes precedence over quiet)", + action="store_true", + dest="verbose", + default=False, + ) + parser.add_option( + "-q", + "--quiet", + help="Be quiet", + action="store_true", + dest="quiet", + default=False, + ) + + options, args = parser.parse_args() + + # Figure out which logging level to use + if options.verbose: + loglevel = logging.DEBUG + elif options.quiet: + loglevel = logging.ERROR + else: + loglevel = logging.INFO + + # Set up logging + setup_logging(loglevel) + + # Validate the digest type to use + if not options.digests: + options.digests = ["sha1"] + + for i in args: + if not os.path.isdir(i): + logger.error("%s is not a directory" % i) + exit(1) + + process_files(args, options.outfile, options.digests) + + +if __name__ == "__main__": + main() |