#!/usr/bin/python3
# -*- coding: utf-8 -*-
# pylint: disable=line-too-long
# kate: space-indent on; indent-width 4; replace-tabs on; indent-mode python; remove-trailing-space modified;
# pylint: enable=line-too-long
# vim: expandtab ts=4
############################################################################
# Copyright © 2017-2020 José Manuel Santamaría Lema <panfaust@gmail.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 2 of the License, or #
# (at your option) any later version. #
############################################################################
"""
This module just provides the KAGraphArchiveBuildStatus class.
"""
import re
from libka.kagraph.ka_graph_node_status import KAGraphNodeStatus
from libka.kagraph.ka_graph import KAGraph
[docs]
class KAGraphArchiveBuildStatus(KAGraph): #pylint: disable= too-many-instance-attributes
"""
Class to represent a build status graph for the official archive;
in addition to packages(nodes) and edges you must feed in the packages
status retrieved with launchpadlib.
"""
def __init__(self, dist, title='',):
#Call the superclass constructor
super(KAGraphArchiveBuildStatus, self).__init__(title)
#Define all possible kinds of status
self._status_ok = KAGraphNodeStatus(
name='status_ok',
color='green3',
text="Successfully built")
self._status_building = KAGraphNodeStatus(
name='status_building',
color='greenyellow',
text="Currently building")
self._status_needsbuilding = KAGraphNodeStatus(
name='status_needsbuilding',
color='yellow',
text="Needs building")
self._status_depwait = KAGraphNodeStatus(
name='status_depwait',
color='lightblue',
text="Dependency wait")
self._status_ftbfs = KAGraphNodeStatus(
name='status_ftbfs',
color='red',
text="Failed to build")
self._status_chrootproblem = KAGraphNodeStatus(
name='status_chrootproblem',
color='orangered',
text="Chroot problem")
self._status_new = KAGraphNodeStatus(
name='status_new',
color='chocolate',
text="Package in the NEW queue",
url="https://launchpad.net/ubuntu/%s/+queue" % dist)
self._status_notfound = KAGraphNodeStatus(
name='status_notfound',
color='grey',
text="Package not found")
self._status_wrongversion = KAGraphNodeStatus(
name='status_wrongversion',
color='firebrick',
text="Incorrect version")
self._status_other = KAGraphNodeStatus(
name='status_other',
color='dimgrey',
text="Other")
self.set_package_status_list([
self._status_ok, self._status_building, self._status_needsbuilding,
self._status_depwait, self._status_ftbfs, self._status_chrootproblem,
self._status_new, self._status_wrongversion,
self._status_notfound, self._status_other
])
#Map to find out which build state is "better"
self._lp_build_status_level = {
"Successfully built": 0,
"Currently building": 3,
"Gathering build output": 3,
"Uploading build": 3,
"Needs building": 2,
"Dependency wait": 1,
"Failed to build": 5,
"Chroot problem": 6,
"Build for superseded Source": 4,
"Failed to upload": 5,
"Cancelling build": 3,
"Cancelled build": 5}
#Map to find out the build status from the build status level
self._build_status_from_level = {
0:self._status_ok,
1:self._status_depwait,
2:self._status_needsbuilding,
3:self._status_building,
4:self._status_other,
5:self._status_ftbfs,
6:self._status_chrootproblem,
7:self._status_wrongversion
}
# pylint: disable=too-many-locals,too-many-branches
[docs]
def set_package_status_from_lp_sources_and_builds(self, all_sources, all_builds, lpseries): # pylint: disable=invalid-name
"""
Sets the package status info from LP.
If you set the lpseries parameter as None, the new queue won't be checked,
that's interesting for PPA builds.
"""
#FIXME: The following situations are not handled correctly:
# - packages with *binaries* waiting in the new queue
#Write package states in the graph
for package in all_sources:
sources = all_sources[package]
if len(sources) == 0:
#This package is not on Proposed nor Release
if lpseries is not None:
#Check new queue
package_uploads_new = lpseries.getPackageUploads(name=package,
exact_match=True,
status='New')
if len(package_uploads_new) == 0:
self.set_package_status(package, self._status_notfound)
else:
self.set_package_status(package, self._status_new)
else:
#Mark the package as not found without checking the new queue
self.set_package_status(package, self._status_notfound)
else:
#This package is either in proposed or release
builds = all_builds[package]
#Check if the package is at the correct version
if package not in self._different_versions:
actual_version = sources[0].source_package_version.split(':')[-1]
expected_version = self._expected_version
if not actual_version.startswith(expected_version):
#This package has a wrong version
self.set_package_status(package, self._status_wrongversion)
#Set the package node url in the graph
url = sources[0].self_link
url = re.sub(r"api\.launchpad\.net/[^/]*",
"launchpad.net", url) + "/+listing-archive-extra"
self.set_package_url(package, url)
continue
#Inspect the architecture builds and escalate the build status level up to
#its higher value
overall_build_status_level = -1
for build in builds:
#Ignore this build if it's not in the arch list; None means 'consider all'
if self._arch_list is not None:
if build.arch_tag not in self._arch_list:
continue
#Update status level
current_build_status_level = self._lp_build_status_level[build.buildstate]
if current_build_status_level > overall_build_status_level:
overall_build_status_level = current_build_status_level
#Set the package node status in the graph
if overall_build_status_level == -1:
#This should not happen, but "shit happens"
package_status = self._status_other
else:
package_status = self._build_status_from_level[overall_build_status_level]
#Check if the package is ok to add url links or check the new queue
if package_status != self._status_ok:
#Set the final package state
self.set_package_status(package, package_status)
#Set the package node url in the graph
url = sources[0].self_link
url = re.sub(r"api\.launchpad\.net/[^/]*",
"launchpad.net", url) + "/+listing-archive-extra"
self.set_package_url(package, url)
else:
#Set the final package state
self.set_package_status(package, package_status)
#Check new queue
#FIXME: this wouldn't work
#if lpseries != None:
# package_uploads_new = lpseries.getPackageUploads(name=package,
# exact_match=True,
# status='New')
# if len(package_uploads_new) != 0:
# self.set_package_status(package, self._status_new)
# pylint: enable=too-many-locals,too-many-branches