From: Michael Tremer Date: Tue, 5 Jul 2022 16:33:13 +0000 (+0000) Subject: events: Build scaffolding to read events X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fb1e80072fda16373df9532b4db338031dbe592;p=pbs.git events: Build scaffolding to read events Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 4472f3e2..787e3f8e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -86,6 +86,7 @@ buildservice_PYTHON = \ src/buildservice/database.py \ src/buildservice/decorators.py \ src/buildservice/distribution.py \ + src/buildservice/events.py \ src/buildservice/git.py \ src/buildservice/jobqueue.py \ src/buildservice/jobs.py \ diff --git a/src/buildservice/__init__.py b/src/buildservice/__init__.py index 48ddb030..35cd4d23 100644 --- a/src/buildservice/__init__.py +++ b/src/buildservice/__init__.py @@ -14,6 +14,7 @@ from . import builds from . import cache from . import database from . import distribution +from . import events from . import jobqueue from . import jobs from . import keys @@ -54,6 +55,7 @@ class Backend(object): self.jobs = jobs.Jobs(self) self.builders = builders.Builders(self) self.distros = distribution.Distributions(self) + self.events = events.Events(self) self.jobqueue = jobqueue.JobQueue(self) self.keys = keys.Keys(self) self.messages = messages.Messages(self) diff --git a/src/buildservice/builds.py b/src/buildservice/builds.py index a2b3e7a4..b9eb58c8 100644 --- a/src/buildservice/builds.py +++ b/src/buildservice/builds.py @@ -597,15 +597,16 @@ class Build(base.DataObject): ## Logging stuff - def get_log(self, limit=None): + @property + def events(self): res = self.db.query(""" WITH events AS ( -- Build creation times SELECT - builds.id AS build_id, + builds.id AS build, builds.created_at AS t, - 'created'::text AS event, - builds.owner_id AS by_user_id + 'build-created'::text AS type, + builds.owner_id AS by_user FROM builds @@ -613,14 +614,14 @@ class Build(base.DataObject): UNION ALL SELECT - builds.id AS build_id, + builds.id AS build, builds.finished_at AS t, CASE WHEN builds.failed IS TRUE - THEN 'failed'::text - ELSE 'finished'::text - END AS event, - NULL AS by_user_id + THEN 'build-failed'::text + ELSE 'build-finished'::text + END AS type, + NULL AS by_user FROM builds WHERE @@ -633,13 +634,13 @@ class Build(base.DataObject): FROM events WHERE - build_id = %s + build = %s ORDER BY t DESC""", self.id, ) - return res # XXX automatically expand all those IDs + return self.backend.events.expand(res) def get_log(self, comments=True, repo=True, limit=None): entries = [] diff --git a/src/buildservice/events.py b/src/buildservice/events.py new file mode 100644 index 00000000..16bea543 --- /dev/null +++ b/src/buildservice/events.py @@ -0,0 +1,97 @@ +#!/usr/bin/python3 +############################################################################### +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2022 Pakfire development team # +# # +# 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 . # +# # +############################################################################### + +import logging + +from . import base + +log = logging.getLogger("pakfire.events") + +from .decorators import * + +class Events(base.Object): + @lazy_property + def map(self): + return { + # Builds + "build" : self.backend.builds.get_by_id, + + # Users + "by_user" : self.backend.users.get_by_id, + } + + def expand(self, events): + """ + Expands any log events + """ + cache = {} + + for event in events: + # Replace any mappable attributes + for attribute in event: + # Check if we are dealing with a mapped attribute + try: + expand = self.map[attribute] + except KeyError as e: + log.debug("Could not map attribute '%s'" % attribute) + continue + + # Fetch attribute value + key = event[attribute] + + # Skip everything that is None + if key is None: + continue + + # Lookup the cache + try: + value = cache[attribute][key] + + # Call the expand function on cache miss + except KeyError: + value = expand(key) + + # Store the expanded value + try: + cache[attribute][key] = value + except KeyError: + cache[attribute] = { key : value } + + # Replace original value with the expanded one + event[attribute] = value + + yield Event(self.backend, event) + + +class Event(base.Object): + def init(self, data): + self.data = data + + # Read some useful attributes + try: + self.type = self.data.type + self.t = self.data.t + except AttributeError as e: + log.error("Could not read event: %s" % e) + raise e + + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, self.type)