summaryrefslogtreecommitdiff
path: root/webapp.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp.py')
-rw-r--r--webapp.py105
1 files changed, 72 insertions, 33 deletions
diff --git a/webapp.py b/webapp.py
index 8acf92f..cc9de37 100644
--- a/webapp.py
+++ b/webapp.py
@@ -35,7 +35,8 @@ index_template = """<!DOCTYPE html>
<tr>
<th>source</th>
<th>version</th>
- <th>architecture</th>
+ <th>build architecture</th>
+ <th>host architecture</th>
<th>started</th>
<th>result log</th>
<th>bugs</th>
@@ -50,7 +51,8 @@ index_template = """<!DOCTYPE html>
</a>
</td>
<td>{{ build.version|e }}</td>
- <td>{{ build.architecture|e }}</td>
+ <td>{{ build.buildarch|e }}</td>
+ <td>{{ build.hostarch|e }}</td>
<td>
{{- build.starttime|sqltimestamp|formatts -}}
</td>
@@ -107,13 +109,13 @@ tr.dep.tempbad td:nth-child(1) {
tr.dep.good td:nth-child(1) {
background-color: #afa;
}
-tr.build.bad td:nth-child(4) {
+tr.build.bad td:nth-child(5) {
background-color: #faa;
}
-tr.build.tempbad td:nth-child(4) {
+tr.build.tempbad td:nth-child(5) {
background-color: #ffa;
}
-tr.build.good td:nth-child(4) {
+tr.build.good td:nth-child(5) {
background-color: #afa;
}
th {
@@ -177,13 +179,13 @@ footer {
{%- for reason, archs in depresult.items()|sort -%}
<tr class="dep {{ "tempbad" if reason.startswith("skew") else "bad" }}">
<td>{{ reason|e }}</td>
- <td>{{ archs|arch_format }}</td>
+ <td>{{ archs|archpairs_format }}</td>
</tr>
{%- endfor -%}
{%- if okarchs -%}
<tr class="dep good">
<td>ok</td>
- <td>{{ okarchs|arch_format }}</td>
+ <td>{{ okarchs|archpairs_format }}</td>
</tr>
{%- endif -%}
</tbody>
@@ -220,7 +222,8 @@ footer {
<tr>
<th>started</th>
<th>version</th>
- <th>architecture</th>
+ <th>build architecture</th>
+ <th>host architecture</th>
<th>result log</th>
</tr>
</thead>
@@ -231,7 +234,8 @@ footer {
{{- build.starttime|sqltimestamp|formatts -}}
</td>
<td>{{ build.version|e }}</td>
- <td>{{ build.architecture|e }}</td>
+ <td>{{ build.buildarch|e }}</td>
+ <td>{{ build.hostarch|e }}</td>
<td>
<a href="{{ url_for("show_log", filename=build.filename[:-3]) }}">
{{- "ok" if build.success else "failed" -}}
@@ -249,10 +253,12 @@ footer {
<input type="submit" name="schedule" value="cross build" />
{{ sourcepackage|e }} for
<input type="hidden" name="source" value="{{ sourcepackage|e }}" />
- <select name="architecture">
- <option value="any">any</option>
- {%- for architecture in architectures|sort -%}
- <option value="{{ architecture|e }}">{{ architecture|e }}</option>
+ <select name="archpair">
+ <option value="any_any">{{ ("any", "any")|archpair_format }}</option>
+ {%- for buildarch, hostarch in architectures|sort -%}
+ <option value="{{ buildarch|e }}_{{ hostarch|e }}">
+ {{- (buildarch, hostarch)|archpair_format -}}
+ </option>
{%- endfor -%}
</select>
</form>
@@ -308,36 +314,64 @@ def formatts_filter(ts):
return jinja2.Markup('<time title="%s" datetime="%s">%s</time>' %
(ts, ts, formatts(ts)))
-@app.template_filter('arch_format')
-@jinja2.contextfilter
-def arch_format_filter(context, some_archs):
- if context["architectures"] == some_archs:
+@app.template_filter("archpair_format")
+def archpair_format_filter(archpair):
+ return jinja2.Markup("%s &rarr; %s" % tuple(map(jinja2.escape, archpair)))
+
+def group_pairs(pairs):
+ result = {}
+ for v, w in pairs:
+ result.setdefault(v, set()).add(w)
+ return result
+
+def render_archset(subset, all_archs):
+ if len(subset) == 1:
+ return next(iter(subset))
+ if subset == all_archs:
return "any"
- return ", ".join(sorted(some_archs))
+ return "{%s}" % ", ".join(map(jinja2.escape, sorted(subset)))
+
+@app.template_filter('archpairs_format')
+@jinja2.contextfilter
+def archpairs_format_filter(context, some_archs):
+ architectures = group_pairs(context["architectures"])
+ fwdmap = {} # build architecture -> host architecture set representation
+ for buildarch, hostarchs in group_pairs(some_archs).items():
+ fwdmap[buildarch] = render_archset(hostarchs, architectures[buildarch])
+ allbuildarchs = set(architectures.keys())
+ # host architecture set representation -> build architecture set
+ flippedit = group_pairs((v, k) for (k, v) in fwdmap.items()).items()
+ maps = ("%s &rarr; %s" % (render_archset(buildarchs, allbuildarchs),
+ hostarchrep)
+ for hostarchrep, buildarchs in flippedit)
+ return jinja2.Markup("; ".join(sorted(maps)))
def collect_depstate(conn, source):
version = None
depstate = None
query = sqlalchemy.text("""
- SELECT version, architecture, satisfiable, reason
+ SELECT version, 'amd64' AS buildarch, architecture AS hostarch,
+ satisfiable, reason
FROM depstate WHERE source = :source;""")
for row in conn.execute(query, source=source):
if version is None or version_compare(version, row.version) > 0:
version = row.version
depstate = {}
- depstate[row.architecture] = None if row.satisfiable else row.reason
+ depstate[row.buildarch, row.hostarch] = \
+ None if row.satisfiable else row.reason
if version is None:
raise werkzeug.exceptions.NotFound()
depresult = {}
- for arch, reason in depstate.items():
- depresult.setdefault(reason, set()).add(arch)
+ for archpair, reason in depstate.items():
+ depresult.setdefault(reason, set()).add(archpair)
return version, depresult
@app.route("/")
def show_index():
with db.engine.connect() as conn:
builds = list(conn.execute("""
- SELECT source, version, architecture, starttime, filename,
+ SELECT source, version, 'amd64' AS buildarch,
+ architecture AS hostarch, starttime, filename,
ifnull((SELECT max(patched + 1) FROM bugs
WHERE affects = source),
0) AS buglvl
@@ -351,12 +385,15 @@ def show_index():
def show_source(source):
context = dict(sourcepackage=source)
with db.engine.connect() as conn:
- query = sqlalchemy.text("SELECT architecture FROM depcheck;")
- context["architectures"] = set(row[0] for row in conn.execute(query))
+ query = sqlalchemy.text("""SELECT 'amd64' AS buildarch,
+ architecture AS hostarch
+ FROM depcheck;""")
+ context["architectures"] = set(map(tuple, conn.execute(query)))
context["version"], context["depresult"] = collect_depstate(conn,
source)
query = sqlalchemy.text("""
- SELECT version, architecture, success, starttime, filename
+ SELECT version, 'amd64' AS buildarch, architecture AS hostarch,
+ success, starttime, filename
FROM builds WHERE source = :source;""")
context["builds"] = list(conn.execute(query, source=source))
query = sqlalchemy.text("""
@@ -388,21 +425,23 @@ def show_log(filename):
@app.route("/schedule", methods=["POST"])
def request_schedule():
source = flask.request.form["source"]
- architecture = flask.request.form["architecture"]
+ buildarch, hostarch = flask.request.form["archpair"].split("_")
+ if buildarch not in ("any", "amd64"):
+ raise werkzeug.exceptions.BadRequest()
with db.engine.connect() as conn:
query = sqlalchemy.text("""
SELECT 1 FROM depstate WHERE source = :source;""")
if not conn.execute(query, source=source).first():
raise werkzeug.exceptions.BadRequest()
- if architecture == "any":
- architecture = None
+ if hostarch == "any":
+ hostarch = None
else:
query = sqlalchemy.text("""
- SELECT 1 FROM depcheck WHERE architecture = :architecture;""")
- if not conn.execute(query, architecture=architecture).first():
+ SELECT 1 FROM depcheck WHERE architecture = :hostarch;""")
+ if not conn.execute(query, hostarch=hostarch).first():
raise werkzeug.exceptions.BadRequest()
query = sqlalchemy.text("""
INSERT INTO buildrequests (source, architecture, requesttime)
- VALUES (:source, :architecture, datetime('now'));""")
- conn.execute(query, source=source, architecture=architecture)
+ VALUES (:source, :hostarch, datetime('now'));""")
+ conn.execute(query, source=source, hostarch=hostarch)
return flask.render_template_string(schedule_template)