histedit: replace pickle with custom serialization
authorDurham Goode <durham@fb.com>
Mon, 13 Apr 2015 08:23:57 -0700
changeset 24756 d71c2da01d0d
parent 24755 cd89f4e6faf2
child 24757 7b59f16174c5
histedit: replace pickle with custom serialization Pickle is undesirable, so let's serialize it ourselves. We keep the ability to parse existing pickle blobs for now.
hgext/histedit.py
--- a/hgext/histedit.py	Wed Apr 15 01:18:09 2015 -0400
+++ b/hgext/histedit.py	Mon Apr 13 08:23:57 2015 -0700
@@ -220,7 +220,12 @@
                 raise
             raise util.Abort(_('no histedit in progress'))
 
-        parentctxnode, rules, keep, topmost, replacements = pickle.load(fp)
+        try:
+            data = pickle.load(fp)
+            parentctxnode, rules, keep, topmost, replacements = data
+        except pickle.UnpicklingError:
+            data = self._load()
+            parentctxnode, rules, keep, topmost, replacements = data
 
         self.parentctxnode = parentctxnode
         self.rules = rules
@@ -230,10 +235,63 @@
 
     def write(self):
         fp = self.repo.vfs('histedit-state', 'w')
-        pickle.dump((self.parentctxnode, self.rules, self.keep,
-                     self.topmost, self.replacements), fp)
+        fp.write('v1\n')
+        fp.write('%s\n' % node.hex(self.parentctxnode))
+        fp.write('%s\n' % node.hex(self.topmost))
+        fp.write('%s\n' % self.keep)
+        fp.write('%d\n' % len(self.rules))
+        for rule in self.rules:
+            fp.write('%s%s\n' % (rule[1], rule[0]))
+        fp.write('%d\n' % len(self.replacements))
+        for replacement in self.replacements:
+            fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
+                for r in replacement[1])))
         fp.close()
 
+    def _load(self):
+        fp = self.repo.vfs('histedit-state', 'r')
+        lines = [l[:-1] for l in fp.readlines()]
+
+        index = 0
+        lines[index] # version number
+        index += 1
+
+        parentctxnode = node.bin(lines[index])
+        index += 1
+
+        topmost = node.bin(lines[index])
+        index += 1
+
+        keep = lines[index] == 'True'
+        index += 1
+
+        # Rules
+        rules = []
+        rulelen = int(lines[index])
+        index += 1
+        for i in xrange(rulelen):
+            rule = lines[index]
+            rulehash = rule[:40]
+            ruleaction = rule[40:]
+            rules.append((ruleaction, rulehash))
+            index += 1
+
+        # Replacements
+        replacements = []
+        replacementlen = int(lines[index])
+        index += 1
+        for i in xrange(replacementlen):
+            replacement = lines[index]
+            original = node.bin(replacement[:40])
+            succ = [node.bin(replacement[i:i + 40]) for i in
+                    range(40, len(replacement), 40)]
+            replacements.append((original, succ))
+            index += 1
+
+        fp.close()
+
+        return parentctxnode, rules, keep, topmost, replacements
+
     def clear(self):
         self.repo.vfs.unlink('histedit-state')