#! /usr/bin/python # Copyright 2012 Canonical Ltd. # # This script will write update metrics for a given Ubuntu release in CSV # format. It will output a file with updates (broken in Security vs Updates) # by month, as well as the number per package. from collections import defaultdict import csv import logging from optparse import OptionParser import sys from launchpadlib.launchpad import Launchpad API_NAME = 'ubuntu-update-metrics' def write_metrics_csv(filename, key_name, metrics): """Write the metrics to a CSV file. :param filename: The CSV filename. :param key_name: The name of the metrics key. :param metrics: This should be a sequence of [key, {'Updates': X, 'Security': X, 'Total': X}] record. """ logging.info('Writing metrics by %s to %s', key_name.lower(), filename) writer = csv.writer(open(filename, 'wb')) writer.writerow([key_name, 'Updates', 'Security', 'Total']) for key, metrics in metrics: writer.writerow( [key, metrics['Updates'], metrics['Security'], metrics['Total']]) def main(argv): parser = OptionParser( usage="%prog [options] ubuntu-release-name") parser.add_option( '-l', '--launchpad', default='production', dest='lp_instance', help="Select the Launchpad instance to run against. Defaults to " "'production'") parser.add_option( '-v', '--verbose', default=0, action='count', dest='verbose', help="Increase verbosity of the script. -v prints info messages, " "-vv will print debug messages.") parser.add_option( '-c', '--credentials', default=None, action='store', dest='credentials', help="Use the OAuth credentials in FILE instead of the desktop " "one.", metavar='FILE') parser.add_option( '-d', '--distribution', default='ubuntu', action='store', dest='distribution', help="The distribution to compute metrics for. Defaults to 'ubuntu'.") options, args = parser.parse_args(argv[1:]) if len(args) != 1: parser.error('Missing archive name.') if options.verbose >= 2: log_level = logging.DEBUG elif options.verbose == 1: log_level = logging.INFO else: log_level = logging.WARNING logging.basicConfig(level=log_level) lp = Launchpad.login_with( API_NAME, options.lp_instance, credentials_file=options.credentials, version='devel') try: distribution = lp.distributions[options.distribution] except KeyError: parser.error('unknown distribution: %s' % options.distribution) series = distribution.getSeries(name_or_version=args[0]) if series is None: parser.error('unknown series: %s' % args[0]) archive = series.main_archive updates_by_package = defaultdict(lambda: defaultdict(int)) updates_by_month = defaultdict(lambda: defaultdict(int)) for pocket in ['Updates', 'Security']: logging.info( 'Retrieving published %s sources for %s...', pocket, args[0]) published_history = archive.getPublishedSources( component_name='main', created_since_date=series.datereleased, distro_series=series, pocket=pocket) for source in published_history: package_metrics = updates_by_package[source.source_package_name] package_metrics[source.pocket] += 1 package_metrics['Total'] += 1 month = source.date_published.strftime('%Y-%m') month_metrics = updates_by_month[month] month_metrics[source.pocket] += 1 month_metrics['Total'] += 1 by_month_filename = '%s-%s-updates-by-month.csv' % ( options.distribution, args[0]) write_metrics_csv( by_month_filename, 'Month', sorted(updates_by_month.items())) by_package_filename = '%s-%s-updates-by-package.csv' % ( options.distribution, args[0]) write_metrics_csv( by_package_filename, 'Package', sorted( updates_by_package.items(), key=lambda m: m[1]['Total'], reverse=True)) if __name__ == '__main__': main(sys.argv)