#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright (C) 2005-2007, TUBITAK/UEKAE # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # import sys import os import codecs import re import getopt import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext from svn import core, client sys.path.append('.') import pisi.specfile import pisi.uri import pisi.package import pisi.metadata import pisi.files from pisi.cli import printu # Main HTML template html_header = """ %(title)s

%(title)s

%(content)s
""" css_template = """ body { margin-left:0; margin-top:0; margin-right:0; background-image:url('http://www.pardus.org.tr/styles/images/HeadTile.png'); background-repeat:repeat-x; background-color: #FFF; } #header-bugzilla { background-image:url('http://www.pardus.org.tr/styles/images/HeadLogo.png'); background-repeat:no-repeat; background-position: 0px 0px; height:119px; padding-bottom:5px; } a { color: #F55400; text-decoration: none; } a:hover { color: #444; background-color:#EEE; } .menu { padding-left: 1em; padding-top: 3px; padding-bottom: 3px; border-bottom: 1px solid #CCC; border-top: 1px solid #CCC; } .content { margin: 0.5em; } """ # default html templates (now obsolete) def_repo_sizes_html = u"""

Boyutlar

Toplam kurulu boyut %(total)s

Dosya tiplerine göre liste:

%(sizes)s
""" def svn_uri(path): # init core.apr_initialize() pool = core.svn_pool_create(None) core.svn_config_ensure(None, pool) # get commit date uri = client.svn_client_url_from_path(path, pool) # cleanup core.svn_pool_destroy(pool) core.apr_terminate() return uri 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 write_html(filename, title, content): f = codecs.open(filename, "w", "utf-8") root = "./" if len(filename.split("/")) > 2: root = "../" dict = { "title": title, "content": content, "root": root, } f.write(html_header % dict) f.close() def make_table(elements, titles=None): def make_row(element): return "%s" % "".join(map(str, element)) title_html = "" if titles: title_html = """ %s """ % "".join(titles) html = """ %s%s
""" % (title_html, "".join(map(make_row, elements))) return html def make_url(name, path="./"): if not path.endswith("/"): path += "/" return "%s" % (path, name, name) def mangle_email(email): return re.sub("@", " [at] ", email) class Histogram: def __init__(self): self.list = {} def add(self, name, value=None): if value: self.list[name] = value else: self.list[name] = self.list.get(name, 0) + 1 def note(self, name): if not self.list.has_key(name): self.list[name] = 0 def get_list(self, max=0): items = self.list.items() items.sort(key=lambda x: x[1], reverse=True) if max != 0: return items[:max] else: return items # Dictionary of all source packages keyed by the source name sources = {} # Dictionary of all binary packages keyed by the package name packages = {} # Dictionary of all packagers keyed by the packager name packagers = {} # Dictionary of missing depended binary packages keyed by the package name missing = {} # List of all repository problems errors = [] class Missing: def __init__(self, name): missing[name] = self self.name = name self.revBuildDeps = [] self.revRuntimeDeps = [] class Package: 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 packages[name] = self self.name = name self.source = source self.pakspec = pakspec self.revBuildDeps = [] self.revRuntimeDeps = [] self.installedSize = 0 def markDeps(self): # mark reverse build dependencies for d in self.source.spec.source.buildDependencies: 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.packageDependencies: 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_html(self): source = self.source.spec.source bDeps = map(lambda x: "%s" % (x, x), (map(lambda x: x.package, source.buildDependencies))) rDeps = map(lambda x: "%s" % (x, x), (map(lambda x: x.package, self.pakspec.packageDependencies))) rbDeps = map(lambda x: "%s" % (x, x), self.revBuildDeps) rrDeps = map(lambda x: "%s" % (x, x), self.revRuntimeDeps) html = """

İkili paket: %s

Kaynak versiyon %s, depo sürümü %s

Kaynak paket: %s

Derlemek için gerekenler:

%s

Çalıştırmak için gerekenler:

%s

Bağımlı paketler (derlenmek için):

%s

Bağımlı paketler (çalışmak için):

%s

""" % ( self.name, self.source.spec.getSourceVersion(), self.source.spec.getSourceRelease(), make_url(source.name, "../source/"), ", ".join(bDeps), ", ".join(rDeps), ", ".join(rbDeps), ", ".join(rrDeps), ) write_html("paksite/binary/%s.html" % self.name, self.name, html) 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 self.uri = svn_uri(path) for p in spec.packages: Package(self, p) def report_html(self): source = self.spec.source paks = map(lambda x: "%s" % (x, x), (map(lambda x: x.name, self.spec.packages))) histdata = map(lambda x: (x.release, x.date, x.version, make_url(x.name, "../packager/"), x.comment), self.spec.history) ptch = map(lambda x: "%s" % (self.uri, x.filename, x.filename), source.patches) titles = "Sürüm", "Sürüm Tarihi", "Versiyon", "Güncelleyen", "Açıklama" hist = make_table(histdata, titles) html = """

Kaynak paket: %s

Kaynak versiyon %s, depo sürümü %s

%s

Açıklama

%s

Lisanslar:

%s

İşlemler:

Paket dosyalarına bak

Hata kayıtlarına bak

Bu kaynaktan derlenen ikili paketler:

%s

Tarihçe

%s

Yamalar

%s """ % ( self.name, self.spec.getSourceVersion(), self.spec.getSourceRelease(), source.homepage, source.homepage, source.summary, ", ".join(source.license), self.uri, self.name, "
".join(paks), "".join(hist), "
".join(ptch), ) write_html("paksite/source/%s.html" % self.name, self.name, html) class Packager: def __init__(self, spec, update=None): if update: name = update.name email = update.email else: 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) if update: packagers[name].updates.append((spec.source.name, update.release, update.comment)) else: packagers[name].sources.append(spec.source.name) else: packagers[name] = self self.name = name self.email = email if update: self.sources = [] self.updates = [(spec.source.name, update.release, update.comment)] else: self.sources = [spec.source.name] self.updates = [] self.errors = [] if not update: for update in spec.history: Packager(spec, update) def report_html(self): srcs = map(lambda x: ("%s" % (x, x), ), self.sources) srcs.sort() upds = map(lambda x: (u"%s (%s)
%s
" % ( x[0], x[0], x[1], x[2]), ), self.updates) html = """

Paketçi: %s (%s)

""" % (self.name, mangle_email(self.email)) html += """

Sahip olduğu paketler:

%s

""" % make_table(srcs) html += """

Yaptığı güncellemeler:

%s

""" % make_table(upds) write_html("paksite/packager/%s.html" % self.name, self.name, html) 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() self.total_installed_size = 0 self.installed_sizes = {} 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 u in spec.history: self.people.note(u.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 processPisi(self, path): p = pisi.package.Package(path) p.extract_files(["metadata.xml", "files.xml"], ".") md = pisi.metadata.MetaData() md.read("metadata.xml") self.total_installed_size += md.package.installedSize if packages.has_key(md.package.name): # FIXME: check version/release match too? packages[md.package.name].installed_size = md.package.installedSize else: printu("Binary package '%s' has no source package in repository %s\n" % (path, self.path)) fd = pisi.files.Files() fd.read("files.xml") for f in fd.list: if self.installed_sizes.has_key(f.type): # Emtpy directories and symlinks has None size if not f.size is None: self.installed_sizes[f.type] += int(f.size) else: self.installed_sizes[f.type] = int(f.size) def scan_bins(self, binpath): for root, dirs, files in os.walk(binpath): for fn in files: if fn.endswith(".pisi"): self.processPisi(os.path.join(root, fn)) def report_html(self): table = ( ("Kaynak paket sayısı", self.nr_sources), ("İkili paket sayısı", self.nr_packages), ("Yama sayısı", self.nr_patches), ("Paketçi sayısı", len(self.people.list)), ) html = make_table(table) html += """

En fazla yamalanmış beş kaynak paket:

%s

""" % make_table(map(lambda x: (make_url(x[0], "./source/"), x[1]), self.mostpatched.get_list(5))) html += """

En uzun inşa betikli beş kaynak paket:

%s

""" % make_table(map(lambda x: (make_url(x[0], "./source/"), x[1]), self.longpy.get_list(5))) write_html("paksite/index.html", "Genel Bilgiler", html) titles = ( "Paketçi", "Paket sayısı" ) people = self.people.get_list() people = map(lambda x: ("%s" % (x[0], x[0]), x[1]), people) write_html("paksite/packagers.html", "Paketçiler (paket sayısına göre)", make_table(people, titles)) people.sort(key=lambda x: x[0]) write_html("paksite/packagers_by_name.html", "Paketçiler (isme göre)", make_table(people, titles)) titles = "Paket adı", "Versiyon", "Açıklama" srclist = map(lambda x: (make_url(x.name, "source/"), x.spec.getSourceVersion(), x.spec.source.summary), sources.values()) srclist.sort(key=lambda x: x[0]) html = make_table(srclist, titles) write_html("paksite/sources.html", "Kaynak Paketler", html) binlist = map(lambda x: (make_url(x.name, "binary/"), x.source.spec.getSourceVersion(), x.source.spec.source.summary), packages.values()) binlist.sort(key=lambda x: x[0]) html = make_table(binlist, titles) write_html("paksite/binaries.html", "İkili Paketler", html) # command line driver def usage(): printu(_("Usage: repostats.py [OPTIONS] source-repo-path [binary-repo-path]\n")) printu(" -t, --test-only: %s" % _("Dont generate the web site.\n")) sys.exit(0) if __name__ == "__main__": try: opts, args = getopt.gnu_getopt(sys.argv[1:], "ht", ["help", "test-only"]) except: usage() if args == []: usage() do_web = True for o, v in opts: if o in ("-h", "--help"): usage() if o in ("-t", "--test-only"): do_web = False repo = Repository(args[0]) printu(_("Scanning source repository...\n")) repo.scan() if len(args) > 1: printu(_("Scanning binary packages...\n")) repo.scan_bins(args[1]) if do_web: if not os.path.exists("paksite/packager"): os.makedirs("paksite/packager") if not os.path.exists("paksite/binary"): os.makedirs("paksite/binary") if not os.path.exists("paksite/source"): os.makedirs("paksite/source") file("paksite/stil.css", "w").write(css_template) repo.report_html() for p in packagers.values(): p.report_html() for p in packages.values(): p.report_html() for p in sources.values(): p.report_html()