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