#!/usr/bin/python # # buildd - command line interface for Launchpad buildd operations. # # Copyright (C) 2007 Canonical Ltd. # Authors: # - Martin Pitt # - Jonathan Davies # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Our modules to import. import os import re import sys import urllib2 from optparse import OptionGroup from optparse import OptionParser from urllib import urlencode # ubuntu-dev-tools modules. import ubuntutools.lp.cookie as lp_cookie import ubuntutools.lp.functions as lp_functions import ubuntutools.lp.urlopener as lp_urlopener from ubuntutools import packages # https_proxy fix import ubuntutools.common # Usage. usage = "%prog \n\n" usage += "Where operation may be one of: rescore, retry, or status.\n" usage += "Only Launchpad Buildd Admins may rescore package builds." # Valid architectures. validArchs = ["armel", "amd64", "hppa", "i386", "ia64", "lpia", "powerpc", "sparc"] # Prepare our option parser. optParser = OptionParser(usage) # Retry options retryRescoreOptions = OptionGroup(optParser, "Retry and rescore options", "These options may only be used with the 'retry' and 'rescore' operations.") retryRescoreOptions.add_option("-a", "--arch", type = "string", action = "store", dest = "architecture", help = "Rebuild or rescore a specific architecture. " \ "Valid architectures include: " \ "%s." % ", ".join(validArchs)) # Add the retry options to the main group. optParser.add_option_group(retryRescoreOptions) # Parse our options. (options, args) = optParser.parse_args() # 'help' called by itself - show our help. try: if args[0].lower() in ("help") and len(args) == 1: optParser.print_help() sys.exit(0) except IndexError: optParser.print_help() sys.exit(0) # Check we have the correct number of arguments. if len(args) < 3: optParser.error("Incorrect number of arguments.") try: package = str(args[0]).lower() release = str(args[1]).lower() op = str(args[2]).lower() except IndexError: optParser.print_help() sys.exit(0) # Check our operation. if op not in ("rescore", "retry", "status"): print >> sys.stderr, "Invalid operation: %s." % op sys.exit(1) # If the user has specified an architecture to build, we only wish to rebuild it # and nothing else. if op not in ("retry", 'rescore') and options.architecture: print >> sys.stderr, "Operation %s does not use the --arch option." % op sys.exit(1) elif op in ("retry", "rescore") and options.architecture: if options.architecture not in validArchs: print >> sys.stderr, "Invalid architecture specified: %s." % options.architecture sys.exit(1) else: oneArch = True else: oneArch = False # Prepare Launchpad cookie. launchpadCookie = lp_cookie.prepareLaunchpadCookie() urlopener = lp_urlopener.setupLaunchpadUrlOpener(launchpadCookie) # Check the release exists. packages.checkReleaseExists(release) # Find out the version in given release. (page, version) = packages.checkSourceExists(package, release) # Get the component the package is in. component = lp_functions.packageComponent(package, release) # Output details. print "The source version for '%s' in %s (%s) is at %s." % (package, release.capitalize(), component, version) # Parse out build URLs, states, and arches. buildstats = {} page = urlopener.open('https://launchpad.net/ubuntu/+source/%s/%s' % (package, version)) url = page.geturl() page = page.read() release = release.split('-')[0] # strip off pocket print "Current build status for this package:" for m in re.finditer('"/ubuntu/\+source/%s/%s(/\+build/\d+)"[^\n]+\n\s*(\w+).*?(\w+).*?\s*([^\n]+)\n' % (package.replace('+', '\+'), version.replace('+', '\+')), page, re.S): if m.group(2) == release: print '%s: %s.' % (m.group(3), m.group(4)) buildstats[url + m.group(1)] = [m.group(3).strip(), m.group(4).strip()] # Check that there actually are builds for that release. if len(buildstats) == 0: print "No builds for '%s' found in the %s release - it may have been " \ "built in a former release." % (package, release.capitalize()) sys.exit(0) # Operations. if op == 'status': sys.exit(0) # Check if the package in question is architecture independent, and if so; that # i386 has been set as the architecture. if len(buildstats) == 1 and options.architecture != "i386": print "Overriding architecture setting to i386 for architecture " \ "independent package..." options.architecture = "i386" # Operations that are remaining may only be done by Ubuntu developers (retry) # or buildd admins (rescore). Check if the proper permissions are in place. if op == "rescore": necessaryPrivs = lp_functions.isLPTeamMember('launchpad-buildd-admins') if op == "retry": necessaryPrivs = lp_functions.canUploadPackage(package, release) if not necessaryPrivs: print >> sys.stderr, "You cannot perform the %s operation on a %s package " \ "as you are not member of the '%s' team on Launchpad." % (op, component, teamNeeded) print "Should this be incorrect, please log in to Launchpad using Firefox, " \ "delete the ~/.lpcookie.txt file and rerun this script." sys.exit(1) for build, (arch, status) in buildstats.iteritems(): if oneArch and not options.architecture == arch: # Skip this architecture. continue if op in ('rescore'): if status in ('Needs building'): print 'Rescoring', build, '(%s).' % arch try: urlopener.open(build + '/+rescore', urlencode( {'field.priority': '5000', 'field.actions.rescore': '1'})) except: print >> sys.stderr, "Unable to request rescore on %s." % arch else: print "Not rescoring on %s; status is: %s." % (arch, status.lower()) if op in ('retry'): # Retry requested. if status in ('Failed to build', 'Chroot problem', 'Failed to upload'): print 'Retrying:', build, '(%s).' % arch try: urlopener.open(build + '/+retry', urlencode( {'RETRY': '1'})) except: # Error encountered while submitting request. print >> sys.stderr, "Unable to request retry on %s." % arch else: # The package does not require rebuilding. print "Not retrying on %s; status is %s." % (arch, status.lower())