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
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"]
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)