##// END OF EJS Templates
Handle transcoding of username and description in changelog
Matt Mackall -
r3771:29d91e57 default
parent child Browse files
Show More
@@ -1,101 +1,103 b''
1 # changelog.py - changelog class for mercurial
1 # changelog.py - changelog class for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from revlog import *
8 from revlog import *
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import demandload
10 from demandload import demandload
11 demandload(globals(), "os time util")
11 demandload(globals(), "os time util")
12
12
13 def _string_escape(text):
13 def _string_escape(text):
14 """
14 """
15 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
15 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
16 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
16 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
17 >>> s
17 >>> s
18 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
18 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
19 >>> res = _string_escape(s)
19 >>> res = _string_escape(s)
20 >>> s == _string_unescape(res)
20 >>> s == _string_unescape(res)
21 True
21 True
22 """
22 """
23 # subset of the string_escape codec
23 # subset of the string_escape codec
24 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
24 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
25 return text.replace('\0', '\\0')
25 return text.replace('\0', '\\0')
26
26
27 def _string_unescape(text):
27 def _string_unescape(text):
28 return text.decode('string_escape')
28 return text.decode('string_escape')
29
29
30 class changelog(revlog):
30 class changelog(revlog):
31 def __init__(self, opener, defversion=REVLOGV0):
31 def __init__(self, opener, defversion=REVLOGV0):
32 revlog.__init__(self, opener, "00changelog.i", "00changelog.d",
32 revlog.__init__(self, opener, "00changelog.i", "00changelog.d",
33 defversion)
33 defversion)
34
34
35 def decode_extra(self, text):
35 def decode_extra(self, text):
36 extra = {}
36 extra = {}
37 for l in text.split('\0'):
37 for l in text.split('\0'):
38 if not l:
38 if not l:
39 continue
39 continue
40 k, v = _string_unescape(l).split(':', 1)
40 k, v = _string_unescape(l).split(':', 1)
41 extra[k] = v
41 extra[k] = v
42 return extra
42 return extra
43
43
44 def encode_extra(self, d):
44 def encode_extra(self, d):
45 items = [_string_escape(":".join(t)) for t in d.iteritems()]
45 items = [_string_escape(":".join(t)) for t in d.iteritems()]
46 return "\0".join(items)
46 return "\0".join(items)
47
47
48 def extract(self, text):
48 def extract(self, text):
49 """
49 """
50 format used:
50 format used:
51 nodeid\n : manifest node in ascii
51 nodeid\n : manifest node in ascii
52 user\n : user, no \n or \r allowed
52 user\n : user, no \n or \r allowed
53 time tz extra\n : date (time is int or float, timezone is int)
53 time tz extra\n : date (time is int or float, timezone is int)
54 : extra is metadatas, encoded and separated by '\0'
54 : extra is metadatas, encoded and separated by '\0'
55 : older versions ignore it
55 : older versions ignore it
56 files\n\n : files modified by the cset, no \n or \r allowed
56 files\n\n : files modified by the cset, no \n or \r allowed
57 (.*) : comment (free text, ideally utf-8)
57 (.*) : comment (free text, ideally utf-8)
58
58
59 changelog v0 doesn't use extra
59 changelog v0 doesn't use extra
60 """
60 """
61 if not text:
61 if not text:
62 return (nullid, "", (0, 0), [], "", {})
62 return (nullid, "", (0, 0), [], "", {})
63 last = text.index("\n\n")
63 last = text.index("\n\n")
64 desc = text[last + 2:]
64 desc = util.tolocal(text[last + 2:])
65 l = text[:last].split('\n')
65 l = text[:last].split('\n')
66 manifest = bin(l[0])
66 manifest = bin(l[0])
67 user = l[1]
67 user = util.tolocal(l[1])
68
68
69 extra_data = l[2].split(' ', 2)
69 extra_data = l[2].split(' ', 2)
70 if len(extra_data) != 3:
70 if len(extra_data) != 3:
71 time = float(extra_data.pop(0))
71 time = float(extra_data.pop(0))
72 try:
72 try:
73 # various tools did silly things with the time zone field.
73 # various tools did silly things with the time zone field.
74 timezone = int(extra_data[0])
74 timezone = int(extra_data[0])
75 except:
75 except:
76 timezone = 0
76 timezone = 0
77 extra = {}
77 extra = {}
78 else:
78 else:
79 time, timezone, extra = extra_data
79 time, timezone, extra = extra_data
80 time, timezone = float(time), int(timezone)
80 time, timezone = float(time), int(timezone)
81 extra = self.decode_extra(extra)
81 extra = self.decode_extra(extra)
82 files = l[3:]
82 files = l[3:]
83 return (manifest, user, (time, timezone), files, desc, extra)
83 return (manifest, user, (time, timezone), files, desc, extra)
84
84
85 def read(self, node):
85 def read(self, node):
86 return self.extract(self.revision(node))
86 return self.extract(self.revision(node))
87
87
88 def add(self, manifest, list, desc, transaction, p1=None, p2=None,
88 def add(self, manifest, list, desc, transaction, p1=None, p2=None,
89 user=None, date=None, extra={}):
89 user=None, date=None, extra={}):
90
90
91 user, desc = util.fromlocal(user), util.fromlocal(desc)
92
91 if date:
93 if date:
92 parseddate = "%d %d" % util.parsedate(date)
94 parseddate = "%d %d" % util.parsedate(date)
93 else:
95 else:
94 parseddate = "%d %d" % util.makedate()
96 parseddate = "%d %d" % util.makedate()
95 if extra:
97 if extra:
96 extra = self.encode_extra(extra)
98 extra = self.encode_extra(extra)
97 parseddate = "%s %s" % (parseddate, extra)
99 parseddate = "%s %s" % (parseddate, extra)
98 list.sort()
100 list.sort()
99 l = [hex(manifest), user, parseddate] + list + ["", desc]
101 l = [hex(manifest), user, parseddate] + list + ["", desc]
100 text = "\n".join(l)
102 text = "\n".join(l)
101 return self.addrevision(text, transaction, self.count(), p1, p2)
103 return self.addrevision(text, transaction, self.count(), p1, p2)
General Comments 0
You need to be logged in to leave comments. Login now