[PATCH V2 STABLE] strip: do not overwrite existing backup bundles

Matt Mackall mpm at selenic.com
Wed Dec 28 22:26:39 UTC 2011


On Wed, 2011-12-28 at 18:55 +0100, Laurens Holst wrote:
> # HG changeset patch
> # User Laurens Holst <laurens.hg at grauw.nl>
> # Date 1325036331 -3600
> # Node ID 894516ae07e4353893e69a3bfabffaf07aa38ccf
> # Parent  3317d5c34f384c6d1d8440e19980a2261beecc7a
> strip: do not overwrite existing backup bundles
> 
> I ran into a data loss issue where a strips backup overwrote a previous backup
> which had more descendants. This happens because the backup file name composed
> of just the hash of the first stripped changeset. The issue is fixed by
> suffixing the backup file with a - and a number as needed.
> 
> diff -r 3317d5c34f38 -r 894516ae07e4 mercurial/repair.py
> --- a/mercurial/repair.py	Wed Dec 21 18:20:15 2011 +0100
> +++ b/mercurial/repair.py	Wed Dec 28 02:38:51 2011 +0100
> @@ -9,7 +9,7 @@
>  from mercurial import changegroup, bookmarks, phases
>  from mercurial.node import short
>  from mercurial.i18n import _
> -import os
> +import os, itertools

While itertools is an interesting module, Mercurial has thus far avoided
using it. I don't think a construct as trivial as itertools.count()
justifies pulling it in[1].

>  def _bundle(repo, bases, heads, node, suffix, compress=True):
>      """create a bundle with the specified revisions as a backup"""
> @@ -17,7 +17,17 @@
>      backupdir = repo.join("strip-backup")
>      if not os.path.isdir(backupdir):
>          os.mkdir(backupdir)
> -    name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
> +
> +    # never overwrite existing bundle
> +    for i in itertools.count(0):
> +        if i < 1:
> +            filename = "%s-%s.hg" % (short(node), suffix)
> +        else:
> +            filename = "%s-%s-%d.hg" % (short(node), suffix, i)
> +        name = os.path.join(backupdir, filename)
> +        if not os.path.exists(name):
> +            break

Compare with this:

name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
i = 0
while os.path.exists(name):
    i += 1
    name = os.path.join(backupdir,
                        "%s-%s-%d.hg" % (short(node), suffix, i))

But really, this probably wants to be a utility function:

basename = os.path.join(backupdir, "%s-%s" % (short(node), suffix))
name = util.uniquename(basename, ".hg")

..so that we don't end up rewriting this loop in various places.

[1] Really some clever person should have just built this into xrange:
xrange() == xrange(None) -> 0,1,2,3..
xrange(5, None) -> 5,6,7,8...

-- 
Mathematics is the supreme nostalgia of our time.





More information about the Mercurial-devel mailing list