diff options
Diffstat (limited to 'yocto-poky/meta/recipes-devtools/python/python-smartpm')
10 files changed, 1050 insertions, 0 deletions
diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-add-for-rpm-ignoresize-check.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-add-for-rpm-ignoresize-check.patch new file mode 100644 index 000000000..8a27f2583 --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-add-for-rpm-ignoresize-check.patch @@ -0,0 +1,37 @@ +python-smartpm: Add checking for "rpm-ignoresize" option + +The do_rootfs takes a very long time when build host has mounted many NFS +devices. syscall lstat() was being called on every filesystem mounted on the +build host during building. +The reason for the lstat() is that rpm is verifying that enough free disk space +is available to do the install. However, since the install is into the target +rootfs it should not matter how much free space there is in the host mounts. +Add checking for "rpm-ignoresize", by it, smart can make whether RPM skip +checking for diskspace when install a rpm package. + +Upstream-Status: Pending + +Signed-off-by: wenlin.kang <wenlin.kang@windriver.com> +Signed-off-by: Chong Lu <Chong.Lu@windriver.com> +--- + smart/backends/rpm/pm.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/smart/backends/rpm/pm.py b/smart/backends/rpm/pm.py +index 5da9ee6..f0488ec 100644 +--- a/smart/backends/rpm/pm.py ++++ b/smart/backends/rpm/pm.py +@@ -241,6 +241,10 @@ class RPMPackageManager(PackageManager): + except AttributeError: + probfilter |= rpm.RPMPROB_FILTER_IGNOREARCH + ++ if sysconf.get("rpm-ignoresize", False): ++ probfilter |= rpm.RPMPROB_FILTER_DISKNODES ++ probfilter |= rpm.RPMPROB_FILTER_DISKSPACE ++ + if force or reinstall: + probfilter |= rpm.RPMPROB_FILTER_REPLACEPKG + probfilter |= rpm.RPMPROB_FILTER_REPLACEOLDFILES +-- +1.9.1 + diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-already-installed-message.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-already-installed-message.patch new file mode 100644 index 000000000..9055555cd --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-already-installed-message.patch @@ -0,0 +1,54 @@ +From a74a9a9eb9d75964a0e978950e8b191d7a18d763 Mon Sep 17 00:00:00 2001 +From: Paul Eggleton <paul.eggleton@linux.intel.com> +Date: Fri, 5 Jun 2015 17:07:16 +0100 +Subject: [PATCH] smart: change "is already installed" message from warning to + info + +This doesn't need to be a warning. + +Upstream-Status: Pending + +Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> +--- + smart/commands/install.py | 4 ++-- + smart/interfaces/text/interactive.py | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/smart/commands/install.py b/smart/commands/install.py +index 6ef9682..80d456b 100644 +--- a/smart/commands/install.py ++++ b/smart/commands/install.py +@@ -152,7 +152,7 @@ def main(ctrl, opts): + for obj in results: + for pkg in obj.packages: + if pkg.installed: +- iface.warning(_("%s (for %s) is already installed") ++ iface.info(_("%s (for %s) is already installed") + % (pkg, arg)) + installed = True + break +@@ -184,7 +184,7 @@ def main(ctrl, opts): + for name in names: + pkg = names[name][0] + if pkg.installed: +- iface.warning(_("%s is already installed") % pkg) ++ iface.info(_("%s is already installed") % pkg) + else: + trans.enqueue(pkg, INSTALL) + +diff --git a/smart/interfaces/text/interactive.py b/smart/interfaces/text/interactive.py +index 9865584..190867b 100644 +--- a/smart/interfaces/text/interactive.py ++++ b/smart/interfaces/text/interactive.py +@@ -278,7 +278,7 @@ class Interpreter(Cmd): + for name in names: + pkg = names[name][0] + if pkg.installed: +- iface.warning(_("%s is already installed") % pkg) ++ iface.info(_("%s is already installed") % pkg) + else: + found = True + transaction.enqueue(pkg, INSTALL) +-- +2.1.0 + diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-attempt-fix.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-attempt-fix.patch new file mode 100644 index 000000000..6e672b332 --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-attempt-fix.patch @@ -0,0 +1,158 @@ +Sadly, smart is not deterministic so the same build can go down multiple different +pathways. We'd expect to see the same warnings however depending on the pathway +taken, it may or may not warn, particularly with Recommends since they're optional. + +For example, where a Recommended package is available but has Conflicts, we'd expect +to see an warning that we couldn't install it. Some code paths silently hide this +(its a LOCKED_CONFLICT). We add printing of warnings for this case. + +Also, if there are two compatible feeds available (e.g. i586 and core2_32), this +changes the code path from direct _install() to _pending() since there are multiple +providers. This patch adds warning handling to _pending() so we don't hit hard +failures there. This is as seen with the mysterious libspeexdsp failures for x86-lsb +on the autobuilder. + +Upstream-Status: Pending +RP +2015/7/16 + +Index: git/smart/transaction.py +=================================================================== +--- git.orig/smart/transaction.py ++++ git/smart/transaction.py +@@ -651,13 +651,14 @@ class Transaction(object): + + if not prvpkgs: + # No packages provide it at all. Give up. ++ ++ reasons = [] ++ for prv in req.providedby: ++ for prvpkg in prv.packages: ++ lockedres = lockedpkgs.get(prvpkg, None) ++ if lockedres: ++ reasons.append(lock_reason(prvpkg, lockedres)) + if reqrequired: +- reasons = [] +- for prv in req.providedby: +- for prvpkg in prv.packages: +- lockedres = lockedpkgs.get(prvpkg, None) +- if lockedres: +- reasons.append(lock_reason(prvpkg, lockedres)) + if reasons: + raise Failed, _("Can't install %s: unable to install provider for %s:\n %s") % \ + (pkg, req, '\n '.join(reasons)) +@@ -665,7 +666,11 @@ class Transaction(object): + raise Failed, _("Can't install %s: no package provides %s") % \ + (pkg, req) + else: ++ if reasons: ++ iface.warning(_("Can't install %s: unable to install provider for %s:\n %s") % \ ++ (pkg, req, '\n '.join(reasons))) ++ + # It's only a recommend, skip + continue + + if len(prvpkgs) == 1: +@@ -846,6 +852,14 @@ class Transaction(object): + isinst = changeset.installed + getweight = self._policy.getWeight + ++ attempt = sysconf.has("attempt-install", soft=True) ++ ++ def handle_failure(msg): ++ if attempt: ++ iface.warning(msg) ++ else: ++ raise Failed, msg ++ + updown = [] + while pending: + item = pending.pop(0) +@@ -870,8 +884,9 @@ class Transaction(object): + + if not prvpkgs: + # No packages provide it at all. Give up. +- raise Failed, _("Can't install %s: no package " +- "provides %s") % (pkg, req) ++ handle_failure(_("Can't install %s: no package " ++ "provides %s") % (pkg, req)) ++ continue + + if len(prvpkgs) > 1: + # More than one package provide it. We use _pending here, +@@ -894,9 +909,10 @@ class Transaction(object): + keeporder, cs, lk)) + keeporder += 0.000001 + if not alternatives: +- raise Failed, _("Can't install %s: all packages " ++ handle_failure(_("Can't install %s: all packages " + "providing %s failed to install:\n%s")\ +- % (pkg, req, "\n".join(failures)) ++ % (pkg, req, "\n".join(failures))) ++ continue + alternatives.sort() + changeset.setState(alternatives[0][1]) + if len(alternatives) == 1: +@@ -954,18 +970,20 @@ class Transaction(object): + + for reqpkg in reqpkgs: + if reqpkg in locked and isinst(reqpkg): +- raise Failed, _("Can't remove %s: requiring " ++ handle_failure(_("Can't remove %s: requiring " + "package %s is locked") % \ +- (pkg, reqpkg) ++ (pkg, reqpkg)) ++ continue + for reqpkg in reqpkgs: + # We check again, since other actions may have + # changed their state. + if not isinst(reqpkg): + continue + if reqpkg in locked: +- raise Failed, _("Can't remove %s: requiring " ++ handle_failure(_("Can't remove %s: requiring " + "package %s is locked") % \ +- (pkg, reqpkg) ++ (pkg, reqpkg)) ++ continue + self._remove(reqpkg, changeset, locked, + pending, depth) + continue +@@ -978,12 +996,14 @@ class Transaction(object): + try: + for reqpkg in reqpkgs: + if reqpkg in locked and isinst(reqpkg): +- raise Failed, _("%s is locked") % reqpkg ++ handle_failure(_("%s is locked") % reqpkg) ++ continue + for reqpkg in reqpkgs: + if not cs.installed(reqpkg): + continue + if reqpkg in lk: +- raise Failed, _("%s is locked") % reqpkg ++ handle_failure(_("%s is locked") % reqpkg) ++ continue + self._remove(reqpkg, cs, lk, None, depth) + except Failed, e: + failures.append(unicode(e)) +@@ -991,9 +1011,10 @@ class Transaction(object): + alternatives.append((getweight(cs), cs, lk)) + + if not alternatives: +- raise Failed, _("Can't install %s: all packages providing " ++ handle_failure(_("Can't install %s: all packages providing " + "%s failed to install:\n%s") \ +- % (pkg, prv, "\n".join(failures)) ++ % (pkg, prv, "\n".join(failures))) ++ continue + + alternatives.sort() + changeset.setState(alternatives[0][1]) +@@ -1246,6 +1267,7 @@ class Transaction(object): + changeset.setRequested(pkg, True) + except Failed, e: + if sysconf.has("attempt-install", soft=True): ++ iface.warning(_("Can't install %s: %s") % (pkg, str(e))) + if pkg in changeset: + del changeset[pkg] + continue diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-attempt.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-attempt.patch new file mode 100644 index 000000000..ec98e03c0 --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-attempt.patch @@ -0,0 +1,177 @@ +From b105e7fe812da3ccaf7155c0fe14c8728b0d39a5 Mon Sep 17 00:00:00 2001 +From: Mark Hatle <mark.hatle@windriver.com> +Date: Mon, 20 Jan 2014 14:30:52 +0000 +Subject: [PATCH] Add mechanism to attempt install without failing + +In OpenEmbedded, for complementary and 'attemptonly' package processing, +we need a way to instruct smart to try to install, but ignore any +failures (usually conflicts). + +This option only works for the install operation. + +If a complementary install fails, an actual error occurred, one that +we can't ignore without losing the entire attempted transaction. Keep +this as an error so that we can catch these cases in the futre. + +Upstream-Status: Pending + +Signed-off-by: Mark Hatle <mark.hatle@windriver.com> +Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> +--- + backends/rpm/pm.py | 35 ++++++++++++++++++++++++++++++++++- + transaction.py | 50 +++++++++++++++++++++++++++++++++++++------------- + 2 files changed, 71 insertions(+), 14 deletions(-) + +diff --git a/smart/backends/rpm/pm.py b/smart/backends/rpm/pm.py +index 9bbd952..ba6405a 100644 +--- a/smart/backends/rpm/pm.py ++++ b/smart/backends/rpm/pm.py +@@ -241,15 +241,48 @@ class RPMPackageManager(PackageManager): + cb = RPMCallback(prog, upgradednames) + cb.grabOutput(True) + probs = None ++ retry = 0 + try: + probs = ts.run(cb, None) + finally: + del getTS.ts + cb.grabOutput(False) ++ if probs and sysconf.has("attempt-install", soft=True): ++ def remove_conflict(pkgNEVR): ++ for key in changeset.keys(): ++ if pkgNEVR == str(key): ++ del changeset[key] ++ del pkgpaths[key] ++ iface.warning("Removing %s due to file %s conflicting with %s" % (pkgNEVR, fname, altNEVR)) ++ break ++ ++ retry = 1 ++ for prob in probs: ++ if prob[1][0] == rpm.RPMPROB_NEW_FILE_CONFLICT: ++ msg = prob[0].split() ++ fname = msg[1] ++ pkgNEVR = msg[7] ++ altNEVR = msg[9] ++ pkgNEVR = pkgNEVR.rsplit('.', 1)[0] + '@' + pkgNEVR.rsplit('.', 1)[1] ++ altNEVR = altNEVR.rsplit('.', 1)[0] + '@' + altNEVR.rsplit('.', 1)[1] ++ remove_conflict(pkgNEVR) ++ elif prob[1][0] == rpm.RPMPROB_FILE_CONFLICT: ++ msg = prob[0].split() ++ fname = msg[1] ++ pkgNEVR = msg[5] ++ altNEVR = msg[11] ++ pkgNEVR = pkgNEVR.rsplit('.', 1)[0] + '@' + pkgNEVR.rsplit('.', 1)[1] ++ altNEVR = altNEVR.rsplit('.', 1)[0] + '@' + altNEVR.rsplit('.', 1)[1] ++ remove_conflict(pkgNEVR) ++ else: ++ retry = 0 ++ + prog.setDone() +- if probs: ++ if probs and (not retry): + raise Error, "\n".join([x[0] for x in probs]) + prog.stop() ++ if retry and len(changeset): ++ self.commit(changeset, pkgpaths) + + class RPMCallback: + def __init__(self, prog, upgradednames): +diff --git a/smart/transaction.py b/smart/transaction.py +index 4b90cb7..3e043e9 100644 +--- a/smart/transaction.py ++++ b/smart/transaction.py +@@ -555,6 +555,8 @@ class Transaction(object): + changeset.set(pkg, INSTALL) + isinst = changeset.installed + ++ attempt = sysconf.has("attempt-install", soft=True) ++ + # Remove packages conflicted by this one. + for cnf in pkg.conflicts: + for prv in cnf.providedby: +@@ -564,11 +566,16 @@ class Transaction(object): + if not isinst(prvpkg): + locked[prvpkg] = (LOCKED_CONFLICT_BY, pkg) + continue +- if prvpkg in locked: +- raise Failed, _("Can't install %s: conflicted package " +- "%s is locked") % (pkg, prvpkg) +- self._remove(prvpkg, changeset, locked, pending, depth) +- pending.append((PENDING_UPDOWN, prvpkg)) ++ if attempt: ++ del changeset[pkg] ++ raise Failed, _("Can't install %s: it conflicts with package " ++ "%s") % (pkg, prvpkg) ++ else: ++ if prvpkg in locked: ++ raise Failed, _("Can't install %s: conflicted package " ++ "%s is locked") % (pkg, prvpkg) ++ self._remove(prvpkg, changeset, locked, pending, depth) ++ pending.append((PENDING_UPDOWN, prvpkg)) + + # Remove packages conflicting with this one. + for prv in pkg.provides: +@@ -579,12 +586,18 @@ class Transaction(object): + if not isinst(cnfpkg): + locked[cnfpkg] = (LOCKED_CONFLICT, pkg) + continue +- if cnfpkg in locked: ++ if attempt: ++ del changeset[pkg] + raise Failed, _("Can't install %s: it's conflicted by " +- "the locked package %s") \ +- % (pkg, cnfpkg) +- self._remove(cnfpkg, changeset, locked, pending, depth) +- pending.append((PENDING_UPDOWN, cnfpkg)) ++ "the package %s") \ ++ % (pkg, cnfpkg) ++ else: ++ if cnfpkg in locked: ++ raise Failed, _("Can't install %s: it's conflicted by " ++ "the locked package %s") \ ++ % (pkg, cnfpkg) ++ self._remove(cnfpkg, changeset, locked, pending, depth) ++ pending.append((PENDING_UPDOWN, cnfpkg)) + + # Remove packages with the same name that can't + # coexist with this one. +@@ -594,10 +607,15 @@ class Transaction(object): + if not isinst(namepkg): + locked[namepkg] = (LOCKED_NO_COEXIST, pkg) + continue +- if namepkg in locked: ++ if attempt: ++ del changeset[pkg] + raise Failed, _("Can't install %s: it can't coexist " + "with %s") % (pkg, namepkg) +- self._remove(namepkg, changeset, locked, pending, depth) ++ else: ++ if namepkg in locked: ++ raise Failed, _("Can't install %s: it can't coexist " ++ "with %s") % (pkg, namepkg) ++ self._remove(namepkg, changeset, locked, pending, depth) + + # Install packages required by this one. + for req in pkg.requires + pkg.recommends: +@@ -1176,6 +1194,8 @@ class Transaction(object): + + self._policy.runStarting() + ++ attempt = sysconf.has("attempt-install", soft=True) ++ + try: + changeset = self._changeset.copy() + isinst = changeset.installed +@@ -1190,7 +1210,11 @@ class Transaction(object): + locked[pkg] = (LOCKED_KEEP, None) + elif op is INSTALL: + if not isinst(pkg) and pkg in locked: +- raise Failed, _("Can't install %s: it's locked") % pkg ++ if attempt: ++ iface.warning(_("Can't install %s: it's locked") % pkg) ++ del changeset[pkg] ++ else: ++ raise Failed, _("Can't install %s: it's locked") % pkg + changeset.set(pkg, INSTALL) + locked[pkg] = (LOCKED_INSTALL, None) + elif op is REMOVE: diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-channelsdir.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-channelsdir.patch new file mode 100644 index 000000000..e621b3387 --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-channelsdir.patch @@ -0,0 +1,24 @@ +Make CHANNELSDIR in smart empty, since this causes host contamination issues +on some RPM-based hosts on which smart is already installed. + +[YOCTO #3881] + +Upstream-Status: Inappropriate [embedded specific] + +diff --git a/smart/plugins/channelsync.py b/smart/plugins/channelsync.py +index 3ba95ff..646d696 100644 +--- a/smart/plugins/channelsync.py ++++ b/smart/plugins/channelsync.py +@@ -23,7 +23,11 @@ from smart.channel import * + from smart import * + import os + +-CHANNELSDIR = "/etc/smart/channels/" ++# For now, we leave the definition of CHANNELSDIR empty. This prevents smart ++# from erroneously consider the build host's channels while setting up its ++# channels [YOCTO #3881]. If this feature will be used in the future, CHANNELSDIR ++# should be set to a proper value. ++CHANNELSDIR = "" + + def syncChannels(channelsdir, force=None): + diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-improve-error-reporting.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-improve-error-reporting.patch new file mode 100644 index 000000000..b82265b3f --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-improve-error-reporting.patch @@ -0,0 +1,91 @@ +Improve error reporting in smart + +Add code to check proper command line arguments for various +smart commands. Exit with error if erroneous/additional arguments +are given in the command line. + +Upstream-Status: Pending + +Signed-off-by: Bogdan Marinescu <bogdan.a.marinescu@intel.com> + +diff --git a/smart/util/optparse.py b/smart/util/optparse.py +index 6fff1bc..f445a3b 100644 +--- a/smart/util/optparse.py ++++ b/smart/util/optparse.py +@@ -70,6 +70,8 @@ import sys, os + import types + import textwrap + from gettext import gettext as _ ++from smart import Error ++import re + + def _repr(self): + return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self) +@@ -710,6 +712,12 @@ class Option: + self.action, self.dest, opt, value, values, parser) + + def take_action(self, action, dest, opt, value, values, parser): ++ # Keep all the options in the command line in the '_given_opts' array ++ # This will be used later to validate the command line ++ given_opts = getattr(parser.values, "_given_opts", []) ++ user_opt = re.sub(r"^\-*", "", opt).replace("-", "_") ++ given_opts.append(user_opt) ++ setattr(parser.values, "_given_opts", given_opts) + if action == "store": + setattr(values, dest, value) + elif action == "store_const": +@@ -821,6 +829,54 @@ class Values: + setattr(self, attr, value) + return getattr(self, attr) + ++ # Check if the given option has the specified number of arguments ++ # Raise an error if the option has an invalid number of arguments ++ # A negative number for 'nargs' means "at least |nargs| arguments are needed" ++ def check_args_of_option(self, opt, nargs, err=None): ++ given_opts = getattr(self, "_given_opts", []) ++ if not opt in given_opts: ++ return ++ values = getattr(self, opt, []) ++ if type(values) != type([]): ++ return ++ if nargs < 0: ++ nargs = -nargs ++ if len(values) >= nargs: ++ return ++ if not err: ++ if nargs == 1: ++ err = _("Option '%s' requires at least one argument") % opt ++ else: ++ err = _("Option '%s' requires at least %d arguments") % (opt, nargs) ++ raise Error, err ++ elif nargs == 0: ++ if len( values ) == 0: ++ return ++ raise Error, err ++ else: ++ if len(values) == nargs: ++ return ++ if not err: ++ if nargs == 1: ++ err = _("Option '%s' requires one argument") % opt ++ else: ++ err = _("Option '%s' requires %d arguments") % (opt, nargs) ++ raise Error, err ++ ++ # Check that at least one of the options in 'actlist' was given as an argument ++ # to the command 'cmdname' ++ def ensure_action(self, cmdname, actlist): ++ given_opts = getattr(self, "_given_opts", []) ++ for action in actlist: ++ if action in given_opts: ++ return ++ raise Error, _("No action specified for command '%s'") % cmdname ++ ++ # Check if there are any other arguments left after parsing the command line and ++ # raise an error if such arguments are found ++ def check_remaining_args(self): ++ if self.args: ++ raise Error, _("Invalid argument(s) '%s'" % str(self.args)) + + class OptionContainer: + diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch new file mode 100644 index 000000000..d607fc475 --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-recommends.patch @@ -0,0 +1,381 @@ +Handle recommended packages in core and rpm backends + +Identify and store recommended packages in the cache, add a query option +to read them and ignore them if they are not present when installing. + +Initial identification code from Mark Hatle <mark.hatle@windriver.com>. + +Upstream-Status: Pending + +Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> + +diff --git a/smart/backends/rpm/base.py b/smart/backends/rpm/base.py +index 9332ea0..4fcfbee 100644 +--- a/smart/backends/rpm/base.py ++++ b/smart/backends/rpm/base.py +@@ -225,6 +225,52 @@ class RPMPackage(Package): + break + else: + return False ++ srecs = fk(self.recommends) ++ orecs = fk(other.recommends) ++ if srecs != orecs: ++ for srec in srecs: ++ if srec.name[0] == "/" or srec in orecs: ++ continue ++ for orec in orecs: ++ if (srec.name == orec.name and ++ srec.relation == orec.relation and ++ checkver(srec.version, orec.version)): ++ break ++ else: ++ return False ++ for orec in orecs: ++ if orec.name[0] == "/" or orec in srecs: ++ continue ++ for srec in srecs: ++ if (srec.name == orec.name and ++ srec.relation == orec.relation and ++ checkver(srec.version, orec.version)): ++ break ++ else: ++ return False ++ srecs = fk(self.recommends) ++ orecs = fk(other.recommends) ++ if srecs != orecs: ++ for srec in srecs: ++ if srec.name[0] == "/" or srec in orecs: ++ continue ++ for orec in orecs: ++ if (srec.name == orec.name and ++ srec.relation == orec.relation and ++ checkver(srec.version, orec.version)): ++ break ++ else: ++ return False ++ for orec in orecs: ++ if orec.name[0] == "/" or orec in srecs: ++ continue ++ for srec in srecs: ++ if (srec.name == orec.name and ++ srec.relation == orec.relation and ++ checkver(srec.version, orec.version)): ++ break ++ else: ++ return False + return True + + def coexists(self, other): +diff --git a/smart/ccache.c b/smart/ccache.c +index 7193185..8b66515 100644 +--- a/smart/ccache.c ++++ b/smart/ccache.c +@@ -500,6 +500,46 @@ Package_equals(PackageObject *self, PackageObject *other) + } + } + ++ ilen = 0; ++ jlen = 0; ++ for (i = 0; i != PyList_GET_SIZE(self->recommends); i++) { ++ PyObject *item = PyList_GET_ITEM(self->recommends, i); ++ if (!PyObject_IsInstance(item, (PyObject *)&Depends_Type)) { ++ PyErr_SetString(PyExc_TypeError, "Depends instance expected"); ++ return NULL; ++ } ++ if (STR(((DependsObject *)item)->name)[0] != '/') ++ ilen += 1; ++ } ++ for (j = 0; j != PyList_GET_SIZE(other->recommends); j++) { ++ PyObject *item = PyList_GET_ITEM(other->recommends, j); ++ if (!PyObject_IsInstance(item, (PyObject *)&Depends_Type)) { ++ PyErr_SetString(PyExc_TypeError, "Depends instance expected"); ++ return NULL; ++ } ++ if (STR(((DependsObject *)item)->name)[0] != '/') ++ jlen += 1; ++ } ++ if (ilen != jlen) { ++ ret = Py_False; ++ goto exit; ++ } ++ ++ ilen = PyList_GET_SIZE(self->recommends); ++ jlen = PyList_GET_SIZE(other->recommends); ++ for (i = 0; i != ilen; i++) { ++ PyObject *item = PyList_GET_ITEM(self->recommends, i); ++ if (STR(((DependsObject *)item)->name)[0] != '/') { ++ for (j = 0; j != jlen; j++) ++ if (item == PyList_GET_ITEM(other->recommends, j)) ++ break; ++ if (j == jlen) { ++ ret = Py_False; ++ goto exit; ++ } ++ } ++ } ++ + exit: + Py_INCREF(ret); + return ret; +@@ -1813,6 +1853,59 @@ Loader_buildPackage(LoaderObject *self, PyObject *args) + } + } + ++ /* if recargs: */ ++ if (recargs) { ++ int i = 0; ++ int len = PyList_GET_SIZE(recargs); ++ /* pkg.recommends = [] */ ++ Py_DECREF(pkgobj->recommends); ++ pkgobj->recommends = PyList_New(len); ++ /* for args in recargs: */ ++ for (; i != len; i++) { ++ PyObject *args = PyList_GET_ITEM(recargs, i); ++ DependsObject *recobj; ++ PyObject *rec; ++ ++ if (!PyTuple_Check(args)) { ++ PyErr_SetString(PyExc_TypeError, ++ "Item in recargs is not a tuple"); ++ return NULL; ++ } ++ ++ /* rec = cache._objmap.get(args) */ ++ rec = PyDict_GetItem(cache->_objmap, args); ++ recobj = (DependsObject *)rec; ++ ++ /* if not rec: */ ++ if (!rec) { ++ if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 2) { ++ PyErr_SetString(PyExc_ValueError, "Invalid recargs tuple"); ++ return NULL; ++ } ++ /* rec = args[0](*args[1:]) */ ++ callargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); ++ rec = PyObject_CallObject(PyTuple_GET_ITEM(args, 0), callargs); ++ Py_DECREF(callargs); ++ if (!rec) return NULL; ++ recobj = (DependsObject *)rec; ++ ++ /* cache._objmap[args] = rec */ ++ PyDict_SetItem(cache->_objmap, args, rec); ++ Py_DECREF(rec); ++ ++ /* cache._recommends.append(rec) */ ++ PyList_Append(cache->_recommends, rec); ++ } ++ ++ /* relpkgs.append(rec.packages) */ ++ PyList_Append(relpkgs, recobj->packages); ++ ++ /* pkg.recommends.append(rec) */ ++ Py_INCREF(rec); ++ PyList_SET_ITEM(pkgobj->recommends, i, rec); ++ } ++ } ++ + /* if upgargs: */ + if (upgargs) { + int i = 0; +@@ -2592,6 +2685,16 @@ Cache_reset(CacheObject *self, PyObject *args) + if (PyList_Check(reqobj->providedby)) + LIST_CLEAR(reqobj->providedby); + } ++ len = PyList_GET_SIZE(self->_recommends); ++ for (i = 0; i != len; i++) { ++ DependsObject *reqobj; ++ PyObject *req; ++ req = PyList_GET_ITEM(self->_recommends, i); ++ reqobj = (DependsObject *)req; ++ LIST_CLEAR(reqobj->packages); ++ if (PyList_Check(reqobj->providedby)) ++ LIST_CLEAR(reqobj->providedby); ++ } + len = PyList_GET_SIZE(self->_upgrades); + for (i = 0; i != len; i++) { + DependsObject *upgobj; +@@ -2834,6 +2937,30 @@ Cache__reload(CacheObject *self, PyObject *args) + } + + /* ++ for rec in pkg.recommends: ++ rec.packages.append(pkg) ++ if rec not in recommends: ++ recommends[rec] = True ++ objmap[rec.getInitArgs()] = rec ++ */ ++ if (PyList_Check(pkg->recommends)) { ++ klen = PyList_GET_SIZE(pkg->recommends); ++ for (k = 0; k != klen; k++) { ++ PyObject *rec = PyList_GET_ITEM(pkg->recommends, k); ++ PyList_Append(((DependsObject *)rec)->packages, ++ (PyObject *)pkg); ++ if (!PyDict_GetItem(recommends, rec)) { ++ PyDict_SetItem(recommends, rec, Py_True); ++ args = PyObject_CallMethod(rec, "getInitArgs", ++ NULL); ++ if (!args) return NULL; ++ PyDict_SetItem(objmap, args, rec); ++ Py_DECREF(args); ++ } ++ } ++ } ++ ++ /* + for upg in pkg.upgrades: + upg.packages.append(pkg) + if upg not in upgrades: +@@ -3097,6 +3224,47 @@ Cache_linkDeps(CacheObject *self, PyObject *args) + Py_DECREF(seq); + } + ++ /* recnames = {} */ ++ recnames = PyDict_New(); ++ /* for rec in self._recommends: */ ++ len = PyList_GET_SIZE(self->_recommends); ++ for (i = 0; i != len; i++) { ++ PyObject *rec = PyList_GET_ITEM(self->_recommends, i); ++ ++ /* for name in rec.getMatchNames(): */ ++ PyObject *names = PyObject_CallMethod(rec, "getMatchNames", NULL); ++ PyObject *seq = PySequence_Fast(names, "getMatchNames() returned " ++ "non-sequence object"); ++ int nameslen; ++ if (!seq) return NULL; ++ nameslen = PySequence_Fast_GET_SIZE(seq); ++ for (j = 0; j != nameslen; j++) { ++ PyObject *name = PySequence_Fast_GET_ITEM(seq, j); ++ ++ /* lst = recnames.get(name) */ ++ lst = PyDict_GetItem(recnames, name); ++ ++ /* ++ if lst: ++ lst.append(rec) ++ else: ++ recnames[name] = [rec] ++ */ ++ if (lst) { ++ PyList_Append(lst, rec); ++ } else { ++ lst = PyList_New(1); ++ Py_INCREF(rec); ++ PyList_SET_ITEM(lst, 0, rec); ++ PyDict_SetItem(recnames, name, lst); ++ Py_DECREF(lst); ++ } ++ } ++ ++ Py_DECREF(names); ++ Py_DECREF(seq); ++ } ++ + /* upgnames = {} */ + upgnames = PyDict_New(); + /* for upg in self._upgrades: */ +@@ -3286,6 +3454,56 @@ Cache_linkDeps(CacheObject *self, PyObject *args) + } + } + ++ /* lst = recnames.get(prv.name) */ ++ lst = PyDict_GetItem(recnames, prv->name); ++ ++ /* if lst: */ ++ if (lst) { ++ /* for rec in lst: */ ++ int reclen = PyList_GET_SIZE(lst); ++ for (j = 0; j != reclen; j++) { ++ DependsObject *rec = (DependsObject *)PyList_GET_ITEM(lst, j); ++ /* if rec.matches(prv): */ ++ PyObject *ret = PyObject_CallMethod((PyObject *)rec, "matches", ++ "O", (PyObject *)prv); ++ if (!ret) return NULL; ++ if (PyObject_IsTrue(ret)) { ++ /* ++ if rec.providedby: ++ rec.providedby.append(prv) ++ else: ++ rec.providedby = [prv] ++ */ ++ if (PyList_Check(rec->providedby)) { ++ PyList_Append(rec->providedby, (PyObject *)prv); ++ } else { ++ PyObject *_lst = PyList_New(1); ++ Py_INCREF(prv); ++ PyList_SET_ITEM(_lst, 0, (PyObject *)prv); ++ Py_DECREF(rec->providedby); ++ rec->providedby = _lst; ++ } ++ ++ /* ++ if prv.recommendedby: ++ prv.recommendedby.append(prv) ++ else: ++ prv.recommendedby = [prv] ++ */ ++ if (PyList_Check(prv->recommendedby)) { ++ PyList_Append(prv->recommendedby, (PyObject *)rec); ++ } else { ++ PyObject *_lst = PyList_New(1); ++ Py_INCREF(rec); ++ PyList_SET_ITEM(_lst, 0, (PyObject *)rec); ++ Py_DECREF(prv->recommendedby); ++ prv->recommendedby = _lst; ++ } ++ } ++ Py_DECREF(ret); ++ } ++ } ++ + /* lst = upgnames.get(prv.name) */ + lst = PyDict_GetItem(upgnames, prv->name); + +@@ -3821,6 +4094,21 @@ Cache__setstate__(CacheObject *self, PyObject *state) + } + + /* ++ for rec in pkg.recommends: ++ rec.packages.append(pkg) ++ recommends[rec] = True ++ */ ++ if (PyList_Check(pkgobj->recommends)) { ++ jlen = PyList_GET_SIZE(pkgobj->recommends); ++ for (j = 0; j != jlen; j++) { ++ PyObject *rec = PyList_GET_ITEM(pkgobj->recommends, j); ++ DependsObject *recobj = (DependsObject *)rec; ++ PyList_Append(recobj->packages, pkg); ++ PyDict_SetItem(recommends, rec, Py_True); ++ } ++ } ++ ++ /* + for upg in pkg.upgrades: + upg.packages.append(pkg) + upgrades[upg] = True +diff --git a/smart/commands/query.py b/smart/commands/query.py +index 9265cd9..b6f5697 100644 +--- a/smart/commands/query.py ++++ b/smart/commands/query.py +@@ -750,6 +750,22 @@ class TextOutput(NullOutput): + name = str(prvpkg) + print " ", "%s (%s)" % (name, prv) + ++ def showRecommends(self, pkg, rec): ++ if self._firstrecommends: ++ self._firstrecommends = False ++ print " ", _("Recommends:") ++ print " ", rec ++ ++ def showRecommendsProvidedBy(self, pkg, req, prv, prvpkg): ++ if self._firstrecommendsprovidedby: ++ self._firstrecommendsprovidedby = False ++ print " ", _("Provided By:") ++ if self.opts.hide_version: ++ name = prvpkg.name ++ else: ++ name = str(prvpkg) ++ print " ", "%s (%s)" % (name, prv) ++ + def showUpgrades(self, pkg, upg): + if self._firstupgrades: + self._firstupgrades = False diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-rpm4-fixes.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-rpm4-fixes.patch new file mode 100644 index 000000000..708ffe67d --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-rpm4-fixes.patch @@ -0,0 +1,49 @@ + +This patch checks for rpm5 related functions in order to allow rpm4 +to work correctly. Currently the rpm4 archscore and filter work +differently enough that they need to be changed. + +Upstream-Status: Inappropriate [OE-Core Specific] + +Signed-off-by: Saul Wold <sgw@linux.intel.com> + +Index: smart-1.4.1/smart/backends/rpm/base.py +=================================================================== +--- smart-1.4.1.orig/smart/backends/rpm/base.py ++++ smart-1.4.1/smart/backends/rpm/base.py +@@ -338,10 +338,14 @@ class RPMObsoletes(Depends): + + _SCOREMAP = {} + def getArchScore(arch, _sm=_SCOREMAP): +- if arch not in _sm: +- score = rpm.archscore(arch) +- _sm[arch] = score +- return _sm.get(arch, 0) ++ try: ++ rpm.platformscore(arch) ++ if arch not in _sm: ++ score = rpm.archscore(arch) ++ _sm[arch] = score ++ return _sm.get(arch, 0) ++ except AttributeError: ++ return 1 + + # TODO: Embed color into nameprovides and obsoletes relations. + _COLORMAP = {"noarch": 0, "x86_64": 2, "ppc64": 2, "s390x": 2, "sparc64": 2} +Index: smart-1.4.1/smart/backends/rpm/pm.py +=================================================================== +--- smart-1.4.1.orig/smart/backends/rpm/pm.py ++++ smart-1.4.1/smart/backends/rpm/pm.py +@@ -235,6 +235,12 @@ class RPMPackageManager(PackageManager): + if sysconf.get("rpm-order"): + ts.order() + probfilter = rpm.RPMPROB_FILTER_OLDPACKAGE ++ try: ++ # Test for RPM5 function ++ rpm.platformscore("") ++ except AttributeError: ++ probfilter |= rpm.RPMPROB_FILTER_IGNOREARCH ++ + if force or reinstall: + probfilter |= rpm.RPMPROB_FILTER_REPLACEPKG + probfilter |= rpm.RPMPROB_FILTER_REPLACEOLDFILES diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-set-noprogress-for-pycurl.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-set-noprogress-for-pycurl.patch new file mode 100644 index 000000000..2885998ac --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smart-set-noprogress-for-pycurl.patch @@ -0,0 +1,20 @@ +Set NOPROGRESS for pycurl just as same as default operation in pycurl module itself. +If set NOPROGRESS with 0 for pycurl, it causes dead lock issue of Python GIL when +call smart library by python gui just like pygtk. + +Upstream-Status: Pending + +Signed-off-by: Kai Kang <kai.kang@windriver.com> +--- +diff -u smart-1.4.1/smart.orig/fetcher.py smart-1.4.1/smart/fetcher.py +--- smart-1.4.1/smart.orig/fetcher.py 2014-07-15 16:42:19.240437080 +0800 ++++ smart-1.4.1/smart/fetcher.py 2014-07-15 17:02:37.812470289 +0800 +@@ -1720,7 +1720,7 @@ + handle.setopt(pycurl.OPT_FILETIME, 1) + handle.setopt(pycurl.LOW_SPEED_LIMIT, 1) + handle.setopt(pycurl.LOW_SPEED_TIME, SOCKETTIMEOUT) +- handle.setopt(pycurl.NOPROGRESS, 0) ++ handle.setopt(pycurl.NOPROGRESS, 1) + handle.setopt(pycurl.PROGRESSFUNCTION, progress) + handle.setopt(pycurl.WRITEDATA, local) + handle.setopt(pycurl.FOLLOWLOCATION, 1) diff --git a/yocto-poky/meta/recipes-devtools/python/python-smartpm/smartpm-rpm5-nodig.patch b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smartpm-rpm5-nodig.patch new file mode 100644 index 000000000..fefb29a66 --- /dev/null +++ b/yocto-poky/meta/recipes-devtools/python/python-smartpm/smartpm-rpm5-nodig.patch @@ -0,0 +1,59 @@ +RPM5 has removed support for RPMVSF_NOSIGNATURES + +Patch smart to no longer use this flag + +Upstream-Status: Pending + +Signed-off-by: Mark Hatle <mark.hatle@windriver.com> + +diff --git a/smart/backends/rpm/base.py b/smart/backends/rpm/base.py +--- a/smart/backends/rpm/base.py ++++ b/smart/backends/rpm/base.py +@@ -63,11 +63,11 @@ def getTS(new=False): + if sysconf.get("rpm-dbpath"): + rpm.addMacro('_dbpath', "/" + sysconf.get("rpm-dbpath")) + getTS.ts = rpm.ts(getTS.root) +- if not sysconf.get("rpm-check-signatures", False): +- if hasattr(rpm, '_RPMVSF_NOSIGNATURES'): +- getTS.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES) +- else: +- raise Error, _("rpm requires checking signatures") ++ #if not sysconf.get("rpm-check-signatures", False): ++ # if hasattr(rpm, '_RPMVSF_NOSIGNATURES'): ++ # getTS.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES) ++ # else: ++ # raise Error, _("rpm requires checking signatures") + rpm_dbpath = sysconf.get("rpm-dbpath", "var/lib/rpm") + dbdir = rpm_join_dbpath(getTS.root, rpm_dbpath) + if not os.path.isdir(dbdir): +@@ -89,11 +89,11 @@ def getTS(new=False): + if sysconf.get("rpm-dbpath"): + rpm.addMacro('_dbpath', "/" + sysconf.get("rpm-dbpath")) + ts = rpm.ts(getTS.root) +- if not sysconf.get("rpm-check-signatures", False): +- if hasattr(rpm, '_RPMVSF_NOSIGNATURES'): +- ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES) +- else: +- raise Error, _("rpm requires checking signatures") ++ #if not sysconf.get("rpm-check-signatures", False): ++ # if hasattr(rpm, '_RPMVSF_NOSIGNATURES'): ++ # ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES) ++ # else: ++ # raise Error, _("rpm requires checking signatures") + return ts + else: + return getTS.ts +diff --git a/smart/plugins/yumchannelsync.py b/smart/plugins/yumchannelsync.py +--- a/smart/plugins/yumchannelsync.py ++++ b/smart/plugins/yumchannelsync.py +@@ -56,8 +56,8 @@ def _getreleasever(): + + rpmroot = sysconf.get("rpm-root", "/") + ts = rpmUtils.transaction.initReadOnlyTransaction(root=rpmroot) +- if hasattr(rpm, '_RPMVSF_NOSIGNATURES') and hasattr(rpm, '_RPMVSF_NODIGESTS'): +- ts.pushVSFlags(~(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)) ++ #if hasattr(rpm, '_RPMVSF_NOSIGNATURES') and hasattr(rpm, '_RPMVSF_NODIGESTS'): ++ # ts.pushVSFlags(~(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)) + releasever = None + # HACK: we're hard-coding the most used distros, will add more if needed + idx = ts.dbMatch('provides', 'fedora-release') |