#!/usr/bin/env python # -*- mode: python; coding: utf-8 -*- # Copyright © 2001, 2002, 2007 Translation Project. # Copyright © 2000 Progiciels Bourbeau-Pinard inc. # François Pinard , 2000. """\ Adjust the database holding PO and POT file statistics. Usage: calc-postats [-dituv] [POFILE]... [POTFILE]... -d delete entries for which the PO file no longer exists -i re-initialise the whole database (takes very long) -t re-initialise just the POT statistics -u update the database with new or changed PO files -v show what's being done """ import os, sys, stat import getopt, re, UserDict import logging sys.path.insert(0, sys.path[0]+'/../lib') import config, data, po, registry def main(*arguments): initialize = template = delete = update = verbose = 0 options, arguments = getopt.getopt(arguments, 'dituv') if not arguments and not options: sys.stdout.write(__doc__) sys.exit(2) for option, value in options: if option == '-d': delete = 1 elif option == '-i': initialize = template = 1 elif option == '-t': template = 1 elif option == '-u': update = 1 elif option == '-v': verbose += 1 if initialize and update: print "*** Option -u does not make sense together with -i" sys.exit(2) if initialize and delete: print "*** Option -d does not make sense together with -i" sys.exit(2) if (initialize or template or update) and arguments: print "*** Arguments are not allowed when initializing or updating" sys.exit(2) if verbose: print "Loading statistics file..." if initialize: postats = UserDict.UserDict() else: try: postats = data.load_postats() except: # Failed to load old data; start from scratch. postats = UserDict.UserDict() initialize = 1 if initialize or update: if verbose: print "Walking..." os.path.walk('%s' % config.pos_path, walker, (postats, verbose)) if delete: if verbose: print "Checking for deletions..." for key in postats.keys(): domain, version, team = key try: name = registry.archive_path(domain, version, team) except KeyError: sys.stderr.write(' unknown - %s-%s.%s.po\n' % (domain, version, team)) del postats[key] continue if not os.path.exists(name): if verbose: sys.stderr.write(' deleted - %s\n' % name) del postats[key] if template: regenerate_potstats(postats, verbose) for name in arguments: # Ignore given path, as file must be in archive, # otherwise calculating stats makes no sense. name = os.path.basename(name) if os.path.splitext(name)[1] == '.po': tally_po(postats, name, verbose) elif os.path.splitext(name)[1] == '.pot': tally_POT(postats, name, verbose) else: print "*** Not a message file:", name if verbose: print "Saving statistics file..." data.save_postats(postats) def walker((postats, verbose), dirname, bases): if verbose: bases.sort() for base in bases: if os.path.splitext(base)[1] == '.po': tally_po(postats, base, verbose) elif not os.path.isdir('%s/%s' % (dirname, base)): print "*** Spurious file: %s/%s" % (dirname, base) def tally_po(postats, name, verbose): # The file name should be just the basename. try: hints = registry.hints(name) except: print "*** Not recognized:", name return if hints.domain and hints.version and hints.team: key = hints.domain.name, hints.version.name, hints.team.name fullname = hints.archive_path() if not os.path.exists(fullname): print "*** File not in archive:", fullname return mtime = os.stat(fullname)[stat.ST_MTIME] oldstats = postats.get(key) if oldstats: try: oldmtime = oldstats[6] except IndexError: pass else: if oldmtime == mtime: if verbose > 1: sys.stderr.write(" same - %s\n" % fullname) return 0 if verbose: if oldstats: sys.stderr.write(" update - %s..." % fullname) else: sys.stderr.write(" new - %s..." % fullname) try: entries = po.read(fullname) except IOError: print "*** Unreadable file:", fullname return 0 header = po.header(entries) translator, mailto = header['last-translator'], None match = re.search('(.*[^ ]) <(.*)>', translator) if match: translator, mailto = match.group(1, 2) try: unicode(translator,"ascii") except UnicodeError: charset = None for f in header['content-type'].split(";"): f = f.strip() if f.startswith("charset="): charset = f[8:] if charset: translator = unicode(translator, charset).encode("utf-8") stats = po.stats(entries) total = stats['translated'] + stats['untranslated'] + stats['fuzzy'] postats[key] = (translator, mailto, stats['translated'], total, stats['translated_length'], stats['total_length'], mtime, stats['date']) if verbose: sys.stderr.write(" %d / %d\n" % (stats['translated'], total)) return 1 else: print "*** Not enough hints:", name return 0 def regenerate_potstats(postats, verbose): versions = {} for file in os.listdir('%s' % config.pots_path): try: hints = registry.hints(file) except ValueError: print "*** Bad filename:", file continue except KeyError: print "*** Unregistered package:", file continue try: hints.version.set_sort_key() except AssertionError: logging.exception("*** Unsortable version: %s", file) continue try: oldver = versions[hints.domain.name][0] except KeyError: versions[hints.domain.name] = hints.version, file continue if hints.version > oldver: versions[hints.domain.name] = hints.version, file postats.potstats = {} for domain, (version, file) in versions.items(): calculate(postats, domain, version, file, verbose) def tally_POT(postats, file, verbose): # The file name should be just the basename. try: hints = registry.hints(file) except ValueError: print "*** Bad filename:", file return except KeyError: print "*** Unregistered package:", file return try: hints.version.set_sort_key() except AssertionError: logging.exception("*** Unsortable version: %s", file) return try: oldfile = postats.potstats[hints.domain.name][0] oldhints = registry.hints(oldfile) except: pass else: if hints.version < oldhints.version: if verbose: sys.stderr.write(" skipping old - %s\n" % file) return if not os.path.exists(hints.template_path()): print "*** File not in archive:", hints.template_path() return calculate(postats, hints.domain.name, hints.version, file, verbose) def calculate(postats, domain, version, file, verbose): if verbose: sys.stderr.write(" recounting - %s... " % file) entries = po.read('%s/%s' % (config.pots_path, file)) stats = po.stats(entries) assert stats['fuzzy'] == 0, file if not domain == "aegis": # aegis.pot has translations assert stats['translated'] == 0, file postats.potstats[domain] = (file, stats['untranslated'], stats['date']) if verbose: sys.stderr.write("%d\n" % stats['untranslated']) if __name__ == '__main__': apply(main, tuple(sys.argv[1:]))