|
|
|
#! /usr/bin/python2.7
|
|
|
|
|
|
|
|
# Copyright (C) 2012 Canonical Ltd.
|
|
|
|
# Author: Colin Watson <cjwatson@ubuntu.com>
|
|
|
|
|
|
|
|
# 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; version 3 of the License.
|
|
|
|
#
|
|
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
"""Promote packages to release pocket based on britney output."""
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
from optparse import OptionParser
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from launchpadlib.errors import HTTPError
|
|
|
|
from launchpadlib.launchpad import Launchpad
|
|
|
|
|
|
|
|
import lputils
|
|
|
|
|
|
|
|
|
|
|
|
def promote(options, name, version, architecture):
|
|
|
|
if architecture is None:
|
|
|
|
display = "%s/%s" % (name, version)
|
|
|
|
else:
|
|
|
|
display = "%s/%s/%s" % (name, version, architecture)
|
|
|
|
|
|
|
|
# check to see if the package and version has already been published or is
|
|
|
|
# pending publication
|
|
|
|
if architecture is None:
|
|
|
|
try:
|
|
|
|
release_sources = options.archive.getPublishedSources(
|
|
|
|
source_name=name, version=version,
|
|
|
|
distro_series=options.series, pocket=options.pocket.title(),
|
|
|
|
exact_match=True, status="Published")
|
|
|
|
except IndexError:
|
|
|
|
release_sources = options.archive.getPublishedSources(
|
|
|
|
source_name=name, version=version,
|
|
|
|
distro_series=options.series, pocket=options.pocket.title(),
|
|
|
|
exact_match=True, status="Pending")
|
|
|
|
except HTTPError as e:
|
|
|
|
print("getPublishedSources %s: %s" % (display, e.content),
|
|
|
|
file=sys.stderr)
|
|
|
|
return True
|
|
|
|
if len(release_sources) > 0:
|
|
|
|
return True
|
|
|
|
|
|
|
|
if options.dry_run:
|
|
|
|
print("Would copy: %s" % display)
|
|
|
|
return
|
|
|
|
elif options.verbose:
|
|
|
|
print("Copying: %s" % display)
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
|
|
|
try:
|
|
|
|
percentage = None
|
|
|
|
if options.pocket == 'updates':
|
|
|
|
percentage = 10
|
|
|
|
options.archive.copyPackage(
|
|
|
|
source_name=name, version=version,
|
|
|
|
from_archive=options.archive,
|
|
|
|
from_series=options.series.name, from_pocket="Proposed",
|
|
|
|
to_series=options.series.name, to_pocket=options.pocket.title(),
|
|
|
|
include_binaries=True, sponsored=options.requestor,
|
|
|
|
phased_update_percentage=percentage,
|
|
|
|
auto_approve=True)
|
|
|
|
except HTTPError as e:
|
|
|
|
print("copyPackage %s: %s" % (display, e.content), file=sys.stderr)
|
|
|
|
return False
|
|
|
|
|
|
|
|
try:
|
|
|
|
proposed_source = options.archive.getPublishedSources(
|
|
|
|
source_name=name, version=version,
|
|
|
|
distro_series=options.series, pocket="Proposed",
|
|
|
|
exact_match=True)[0]
|
|
|
|
except HTTPError as e:
|
|
|
|
print("getPublishedSources %s: %s" % (display, e.content),
|
|
|
|
file=sys.stderr)
|
|
|
|
return True
|
|
|
|
except IndexError:
|
|
|
|
print("getPublishedSources %s found no publication" % display,
|
|
|
|
file=sys.stderr)
|
|
|
|
return True
|
|
|
|
|
|
|
|
if architecture is None:
|
|
|
|
try:
|
|
|
|
proposed_source.requestDeletion(removal_comment="moved to %s" %
|
|
|
|
options.pocket)
|
|
|
|
except HTTPError as e:
|
|
|
|
print("requestDeletion %s: %s" % (display, e.content),
|
|
|
|
file=sys.stderr)
|
|
|
|
else:
|
|
|
|
for bpph in proposed_source.getPublishedBinaries():
|
|
|
|
if bpph.is_debug:
|
|
|
|
continue
|
|
|
|
elif bpph.architecture_specific:
|
|
|
|
if architecture != bpph.distro_arch_series.architecture_tag:
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
if architecture != "i386":
|
|
|
|
continue
|
|
|
|
try:
|
|
|
|
bpph.requestDeletion(removal_comment="moved to %s" %
|
|
|
|
options.pocket)
|
|
|
|
except HTTPError as e:
|
|
|
|
print("requestDeletion %s/%s/%s: %s" %
|
|
|
|
(bpph.binary_package_name, bpph.binary_package_version,
|
|
|
|
bpph.distro_arch_series.architecture_tag, e.content),
|
|
|
|
file=sys.stderr)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def promote_all(options, delta):
|
|
|
|
with open(delta) as delta_file:
|
|
|
|
for line in delta_file:
|
|
|
|
if line.startswith("#"):
|
|
|
|
continue
|
|
|
|
words = line.rstrip("\n").split(" ")
|
|
|
|
if len(words) == 1:
|
|
|
|
name = words[0]
|
|
|
|
print("Cannot handle removal: %s" % name, file=sys.stderr)
|
|
|
|
continue
|
|
|
|
elif len(words) == 2:
|
|
|
|
name = words[0]
|
|
|
|
if name.startswith("-"):
|
|
|
|
print("Cannot handle removal: %s" % name[1:],
|
|
|
|
file=sys.stderr)
|
|
|
|
continue
|
|
|
|
elif "/" in name:
|
|
|
|
name, architecture = name.split("/", 1)
|
|
|
|
else:
|
|
|
|
architecture = None
|
|
|
|
version = words[1]
|
|
|
|
if not promote(options, name, version, architecture):
|
|
|
|
# Stop on any single failure. Britney's output delta
|
|
|
|
# should be ordered such that the optimal order of
|
|
|
|
# copying is from start to finish, and skipping one is
|
|
|
|
# more likely to cause problems than aborting.
|
|
|
|
return False
|
|
|
|
elif len(words) == 3:
|
|
|
|
name = words[0]
|
|
|
|
if name.startswith("-"):
|
|
|
|
print("Cannot handle removal: %s" % name[1:],
|
|
|
|
file=sys.stderr)
|
|
|
|
continue
|
|
|
|
version = words[1]
|
|
|
|
architecture = words[2]
|
|
|
|
if not promote(options, name, version, architecture):
|
|
|
|
# Stop on any single failure. Britney's output delta
|
|
|
|
# should be ordered such that the optimal order of
|
|
|
|
# copying is from start to finish, and skipping one is
|
|
|
|
# more likely to cause problems than aborting.
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = OptionParser(usage="usage: %prog [options] BRITNEY-OUTPUT-DELTA")
|
|
|
|
parser.add_option(
|
|
|
|
"-l", "--launchpad", dest="launchpad_instance", default="production")
|
|
|
|
parser.add_option(
|
|
|
|
"-n", "--dry-run", default=False, action="store_true",
|
|
|
|
help="only show copies that would be performed")
|
|
|
|
parser.add_option(
|
|
|
|
"-v", "--verbose", default=False, action="store_true",
|
|
|
|
help="be more verbose (redundant in --dry-run mode)")
|
|
|
|
parser.add_option(
|
|
|
|
"-d", "--distribution", default="ubuntu",
|
|
|
|
metavar="DISTRIBUTION", help="promote within DISTRIBUTION")
|
|
|
|
# dest="suite" to make lputils.setup_location's job easier.
|
|
|
|
parser.add_option(
|
|
|
|
"-s", "--series", dest="suite",
|
|
|
|
metavar="SERIES", help="promote from SERIES-proposed to SERIES")
|
|
|
|
parser.add_option(
|
|
|
|
"-p", "--pocket", default="release",
|
|
|
|
help="the pocket to which the package should be copied")
|
|
|
|
options, args = parser.parse_args()
|
|
|
|
if len(args) != 1:
|
|
|
|
parser.error("need britney output delta file")
|
|
|
|
if options.pocket not in ('updates', 'release'):
|
|
|
|
parser.error("pocket must be updates or release not %s" %
|
|
|
|
options.pocket)
|
|
|
|
|
|
|
|
options.launchpad = Launchpad.login_with(
|
|
|
|
"promote-to-release", options.launchpad_instance, version="devel")
|
|
|
|
lputils.setup_location(options)
|
|
|
|
options.dases = {}
|
|
|
|
for das in options.series.architectures:
|
|
|
|
options.dases[das.architecture_tag] = das
|
|
|
|
|
|
|
|
options.requestor = options.launchpad.people["katie"]
|
|
|
|
|
|
|
|
if promote_all(options, args[0]):
|
|
|
|
return 0
|
|
|
|
else:
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main())
|