diff options
Diffstat (limited to 'build/checksums.py')
-rwxr-xr-x | build/checksums.py | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/build/checksums.py b/build/checksums.py new file mode 100755 index 000000000..9b13b50cb --- /dev/null +++ b/build/checksums.py @@ -0,0 +1,158 @@ +#!/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 logging +import os +try: + import hashlib +except: + hashlib = None + +def digest_file(filename, digest, chunk_size=1024): + '''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 = logging.getLogger('checksums.py') + if hashlib is not None: + 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 + else: + # In this case we could subprocess.Popen and .communicate with + # sha1sum or md5sum + logger.warn('The python module for hashlib is missing!') + return None + + +def process_files(files, output_filename, digests, strip): + '''This function takes a list of file names, 'files'. It will then + compute the checksum for each of the files 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 + ''' + + logger = logging.getLogger('checksums.py') + 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 file in files: + if os.path.isdir(file): + logger.warn('%s is a directory, skipping' % file) + else: + for digest in digests: + hash = digest_file(file, digest) + if hash is None: + logger.warn('Unable to generate a hash for %s. ' + + 'Skipping.' % file) + continue + if file.startswith(strip): + short_file = file[len(strip):] + short_file = short_file.lstrip('/') + else: + short_file = file + print >>output, '%s %s %s %s' % (hash, digest, + os.path.getsize(file), + short_file) + +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) + parser.add_option('-s', '--strip', + help='strip this path from the filenames', + dest='strip', default=os.getcwd()) + 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) + logger = logging.getLogger('checksums.py') + + # Validate the digest type to use + if not options.digests: + options.digests = ['sha1'] + try: + for digest in options.digests: + hashlib.new(digest) + except ValueError, ve: + logger.error('Could not create a "%s" hash object (%s)' % + (digest, ve.args[0])) + exit(1) + + # Validate the files to checksum + files = [] + for i in args: + if os.path.exists(i): + files.append(i) + else: + logger.info('File "%s" was not found on the filesystem' % i) + process_files(files, options.outfile, options.digests, options.strip) + +if __name__ == '__main__': + main() |