[yum-commits] Branch 'yum-3_2_X' - 6 commits - docs/yum.8 output.py yumcommands.py yum/history.py yum/__init__.py yum/packages.py

James Antill james at osuosl.org
Fri Aug 5 13:39:29 UTC 2011


 docs/yum.8      |   18 ++-
 output.py       |   99 ++++++++++++++++-
 yum/__init__.py |   16 ++
 yum/history.py  |  315 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 yum/packages.py |    8 +
 yumcommands.py  |   40 ++++++-
 6 files changed, 463 insertions(+), 33 deletions(-)

New commits:
commit 8b47091710b2fda8ca5b1006787183824aa88ae9
Author: James Antill <james at and.org>
Date:   Thu Aug 4 15:11:31 2011 -0400

    Add ui_evr, like ui_nevra ... for "yum list" like output.

diff --git a/yum/packages.py b/yum/packages.py
index 79c15db..f72c068 100644
--- a/yum/packages.py
+++ b/yum/packages.py
@@ -271,6 +271,14 @@ class PackageObject(object):
         return out
     ui_nevra = property(fget=lambda self: self._ui_nevra())
 
+    def _ui_evr(self):
+        if self.epoch == '0':
+            out = '%s-%s' % (self.version, self.release)
+        else:
+            out = '%s:%s-%s' % (self.epoch, self.version, self.release)
+        return out
+    ui_evr = property(fget=lambda self: self._ui_evr())
+
     def __str__(self):
         return self.ui_envra
 
commit 72102db9b92a97ad35231fd4106a896e66516acf
Author: James Antill <james at and.org>
Date:   Thu Aug 4 10:06:29 2011 -0400

    Accept old outputs of "-q history addon-info saved_tx" in load_ts. BZ 728253

diff --git a/yum/__init__.py b/yum/__init__.py
index fe312ce..530bfd4 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -5318,6 +5318,16 @@ class YumBase(depsolve.Depsolve):
         # 3+numrepos = num pkgs
         # 3+numrepos+1 -> EOF= txmembers
         
+        if data[0] == 'saved_tx:\n':
+            #  Old versions of yum would put "saved_tx:" at the begining and
+            # two blank lines at the end when you used:
+            # "yum -q history addon-info saved_tx".
+            if data[-1] == 'history addon-info\n':
+                # Might as well also DTRT if they hand removed the plugins line
+                data = data[1:-3]
+            else:
+                data = data[1:-2]
+
         # rpm db ver
         rpmv = data[0].strip()
         if rpmv != str(self.rpmdb.simpleVersion(main_only=True)[0]):
commit 47b07cd12e16cdc82f9b63667f32647e41cb3381
Author: James Antill <james at and.org>
Date:   Thu Aug 4 09:52:34 2011 -0400

    Make "yum -q history addon-info last saved_tx" valid input for load-ts.

diff --git a/output.py b/output.py
index da34382..00e0e6f 100755
--- a/output.py
+++ b/output.py
@@ -2349,12 +2349,12 @@ to exit.
         
         for item in extcmds[2:]:
             if item in addon_info:
-                print '%s:' % item
-                print self.history.return_addon_data(hist_data.tid, item)
+                self.verbose_logger.log(logginglevels.INFO_2, '%s:', item)
+                print self.history.return_addon_data(hist_data.tid, item),
+                self.verbose_logger.log(logginglevels.INFO_2, '')
             else:
                 print _('%s: No additional data found by this name') % item
-
-            print ''
+            self.verbose_logger.log(logginglevels.INFO_2, '')
 
     def historyPackageListCmd(self, extcmds):
         """Print a list of information about transactions from history
commit a4b5c4cd6a670a2a9332bd0f7957c280b4bbad37
Author: James Antill <james at and.org>
Date:   Wed Aug 3 14:13:19 2011 -0400

    Add some docs. for the new history commands.

diff --git a/docs/yum.8 b/docs/yum.8
index a1375de..255c755 100644
--- a/docs/yum.8
+++ b/docs/yum.8
@@ -69,7 +69,7 @@ gnome\-packagekit application\&.
 .br
 .I \fR * version [ all | installed | available | group-* | nogroups* | grouplist | groupinfo ]
 .br
-.I \fR * history [info|list|packages-list|summary|addon-info|redo|undo|rollback|new] 
+.I \fR * history [info|list|packages-list|packages-info|summary|addon-info|redo|undo|rollback|new|sync|stats] 
 .br
 .I \fR * load-transaction [txfile]
 .br
@@ -323,15 +323,17 @@ and so takes sub-commands:
 .IP "\fBhistory\fP"
 The history command allows the user to view what has happened in past
 transactions (assuming the history_record config. option is set). You can use
-info/list/packages-list/summary to view what happened, undo/redo/rollback to act
-on that information and new to start a new history file.
+info/list/packages-list/packages-info/summary to view what happened,
+undo/redo/rollback to act on that information and new to start a new history
+file.
 
 The info/list/summary commands take either a transaction id or a package (with
 wildcards, as in \fBSpecifying package names\fP), all three can also be passed
 no arguments. list can be passed the keyword "all" to list all the transactions.
 
-The packages-list command takes a package  (with wildcards, as in
-\fBSpecifying package names\fP).
+The packages-list/packages-info commands takes a package  (with wildcards, as in
+\fBSpecifying package names\fP). And show data from the point of view of that
+package.
 
 The undo/redo/rollback commands take either a single transaction id or the
 keyword last and an offset from the last transaction (Eg. if you've done 250
@@ -351,6 +353,12 @@ transactions 1 and 4.
 The addon-info command takes a transaction ID, and the packages-list command
 takes a package (with wildcards).
 
+The stats command shows some statistics about the current history DB.
+
+The sync commands allows you to change the rpmdb/yumdb data stored for any
+installed packages, to whaever is in the current rpmdb/yumdb (this is mostly
+useful when this data was not stored when the package went into the history DB).
+
 In "history list" you can change the behaviour of the 2nd column via. the
 configuration option history_list_view.
 
commit fb5434395ed74d6f730dbf7b3f3201e322c9d14e
Author: James Antill <james at and.org>
Date:   Wed Aug 3 14:08:56 2011 -0400

     Add stats/pkg-info/sync history commands, so we can use/see the new
    rpmdb/yumdb data.

diff --git a/output.py b/output.py
index 00a938d..da34382 100755
--- a/output.py
+++ b/output.py
@@ -47,6 +47,8 @@ import yum.history
 
 from yum.i18n import utf8_width, utf8_width_fill, utf8_text_fill
 
+import locale
+
 def _term_width():
     """ Simple terminal width, limit to 20 chars. and make 0 == 80. """
     if not hasattr(urlgrabber.progress, 'terminal_width_cached'):
@@ -2445,6 +2447,92 @@ to exit.
             if lastdbv.end_rpmdbversion != rpmdbv:
                 self._rpmdb_warn_checks()
 
+    def historyPackageInfoCmd(self, extcmds):
+        """Print information about packages in history transactions.
+
+        :param extcmds: list of extra command line arguments
+        """
+        tids = self.history.search(extcmds)
+        limit = None
+        if extcmds and not tids:
+            self.logger.critical(_('Bad transaction IDs, or package(s), given'))
+            return 1, ['Failed history packages-info']
+        if not tids:
+            limit = 20
+
+        all_uistates = self._history_state2uistate
+
+        num = 0
+        for old in self.history.old(tids, limit=limit):
+            if limit is not None and num and (num +len(old.trans_data)) > limit:
+                break
+            last = None
+
+            for hpkg in old.trans_data: # Find a pkg to go with each cmd...
+                if limit is None:
+                    x,m,u = yum.packages.parsePackages([hpkg], extcmds)
+                    if not x and not m:
+                        continue
+
+                uistate = all_uistates.get(hpkg.state, hpkg.state)
+                if num:
+                    print ""
+                print _("Transaction ID :"), old.tid
+                tm = time.ctime(old.beg_timestamp)
+                print _("Begin time     :"), tm
+                print _("Package        :"), hpkg.ui_nevra
+                print _("State          :"), uistate
+                if hpkg.size is not None:
+                    num = int(hpkg.size)
+                    print _("Size           :"), locale.format("%d", num, True)
+                if hpkg.buildhost is not None:
+                    print _("Build host     :"), hpkg.buildhost
+                if hpkg.buildtime is not None:
+                    tm = time.ctime(int(hpkg.buildtime))
+                    print _("Build time     :"), tm
+                if hpkg.packager is not None:
+                    print _("Packager       :"), hpkg.packager
+                if hpkg.vendor is not None:
+                    print _("Vendor         :"), hpkg.vendor
+                if hpkg.license is not None:
+                    print _("License        :"), hpkg.license
+                if hpkg.url is not None:
+                    print _("URL            :"), hpkg.url
+                if hpkg.sourcerpm is not None:
+                    print _("Source RPM     :"), hpkg.sourcerpm
+                if hpkg.committime is not None:
+                    tm = time.ctime(int(hpkg.committime))
+                    print _("Commit Time    :"), tm
+                if hpkg.committer is not None:
+                    print _("Committer      :"), hpkg.committer
+                if hpkg.yumdb_info.reason is not None:
+                    print _("Reason         :"), hpkg.yumdb_info.reason
+                if hpkg.yumdb_info.command_line is not None:
+                    print _("Command Line   :"), hpkg.yumdb_info.command_line
+                if hpkg.yumdb_info.from_repo is not None:
+                    print _("From repo      :"), hpkg.yumdb_info.from_repo
+                if hpkg.yumdb_info.installed_by is not None:
+                    uid = int(hpkg.yumdb_info.installed_by)
+                    name = self._pwd_ui_username(uid)
+                    print _("Installed by   :"), name
+                if hpkg.yumdb_info.changed_by is not None:
+                    uid = int(hpkg.yumdb_info.changed_by)
+                    name = self._pwd_ui_username(uid)
+                    print _("Changed by     :"), name
+
+                num += 1
+
+        # And, again, copy and paste...
+        lastdbv = self.history.last()
+        if lastdbv is None:
+            self._rpmdb_warn_checks(warn=False)
+        else:
+            #  If this is the last transaction, is good and it doesn't
+            # match the current rpmdb ... then mark it as bad.
+            rpmdbv  = self.rpmdb.simpleVersion(main_only=True)[0]
+            if lastdbv.end_rpmdbversion != rpmdbv:
+                self._rpmdb_warn_checks()
+
 
 class DepSolveProgressCallBack:
     """A class to provide text output callback functions for Dependency Solver callback."""
diff --git a/yum/history.py b/yum/history.py
index 609394f..c91c33a 100644
--- a/yum/history.py
+++ b/yum/history.py
@@ -1350,6 +1350,35 @@ class YumHistory:
         self._commit()
         return True
 
+    def _pkg_stats(self):
+        """ Some stats about packages in the DB. """
+
+        ret = {'nevrac' : 0,
+               'nevra'  : 0,
+               'nevr'   : 0,
+               'na'     : 0,
+               'rpmdb'  : 0,
+               'yumdb'  : 0,
+               }
+        cur = self._get_cursor()
+        if cur is None or not self._update_db_file_3():
+            return False
+
+        data = (('nevrac', "COUNT(*)",                      "pkgtups"),
+                ('na',     "COUNT(DISTINCT(name || arch))", "pkgtups"),
+                ('nevra',"COUNT(DISTINCT(name||version||epoch||release||arch))",
+                 "pkgtups"),
+                ('nevr',   "COUNT(DISTINCT(name||version||epoch||release))",
+                 "pkgtups"),
+                ('rpmdb',  "COUNT(DISTINCT(pkgtupid))", "pkg_rpmdb"),
+                ('yumdb',  "COUNT(DISTINCT(pkgtupid))", "pkg_yumdb"))
+
+        for key, bsql, esql in data:
+            executeSQL(cur, "SELECT %s FROM %s" % (bsql, esql))
+            for row in cur:
+                ret[key] = row[0]
+        return ret
+
     def _yieldSQLDataList(self, patterns, fields, ignore_case):
         """Yields all the package data for the given params. """
 
diff --git a/yumcommands.py b/yumcommands.py
index 3a985c3..d9c70f3 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -2425,6 +2425,36 @@ class HistoryCommand(YumCommand):
     def _hcmd_new(self, base, extcmds):
         base.history._create_db_file()
 
+    def _hcmd_stats(self, base, extcmds):
+        print "File        :", base.history._db_file
+        num = os.stat(base.history._db_file).st_size
+        print "Size        :", locale.format("%d", num, True)
+        counts = base.history._pkg_stats()
+        trans_1 = base.history.old("1")[0]
+        trans_N = base.history.last()
+        print _("Transactions:"), trans_N.tid
+        print _("Begin time  :"), time.ctime(trans_1.beg_timestamp)
+        print _("End time    :"), time.ctime(trans_N.end_timestamp)
+        print _("Counts      :")
+        print _("  NEVRAC :"), locale.format("%6d", counts['nevrac'], True)
+        print _("  NEVRA  :"), locale.format("%6d", counts['nevra'],  True)
+        print _("  NA     :"), locale.format("%6d", counts['na'],     True)
+        print _("  NEVR   :"), locale.format("%6d", counts['nevr'],   True)
+        print _("  rpm DB :"), locale.format("%6d", counts['rpmdb'],  True)
+        print _("  yum DB :"), locale.format("%6d", counts['yumdb'],  True)
+
+    def _hcmd_sync(self, base, extcmds):
+        extcmds = extcmds[1:]
+        if not extcmds:
+            extcmds = None
+        for ipkg in sorted(base.rpmdb.returnPackages(patterns=extcmds)):
+            if base.history.pkg2pid(ipkg, create=False) is None:
+                continue
+
+            print "Syncing rpm/yum DB data for:", ipkg, "...",
+            base.history.sync_alldb(ipkg)
+            print "Done."
+
     def doCheck(self, base, basecmd, extcmds):
         """Verify that conditions are met so that this command can
         run.  The exact conditions checked will vary depending on the
@@ -2437,8 +2467,10 @@ class HistoryCommand(YumCommand):
         cmds = ('list', 'info', 'summary', 'repeat', 'redo', 'undo', 'new',
                 'rollback',
                 'addon', 'addon-info',
+                'stats', 'statistics', 'sync', 'synchronize'
                 'pkg', 'pkgs', 'pkg-list', 'pkgs-list',
-                'package', 'package-list', 'packages', 'packages-list')
+                'package', 'package-list', 'packages', 'packages-list',
+                'pkg-info', 'pkgs-info', 'package-info', 'packages-info')
         if extcmds and extcmds[0] not in cmds:
             base.logger.critical(_('Invalid history sub-command, use: %s.'),
                                  ", ".join(cmds))
@@ -2488,6 +2520,12 @@ class HistoryCommand(YumCommand):
             ret = self._hcmd_rollback(base, extcmds)
         elif vcmd == 'new':
             ret = self._hcmd_new(base, extcmds)
+        elif vcmd in ('stats', 'statistics'):
+            ret = self._hcmd_stats(base, extcmds)
+        elif vcmd in ('sync', 'synchronize'):
+            ret = self._hcmd_sync(base, extcmds)
+        elif vcmd in ('pkg-info', 'pkgs-info', 'package-info', 'packages-info'):
+            ret = base.historyPackageInfoCmd(extcmds)
 
         if ret is None:
             return 0, ['history %s' % (vcmd,)]
commit 53b0bb6088ff96659398e25ae81551feaa725121
Author: James Antill <james at and.org>
Date:   Wed Aug 3 14:02:41 2011 -0400

     Add extra history DB data, rpmdb and yumdb. BZ 662243.
    
     This does a few things, the only really user visible part though is
    that "yum history info" will now get the from_repo data from the history
    DB ... if available. And the history DB will get bigger :).
     The history package class is also tweaked so that YumHistoryPackage objects
    now act a lot more like YumHeaderPackage objects (using rpmdb/yumdb
    data).
    
     We also change pkg2pid() so that you can "lookup" a pkg. to see if it's
    in the history, without changing the DB.

diff --git a/output.py b/output.py
index 9610232..00a938d 100755
--- a/output.py
+++ b/output.py
@@ -2002,6 +2002,9 @@ to exit.
     def _hpkg2from_repo(self, hpkg):
         """ Given a pkg, find the ipkg.ui_from_repo ... if none, then
             get an apkg. ... and put a ? in there. """
+        if 'from_repo' in hpkg.yumdb_info:
+            return hpkg.ui_from_repo
+
         ipkgs = self.rpmdb.searchPkgTuple(hpkg.pkgtup)
         if not ipkgs:
             apkgs = self.pkgSack.searchPkgTuple(hpkg.pkgtup)
diff --git a/yum/__init__.py b/yum/__init__.py
index b29dc80..fe312ce 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -881,7 +881,8 @@ class YumBase(depsolve.Depsolve):
         if self._history is None:
             pdb_path = self.conf.persistdir + "/history"
             self._history = yum.history.YumHistory(root=self.conf.installroot,
-                                                   db_path=pdb_path)
+                                                   db_path=pdb_path,
+                                                   releasever=self.conf.yumvar['releasever'])
         return self._history
     
     # properties so they auto-create themselves with defaults
@@ -1647,6 +1648,9 @@ class YumBase(depsolve.Depsolve):
                 elif loginuid is not None:
                     po.yumdb_info.installed_by = str(loginuid)
 
+                if self.conf.history_record:
+                    self.history.sync_alldb(po)
+
         # Remove old ones after installing new ones, so we can copy values.
         for txmbr in self.tsInfo:
             if txmbr.output_state in TS_INSTALL_STATES:
diff --git a/yum/history.py b/yum/history.py
index 5385bd1..609394f 100644
--- a/yum/history.py
+++ b/yum/history.py
@@ -97,9 +97,58 @@ def _setupHistorySearchSQL(patterns=None, ignore_case=False):
     return (need_full, patterns, fields, False)
 # ---- horrible Copy and paste from sqlitesack ----
 
+class _YumHistPackageYumDB:
+    """ Class to pretend to be yumdb_info for history packages. """
+
+    def __init__(self, pkg):
+        self._pkg = pkg
+
+    _valid_yumdb_keys = set(["command_line",
+                             "from_repo", "from_repo_revision",
+                             "from_repo_timestamp",
+                             "installed_by", "changed_by",
+                             "reason", "releasever"])
+    def __getattr__(self, attr):
+        """ Load yumdb attributes from the history sqlite. """
+        pkg = self._pkg
+        if attr.startswith('_'):
+            raise AttributeError, "%s has no yum attribute %s" % (pkg, attr)
+
+        if attr not in self._valid_yumdb_keys:
+            raise AttributeError, "%s has no yum attribute %s" % (pkg, attr)
+
+        val = pkg._history._load_yumdb_key(pkg, attr)
+        if False and val is None:
+            raise AttributeError, "%s has no yum attribute %s" % (pkg, attr)
+
+        if val is None:
+            return None
+
+        val = str(val) or ""
+        setattr(self, attr, val)
+
+        return val
+
+    def __contains__(self, attr):
+        #  This is faster than __iter__ and it makes things fail in a much more
+        # obvious way in weird FS corruption cases like: BZ 593436
+        x = self.get(attr)
+        return x is not None
+
+    def get(self, attr, default=None):
+        """retrieve an add'l data obj"""
+
+        try:
+            res = getattr(self, attr)
+        except AttributeError:
+            return default
+        return res
+
+
 class YumHistoryPackage(PackageObject):
 
-    def __init__(self, name, arch, epoch, version, release, checksum=None):
+    def __init__(self, name, arch, epoch, version, release, checksum=None,
+                 history=None):
         self.name    = name
         self.version = version
         self.release = release
@@ -111,21 +160,69 @@ class YumHistoryPackage(PackageObject):
             self._checksums = [] # (type, checksum, id(0,1)
         else:
             chk = checksum.split(':')
-            self._checksums = [(chk[0], chk[1], 0)] # (type, checksum, id(0,1))
+            self._checksums = [(chk[0], chk[1], 1)] # (type, checksum, id(0,1))
         # Needed for equality comparisons in PackageObject
         self.repoid = "<history>"
 
+        self._history = history
+        self.yumdb_info = _YumHistPackageYumDB(self)
+
+    _valid_rpmdb_keys = set(["buildtime", "buildhost",
+                             "license", "packager",
+                             "size", "sourcerpm", "url", "vendor",
+                             # ?
+                             "committer", "committime"])
+    def __getattr__(self, attr):
+        """ Load rpmdb attributes from the history sqlite. """
+        if attr.startswith('_'):
+            raise AttributeError, "%s has no attribute %s" % (self, attr)
+
+        if attr not in self._valid_rpmdb_keys:
+            raise AttributeError, "%s has no attribute %s" % (self, attr)
+
+        val = self._history._load_rpmdb_key(self, attr)
+        if False and val is None:
+            raise AttributeError, "%s has no attribute %s" % (self, attr)
+
+        if val is None:
+            return None
+
+        val = str(val) or ""
+        setattr(self, attr, val)
+
+        return val
+
+    def _ui_from_repo(self):
+        """ This reports the repo the package is from, we integrate YUMDB info.
+            for RPM packages so a package from "fedora" that is installed has a
+            ui_from_repo of "@fedora". Note that, esp. with the --releasever
+            option, "fedora" or "rawhide" isn't authoritive.
+            So we also check against the current releasever and if it is
+            different we also print the YUMDB releasever. This means that
+            installing from F12 fedora, while running F12, would report as
+            "@fedora/13". """
+        if 'from_repo' in self.yumdb_info:
+            self._history.releasever
+            end = ''
+            if (self._history.releasever is not None and
+                'releasever' in self.yumdb_info and
+                self.yumdb_info.releasever != self._history.releasever):
+                end = '/' + self.yumdb_info.releasever
+            return '@' + self.yumdb_info.from_repo + end
+        return self.repoid
+    ui_from_repo = property(fget=lambda self: self._ui_from_repo())
+
+
 class YumHistoryPackageState(YumHistoryPackage):
-    def __init__(self, name,arch, epoch,version,release, state, checksum=None):
+    def __init__(self, name,arch, epoch,version,release, state, checksum=None,
+                 history=None):
         YumHistoryPackage.__init__(self, name,arch, epoch,version,release,
-                                   checksum)
+                                   checksum, history)
         self.done  = None
         self.state = state
 
-        self.repoid = '<history>'
-
 
-class YumHistoryRpmdbProblem(PackageObject):
+class YumHistoryRpmdbProblem:
     """ Class representing an rpmdb problem that existed at the time of the
         transaction. """
 
@@ -328,7 +425,8 @@ class YumMergedHistoryTransaction(YumHistoryTransaction):
     @staticmethod
     def _conv_pkg_state(pkg, state):
         npkg = YumHistoryPackageState(pkg.name, pkg.arch,
-                                      pkg.epoch,pkg.version,pkg.release, state)
+                                      pkg.epoch,pkg.version,pkg.release, state,
+                                      pkg._history)
         npkg._checksums = pkg._checksums
         npkg.done = pkg.done
         if _sttxt2stcode[npkg.state] in TS_INSTALL_STATES:
@@ -557,7 +655,7 @@ class YumMergedHistoryTransaction(YumHistoryTransaction):
 class YumHistory:
     """ API for accessing the history sqlite data. """
 
-    def __init__(self, root='/', db_path=_history_dir):
+    def __init__(self, root='/', db_path=_history_dir, releasever=None):
         self._conn = None
         
         self.conf = yum.misc.GenericHolder()
@@ -568,6 +666,8 @@ class YumHistory:
         self.conf.writable = False
         self.conf.readable = True
 
+        self.releasever = releasever
+
         if not os.path.exists(self.conf.db_path):
             try:
                 os.makedirs(self.conf.db_path)
@@ -644,7 +744,7 @@ class YumHistory:
             self._conn.close()
             self._conn = None
 
-    def _pkgtup2pid(self, pkgtup, checksum=None):
+    def _pkgtup2pid(self, pkgtup, checksum=None, create=True):
         cur = self._get_cursor()
         executeSQL(cur, """SELECT pkgtupid, checksum FROM pkgtups
                            WHERE name=? AND arch=? AND
@@ -659,6 +759,9 @@ class YumHistory:
             if checksum == sql_checksum:
                 return sql_pkgtupid
         
+        if not create:
+            return None
+
         (n,a,e,v,r) = pkgtup
         (n,a,e,v,r) = (to_unicode(n),to_unicode(a),
                        to_unicode(e),to_unicode(v),to_unicode(r))
@@ -674,23 +777,28 @@ class YumHistory:
                                 (name, arch, epoch, version, release)
                                 VALUES (?, ?, ?, ?, ?)""", (n,a,e,v,r))
         return cur.lastrowid
-    def _apkg2pid(self, po):
+    def _apkg2pid(self, po, create=True):
         csum = po.returnIdSum()
         if csum is not None:
             csum = "%s:%s" % (str(csum[0]), str(csum[1]))
-        return self._pkgtup2pid(po.pkgtup, csum)
-    def _ipkg2pid(self, po):
+        return self._pkgtup2pid(po.pkgtup, csum, create)
+    def _ipkg2pid(self, po, create=True):
         csum = None
         yumdb = po.yumdb_info
         if 'checksum_type' in yumdb and 'checksum_data' in yumdb:
             csum = "%s:%s" % (yumdb.checksum_type, yumdb.checksum_data)
-        return self._pkgtup2pid(po.pkgtup, csum)
-    def pkg2pid(self, po):
+        return self._pkgtup2pid(po.pkgtup, csum, create)
+    def _hpkg2pid(self, po, create=False):
+        return self._apkg2pid(po, create)
+
+    def pkg2pid(self, po, create=True):
         if isinstance(po, YumInstalledPackage):
-            return self._ipkg2pid(po)
+            return self._ipkg2pid(po, create)
         if isinstance(po, YumAvailablePackage):
-            return self._apkg2pid(po)
-        return self._pkgtup2pid(po.pkgtup, None)
+            return self._apkg2pid(po, create)
+        if isinstance(po, YumHistoryPackage):
+            return self._hpkg2pid(po, create)
+        return self._pkgtup2pid(po.pkgtup, None, create)
 
     @staticmethod
     def txmbr2state(txmbr):
@@ -984,7 +1092,8 @@ class YumHistory:
                       ORDER BY name ASC, epoch ASC""", (tid,))
         ret = []
         for row in cur:
-            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5])
+            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5],
+                                    history=self)
             ret.append(obj)
         return ret
     def _old_data_pkgs(self, tid):
@@ -998,7 +1107,7 @@ class YumHistory:
         ret = []
         for row in cur:
             obj = YumHistoryPackageState(row[0],row[1],row[2],row[3],row[4],
-                                         row[7], row[5])
+                                         row[7], row[5], history=self)
             obj.done     = row[6] == 'TRUE'
             obj.state_installed = None
             if _sttxt2stcode[obj.state] in TS_INSTALL_STATES:
@@ -1018,7 +1127,8 @@ class YumHistory:
                       ORDER BY name ASC, epoch ASC""", (tid,))
         ret = []
         for row in cur:
-            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5])
+            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5],
+                                    history=self)
             ret.append(obj)
         return ret
     def _old_prob_pkgs(self, rpid):
@@ -1032,7 +1142,8 @@ class YumHistory:
                       ORDER BY name ASC, epoch ASC""", (rpid,))
         ret = []
         for row in cur:
-            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5])
+            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5],
+                                    history=self)
             obj.main = row[6] == 'TRUE'
             ret.append(obj)
         return ret
@@ -1151,6 +1262,94 @@ class YumHistory:
         assert len(ret) == 1
         return ret[0]
 
+    def _load_anydb_key(self, pkg, db, attr):
+        cur = self._get_cursor()
+        if cur is None or not self._update_db_file_3():
+            return None
+
+        pid = self.pkg2pid(pkg, create=False)
+        if pid is None:
+            return None
+
+        sql = """SELECT %(db)sdb_val FROM pkg_%(db)sdb
+                  WHERE pkgtupid=? and %(db)sdb_key=? """ % {'db' : db}
+        executeSQL(cur, sql, (pid, attr))
+        for row in cur:
+            return row[0]
+
+        return None
+
+    def _load_rpmdb_key(self, pkg, attr):
+        return self._load_anydb_key(pkg, "rpm", attr)
+    def _load_yumdb_key(self, pkg, attr):
+        return self._load_anydb_key(pkg, "yum", attr)
+
+    def _save_anydb_key(self, pkg, db, attr, val):
+        cur = self._get_cursor()
+        if cur is None or not self._update_db_file_3():
+            return None
+
+        pid = self.pkg2pid(pkg, create=False)
+        if pid is None:
+            return None
+
+        sql = """INSERT INTO pkg_%(db)sdb (pkgtupid, %(db)sdb_key, %(db)sdb_val)
+                        VALUES (?, ?, ?)""" % {'db' : db}
+        executeSQL(cur, sql, (pid, attr, val))
+        for row in cur:
+            return row[0]
+
+        return None
+
+    def _save_rpmdb_key(self, pkg, attr, val):
+        return self._save_anydb_key(pkg, "rpm", attr, val)
+    def _save_yumdb_key(self, pkg, attr, val):
+        return self._save_anydb_key(pkg, "yum", attr, val)
+
+    def _save_rpmdb(self, ipkg):
+        """ Save all the data for rpmdb for this installed pkg, assumes
+            there is no data currently. """
+        for attr in YumHistoryPackage._valid_rpmdb_keys:
+            val = getattr(ipkg, attr, None)
+            if val is None:
+                continue
+            self._save_anydb_key(ipkg, "rpm", attr, val)
+
+    def _save_yumdb(self, ipkg):
+        """ Save all the data for yumdb for this installed pkg, assumes
+            there is no data currently. """
+        for attr in _YumHistPackageYumDB._valid_yumdb_keys:
+            val = ipkg.yumdb_info.get(attr)
+            if val is None:
+                continue
+            self._save_anydb_key(ipkg, "yum", attr, val)
+
+    def _wipe_anydb(self, pkg, db):
+        """ Delete all the data for rpmdb/yumdb for this installed pkg. """
+        cur = self._get_cursor()
+        if cur is None or not self._update_db_file_3():
+            return False
+
+        pid = self.pkg2pid(pkg, create=False)
+        if pid is None:
+            return False
+
+        sql = """DELETE FROM pkg_%(db)sdb WHERE pkgtupid=?""" % {'db' : db}
+        executeSQL(cur, sql, (pid,))
+
+        return True
+
+    def sync_alldb(self, ipkg):
+        """ Sync. all the data for rpmdb/yumdb for this installed pkg. """
+        if not self._wipe_anydb(ipkg, "rpm"):
+            return False
+        self._wipe_anydb(ipkg, "yum")
+        if not self._save_rpmdb(ipkg):
+            return False
+        self._save_yumdb(ipkg)
+        self._commit()
+        return True
+
     def _yieldSQLDataList(self, patterns, fields, ignore_case):
         """Yields all the package data for the given params. """
 
@@ -1220,6 +1419,47 @@ class YumHistory:
             tids.add(row[0])
         return tids
 
+    _update_ops_3 = ['''\
+\
+ CREATE TABLE pkg_rpmdb (
+     pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
+     rpmdb_key TEXT NOT NULL,
+     rpmdb_val TEXT NOT NULL);
+''', '''\
+ CREATE INDEX i_pkgkey_rpmdb ON pkg_rpmdb (pkgtupid, rpmdb_key);
+''', '''\
+ CREATE TABLE pkg_yumdb (
+     pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
+     yumdb_key TEXT NOT NULL,
+     yumdb_val TEXT NOT NULL);
+''', '''\
+ CREATE INDEX i_pkgkey_yumdb ON pkg_yumdb (pkgtupid, yumdb_key);
+''']
+
+    def _update_db_file_3(self):
+        """ Update to version 3 of history, rpmdb/yumdb data. """
+        if not self._update_db_file_2():
+            return False
+
+        if hasattr(self, '_cached_updated_3'):
+            return self._cached_updated_3
+
+        cur = self._get_cursor()
+        if cur is None:
+            return False
+
+        executeSQL(cur, "PRAGMA table_info(pkg_yumdb)")
+        #  If we get anything, we're fine. There might be a better way of
+        # saying "anything" but this works.
+        for ob in cur:
+            break
+        else:
+            for op in self._update_ops_3:
+                cur.execute(op)
+            self._commit()
+        self._cached_updated_3 = True
+        return True
+
     _update_ops_2 = ['''\
 \
  CREATE TABLE trans_skip_pkgs (
@@ -1374,6 +1614,8 @@ class YumHistory:
             cur.execute(op)
         for op in self._update_ops_2:
             cur.execute(op)
+        for op in self._update_ops_3:
+            cur.execute(op)
         self._commit()
 
 # Pasted from sqlitesack


More information about the Yum-commits mailing list