Evet, yeni repostats hazır. Kullanım için:

tools/repostats.py ~/pardus/pardus-devel

Önce bulduğu hataları (varsa, ki var!) sonra da genel istatistikleri
ekrana basacak.

tools/repostats.py ~/pardus/pardus-devel packager "Gürer Özen"
tools/repostats.py ~/pardus/pardus-devel package k3b

gibi iki özel kullanımı daha var. Bir de

tools/repostats.py ~/pardus/pardus-devel html

ile paksite adlı bir dizin açıp, içine paketler, paketçiler vs
herbiri için bilgilerin olduğu bir site oluşturuyor.

firefox paksite/index.html

Eğer bulunduğunuz dizinde programın başındaki def_repo_html gibi
templatelere karşılık repo.html gibi dosyalar varsa, onlara göre
sayfalar oluşturuluyor.

Eksikleri var, daha gelişecek.
This commit is contained in:
Gürer Özen
2005-10-09 17:39:14 +00:00
parent 1723245daf
commit d7055cb33e
+504 -122
View File
@@ -11,6 +11,7 @@
import sys import sys
import os import os
import codecs
import gettext import gettext
__trans = gettext.translation('pisi', fallback=True) __trans = gettext.translation('pisi', fallback=True)
@@ -20,8 +21,134 @@ sys.path.append('.')
import pisi.specfile import pisi.specfile
import pisi.uri import pisi.uri
def echo(string): # default html templates
print string.encode("utf8")
def_table_html = u"""
<tr><td>%s</td><td>%s</td></tr>
"""
def_repo_html = u"""
<html><head>
<title>Depo istatistikleri</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body>
<p>
Depoda toplam %(nr_source)d kaynak paket, ve bu paketlerden oluşturulacak
%(nr_packages)d ikili paket bulunmaktadır. Toplam %(nr_patches)d yama mevcuttur.
</p>
<p>
%(errors)s
</p>
<h3>En fazla yamalanmış 5 kaynak paket:</h3><p><table><tbody>
%(most_patched)s
</tbody></table></p>
<h3>Eksik paketler</h3><p><table><tbody>
%(missing)s
</tbody></table></p>
<h3>Paketçiler:</h3><p><table><tbody>
%(packagers)s
</tbody></table></p>
</body></html>
"""
def_packager_html = u"""
<html><head>
<title>Paketçi %(name)s</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body>
<p>%(name)s &lt;%(email)s&gt;</p>
<p>Paketler:</p>
<p>%(sources)s</p>
</body></html>
"""
def_package_html = u"""
<html><head>
<title>İkili paket %(name)s</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body>
<h1>İkili paket: %(name)s</h1>
<h2>Versiyon %(version)s, sürüm %(release)s</h2>
<h3>Derlemek için bağımlılar:</h3>
<p>%(buildDeps)s</p>
<h3>Çalıştırmak için bağımlılar:</h3>
<p>%(runtimeDeps)s</p>
<h3>Pakete derlenmek için bağımlılar:</h3>
<p>%(revBuildDeps)s</p>
<h3>Pakete çalışmak için bağımlılar:</h3>
<p>%(revRuntimeDeps)s</p>
</body></html>
"""
def_source_html = u"""
<html><head>
<title>Kaynak paket %(name)s</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body>
<h1>Kaynak paket: %(name)s</h1>
<h2>Versiyon %(version)s, sürüm %(release)s</h2>
<h3>Bu kaynaktan derlenen ikili paketler:</h3>
<p>%(packages)s</p>
</body></html>
"""
def_missing_html = u"""
<html><head>
<title>Eksik ikili paket %(name)s</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body>
<h1>Eksik ikili paket: %(name)s</h1>
<h3>Pakete derlenmek için bağımlılar:</h3>
<p>%(revBuildDeps)s</p>
<h3>Pakete çalışmak için bağımlılar:</h3>
<p>%(revRuntimeDeps)s</p>
</body></html>
"""
# FIXME: This check should be in specfile
valid_filetypes = [
"executable",
"library",
"data",
"config",
"doc",
"man",
"info",
"localedata",
"header",
"all"
]
def printu(obj):
if isinstance(obj, unicode):
print obj.encode('utf-8')
elif isinstance(obj, str):
print obj.decode('utf-8')
else:
print str(obj)
def valuesort(x, y): def valuesort(x, y):
if x[1] > y[1]: if x[1] > y[1]:
@@ -31,11 +158,41 @@ def valuesort(x, y):
else: else:
return 1 return 1
def find_pspecs(folder):
paks = []
for root, dirs, files in os.walk(folder):
if "pspec.xml" in files:
paks.append(root)
# dont walk into the versioned stuff
if ".svn" in dirs:
dirs.remove(".svn")
return paks
def template_get(tmpl_name):
try:
f = codecs.open(tmpl_name + ".html", "r", "utf-8")
data = f.read()
f.close()
return data
except:
return globals()["def_" + tmpl_name + "_html"]
def template_write(filename, tmpl_name, dict):
f = codecs.open(filename, "w", "utf-8")
f.write(template_get(tmpl_name) % dict)
f.close()
def template_table(tmpl_name, list):
tmpl = template_get(tmpl_name)
data = ""
for item in list:
data += (tmpl % item)
return data
class Histogram: class Histogram:
def __init__(self, title): def __init__(self):
self.list = {} self.list = {}
self.title = title
def add(self, name, value=None): def add(self, name, value=None):
if value: if value:
@@ -46,138 +203,363 @@ class Histogram:
else: else:
self.list[name] = 1 self.list[name] = 1
def get_list(self): def get_list(self, max=0):
items = self.list.items() items = self.list.items()
items.sort(valuesort) items.sort(valuesort)
return items
def html_out(self, max=0):
echo("<h1>%s</h1><table>" % self.title)
list = self.get_list()
if max != 0: if max != 0:
list = list[:max] return items[:max]
for name,cnt in list: else:
echo("<tr><td>%s</td><td>%s</td></tr>" % (name, cnt)) return items
echo("</table>")
def scan_pspec(folder): # Dictionary of all source packages keyed by the source name
paks = [] sources = {}
for root, dirs, files in os.walk(folder):
if "pspec.xml" in files:
paks.append(root)
# dont walk into the versioned stuff
if ".svn" in dirs:
dirs.remove(".svn")
return paks
def add_deps(deps, spec): # Dictionary of all binary packages keyed by the package name
a = {} packages = {}
for d in spec.source.buildDeps:
p = d.package
if not a.has_key(p):
a[p] = 1
for pak in spec.packages:
for d in pak.runtimeDeps:
p = d.package
if not a.has_key(p):
a[p] = 1
for p in a:
deps.add(p)
hosts = Histogram(_("Source hosts")) # Dictionary of all packagers keyed by the packager name
people = Histogram(_("Packagers")) packagers = {}
licenses = Histogram(_("Licenses"))
categories = Histogram(_("Categories"))
components = Histogram(_("Components"))
dependencies = Histogram(_("Dependencies"))
releases = Histogram(_("Releases"))
types = Histogram(_("File types"))
mostpatched = Histogram(_("Top five most patched source"))
longpy = Histogram(_("Top five longest action.py scripts"))
nr_binpaks = 0
nr_patches = 0
paknames = {}
# Dictionary of missing depended binary packages keyed by the package name
missing = {}
# List of all repository problems
errors = [] errors = []
paks = scan_pspec(sys.argv[1])
for pak in paks:
spec = pisi.specfile.SpecFile()
try:
spec.read(os.path.join(pak, "pspec.xml"))
except Exception, inst:
errors.append([pak, str(inst)])
continue
try:
f = file(os.path.join(pak, "actions.py"))
L = len(f.readlines())
longpy.add(spec.source.name, L)
f.close()
except:
pass
nr_binpaks += len(spec.packages)
nr_patches += len(spec.source.patches)
mostpatched.add(spec.source.name, len(spec.source.patches))
releases.add(str(spec.source.release))
for p in spec.packages:
if p.partof:
components.add(p.partof)
for x in p.isa:
categories.add(x)
for x in p.paths:
types.add(x.fileType)
paknames[spec.source.name] = 1
add_deps(dependencies, spec)
name = spec.source.packager.name
lices = spec.source.license
people.add(name)
for lice in lices:
licenses.add(lice)
host = pisi.uri.URI(spec.source.archiveUri).location()
if host == "":
print pisi.uri.URI(spec.source.archiveUri)
hosts.add(host)
print "<html><head><title>%s İstatistikleri</title>" % (sys.argv[1]) class Missing:
print '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' def __init__(self, name):
echo("</head><body>") missing[name] = self
self.name = name
self.revBuildDeps = []
self.revRuntimeDeps = []
def report_html(self):
bDeps = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x), self.revBuildDeps)
rDeps = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x), self.revRuntimeDeps)
dict = {
"name": self.name,
"revBuildDeps": ", ".join(bDeps),
"revRuntimeDeps": ", ".join(rDeps)
}
template_write("paksite/package-%s.html" % self.name, "missing", dict)
print "<p>Toplam %d kod paketi, ve bunlardan oluşturulacak %d ikili paket var.</p>" % (len(paks), nr_binpaks)
echo(u"<p>Toplam peç sayısı %d</p>" % nr_patches)
mostpatched.html_out(5) class Package:
longpy.html_out(5) def __init__(self, source, pakspec):
name = pakspec.name
if packages.has_key(name):
errors.append(_("Duplicate binary packages:\n%s\n%s\n") % (
source.name, packages[name].source.name))
return
for p in pakspec.paths:
if p.fileType not in valid_filetypes:
e = _("Unknown file type '%s' in package '%s'") % (
p.fileType, source.name)
errors.append(e)
packages[name] = self
self.name = name
self.source = source
self.pakspec = pakspec
self.revBuildDeps = []
self.revRuntimeDeps = []
def markDeps(self):
# mark reverse build dependencies
for d in self.source.spec.source.buildDeps:
p = d.package
if packages.has_key(p):
packages[p].revBuildDeps.append(self.name)
else:
if not missing.has_key(p):
Missing(p)
missing[p].revBuildDeps.append(self.name)
# mark reverse runtime dependencies
for d in self.pakspec.runtimeDeps:
p = d.package
if packages.has_key(p):
packages[p].revRuntimeDeps.append(self.name)
else:
if not missing.has_key(p):
Missing(p)
missing[p].revRuntimeDeps.append(self.name)
def report(self):
source = self.source.spec.source
printu(_("Binary package: %s") % self.name)
printu(_(" Version %s release %s") % (source.version, source.release))
printu(_(" Packager: %s <%s>") % (
source.packager.name, source.packager.email))
printu(_(" Build dependencies:"))
for d in source.buildDeps:
printu(" %s" % d.package)
printu(_(" Runtime dependencies:"))
for d in self.pakspec.runtimeDeps:
printu(" %s" % d.package)
if self.revBuildDeps:
printu(_(" Reverse build dependencies:"))
for d in self.revBuildDeps:
printu(" %s" % d)
if self.revRuntimeDeps:
printu(_(" Reverse runtime dependencies:"))
for d in self.revRuntimeDeps:
printu(" %s" % d)
def report_html(self):
source = self.source.spec.source
bDeps = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x),
(map(lambda x: x.package, source.buildDeps)))
rDeps = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x),
(map(lambda x: x.package, self.pakspec.runtimeDeps)))
rbDeps = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x), self.revBuildDeps)
rrDeps = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x), self.revRuntimeDeps)
dict = {
"name": self.name,
"version": source.version,
"release": source.release,
"buildDeps": ", ".join(bDeps),
"runtimeDeps": ", ".join(rDeps),
"revBuildDeps": ", ".join(rbDeps),
"revRuntimeDeps": ", ".join(rrDeps)
}
template_write("paksite/package-%s.html" % self.name, "package", dict)
if errors != []:
print "<h1>Hatalar</h1><table>" class Source:
def __init__(self, path, spec):
name = spec.source.name
if sources.has_key(name):
errors.append(_("Duplicate source packages:\n%s\n%s\n") % (
path, sources[name].path))
return
sources[name] = self
self.spec = spec
self.name = name
self.path = path
for p in spec.packages:
Package(self, p)
self.checkRelease()
def checkRelease(self):
# FIXME: this check also belongs to specfile
prev = None
for h in self.spec.source.history:
if prev:
prev -= 1
if prev <= 0:
e = _("Source package '%s' has wrong release numbers") % self.name
errors.append(e)
return
if int(h.release) != prev:
e = _("Source package '%s' lacks release %d") % (self.name, prev)
errors.append(e)
return
else:
prev = int(h.release)
if prev != 1:
e = _("Source package '%s' has no first release") % self.name
errors.append(e)
def report_html(self):
source = self.spec.source
paks = map(lambda x: "<a href='package-%s.html'>%s</a>" % (x, x),
(map(lambda x: x.name, self.spec.packages)))
dict = {
"name": self.name,
"version": source.version,
"release": source.release,
"packages": ", ".join(paks)
}
template_write("paksite/source-%s.html" % self.name, "source", dict)
class Packager:
def __init__(self, spec):
name = spec.source.packager.name
email = spec.source.packager.email
if packagers.has_key(name):
if email != packagers[name].email:
e = _("Developer '%s <%s>' has another mail address '%s' in source package '%s'") % (
name, packagers[name].email, email, spec.source.name)
packagers[name].errors.append(e)
errors.append(e)
packagers[name].sources.append(spec.source.name)
else:
packagers[name] = self
self.name = name
self.email = email
self.sources = [spec.source.name]
self.errors = []
def report(self):
printu(_("Packager: %s <%s>") % (self.name, self.email))
if self.errors:
printu(_(" Errors:"))
for e in self.errors:
printu(" %s" % e)
printu(_(" Source packages (%d):") % len(self.sources))
for s in self.sources:
printu(" %s" % s)
def report_html(self):
srcs = map(lambda x: "<a href='source-%s.html'>%s</a>" % (x, x), self.sources)
dict = {
"name": self.name,
"email": self.email,
"sources": ", ".join(srcs)
}
template_write("paksite/%s.html" % self.name, "packager", dict)
class Repository:
def __init__(self, path):
self.path = path
self.nr_sources = 0
self.nr_packages = 0
self.nr_patches = 0
self.people = Histogram()
self.licenses = Histogram()
self.mostpatched = Histogram()
self.longpy = Histogram()
self.cscripts = Histogram()
def processPspec(self, path, spec):
# new classes
Packager(spec)
Source(path, spec)
# update global stats
self.nr_sources += 1
self.nr_packages += len(spec.packages)
self.nr_patches += len(spec.source.patches)
# update top fives
self.people.add(spec.source.packager.name)
for p in spec.packages:
for cs in p.providesComar:
self.cscripts.add(cs.om)
for L in spec.source.license:
self.licenses.add(L)
self.mostpatched.add(spec.source.name, len(spec.source.patches))
try:
f = file(os.path.join(path, "actions.py"))
L = len(f.readlines())
self.longpy.add(spec.source.name, L)
f.close()
except:
pass
def scan(self):
for pak in find_pspecs(self.path):
spec = pisi.specfile.SpecFile()
try:
spec.read(os.path.join(pak, "pspec.xml"))
except Exception, inst:
errors.append(_("Cannot parse '%s':\n%s\n") % (pak, inst.args[0]))
continue
self.processPspec(pak, spec)
for p in packages.values():
p.markDeps()
def report(self):
printu(_("Repository Statistics:"))
# general stats
printu(_(" Total of %d source packages, and %d binary packages.") % (
self.nr_sources, self.nr_packages))
printu(_(" There are %d patches applied.") % self.nr_patches)
# problems
if missing:
printu(_(" Missing packages (%d):") % len(missing))
for m in missing.values():
printu(" %s" % m.name)
# trivia
printu(_(" Top five most patched source:"))
for p in self.mostpatched.get_list(5):
printu(" %4d %s" % (p[1], p[0]))
printu(_(" Top five longest action.py scripts:"))
for p in self.longpy.get_list(5):
printu(" %4d %s" % (p[1], p[0]))
# lists
printu(_(" COMAR scripts:"))
for cs in self.cscripts.get_list():
printu(" %4d %s" % (cs[1], cs[0]))
people = self.people.get_list()
printu(_(" Packagers (%d):") % len(people))
for p in people:
printu(" %4d %s" % (p[1], p[0]))
licenses = self.licenses.get_list()
printu(_(" Licenses (%d):") % len(licenses))
for p in licenses:
printu(" %4d %s" % (p[1], p[0]))
def report_html(self):
miss = map(lambda x: "<tr><td><a href='package-%s.html'>%s</a></td></tr>" % (x, x), missing.keys())
people = self.people.get_list()
upeople = {}
for p in people:
upeople["<a href='./%s.html'>%s</a>" % (p[0], p[0])] = p[1]
if errors:
e = "<br>".join(errors)
else:
e = ""
dict = {
"nr_source": self.nr_sources,
"nr_packages": self.nr_packages,
"nr_patches": self.nr_patches,
"most_patched": template_table("table", self.mostpatched.get_list(5)),
"packagers": template_table("table", upeople.items()),
"missing": "\n".join(miss),
"errors": e
}
template_write("paksite/index.html", "repo", dict)
# command line driver
if len(sys.argv) < 2:
printu(_("Usage: repostats.py source-repo-path [ command [arg] ]"))
sys.exit(0)
repo = Repository(sys.argv[1])
printu(_("Scanning source repository..."))
repo.scan()
if errors:
printu("***")
printu(_("Encountered %d errors! Fix them immediately!") % len(errors))
for e in errors: for e in errors:
print "<tr><td>%s</td><td>%s</td></tr>" % (e[0], e[1]) printu(e)
print "</table>" printu("***")
else:
print "<p>Hata yok, tebrikler!</p>"
components.html_out() if len(sys.argv) > 2:
categories.html_out() if sys.argv[2] == "packager":
people.html_out() if len(sys.argv) > 3:
licenses.html_out() packagers[unicode(sys.argv[3].decode('utf-8'))].report()
releases.html_out() sys.exit(0)
types.html_out() else:
for p in packagers.values():
printu(_("%s <%s>, %s source package") % (p.name, p.email, len(p.sources)))
sys.exit(0)
elif sys.argv[2] == "package":
if len(sys.argv) > 3:
packages[unicode(sys.argv[3].decode('utf-8'))].report()
sys.exit(0)
else:
printu(_("Which package?"))
sys.exit(0)
elif sys.argv[2] == "html":
try:
os.mkdir("paksite")
except:
pass
repo.report_html()
for p in packagers.values():
p.report_html()
for p in missing.values():
p.report_html()
for p in packages.values():
p.report_html()
for p in sources.values():
p.report_html()
sys.exit(0)
echo(_("<h1>Dependencies<br>")) repo.report()
echo(_("<small>package name with italics are not available in the repository</small></h1>"))
print "<table>"
notavail = 0
for name,cnt in dependencies.get_list():
if paknames.has_key(name):
print "<tr><td><b>%s</b></td><td>%d</td></tr>" % (name, cnt)
else:
notavail += 1
print "<tr><td><i>%s</i></td><td>%d</td></tr>" % (name, cnt)
print "</table>"
print "<p>%d packages are not available in repository.</p>" % notavail
hosts.html_out()
print "</body>"