From 848da97a64b2d3d13c3fbc794c57dae714009854 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Fri, 17 Feb 2012 19:40:03 -0800 Subject: [PATCH] MtimeDB: add JSON read/write Support serialization as JSON instead of pickle, so that /var/cache/edb/mtimedb is human readable/writable, for those rare cases where it may be useful. Currently, pickle is still used for writes. The plan is to migrate to JSON after JSON read has been supported for some time. --- pym/portage/util/mtimedb.py | 69 +++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/pym/portage/util/mtimedb.py b/pym/portage/util/mtimedb.py index 0a2716693..4ccea2438 100644 --- a/pym/portage/util/mtimedb.py +++ b/pym/portage/util/mtimedb.py @@ -10,13 +10,32 @@ except ImportError: import pickle import errno +import io +import json +import sys + import portage +from portage import _encodings +from portage import _unicode_decode from portage import _unicode_encode from portage.data import portage_gid, uid from portage.localization import _ from portage.util import apply_secpass_permissions, atomic_ofstream, writemsg class MtimeDB(dict): + + # Enable this after JSON read has been supported for some time. + _json_write = False + + _json_write_opts = { + "ensure_ascii": False, + "indent": "\t", + "sort_keys": True + } + if sys.hexversion < 0x3020000: + # indent only supports int number of spaces + _json_write_opts["indent"] = 4 + def __init__(self, filename): dict.__init__(self) self.filename = filename @@ -24,28 +43,45 @@ class MtimeDB(dict): def _load(self, filename): f = None + content = None try: f = open(_unicode_encode(filename), 'rb') - mypickle = pickle.Unpickler(f) - try: - mypickle.find_global = None - except AttributeError: - # TODO: If py3k, override Unpickler.find_class(). - pass - d = mypickle.load() - except (AttributeError, EOFError, EnvironmentError, ValueError, pickle.UnpicklingError) as e: - if isinstance(e, EnvironmentError) and \ - getattr(e, 'errno', None) in (errno.ENOENT, errno.EACCES): + content = f.read() + except EnvironmentError as e: + if getattr(e, 'errno', None) in (errno.ENOENT, errno.EACCES): pass else: writemsg(_("!!! Error loading '%s': %s\n") % \ - (filename, str(e)), noiselevel=-1) - del e - d = {} + (filename, e), noiselevel=-1) finally: if f is not None: f.close() + d = None + if content: + try: + mypickle = pickle.Unpickler(io.BytesIO(content)) + try: + mypickle.find_global = None + except AttributeError: + # TODO: If py3k, override Unpickler.find_class(). + pass + d = mypickle.load() + except SystemExit: + raise + except Exception as e: + try: + d = json.loads(_unicode_decode(content, + encoding=_encodings['repo.content'], errors='strict')) + except SystemExit: + raise + except Exception: + writemsg(_("!!! Error loading '%s': %s\n") % \ + (filename, e), noiselevel=-1) + + if d is None: + d = {} + if "old" in d: d["updates"] = d["old"] del d["old"] @@ -80,7 +116,12 @@ class MtimeDB(dict): except EnvironmentError: pass else: - pickle.dump(d, f, protocol=2) + if self._json_write: + f.write(_unicode_encode( + json.dumps(d, **self._json_write_opts), + encoding=_encodings['repo.content'], errors='strict')) + else: + pickle.dump(d, f, protocol=2) f.close() apply_secpass_permissions(self.filename, uid=uid, gid=portage_gid, mode=0o644) -- 2.26.2