From: Michael Tremer Date: Sun, 17 Feb 2013 15:47:09 +0000 (+0100) Subject: Show ETA of build jobs. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a90bd9b007c1360abfa08465138027ec69cc9e00;p=pbs.git Show ETA of build jobs. --- diff --git a/backend/builds.py b/backend/builds.py index 43a557d1..ef1e7c1f 100644 --- a/backend/builds.py +++ b/backend/builds.py @@ -333,7 +333,7 @@ class Builds(base.Object): return comments - def get_build_times_summary(self, name=None, job_type=None): + def get_build_times_summary(self, name=None, job_type=None, arch=None): query = "\ SELECT \ builds_times.arch AS arch, \ @@ -355,10 +355,15 @@ class Builds(base.Object): args.append(name) # Filter by job types. - if type: + if job_type: conditions.append("builds_times.job_type = %s") args.append(job_type) + # Filter by arch. + if arch: + conditions.append("builds_times.arch = %s") + args.append(arch) + # Add conditions. if conditions: query += " WHERE %s" % " AND ".join(conditions) @@ -368,6 +373,15 @@ class Builds(base.Object): return self.db.query(query, *args) + def get_build_times_by_arch(self, arch, **kwargs): + kwargs.update({ + "arch" : arch, + }) + + build_times = self.get_build_times_summary(**kwargs) + if build_times: + return build_times[0] + class Build(base.Object): def __init__(self, pakfire, id, data=None): @@ -1762,6 +1776,12 @@ class Job(base.Object): def size(self): return sum((p.size for p in self.packages)) + def is_running(self): + """ + Returns True if job is in a running state. + """ + return self.state in ("pending", "dispatching", "running", "uploading") + def get_state(self): return self.data.state @@ -1887,6 +1907,28 @@ class Job(base.Object): def time_finished(self): return self.data.time_finished + @property + def expected_runtime(self): + """ + Returns the estimated time and stddev, this job takes to finish. + """ + # Get the average build time. + build_times = self.pakfire.builds.get_build_times_by_arch(self.arch.name, + name=self.pkg.name) + + # If there is no statistical data, we cannot estimate anything. + if not build_times: + return None, None + + return build_times.average, build_times.stddev + + @property + def eta(self): + expected_runtime, stddev = self.expected_runtime + + if expected_runtime: + return expected_runtime - int(self.duration), stddev + @property def tries(self): return self.data.tries diff --git a/data/templates/jobs-detail.html b/data/templates/jobs-detail.html index 1db1f040..1ce30a88 100644 --- a/data/templates/jobs-detail.html +++ b/data/templates/jobs-detail.html @@ -129,6 +129,12 @@ {{ format_date(job.time_finished, full_format=True) }}

{% end %} + {% if job.is_running() %} +

+ {{ _("ETA") }}
+ {{ format_eta(job.eta) }} +

+ {% end %} diff --git a/data/templates/modules/jobs/boxes.html b/data/templates/modules/jobs/boxes.html index 23fa2315..4f7f0cfc 100644 --- a/data/templates/modules/jobs/boxes.html +++ b/data/templates/modules/jobs/boxes.html @@ -15,6 +15,12 @@ {{ _("Builder") }}: {{ j.builder.name }} {% end %} + + {% if j.is_running() %} +
  • + {{ _("ETA") }}: {{ format_eta(j.eta) }} +
  • + {% end %} {% end %} diff --git a/data/templates/modules/jobs/list.html b/data/templates/modules/jobs/list.html index 78df1cc7..d48b58e9 100644 --- a/data/templates/modules/jobs/list.html +++ b/data/templates/modules/jobs/list.html @@ -47,6 +47,10 @@ {{ friendly_time(job.duration) }} + + {% if job.is_running() %} +
    {{ _("ETA") }}: {{ format_eta(job.eta) }} + {% end %} {% end %} diff --git a/web/__init__.py b/web/__init__.py index 1315dfe2..b40e5f27 100644 --- a/web/__init__.py +++ b/web/__init__.py @@ -1,4 +1,5 @@ #!/usr/bin/python +# encoding: utf-8 import logging import multiprocessing @@ -88,6 +89,7 @@ class Application(tornado.web.Application): "SelectTimezone" : SelectTimezoneModule, }, ui_methods = { + "format_eta" : self.format_eta, "format_time" : self.format_time, }, xsrf_cookies = True, @@ -298,6 +300,19 @@ class Application(tornado.web.Application): ## UI methods + def format_eta(self, handler, (s, stddev)): + if s is None: + _ = handler.locale.translate + return _("Unknown") + + if s < 0: + s = 0 + + return "%s ± %s" % ( + self.format_time(handler, s), + self.format_time_short(handler, stddev), + ) + def format_time(self, handler, s): _ = handler.locale.translate @@ -308,3 +323,16 @@ class Application(tornado.web.Application): min += 1 return _("%(hrs)d:%(min)02d hrs") % {"hrs" : hrs, "min" : min} + + def format_time_short(self, handler, s): + _ = handler.locale.translate + + hrs = s / 3600 + if hrs >= 1: + return _("%dh") % hrs + + min = s / 60 + if min >= 1: + return _("%dm") % min + + return _("%ds") % s