ubuntu-dev-tools/ubuntu-build
Gianfranco Costamagna 6f0caf1fc0 ubuntu-build: For some reasons, now you need to be authenticated before trying to use the "PersonTeam" class features.
Do it at the begin instead of replicating the same code inside the tool itself.

This fixes e.g. this failure:

./ubuntu-build --batch --retry morsmall
Traceback (most recent call last):
  File "/tmp/ubuntu-dev-tools/ubuntu-build", line 317, in <module>
    main()
  File "/tmp/ubuntu-dev-tools/ubuntu-build", line 289, in main
    can_retry = args.retry and me.canUploadPackage(
AttributeError: 'NoneType' object has no attribute 'canUploadPackage'
2023-07-07 19:23:41 +02:00

316 lines
10 KiB
Python
Executable File

#!/usr/bin/python3
#
# ubuntu-build - command line interface for Launchpad buildd operations.
#
# Copyright (C) 2007 Canonical Ltd.
# Authors:
# - Martin Pitt <martin.pitt@canonical.com>
# - Jonathan Davies <jpds@ubuntu.com>
# - Michael Bienia <geser@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, 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 <http://www.gnu.org/licenses/>.
#
# pylint: disable=invalid-name
# pylint: enable=invalid-name
import argparse
import sys
from launchpadlib.credentials import TokenAuthorizationException
from ubuntutools import getLogger
from ubuntutools.lp.lpapicache import Distribution, Launchpad, PersonTeam
from ubuntutools.lp.udtexceptions import (
PackageNotFoundException,
PocketDoesNotExistError,
SeriesNotFoundException,
)
from ubuntutools.misc import split_release_pocket
Logger = getLogger()
def main():
# Usage.
usage = "%(prog)s <srcpackage> <release> <operation>\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.
valid_archs = set(
[
"armhf",
"arm64",
"amd64",
"i386",
"powerpc",
"ppc64el",
"riscv64",
"s390x",
]
)
# Prepare our option parser.
parser = argparse.ArgumentParser(usage=usage)
# Retry options
retry_rescore_options = parser.add_argument_group(
"Retry and rescore options",
"These options may only be used with the 'retry' and 'rescore' operations.",
)
retry_rescore_options.add_argument(
"-a",
"--arch",
action="append",
dest="architecture",
help=f"Rebuild or rescore a specific architecture. Valid architectures "
f"include: {', '.join(valid_archs)}.",
)
# Batch processing options
batch_options = parser.add_argument_group(
"Batch processing",
"These options and parameter ordering is only "
"available in --batch mode.\nUsage: "
"ubuntu-build --batch [options] <package>...",
)
batch_options.add_argument(
"--batch", action="store_true", dest="batch", help="Enable batch mode"
)
batch_options.add_argument(
"--series",
action="store",
dest="series",
help="Selects the Ubuntu series to operate on (default: current development series)",
)
batch_options.add_argument(
"--retry", action="store_true", dest="retry", help="Retry builds (give-back)."
)
batch_options.add_argument(
"--rescore",
action="store",
dest="priority",
type=int,
help="Rescore builds to <priority>.",
)
batch_options.add_argument(
"--arch2",
action="append",
dest="architecture",
help=f"Affect only 'architecture' (can be used several times)."
f" Valid architectures are: {', '.join(valid_archs)}.",
)
parser.add_argument("packages", metavar="package", nargs="+", help=argparse.SUPPRESS)
# Parse our options.
args = parser.parse_args()
try:
# Will fail here if we have no credentials, bail out
Launchpad.login()
except TokenAuthorizationException:
sys.exit(1)
me = PersonTeam.me
if not args.batch:
# Check we have the correct number of arguments.
if len(args.packages) < 3:
parser.error("Incorrect number of arguments.")
try:
package = str(args.packages[0]).lower()
release = str(args.packages[1]).lower()
operation = str(args.packages[2]).lower()
except IndexError:
parser.print_help()
sys.exit(1)
# Check our operation.
if operation not in ("rescore", "retry", "status"):
Logger.error("Invalid operation: %s.", operation)
sys.exit(1)
# If the user has specified an architecture to build, we only wish to
# rebuild it and nothing else.
if args.architecture:
if args.architecture[0] not in valid_archs:
Logger.error("Invalid architecture specified: %s.", args.architecture[0])
sys.exit(1)
else:
one_arch = True
else:
one_arch = False
# split release and pocket
try:
(release, pocket) = split_release_pocket(release)
except PocketDoesNotExistError as error:
Logger.error(error)
sys.exit(1)
ubuntu_archive = Distribution("ubuntu").getArchive()
# Get list of published sources for package in question.
try:
sources = ubuntu_archive.getSourcePackage(package, release, pocket)
distroseries = Distribution("ubuntu").getSeries(release)
except (SeriesNotFoundException, PackageNotFoundException) as error:
Logger.error(error)
sys.exit(1)
# Get list of builds for that package.
builds = sources.getBuilds()
# Find out the version and component in given release.
version = sources.getVersion()
component = sources.getComponent()
# 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 operation == "rescore":
necessary_privs = me.isLpTeamMember("launchpad-buildd-admins")
if operation == "retry":
necessary_privs = me.canUploadPackage(
ubuntu_archive,
distroseries,
sources.getPackageName(),
sources.getComponent(),
pocket=pocket,
)
if operation in ("rescore", "retry") and not necessary_privs:
Logger.error(
"You cannot perform the %s operation on a %s package as you"
" do not have the permissions to do this action.",
operation,
component,
)
sys.exit(1)
# Output details.
Logger.info(
"The source version for '%s' in %s (%s) is at %s.",
package,
release.capitalize(),
component,
version,
)
Logger.info("Current build status for this package:")
# Output list of arches for package and their status.
done = False
for build in builds:
if one_arch and build.arch_tag != args.architecture[0]:
# Skip this architecture.
continue
done = True
Logger.info("%s: %s.", build.arch_tag, build.buildstate)
if operation == "rescore":
if build.can_be_rescored:
# FIXME: make priority an option
priority = 5000
Logger.info("Rescoring build %s to %d...", build.arch_tag, priority)
build.rescore(score=priority)
else:
Logger.info("Cannot rescore build on %s.", build.arch_tag)
if operation == "retry":
if build.can_be_retried:
Logger.info("Retrying build on %s...", build.arch_tag)
build.retry()
else:
Logger.info("Cannot retry build on %s.", build.arch_tag)
# We are done
if done:
sys.exit(0)
Logger.info("No builds for '%s' found in the %s release", package, release.capitalize())
Logger.info("It may have been built in a former release.")
sys.exit(0)
# Batch mode
if not args.architecture:
# no specific architectures specified, assume all valid ones
archs = valid_archs
else:
archs = set(args.architecture)
# filter out duplicate and invalid architectures
archs.intersection_update(valid_archs)
release = args.series
if not release:
release = Distribution("ubuntu").getDevelopmentSeries().name + "-proposed"
try:
(release, pocket) = split_release_pocket(release)
except PocketDoesNotExistError as error:
Logger.error(error)
sys.exit(1)
ubuntu_archive = Distribution("ubuntu").getArchive()
try:
distroseries = Distribution("ubuntu").getSeries(release)
except SeriesNotFoundException as error:
Logger.error(error)
sys.exit(1)
# Check permisions (part 1): Rescoring can only be done by buildd admins
can_rescore = args.priority and me.isLpTeamMember("launchpad-buildd-admins")
if args.priority and not can_rescore:
Logger.error(
"You don't have the permissions to rescore builds. Ignoring your rescore request."
)
for pkg in args.packages:
try:
pkg = ubuntu_archive.getSourcePackage(pkg, release, pocket)
except PackageNotFoundException as error:
Logger.error(error)
continue
# Check permissions (part 2): check upload permissions for the source
# package
can_retry = args.retry and me.canUploadPackage(
ubuntu_archive, distroseries, pkg.getPackageName(), pkg.getComponent()
)
if args.retry and not can_retry:
Logger.error(
"You don't have the permissions to retry the "
"build of '%s'. Ignoring your request.",
pkg.getPackageName(),
)
Logger.info(
"The source version for '%s' in '%s' (%s) is: %s",
pkg.getPackageName(),
release,
pocket,
pkg.getVersion(),
)
Logger.info(pkg.getBuildStates(archs))
if can_retry:
Logger.info(pkg.retryBuilds(archs))
if args.priority and can_rescore:
Logger.info(pkg.rescoreBuilds(archs, args.priority))
Logger.info("")
if __name__ == "__main__":
main()