Patchwork [2,of,2,V2] shelve: only keep the latest N shelve backups

login
register
mail settings
Submitter Colin Chan
Date July 2, 2015, 4:50 p.m.
Message ID <09488d9fa8235de54e35.1435855815@devvm264.prn1.facebook.com>
Download mbox | patch
Permalink /patch/9877/
State Accepted
Headers show

Comments

Colin Chan - July 2, 2015, 4:50 p.m.
# HG changeset patch
# User Colin Chan <colinchan@fb.com>
# Date 1435781643 25200
#      Wed Jul 01 13:14:03 2015 -0700
# Node ID 09488d9fa8235de54e356fc41d15c57e83f4f817
# Parent  2fb801a45897eaa5f7cb45225b2f9db4c7ec73d6
shelve: only keep the latest N shelve backups

This will keep the backup directory from growing indefinitely. The number of
backups to keep can be set using the shelve.maxbackups config option (defaults
to 10 backups).
Matt Mackall - July 6, 2015, 11:01 p.m.
On Thu, 2015-07-02 at 09:50 -0700, Colin Chan wrote:
> # HG changeset patch
> # User Colin Chan <colinchan@fb.com>
> # Date 1435781643 25200
> #      Wed Jul 01 13:14:03 2015 -0700
> # Node ID 09488d9fa8235de54e356fc41d15c57e83f4f817
> # Parent  2fb801a45897eaa5f7cb45225b2f9db4c7ec73d6
> shelve: only keep the latest N shelve backups

Thanks, Colin, these are queued for default. Congratulations on your
first Mercurial patches!

Patch

diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -40,6 +40,8 @@ 
 # leave the attribute unspecified.
 testedwith = 'internal'
 
+backupdir = 'shelve-backup'
+
 class shelvedfile(object):
     """Helper for the file storing a single shelve
 
@@ -49,7 +51,7 @@ 
         self.repo = repo
         self.name = name
         self.vfs = scmutil.vfs(repo.join('shelved'))
-        self.backupvfs = scmutil.vfs(repo.join('shelve-backup'))
+        self.backupvfs = scmutil.vfs(repo.join(backupdir))
         self.ui = self.repo.ui
         if filetype:
             self.fname = name + '.' + filetype
@@ -156,6 +158,20 @@ 
     def clear(cls, repo):
         util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
 
+def cleanupoldbackups(repo):
+    vfs = scmutil.vfs(repo.join(backupdir))
+    maxbackups = repo.ui.configint('shelve', 'maxbackups', 10)
+    hgfiles = [f for f in vfs.listdir() if f.endswith('.hg')]
+    hgfiles = sorted([(vfs.stat(f).st_mtime, f) for f in hgfiles])
+    for mtime, f in hgfiles[:len(hgfiles) - maxbackups]:
+        base = f[:-3]
+        for ext in 'hg patch'.split():
+            try:
+                vfs.unlink(base + '.' + ext)
+            except OSError as err:
+                if err.errno != errno.ENOENT:
+                    raise
+
 def createcmd(ui, repo, pats, opts):
     """subcommand that creates a new shelve"""
 
@@ -298,6 +314,7 @@ 
             suffix = name.rsplit('.', 1)[-1]
             if suffix in ('hg', 'patch'):
                 shelvedfile(repo, name).movetobackup()
+            cleanupoldbackups(repo)
     finally:
         lockmod.release(wlock)
 
@@ -310,6 +327,7 @@ 
         for name in pats:
             for suffix in 'hg patch'.split():
                 shelvedfile(repo, name, suffix).movetobackup()
+        cleanupoldbackups(repo)
     except OSError as err:
         if err.errno != errno.ENOENT:
             raise
@@ -459,6 +477,7 @@ 
     if not opts['keep']:
         for filetype in 'hg patch'.split():
             shelvedfile(repo, name, filetype).movetobackup()
+        cleanupoldbackups(repo)
 
 def unshelvecontinue(ui, repo, state, opts):
     """subcommand to continue an in-progress unshelve"""
@@ -534,6 +553,11 @@ 
     (Alternatively, you can use ``--abort`` to abandon an unshelve
     that causes a conflict. This reverts the unshelved changes, and
     leaves the bundle in place.)
+
+    After a successful unshelve, the shelved changes are stored in a
+    backup directory. Only the N most recent backups are kept. N
+    defaults to 10 but can be overridden using the shelve.maxbackups
+    configuration option.
     """
     abortf = opts['abort']
     continuef = opts['continue']
diff --git a/tests/test-shelve.t b/tests/test-shelve.t
--- a/tests/test-shelve.t
+++ b/tests/test-shelve.t
@@ -5,6 +5,8 @@ 
   > [defaults]
   > diff = --nodates --git
   > qnew = --date '0 0'
+  > [shelve]
+  > maxbackups = 2
   > EOF
 
   $ hg init repo
@@ -248,6 +250,14 @@ 
     c
   R b/b
 
+ensure old shelve backups are being deleted automatically
+
+  $ ls .hg/shelve-backup/
+  default-01.hg
+  default-01.patch
+  wibble.hg
+  wibble.patch
+
 cause unshelving to result in a merge with 'a' conflicting
 
   $ hg shelve -q