diff options
Diffstat (limited to 'pym/gentoolkit')
-rw-r--r-- | pym/gentoolkit/imlate/Makefile | 18 | ||||
-rwxr-xr-x | pym/gentoolkit/imlate/imlate | 480 | ||||
-rw-r--r-- | pym/gentoolkit/imlate/imlate.1 | 48 |
3 files changed, 546 insertions, 0 deletions
diff --git a/pym/gentoolkit/imlate/Makefile b/pym/gentoolkit/imlate/Makefile new file mode 100644 index 0000000..6735696 --- /dev/null +++ b/pym/gentoolkit/imlate/Makefile @@ -0,0 +1,18 @@ +# Copyright 1999-2009 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +include ../../makedefs.mak + +.PHONY: all + +all: + +dist: + mkdir -p ../../$(DISTDIR)/src/imlate/ + cp Makefile imlate imlate.1 ../../$(DISTDIR)/src/imlate/ + +install: all + install -m 0755 imlate $(BINDIR)/ + install -m 0644 imlate.1 $(MAN1DIR)/ + diff --git a/pym/gentoolkit/imlate/imlate b/pym/gentoolkit/imlate/imlate new file mode 100755 index 0000000..0be72e4 --- /dev/null +++ b/pym/gentoolkit/imlate/imlate @@ -0,0 +1,480 @@ +#!/usr/bin/python +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ +# Author: Christian Ruppert <idl0r@gentoo.org> + +# Python 2.6 compatibility +from __future__ import print_function + +VERSION = "1.0.1" + +# works just with stable keywords! +MAIN_ARCH = "auto" # can be overridden by -m ARCH +TARGET_ARCH = "auto" # can be overridden by -t ARCH +# auto means e.g.: +# MAIN_ARCH = amd64 +# TARGET_ARCH = ~amd64 +# That will show you general stable candidates for amd64. +# The arch will be taken from your portage settings (e.g. make.conf). + +################################ +# do not change anything below # +################################ + +from os.path import join, basename +from sys import stderr, stdout +from os import stat +from time import time +from xml.dom import minidom, NotFoundErr +from xml.parsers.expat import ExpatError +# TODO: just import needed stuff to safe memory/time and maybe use "as foo" +import portage +import portage.versions + +if __name__ == "__main__": + from optparse import OptionParser + from time import gmtime, strftime + +# override/change portage module settings +def _portage_settings( var, value, settings = None ): + if not settings: + settings = portage.settings + + settings.unlock() + settings[var] = value + # backup_changes is very important since it can cause trouble, + # if we do not backup our changes! + settings.backup_changes( var ) + settings.lock() + +# add stuff to our imlate dict +def _add_ent( imlate, cat, pkg, ver, our_ver ): + if not cat in list(imlate.keys()): + imlate[cat] = {} + if not pkg in list(imlate[cat].keys()): + imlate[cat][pkg] = [] + + imlate[cat][pkg].append( ver ) + imlate[cat][pkg].append( our_ver ) + + return imlate + +def _fill( width, line, fill = " " ): + while len( line ) < width: + line = "%s%s" % ( str( line ), str( fill ) ) + return line + +# create a hopefully pretty result +def show_result( conf, pkgs ): + # X - len(colX) = space to fill + col1 = 40 + col2 = 20 + + _header = "%s candidates for 'gentoo' on '%s'" + _helper = "category/package[:SLOT] our version best version" + _cand = "" + header = "" + + if conf["FILE"] == "stdout": + out = stdout + elif conf["FILE"] == "stderr": + out = stderr + else: + out = open( conf["FILE"], "w" ) + + if conf["STABLE"] and conf["KEYWORD"]: + _cand = "%i Stable and %i Keyword(~)" % ( conf["STABLE_SUM"], + conf["KEYWORD_SUM"] ) + elif conf["STABLE"]: + _cand = "%i Stable" % conf["STABLE_SUM"] + elif conf["KEYWORD"]: + _cand = "%i Keyword(~)" % conf["KEYWORD_SUM"] + + header = _header % ( _cand, conf["MAIN_ARCH"] ) + + print("Generated on: %s" % conf["TIME"], file=out) + print(_fill( len( header ), "", "=" ), file=out) + print(header, file=out) + print(_fill( len( header ), "", "=" ), file=out) + print(file=out) + + print(_helper, file=out) + print(_fill( len( _helper ), "", "-" ), file=out) + + for cat in sorted( pkgs.keys() ): + print("%s/" % cat, file=out) + for pkg in sorted( pkgs[cat].keys() ): + print("%s%s%s" % ( _fill( col1, ( " %s" % pkg ) ), + _fill( col2, pkgs[cat][pkg][1] ), + pkgs[cat][pkg][0] ), file=out) + + if conf["FILE"] != "stdout": + out.close() + +def _get_metadata(metadata, element, tag): + values = [] + + try: + metadatadom = minidom.parse(metadata) + except ExpatError as e: + raise ExpatError("%s: %s" % (metadata, e,)) + + try: + elements = metadatadom.getElementsByTagName(element) + if not elements: + return values + except NotFoundErr: + return values + + try: + for _element in elements: + node = _element.getElementsByTagName(tag) + + if tag == "herd" and (not node or not node[0].childNodes): +# print >> stderr, "'%s' is missing a <herd> tag or it is empty," % metadata +# print >> stderr, "please file a bug at https://bugs.gentoo.org and refer to http://www.gentoo.org/proj/en/devrel/handbook/handbook.xml?part=2&chap=4" + values.append("no-herd") + continue + + try: + values.append(node[0].childNodes[0].data) + except IndexError: + pass + except NotFoundErr: + raise NotFoundErr("%s: Malformed input: missing 'flag' tag(s)" % (metadata)) + + metadatadom.unlink() + return values + +def is_maintainer(maintainer, metadata): + data = [] + + if maintainer == None: + return True + + mtainer = maintainer.split(",") + + data = _get_metadata(metadata, "maintainer", "email") + + if not data and len(maintainer) == 0: + return True + elif not data and len(maintainer) > 0: + return False + else: + for addy in data: + for contact in mtainer: + if addy == contact: + return True + if addy.startswith(contact): + return True + return False + +def is_herd(herd, metadata): + data = [] + + if herd == None: + return True + + hrd = herd.split(",") + data = _get_metadata(metadata, "pkgmetadata", "herd") + + if not data and len(herd) == 0: + return True + elif not data and len(herd) > 0: + return False + else: + for hd in data: + for hd2 in hrd: + if hd == hd2: + return True + if hd.startswith(hd2): + return True + + return False + + +# fetch a list of arch (just stable) packages +# -* is important to be sure that just arch is used +def get_packages( conf ): + _pkgs = {} + + _portage_settings( "ACCEPT_KEYWORDS", ( "-* %s" % str( conf["TARGET_ARCH"] ) ), + conf["portdb"].settings ) + + for cp in conf["portdb"].dbapi.cp_all(): + cpvrs = [] + slots = {} + + if conf["USER_PKGS"]: + if not cp in conf["USER_PKGS"] and not basename(cp) in conf["USER_PKGS"]: + continue + + # None is important to match also on empty string + if conf["MAINTAINER"] != None: + if not is_maintainer(conf["MAINTAINER"], join(conf["PORTDIR"], cp, "metadata.xml")): + continue + if conf["HERD"] != None: + if not is_herd(conf["HERD"], join(conf["PORTDIR"], cp, "metadata.xml")): + continue + + cpvrs = conf["portdb"].dbapi.match( cp ) + + for cpvr in cpvrs: + slot = conf["portdb"].dbapi.aux_get( cpvr, ["SLOT"] )[0] + if not slot in slots: + slots[slot] = [] + slots[slot].append(cpvr) + + for slot in sorted(slots): + cpvr = portage.versions.best( slots[slot] ) + + if cpvr: + ( cat, pkg, ver, rev ) = portage.versions.catpkgsplit( cpvr ) + + if not cat in list(_pkgs.keys()): + _pkgs[cat] = {} + if not pkg in list(_pkgs[cat].keys()): + _pkgs[cat][pkg] = [] + + if rev != "r0": + ver = "%s-%s" % ( ver, rev ) + + _pkgs[cat][pkg].append( ver ) + + return _pkgs + +# compare get_packages() against MAIN_ARCH +def get_imlate( conf, pkgs ): + _portage_settings( "ACCEPT_KEYWORDS", ( "-* %s" % str( conf["MAIN_ARCH"] ) ), + conf["portdb"].settings ) + + stable = str( conf["MAIN_ARCH"].lstrip("~") ) + testing = "~%s" % stable + exclude = "-%s" % stable + exclude_all = "-*" + + imlate = {} + + for cat in sorted( pkgs.keys() ): + for pkg in sorted( pkgs[cat].keys() ): + for vr in pkgs[cat][pkg]: + cpvr = "" + abs_pkg = "" + kwds = "" + our = "" + our_ver = "" + mtime = 0 + slot = 0 + + # 0 = none(default), 1 = testing(~arch), 2 = stable(arch), + # 3 = exclude(-arch), 4 = exclude_all(-*) + # -* would be overridden by ~arch or arch + kwd_type = 0 + + cpvr = "%s/%s-%s" % ( cat, pkg, vr ) + + # absolute ebuild path for mtime check + abs_pkg = join( conf["PORTDIR"], cat, pkg, basename( cpvr ) ) + abs_pkg = "%s.ebuild" % str( abs_pkg ) + + kwds = conf["portdb"].dbapi.aux_get( cpvr, ["KEYWORDS"] )[0] + + # FIXME: %s is bad.. maybe even cast it, else there are issues because its unicode + slot = ":%s" % conf["portdb"].dbapi.aux_get( cpvr, ["SLOT"] )[0] + if slot == ":0": + slot = "" + + # sorted() to keep the right order + # e.g. -* first, -arch second, arch third and ~arch fourth + # -* -foo ~arch + # example: -* would be overridden by ~arch + for kwd in sorted( kwds.split() ): + if kwd == stable: + kwd_type = 2 + break + elif kwd == exclude: + kwd_type = 3 + break + elif kwd == exclude_all: + kwd_type = 4 + elif kwd == testing: + kwd_type = 1 + break + + # ignore -arch and already stabilized packages + if kwd_type == 3 or kwd_type == 2: + continue + # drop packages with -* and without ~arch or arch + # even if there is another version which includes arch or ~arch + if kwd_type == 4: + continue + # drop "stable candidates" with mtime < 30 days + # Shall we use gmtime/UTC here? + if kwd_type == 1: + mtime = int( ( time() - stat( abs_pkg ).st_mtime ) / 60 / 60 / 24 ) + if mtime < conf["MTIME"]: + continue + + # look for an existing stable version + our = portage.versions.best( conf["portdb"].dbapi.match( "%s/%s%s" % ( cat, pkg, slot ) ) ) + if our: + _foo = portage.versions.pkgsplit( our ) + our_ver = _foo[1] + if _foo[2] != "r0": + our_ver = "%s-%s" % ( our_ver, _foo[2] ) + else: + our_ver = "" + + # we just need the version if > our_ver + if our_ver: + if portage.versions.vercmp( our_ver, vr ) >= 0: + continue + + if kwd_type == 1 and conf["STABLE"]: + imlate = _add_ent( imlate, cat, ("%s%s" % (pkg, slot)), vr, our_ver ) + conf["STABLE_SUM"] += 1 + elif kwd_type == 0 and conf["KEYWORD"]: + conf["KEYWORD_SUM"] += 1 + imlate = _add_ent( imlate, cat, ( "~%s%s" % (pkg, slot) ), + vr, our_ver ) + + return imlate + +# fetch portage related settings +def get_settings( conf = None ): + if not isinstance( conf, dict ) and conf: + raise TypeError("conf must be dict() or None") + if not conf: + conf = {} + + # TODO: maybe we should improve it a bit ;) + mysettings = portage.config( config_incrementals = portage.const.INCREMENTALS, local_config = False ) + + if conf["MAIN_ARCH"] == "auto": + conf["MAIN_ARCH"] = "%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip("~") + if conf["TARGET_ARCH"] == "auto": + conf["TARGET_ARCH"] = "~%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip("~") + + # TODO: exclude overlay categories from check + if conf["CATEGORIES"]: + _mycats = [] + for _cat in conf["CATEGORIES"].split(","): + _cat = _cat.strip() + _mycats.append(_cat ) + if _cat not in mysettings.categories: + raise ValueError("invalid category for -C switch '%s'" % _cat) + mysettings.categories = _mycats + + # maybe thats not necessary because we override porttrees below.. + _portage_settings( "PORTDIR_OVERLAY", "", mysettings ) + trees = portage.create_trees() + trees["/"]["porttree"].settings = mysettings + portdb = trees["/"]["porttree"] + portdb.dbapi.settings = mysettings + portdb.dbapi.porttrees = [portage.portdb.porttree_root] + # does it make sense to remove _all_ useless stuff or just leave it as it is? + #portdb.dbapi._aux_cache_keys.clear() + #portdb.dbapi._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"]) + + conf["PORTDIR"] = portage.settings["PORTDIR"] + conf["portdb"] = portdb + + return conf + + +# just for standalone +def main(): + conf = {} + pkgs = {} + + parser = OptionParser( version = "%prog " + VERSION ) + parser.usage = "%prog [options] [category/package] ..." + parser.disable_interspersed_args() + + parser.add_option( "-f", "--file", dest = "filename", action = "store", type = "string", + help = "write result into FILE [default: %default]", metavar = "FILE", default = "stdout" ) + parser.add_option( "-m", "--main", dest = "main_arch", action = "store", type = "string", + help = "set main ARCH (e.g. your arch) [default: %default]", metavar = "ARCH", default = MAIN_ARCH ) + parser.add_option( "-t", "--target", dest = "target_arch", action = "store", type = "string", + help = "set target ARCH (e.g. x86) [default: %default]", metavar = "ARCH", default = TARGET_ARCH ) + parser.add_option( "--mtime", dest = "mtime", action = "store", type = "int", + help = "set minimum MTIME in days [default: %default]", metavar = "MTIME", default = 30 ) + + # TODO: leave a good comment here (about True/False) :) + parser.add_option( "-s", "--stable", dest = "stable", action = "store_true", default = False, + help = "just show stable candidates (e.g. -s and -k is the default result) [default: True]" ) + parser.add_option( "-k", "--keyword", dest = "keyword", action = "store_true", default = False, + help = "just show keyword candidates (e.g. -s and -k is the default result) [default: True]" ) + + parser.add_option( "-M", "--maintainer", dest = "maintainer", action = "store", type = "string", + help = "Show only packages from the specified maintainer", metavar = "MAINTAINER", default = None) + + parser.add_option( "-H", "--herd", dest = "herd", action = "store", type = "string", + help = "Show only packages from the specified herd", metavar = "HERD", default = None) + +# # EXPERIMENTAL +# parser.add_option( "-e", "--experimental", dest = "experimental", action = "store_true", default = False, +# help = "enables experimental functions/features (have a look for # EXPERIMENTAL comments in the source) [default: %default]" ) + + parser.add_option( "-C", "--category", "--categories", dest = "categories", action = "store", default = None, + metavar = "CATEGORIES", + help = "just check in the specified category/categories (comma separated) [default: %default]") + + ( options, args ) = parser.parse_args() + + if len( args ) > 0: + conf["USER_PKGS"] = args + else: + conf["USER_PKGS"] = [] + + # cleanup optparse + try: + parser.destroy() + except AttributeError: + # to be at least python 2.4 compatible + del parser._short_opt + del parser._long_opt + del parser.defaults + + # generated timestamp (UTC) + conf["TIME"] = strftime( "%a %b %d %H:%M:%S %Z %Y", gmtime() ) + + # package counter + conf["KEYWORD_SUM"] = 0 + conf["STABLE_SUM"] = 0 + + if not options.main_arch in portage.archlist and options.main_arch != "auto": + raise ValueError("invalid MAIN ARCH defined!") + if not options.target_arch in portage.archlist and options.target_arch != "auto": + raise ValueError("invalid TARGET ARCH defined!") + + conf["MAIN_ARCH"] = options.main_arch + conf["TARGET_ARCH"] = options.target_arch + + conf["FILE"] = options.filename + conf["MTIME"] = options.mtime + + if not options.stable and not options.keyword: + conf["STABLE"] = True + conf["KEYWORD"] = True + else: + conf["STABLE"] = options.stable + conf["KEYWORD"] = options.keyword + +# conf["EXPERIMENTAL"] = options.experimental + conf["CATEGORIES"] = options.categories + + conf["MAINTAINER"] = options.maintainer + conf["HERD"] = options.herd + + # append to our existing + conf = get_settings( conf ) + pkgs = get_packages( conf ) + pkgs = get_imlate( conf, pkgs ) + + show_result( conf, pkgs ) + +if __name__ == "__main__": + main() + diff --git a/pym/gentoolkit/imlate/imlate.1 b/pym/gentoolkit/imlate/imlate.1 new file mode 100644 index 0000000..b9163a4 --- /dev/null +++ b/pym/gentoolkit/imlate/imlate.1 @@ -0,0 +1,48 @@ +.TH "imlate" "1" "1.0.0" "Christian Ruppert" "gentoolkit-dev" +.SH "NAME" +.LP +imlate \- Displays candidates for keywords for an architecture based upon a target architecture. +.SH "SYNTAX" +.LP +imlate [options] + + +.SH "OPTIONS" +.TP +.B \-\-version +show program's version number and exit +.TP +.B \-h, \-\-help +show this help message and exit +.TP +.B \-f FILE, \-\-file=FILE +write result into FILE [default: stdout] +.TP +.B \-m ARCH, \-\-main=ARCH +set main ARCH (e.g. your arch) [default: amd64] +.TP +.B \-t ARCH, \-\-target=ARCH +set target ARCH (e.g. x86) [default: x86] +.TP +.B \-\-mtime=MTIME +set minimum MTIME in days [default: 30] +.TP +.B \-s, \-\-stable +just show stable candidates (e.g. \-s and \-k is the default result) [default: True] +.TP +.B \-k, \-\-keyword +just show keyword candidates (e.g. \-s and \-k is the default result) [default: True] +.TP +.B \-M MAINTAINER, \-\-maintainer=MAINTAINER +Show only packages from the specified maintainer +.TP +.B \-H HERD, \-\-herd=HERD +Show only packages from the specified herd +.TP +.B \-C CATEGORIES, \-\-category=CATEGORIES, \-\-categories=CATEGORIES +just check in the specified category/categories (comma separated) [default: none] +.SH "AUTHORS" +.LP +Christian Ruppert <idl0r@gentoo.org> +.SH "BUGS" +Please report any bugs to http://bugs.gentoo.org |