...
 
Commits (2)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ report_title }}</title>
<style>
table {border:1px solid;border-collapse:collapse}
.c {text-align:left; padding:0.5rem; border:1px solid; font-size:small}
.p {text-align:left; padding:0.5rem; border:1px solid; font-size:small}
.x {text-align:left; padding:0.5rem; border:1px solid; font-size:small}
.e {text-align:left; padding:0.5rem; border:1px solid; font-size:small}
</style>
<script src="sorttable.js"></script>
</head>
<body>
<h1>{{ report_title }}</h1>
<p>Report generated: {{ report_datetime }}
<br>Problems: {{ "{:d}".format(stats_problems) }}
</p>
<table class="sortable">
<thead>
<tr>
<th class="c"><a href="#!">catnam</a></th>
<th class="p"><a href="#!">prgnam</a></th>
<th class="x"><a href="#!">problem</a></th>
<th class="e"><a href="#!">maintainer</a></th>
</tr>
</thead>
<tbody>
{% for p in problems %}
<tr id="{{ p['catnam']+'/'+p['prgnam'] }}">
<td class="c">{{ p['catnam'] }}</td>
<td class="p">{{ p['prgnam'] }}</td>
<td class="x">{{ p['problem'] }}</td>
<td class="x">{{ p['maintainer'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
#!/usr/bin/python3
#-----------------------------------------------------------------------
# maintainers
# SBo Reports
# report_maintainers
#
# Format a HTML report of SBo maintainers and their activity status
# Create a report of SBo maintainers and their activity status
# David Spencer 2018-05-28
# WTFPL, if anybody is worried
# WTFPL
#
# Usage: maintainers [/path/to/git/repo] > reportname.html
# Usage: report_maintainers [/path/to/slackbuilds/git/repo] > reportname.html
#
# Environment variables:
# SLACKBUILDS="/path/to/slackbuilds/git/repo"
# SITEURL="http://localhost/sbo-reports"
#
# Don't run this too often, because it hammers the Repology API for
# maybe twenty minutes. Repology results may be empty or incomplete due
......@@ -33,10 +38,27 @@ import collections
import datetime
import urllib
# external modules
import requests
import jinja2
report_title="SBo Maintainers"
report_datetime=datetime.datetime.now(datetime.timezone.utc)
repopath=os.getenv("SLACKBUILDS",default="./slackbuilds")
siteurl=os.getenv("SITEURL",default="http://localhost/sbo-status/")
stats_sb=0
stats_new=0
stats_old=0
stats_maint=0
stats_active=0
stats_recent=0
#-----------------------------------------------------------------------
......@@ -78,22 +100,6 @@ def setlatest(mname,cdate,commit):
maintainerinfo[mname]["latest"]={"date":cdate, "commit":commit}
#-----------------------------------------------------------------------
# (0) Find the repo and initialise global statistics.
if len(sys.argv) >= 2:
repopath=sys.argv[1]
else:
repopath=os.path.expanduser("~/slackbuilds")
stats_sb=0
stats_new=0
stats_old=0
stats_maint=0
stats_active=0
stats_recent=0
#-----------------------------------------------------------------------
# (1) Make a list of current maintainers & emails from the .info files.
#
......@@ -259,13 +265,9 @@ for rawline in gitlog.stdout.splitlines():
#-----------------------------------------------------------------------
# (3) Add details from repology (if available) and format it all up.
report_title="SBo Maintainers"
rightnow=datetime.datetime.now(datetime.timezone.utc)
report_datetime=rightnow.strftime("%Y-%m-%d %T %Z")
# Date since which a maintainer is "recent"
recentdays=180
recentdate=(rightnow-datetime.timedelta(days=recentdays)).strftime("%Y-%m-%d")
recentdays = 180
recentdate = (report_datetime - datetime.timedelta(days=recentdays)).strftime("%Y-%m-%d")
# Date before which a maintainer is "inactive" (hardcoded release date of 14.2)
inactivedate="2016-06-30"
......@@ -313,12 +315,13 @@ for mname, mdeets in maintainerinfo.items():
# (3) Render the template and print the results.
jenv = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'),autoescape=None)
rtemplate = jenv.get_template('maintainers.jinja2')
rtemplate = jenv.get_template(os.path.basename(__file__)+'.jinja2')
print(
rtemplate.render(
siteurl=siteurl,
page_title=report_title,
page_datetime=report_datetime.strftime("%Y-%m-%d %T %Z"),
maintainerinfo=maintainerinfo,
report_title=report_title,
report_datetime=report_datetime,
stats_sb=stats_sb,
stats_new=stats_new,
stats_old=stats_old,
......
#!/usr/bin/python3
#-----------------------------------------------------------------------
# problems
# SBo Reports
# report_problems
#
# Format a HTML report of problems according to Repology
# Create a report of SBo problems
# David Spencer 2018-08-05
# WTFPL, if anybody is worried
# WTFPL
#
# Usage: problems [/path/to/git/repo] > reportname.html
# Usage: report_problems > reportname.html
#
# Environment variables:
# SLACKBUILDS="/path/to/slackbuilds/git/repo"
# SITEURL="https://localhost/sbo-reports"
#
# Requires: python3, and the following (all built with python3 support)
# python-requests
......@@ -25,17 +30,16 @@ import subprocess
import json
import datetime
# external modules
import requests
import jinja2
#-----------------------------------------------------------------------
report_title="SBo Problems"
report_datetime=datetime.datetime.now(datetime.timezone.utc)
# Find the repo
if len(sys.argv) >= 2:
repopath=sys.argv[1]
else:
repopath=os.path.expanduser("~/slackbuilds")
repopath=os.getenv("SLACKBUILDS",default="./slackbuilds")
siteurl=os.getenv("SITEURL",default="http://localhost/sbo-status")
#-----------------------------------------------------------------------
def find_catnam(prgnam):
......@@ -48,51 +52,64 @@ def find_catnam(prgnam):
return "Ambiguous"
def get_cp(prob):
return prob["catnam"]+"/"+prob["prgnam"]
def catnamprgnam(p):
return p["catnam"]+"/"+p["prgnam"]
#-----------------------------------------------------------------------
def repologyproblems(repo):
# Get a list of problems from the Repology API for the specified repo
# Return a list of dicts:
# {"catnam":"SBo category", "prgnam":"SBo prgnam", "problem":"problem text"}
# { "catnam":"SBo category", "prgnam":"SBo prgnam", "maintainer":"email",
# "problem":"problem type", "description":"description text" }
repologyAPI="https://repology.org/api/v1/repository/{:s}/problems".format(repo)
problist=[]
# does this return chunks?
probchunk=requests.get(repologyAPI).json()
if len(probchunk) == 0:
# the API spec doesn't say that the 'problems' result set is is chunked,
# so let's assume that it isn't.
problist=requests.get(repologyAPI).json()
if len(problist) == 0:
return None
problist.extend(probchunk)
problems=[]
for p in problist:
prgnam=p["name"]
catnam=find_catnam(prgnam)
problem=p["problem"]
maintainer=p["maintainer"]
problems.append({"catnam": catnam, "prgnam": prgnam, "problem": problem, "maintainer": maintainer})
return sorted(problems,key=get_cp)
# All Repology problems currently start with "Homepage link" and
# a URL, but we'll classify any that don't as "other". To make the
# included URL clickable we need to remove the surrounding quotes.
hstr="Homepage link \""
if p["problem"].startswith(hstr):
problem="homepage"
description=p["problem"][len(hstr):].replace("\" "," ",1)
else:
problem="other"
description=p["problem"]
#-----------------------------------------------------------------------
problems.append({ "prgnam": prgnam,
"catnam": catnam,
"maintainer": maintainer,
"problem": problem,
"description": description
})
report_title="SBo Problems"
report_datetime=datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %T %Z")
return sorted(problems,key=catnamprgnam)
Problems = repologyproblems('slackbuilds')
#-----------------------------------------------------------------------
Problems = repologyproblems('slackbuilds')
jenv = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'),autoescape=None)
rtemplate = jenv.get_template('problems.jinja2')
rtemplate = jenv.get_template(os.path.basename(__file__)+'.jinja2')
print(
rtemplate.render(
siteurl=siteurl,
page_title=report_title,
page_datetime=report_datetime.strftime("%Y-%m-%d %T %Z"),
problems=Problems,
report_title=report_title,
report_datetime=report_datetime,
stats_problems=len(Problems)
)
)
......
#!/bin/sh
#-----------------------------------------------------------------------
# SBo Reports
# run_reports
#
# Run SlackBuilds.org reports
# David Spencer 2018-08-11
# WTFPL
#
# Usage: run_reports
# Environment variables:
# SLACKBUILDS=/path/to/slackbuilds/git/repo
# REPORTS=/path/to/reports/directory
#-----------------------------------------------------------------------
export SLACKBUILDS=${SLACKBUILDS:-/var/lib/sbo-reports/slackbuilds}
export REPORTS=${REPORTS:-/srv/www/htdocs/sbo-reports}
set -eu
if [ -f "${SLACKBUILDS}"/ChangeLog.txt ]; then
cd "${SLACKBUILDS}"
git fetch --all || true
git checkout master
git merge --ff-only origin/master || true
cd - >/dev/null
else
git clone git://git.slackbuilds.org/slackbuilds.git "${SLACKBUILDS}"
fi
for run in report_*; do
if [ -x ${run} ]; then
./${run} > "${REPORTS}/${run}.html"
fi
done
exit 0
body { font-family: Sans-Serif; font-size: 75%; text-align:left; }
table { border:1px solid;border-collapse:collapse }
th, td { padding:0.5rem; border:1px solid }
.m-inactive { background-color:#ffdddd }
.m-normal { background-color:#ffffff }
.m-recent { background-color:#ddffdd }
.m { padding:0.5rem; border:1px solid }
.l { text-align:center; padding:0.5rem; border:1px solid }
.s { text-align:center; padding:0.5rem; border:1px solid }
.n { text-align:center; padding:0.5rem; border:1px solid }
.np { text-align:right; padding:0.5rem; border:1px solid }
.o { text-align:center; padding:0.5rem; border:1px solid }
.op { text-align:right; padding:0.5rem; border:1px solid }
.t { height: 320px; overflow-y:auto }
.modal {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background: rgba(0,0,0,0.8);
z-index: 9;
opacity:0;
pointer-events: none;
}
.modal:target { opacity: 1; pointer-events:auto }
.modal > div {
width: 400px; height: 400px;
position: relative;
margin: 10% auto;
padding: 5px 5px 5px 5px;
background: #ffffff;
}
.closebutton {
color: #ffffff; background: #606060;
-webkit-box-shadow: 1px 1px 3px #000000;
-moz-box-shadow: 1px 1px 3px #000000;
box-shadow: 1px 1px 3px #000000;
position: absolute;
line-height: 24px; width: 24px;
right: 0; top: 0;
text-align: center; text-decoration: none;
}
.closebutton:hover { color: #ffffff; background: #ff4444; }
<head>
<meta charset="utf-8">
<title>{{ page_title }}</title>
<link rel="stylesheet" href="{{ siteurl }}/support/style.css">
<link rel="icon" type="image/png" href="{{ siteurl }}/support/favicon.png">
<script src="{{ siteurl }}/support/sorttable.js"></script>
</head>
<!DOCTYPE html>
<html>
{% include 'head.jinja2' %}
<body>
<h1>{{ page_title }}</h1>
<p>Updated: {{ page_datetime }}</p>
<h3>Reports</h3>
<ul>
<li><a href="{{ siteurl }}/reports/report_maintainers.html">Maintainers</a></li>
<li><a href="{{ siteurl }}/reports/report_problems.html">Problems</a></li>
</ul>
<h3>Details</h3>
<ul>
<li><a href="{{ siteurl }}/maintainers/">Maintainers</a></li>
<li><a href="{{ siteurl }}/slackbuilds/">SlackBuilds</a></li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ report_title }}</title>
<style>
table {border:1px solid;border-collapse:collapse}
.inactive {background-color:#ffdddd}
.active {background-color:#ffffff}
.recent {background-color:#ddffdd}
.e {font-size:small}
.t {font-size:small; height: 320px; overflow-y:auto}
.m {text-align:left; padding:0.5rem; border:1px solid}
.l {text-align:center; padding:0.5rem; border:1px solid}
.s {text-align:center; padding:0.5rem; border:1px solid}
.n {text-align:center; padding:0.5rem; border:1px solid}
.np {text-align:right; padding:0.5rem; border:1px solid}
.o {text-align:center; padding:0.5rem; border:1px solid}
.op {text-align:right; padding:0.5rem; border:1px solid}
.modal {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background: rgba(0,0,0,0.8);
z-index: 9;
opacity:0;
pointer-events: none;
}
.modal:target { opacity:1; pointer-events:auto }
.modal > div {
width: 400px; height: 400px;
position: relative;
margin: 10% auto;
padding: 5px 5px 5px 5px;
background: #ffffff;
}
.close {
background: #606060;
color: #ffffff;
position: absolute;
line-height: 24px;
width: 24px;
right: 0; top: 0;
text-align: center;
text-decoration: none;
-webkit-box-shadow: 1px 1px 3px #000000;
-moz-box-shadow: 1px 1px 3px #000000;
box-shadow: 1px 1px 3px #000000;
}
.close:hover { background: #ff4444; }
</style>
<!-- sortable.js from https://www.kryogenix.org/code/browser/sorttable/ -->
<script src="sorttable.js"></script>
</head>
{% include 'head.jinja2' %}
<body>
<h1>{{ report_title }}</h1>
<h1>{{ page_title }}</h1>
<p>Updated: {{ page_datetime }}</p>
<p>Report generated: {{ report_datetime }}</p>
<p>SlackBuilds
<br>&nbsp;&nbsp;&nbsp;total: {{ "{:d}".format(stats_sb) }}
<br>&nbsp;&nbsp;&nbsp;newest: {{ "{:d} ({:.1f}%)".format(stats_new,stats_new*100/stats_sb) }}
......@@ -72,7 +19,6 @@
<br>&nbsp;&nbsp;&nbsp;recent: {{ "{:d} ({:.1f}%)".format(stats_recent,stats_recent*100/stats_maint) }} last 180 days
</p>
<table class="sortable">
<thead>
......@@ -89,7 +35,7 @@
<tbody>
{% for mname, mdeets in maintainerinfo|dictsort(true) %}
<tr id="m{{ mdeets['mnum'] }}" class="{{ mdeets['status'] }}">
<tr id="m{{ mdeets['mnum'] }}" class="{{ 'm-'+mdeets['status'] }}">
<td class="m">{{ mdeets["tdmaintainer"] }}</td>
<td class="l">{{ mdeets["tdlatest"] }}</td>
<td class="s"><a href="#sb{{ mdeets["mnum"] }}">{{ mdeets["tdslackbuilds"] }}</a></td>
......@@ -106,7 +52,7 @@
{% for mname, mdeets in maintainerinfo.items() %}
<div id="sb{{ mdeets['mnum'] }}" class="modal">
<div>
<a href="#close" title="Close" class="close">&otimes;</a>
<a href="#close" title="Close" class="closebutton">&otimes;</a>
<p>{{ mname }}</p>
<p class="t">{{ mdeets["slackbuilds"]|sort|join("<br>") }}</p>
</div>
......
<!DOCTYPE html>
<html>
{% include 'head.jinja2' %}
<body>
<h1>{{ page_title }}</h1>
<p>Updated: {{ page_datetime }}</p>
<p>Problems: {{ "{:d}".format(stats_problems) }}</p>
<table class="sortable">
<thead>
<tr>
<th class="catnam"><a href="#!">catnam</a></th>
<th class="prgnam"><a href="#!">prgnam</a></th>
<th class="problem"><a href="#!">problem</a></th>
<th class="description"><a href="#!">description</a></th>
<th class="maintainer"><a href="#!">maintainer</a></th>
</tr>
</thead>
<tbody>
{% for p in problems %}
<tr id="{{ p['catnam']+'/'+p['prgnam'] }}">
<td class="catnam">{{ p['catnam'] }}</td>
<td class="prgnam"><a href="{{ siteurl }}/slackbuilds/{{ p['catnam']+"/"+p['prgnam'] }}" target="_blank">{{ p['prgnam'] }}</a></td>
<td class="problem">{{ p['problem'] }}</td>
<td class="description">{{ p['description']|urlize(40,target='_blank') }}</td>
<td class="maintainer"><a href="{{ siteurl }}/maintainers/{{ p['maintainer'] }}" target="_blank">{{ p['maintainer'] }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>