summaryrefslogtreecommitdiffstats
path: root/build/checksums.py
diff options
context:
space:
mode:
Diffstat (limited to 'build/checksums.py')
-rwxr-xr-xbuild/checksums.py158
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()