diff --git a/TODO b/TODO index 128fe0d7..1a4d194d 100644 --- a/TODO +++ b/TODO @@ -75,7 +75,6 @@ Legend: * high priority - / configure-pending (eray) / i18n support - summary,description için doğru dili kullanmak / pisi mesajlarının çevrilebilir hale getirilmesi (build.py yi örnek alın) @@ -99,6 +98,7 @@ Legend: + ask alternatives to choose from (eray) + eliminate \n's from infos, what's the point? + metaclass coolness for CLI command framework (eray) + + configure-pending (eray) + ignore-deps + more robust upgrade diff --git a/pisi/comariface.py b/pisi/comariface.py index 43d71012..f3d3abd6 100644 --- a/pisi/comariface.py +++ b/pisi/comariface.py @@ -18,8 +18,12 @@ import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext +import pisi import pisi.context as ctx +class Error(pisi.Error): + pass + def run_postinstall(package_name): "run postinstall scripts trough COMAR" @@ -34,11 +38,11 @@ def run_postinstall(package_name): elif reply[0] == com.NONE: # package has no postInstall script break elif reply[0] == com.FAIL: - e = _("COMAR.call_package(System.Pakcage.postInstall, %s) failed!: %s") % ( + e = _("COMAR.call_package(System.Package.postInstall, %s) failed!: %s") % ( self.metadata.package.name, reply[2]) - raise InstallError, e + raise Error, e else: - raise InstallError, _("COMAR.call_package ERROR: %d") % reply[0] + raise Error, _("COMAR.call_package ERROR: %d") % reply[0] def run_preremove(package_name): com = ctx.comard diff --git a/pisi/install.py b/pisi/install.py index 2d1b665b..b9c0e40c 100644 --- a/pisi/install.py +++ b/pisi/install.py @@ -32,7 +32,7 @@ from pisi.metadata import MetaData import pisi.comariface as comariface #import conflicts -class InstallError(pisi.Error): +class Error(pisi.Error): pass class Installer: @@ -48,7 +48,7 @@ class Installer: def install(self, ask_reinstall = True): "entry point" - ctx.ui.info('Installing %s, version %s, release %s, build %s' % + ctx.ui.info(_('Installing %s, version %s, release %s, build %s') % (self.pkginfo.name, self.pkginfo.version, self.pkginfo.release, self.pkginfo.build)) self.ask_reinstall = ask_reinstall @@ -78,14 +78,14 @@ class Installer: # check conflicts for pkg in self.metadata.package.conflicts: if ctx.installdb.is_installed(self.pkginfo): - raise InstallError("Package conflicts " + pkg) + raise Error(_("Package conflicts %s") % pkg) # check dependencies if not ctx.config.get_option('ignore_dependency'): if not dependency.installable(self.pkginfo.name): ctx.ui.error(_('Dependencies for %s not satisfied') % self.pkginfo.name) - raise InstallError(_("Package not installable")) + raise Error(_("Package not installable")) def check_reinstall(self): "check reinstall, confirm action, and schedule reinstall" @@ -110,7 +110,7 @@ class Installer: if same_ver: if self.ask_reinstall: if not ctx.ui.confirm(_('Re-install same version package?')): - raise InstallError(_('Package re-install declined')) + raise Error(_('Package re-install declined')) else: upgrade = False # is this an upgrade? @@ -135,7 +135,7 @@ class Installer: else: x = _('Downgrade to old distribution build?') if not ctx.ui.confirm(x): - raise InstallError(_('Package downgrade declined')) + raise Error(_('Package downgrade declined')) # schedule for reinstall self.old_files = ctx.installdb.files(pkg.name) @@ -193,7 +193,7 @@ class Installer: if reply[0] == com.RESULT: break else: - raise InstallError, _("COMAR.register ERROR!") + raise Error, _("COMAR.register ERROR!") def update_databases(self): diff --git a/pisi/lockeddbshelve.py b/pisi/lockeddbshelve.py index 6d4c1832..8d8bd306 100644 --- a/pisi/lockeddbshelve.py +++ b/pisi/lockeddbshelve.py @@ -9,7 +9,6 @@ # # Please read the COPYING file. # -# A simple wrapper to implement locking for bsddb's dbshelf # # Authors: Eray Ozkural @@ -19,10 +18,18 @@ import bsddb.db as db import os import fcntl +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + import pisi import pisi.context +class Error(pisi.Error): + pass + class LockedDBShelf(shelve.DBShelf): + """A simple wrapper to implement locking for bsddb's dbshelf""" def __init__(self, dbname, flags=db.DB_CREATE, mode=0660, filetype=db.DB_HASH, dbenv=None): @@ -40,7 +47,7 @@ class LockedDBShelf(shelve.DBShelf): elif sflag == 'n': flags = db.DB_TRUNCATE | db.DB_CREATE else: - raise error, "flags should be one of 'r', 'w', 'c' or 'n' or use the bsddb.db.DB_* flags" + raise Error, _("Flags should be one of 'r', 'w', 'c' or 'n' or use the bsddb.db.DB_* flags") filename = os.path.join( pisi.context.config.db_dir(), dbname + '.bdb') self.open(filename, dbname, filetype, flags, mode) @@ -51,7 +58,7 @@ class LockedDBShelf(shelve.DBShelf): fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: import sys - pisi.context.ui.error("Another instance of PISI is running. Try later!") + pisi.context.ui.error(_("Another instance of PISI is running. Try later!")) sys.exit(1) return self.db.open(filename, dbname, filetype, flags, mode) diff --git a/pisi/metadata.py b/pisi/metadata.py index 6aa2bdcb..067041d1 100644 --- a/pisi/metadata.py +++ b/pisi/metadata.py @@ -7,15 +7,20 @@ # # Please read the COPYING file. # - -# Metadata module provides access to metadata.xml. metadata.xml is -# generated during the build process of a package and used in the -# installation. Package repository also uses metadata.xml for building -# a package index. - # Authors: Eray Ozkural # Baris Metin -# we basically store everything in sourceinfo class -# yes, we are cheap +""" +package source database +interface for update/query to local package repository +we basically store everything in sourceinfo class +yes, we are cheap +""" import bsddb.dbshelve as shelve import os import fcntl from bsddb import db +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + import pisi.util as util import pisi.context as ctx @@ -49,9 +53,7 @@ class SourceDB(object): return self.d[name] def add_source(self, source_info): - # FIXME: how can you make a negative assertion -gurer - # and yes i'm not very clever :) - # assert source_info.has_errors() + assert not source_info.has_errors() name = str(source_info.name) self.d[name] = source_info diff --git a/pisi/sourcefetcher.py b/pisi/sourcefetcher.py index d9314651..432da801 100644 --- a/pisi/sourcefetcher.py +++ b/pisi/sourcefetcher.py @@ -12,6 +12,10 @@ from os.path import basename, dirname, join +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + import pisi.context as ctx from pisi.uri import URI from pisi.specfile import SpecFile @@ -74,7 +78,7 @@ class SourceFetcher(object): def fetch(self, appendDest=""): from fetcher import fetch_url - ctx.ui.info("Fetching %s" % self.url.uri) + ctx.ui.info(_("Fetching %s") % self.url.uri) dest = join(self.dest, appendDest) fetch_url(self.url, dest) diff --git a/pisi/specfile.py b/pisi/specfile.py index afc38893..710108a7 100644 --- a/pisi/specfile.py +++ b/pisi/specfile.py @@ -18,13 +18,19 @@ # with Gurer's observations. -"""Specfile module is our handler for PSPEC files. PSPEC (PISI SPEC) +""" +Specfile module is our handler for PSPEC files. PSPEC (PISI SPEC) files are specification files for PISI source packages. This module -provides read and write access to PSPEC files.""" +provides read and write access to PSPEC files. +""" # standard python modules from os.path import basename +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + # pisi modules import pisi from pisi.xmlext import * @@ -77,9 +83,9 @@ class AdditionalFileInfo: def has_errors(self): err = Checks() if not self.filename: - err.add("AdditionalFile should have file name string") + err.add(_("AdditionalFile should have file name string")) if not self.target: - err.add("AdditionalFile should have a target attribute") + err.add(_("AdditionalFile should have a target attribute")) return err.list def __str__(self): @@ -116,7 +122,7 @@ class PatchInfo: def has_errors(self): if not self.filename: - return [ "Patch should have a filename string" ] + return [ _("Patch should have a filename string") ] return None def __str__(self): @@ -175,7 +181,7 @@ class PathInfo: def has_errors(self): if not self.pathname: - return [ "Path tag should have a name string" ] + return [ _("Path tag should have a name string") ] return None def __str__(self): @@ -197,7 +203,7 @@ class ComarProvide: def has_errors(self): if not self.om or not self.script: - return [ "COMAR provide should have something :)" ] + return [ _("COMAR provide should have something :)") ] return None def __str__(self): @@ -267,11 +273,11 @@ class SourceInfo: err.has_tag(self.packager, "Source", "Packager") err.has_tag(self.license, "Source", "License") if (not self.archiveUri) or (not self.archiveType): - err.add("Source archive URI and type should be given") + err.add(_("Source archive URI and type should be given")) if not self.archiveSHA1: - errd.add("Source archive should have a SHA1 sum") + errd.add(_("Source archive should have a SHA1 sum")) if len(self.history) <= 0: - err.add("Source needs some education about History :)") + err.add(_("Source needs some education in History :)")) err.join(self.packager.has_errors()) for update in self.history: @@ -347,7 +353,7 @@ class PackageInfo: err.has_tag(self.description, "Package", "Description") err.has_tag(self.license, "Package", "License") if len(self.paths) <= 0: - err.add("Package should have some files") + err.add(_("Package should have some files")) for path in self.paths: err.join(path.has_errors()) @@ -404,7 +410,7 @@ class SpecFile(XmlFile): e = "" for x in errs: e += x + "\n" - raise XmlError("File '%s' has errors:\n%s" % (filename, e)) + raise XmlError(_("File '%s' has errors:\n%s") % (filename, e)) def override_tags(self): """Override tags from Source in Packages. Some tags in Packages @@ -457,7 +463,7 @@ class SpecFile(XmlFile): err = Checks() err.join(self.source.has_errors()) if len(self.packages) <= 0: - errs.add("There should be at least one Package section") + errs.add(_("There should be at least one Package section")) for p in self.packages: err.join(p.has_errors()) return err.list diff --git a/pisi/uri.py b/pisi/uri.py index a9ac0589..37ef9ebc 100644 --- a/pisi/uri.py +++ b/pisi/uri.py @@ -13,6 +13,10 @@ from urlparse import urlparse from os.path import basename +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + import pisi.util as util class URI(object): @@ -69,7 +73,7 @@ class URI(object): def set_auth_info(self, authTuple): if not isinstance(authTuple, tuple): - raise Exception, "setAuthInfo needs a tuple (user, pass)" + raise Exception, _("setAuthInfo needs a tuple (user, pass)") self.__authinfo = authTuple def auth_info(self): diff --git a/pisi/util.py b/pisi/util.py index 5518e419..b4215d88 100644 --- a/pisi/util.py +++ b/pisi/util.py @@ -24,14 +24,18 @@ import sha import shutil import statvfs +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + # pisi modules import pisi import pisi.context as ctx -class FileError(pisi.Error): +class Error(pisi.Error): pass -class UtilError(pisi.Error): +class FileError(Error): pass @@ -58,7 +62,7 @@ class Checks: if not var: if not self.list: self.list = [] - self.list.append("%s section should have a '%s' tag" % (section, name)) + self.list.append(_("%s section should have a '%s' tag") % (section, name)) ######################### @@ -115,17 +119,16 @@ def remove_prefix(a,b): def run_batch(cmd): """run command non-interactively and report return value and output""" - ui.info('running ' + cmd) + ui.info(_('running ') + cmd) a = os.popen(cmd) lines = a.readlines() ret = a.close() - ui.debug('return value ' + ret) + ui.debug(_('return value ') + ret) successful = ret == None if not successful: - ui.error('ERROR: executing command: ' + cmd + '\n' + strlist(lines)) + ui.error(_('Failed command: %s') % cmd + strlist(lines)) return (successful,lines) - def xterm_title(message): """sets message as a console window's title""" if os.environ.has_key("TERM") and sys.stderr.isatty(): @@ -230,7 +233,7 @@ def copy_file(src,dest): def get_file_hashes(top, exclude_prefix=None, removePrefix=None): """Generator function iterates over a toplevel path and returns the - (filePath, sha1Hash) tuple for all files. If excludePrefixes list + (filePath, sha1Hash) tuples for all files. If excludePrefixes list is given as a parameter, function will exclude the filePaths matching those prefixes. The removePrefix string parameter will be used to remove prefix from filePath while matching excludes, if @@ -346,8 +349,8 @@ def do_patch(sourceDir, patchFile, level, target = ''): o = p.readlines() retval = p.close() if retval: - raise UtilError("ERROR: patch (%s) failed: %s" % (patchFile, - strlist (o))) + raise Error(_("ERROR: patch (%s) failed: %s") % (patchFile, + strlist (o))) os.chdir(cwd) @@ -379,7 +382,7 @@ def strip_file(filepath): p = os.popen("strip %s %s" %(flags, f)) ret = p.close() if ret: - ctx.ui.warning("strip command failed for file '%s'!" % f) + ctx.ui.warning(_("strip command failed for file '%s'!") % f) if "current ar archive" in o: run_strip(filepath, "-g") @@ -406,7 +409,7 @@ def clean_locks(top = '.'): for fn in files: if fn.endswith('.lock'): path = os.path.join(root, fn) - ctx.ui.info('Removing lock %s', path) + ctx.ui.info(_('Removing lock %s'), path) os.unlink(path) ######################################## diff --git a/pisi/version.py b/pisi/version.py index 263b6a2f..e0974114 100644 --- a/pisi/version.py +++ b/pisi/version.py @@ -17,7 +17,6 @@ import re import pisi.util as util - # Basic rule is: # p > (no suffix) > rc > pre > beta > alpha keywords = {"alpha": 0, @@ -35,7 +34,6 @@ def has_keyword(versionitem): return False - class VersionItem: _keyword = "NOKEY" _value = 0 @@ -157,5 +155,3 @@ class Version: def __ge__(self,rhs): return self.pred(rhs, lambda x,y: x>=y) - - diff --git a/pisi/xmlext.py b/pisi/xmlext.py index f8262164..97819846 100644 --- a/pisi/xmlext.py +++ b/pisi/xmlext.py @@ -18,6 +18,10 @@ an old library """ +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + import pisi class XmlError(pisi.Error): @@ -50,7 +54,7 @@ def getNodeText(node, tagpath = ""): # in any case, strip whitespaces... return child.data.strip() else: - raise XmlError("getNodeText: Expected text node, got something else!") + raise XmlError(_("getNodeText: Expected text node, got something else!")) def getChildText(node_s, tagpath): """get the text of a child at the end of a tag path""" diff --git a/pisi/xmlfile.py b/pisi/xmlfile.py index 7e504118..fbcd77f4 100644 --- a/pisi/xmlfile.py +++ b/pisi/xmlfile.py @@ -73,27 +73,19 @@ class LocalText(object): nodes = getAllNodes(node, self.tag) if not nodes: if self.req == mandatory: - errs.append("LocalText '%s' should have at least one '%s' tag\n" % + errs.append(_("LocalText '%s' should have at least one '%s' tag\n") % self.tag) else: for node in nodes: lang = getNodeAttribute(node, "xml:lang") c = getNodeText(node) if not c: - errs.append("'%s' language of tag '%s' should have some text data\n" % + errs.append(_("'%s' language of tag '%s' should have some text data\n") % (lang, self.tag)) # FIXME: check for dups and 'en' if not lang: lang = 'en' self.locs[lang] = c - # FIXME: return full list too - #L = language - #if not self.locs.has_key(L): - # L = 'en' - #if not self.locs.has_key(L): - # #errs.append("Tag '%s' should have an English version\n" % d[2]) - # return "" - #retur def encode(self, xml, node, errs): for key in self.locs.iterkeys(): @@ -105,6 +97,15 @@ class LocalText(object): def format(self, errs): return '' + + # FIXME: use something like the below to return a default + #L = language + #if not self.locs.has_key(L): + # L = 'en' + #if not self.locs.has_key(L): + # #errs.append("Tag '%s' should have an English version\n" % d[2]) + # return "" + #retur class autoxml(type): """High-level automatic XML transformation interface for xmlfile. @@ -283,7 +284,7 @@ class autoxml(type): elif type(tag_type) is autoxml or type(tag_type) is types.TypeType: return cls.gen_class_tag(tag, spec) else: - raise Error('gen_tag: unrecognized tag type %s in spec' % + raise Error(_('gen_tag: unrecognized tag type %s in spec') % str(tag_type)) def gen_named_comp(cls, token, spec, anonfuns): @@ -316,7 +317,7 @@ class autoxml(type): return '%s: %s\n' % (token, format_a(value, errs)) else: if req == mandatory: - raise Error('Mandatory variable %s not available' % name) + raise Error(_('Mandatory variable %s not available') % name) return '' return (init, decode, encode, format) @@ -371,11 +372,11 @@ class autoxml(type): value = autoxml.basic_cons_map[token_type](text) except Error: value = None - errs.append('Type mismatch: read text cannot be decoded') + errs.append(_('Type mismatch: read text cannot be decoded')) return value else: if req == mandatory: - errs.append('Mandatory token %s not available' % token) + errs.append(_('Mandatory token %s not available') % token) return None def encode(xml, node, value, errs): @@ -384,7 +385,7 @@ class autoxml(type): writetext(xml, node, token, str(value)) else: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) def format(value, errs): """format value for pretty printing""" @@ -412,10 +413,10 @@ class autoxml(type): obj.decode(node, errs) return obj except Error: - errs.append('Type mismatch: DOM cannot be decoded') + errs.append(_('Type mismatch: DOM cannot be decoded')) else: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) return None def encode(xml, node, obj, errs): @@ -428,17 +429,17 @@ class autoxml(type): except Error: if req == mandatory: # note: we can receive an error if obj has no content - errs.append('Object cannot be encoded') + errs.append(_('Object cannot be encoded')) else: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) def format(obj, errs): try: return obj.format(errs) except Error: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) else: return '' return (init, decode, encode, format) @@ -449,7 +450,7 @@ class autoxml(type): #head, last = cls.tagpath_head_last(path) if len(tag_type) != 1: - raise Error('List type must contain only one element') + raise Error(_('List type must contain only one element')) x = cls.gen_tag(comp_tag, [tag_type[0], mandatory]) (init_item, decode_item, encode_item, format_item) = x @@ -462,7 +463,7 @@ class autoxml(type): nodes = getAllNodes(node, tag + '/' + comp_tag) #print node, tag + '/' + comp_tag, nodes if len(nodes) is 0 and req is mandatory: - errs.append('Mandatory list empty') + errs.append(_('Mandatory list empty')) for node in nodes: dummy = node.ownerDocument.createElement("Dummy") dummy.appendChild(node) @@ -477,7 +478,7 @@ class autoxml(type): node.appendChild(listnode) else: if req is mandatory: - errs.append('Mandatory list empty') + errs.append(_('Mandatory list empty')) def format(l, errs): #print 'format:', name @@ -513,10 +514,10 @@ class autoxml(type): obj.decode(node, errs) return obj except Error: - errs.append('Type mismatch: DOM cannot be decoded') + errs.append(_('Type mismatch: DOM cannot be decoded')) else: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) return None def encode(xml, node, obj, errs): @@ -527,17 +528,17 @@ class autoxml(type): except Error: if req == mandatory: # note: we can receive an error if obj has no content - errs.append('Object cannot be encoded') + errs.append(_('Object cannot be encoded')) else: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) def format(obj, errs): try: return obj.format(errs) except Error: if req == mandatory: - errs.append('Mandatory argument not available') + errs.append(_('Mandatory argument not available')) else: return '' return (init, decode, encode, format) @@ -572,8 +573,8 @@ class XmlFile(object): try: self.dom = mdom.parse(fileName) except ExpatError, inst: - raise Error("File '%s' has invalid XML: %s\n" % (fileName, - str(inst))) + raise Error(_("File '%s' has invalid XML: %s\n") % (fileName, + str(inst))) def writexml(self, fileName): f = codecs.open(fileName,'w', "utf-8") @@ -583,7 +584,7 @@ class XmlFile(object): def verifyRootTag(self): actual_roottag = self.rootNode().tagName if actual_roottag != self.rootTag: - raise Error("Root tagname %s not identical to %s as expected " % + raise Error(_("Root tagname %s not identical to %s as expected") % (actual_roottag, self.rootTag) ) # construction helpers