mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 00:14:35 +03:00
scmutil: make simplekeyvaluefile able to have a non-key-value first line
To ease migration from files with version numbers in their first lines, we want simplekeyvaluefile to support a non-key-value first line. In this way, old versions of Mercurial will read such files, discover a newer version than the one they know how to handle and fail gracefully, rather than with exception. Shelve's shelvestate file is an example.
This commit is contained in:
parent
e4f8ca5106
commit
ff9a0dc5da
@ -917,28 +917,57 @@ class simplekeyvaluefile(object):
|
||||
|
||||
Keys must be alphanumerics and start with a letter, values must not
|
||||
contain '\n' characters"""
|
||||
firstlinekey = '__firstline'
|
||||
|
||||
def __init__(self, vfs, path, keys=None):
|
||||
self.vfs = vfs
|
||||
self.path = path
|
||||
|
||||
def read(self):
|
||||
def read(self, firstlinenonkeyval=False):
|
||||
"""Read the contents of a simple key-value file
|
||||
|
||||
'firstlinenonkeyval' indicates whether the first line of file should
|
||||
be treated as a key-value pair or reuturned fully under the
|
||||
__firstline key."""
|
||||
lines = self.vfs.readlines(self.path)
|
||||
d = {}
|
||||
if firstlinenonkeyval:
|
||||
if not lines:
|
||||
e = _("empty simplekeyvalue file")
|
||||
raise error.CorruptedState(e)
|
||||
# we don't want to include '\n' in the __firstline
|
||||
d[self.firstlinekey] = lines[0][:-1]
|
||||
del lines[0]
|
||||
|
||||
try:
|
||||
# the 'if line.strip()' part prevents us from failing on empty
|
||||
# lines which only contain '\n' therefore are not skipped
|
||||
# by 'if line'
|
||||
d = dict(line[:-1].split('=', 1) for line in lines if line.strip())
|
||||
updatedict = dict(line[:-1].split('=', 1) for line in lines
|
||||
if line.strip())
|
||||
if self.firstlinekey in updatedict:
|
||||
e = _("%r can't be used as a key")
|
||||
raise error.CorruptedState(e % self.firstlinekey)
|
||||
d.update(updatedict)
|
||||
except ValueError as e:
|
||||
raise error.CorruptedState(str(e))
|
||||
return d
|
||||
|
||||
def write(self, data):
|
||||
def write(self, data, firstline=None):
|
||||
"""Write key=>value mapping to a file
|
||||
data is a dict. Keys must be alphanumerical and start with a letter.
|
||||
Values must not contain newline characters."""
|
||||
Values must not contain newline characters.
|
||||
|
||||
If 'firstline' is not None, it is written to file before
|
||||
everything else, as it is, not in a key=value form"""
|
||||
lines = []
|
||||
if firstline is not None:
|
||||
lines.append('%s\n' % firstline)
|
||||
|
||||
for k, v in data.items():
|
||||
if k == self.firstlinekey:
|
||||
e = "key name '%s' is reserved" % self.firstlinekey
|
||||
raise error.ProgrammingError(e)
|
||||
if not k[0].isalpha():
|
||||
e = "keys must start with a letter in a key-value file"
|
||||
raise error.ProgrammingError(e)
|
||||
|
@ -72,5 +72,13 @@ class testsimplekeyvaluefile(unittest.TestCase):
|
||||
self.assertRaises(error.CorruptedState,
|
||||
scmutil.simplekeyvaluefile(self.vfs, 'badfile').read)
|
||||
|
||||
def testfirstline(self):
|
||||
dw = {'key1': 'value1'}
|
||||
scmutil.simplekeyvaluefile(self.vfs, 'fl').write(dw, firstline='1.0')
|
||||
self.assertEqual(self.vfs.read('fl'), '1.0\nkey1=value1\n')
|
||||
dr = scmutil.simplekeyvaluefile(self.vfs, 'fl')\
|
||||
.read(firstlinenonkeyval=True)
|
||||
self.assertEqual(dr, {'__firstline': '1.0', 'key1': 'value1'})
|
||||
|
||||
if __name__ == "__main__":
|
||||
silenttestrunner.main(__name__)
|
||||
|
Loading…
Reference in New Issue
Block a user