[PATCH 2 of 4 shelve-ext v4] scmutil: make simplekeyvaluefile able to have a non-key-value first line

Yuya Nishihara yuya at tcha.org
Thu May 11 09:30:47 EDT 2017


On Sun, 7 May 2017 06:07:04 -0700, Kostia Balytskyi wrote:
> # HG changeset patch
> # User Kostia Balytskyi <ikostia at fb.com>
> # Date 1494158131 25200
> #      Sun May 07 04:55:31 2017 -0700
> # Node ID d78507e5b31ac9d5dbf3b8ab45c0c94b01491a0b
> # Parent  e9b77b6f16c04efced06169735a813d5db82dddf
> 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.
> 
> diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
> --- a/mercurial/scmutil.py
> +++ b/mercurial/scmutil.py
> @@ -917,28 +917,50 @@ 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:
> +            # we don't want to include '\n' in the __firstline
> +            d[self.firstlinekey] = lines[0][:-1]
> +            del lines[0]

lines may be an empty list. In which case, CorruptedState should be raised.

>          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())
> +            d.update(dict(line[:-1].split('=', 1) for line in lines
> +                                                  if line.strip()))

Perhaps '__firstline=' should be rejected as CorruptedState for consistency
with write() ?

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


More information about the Mercurial-devel mailing list