[PATCH] [RFC] rollback -n
Brendan Cully
brendan at kublai.com
Tue Apr 1 00:04:46 UTC 2008
Here's a hacky version of a -n flag for rollback, which prints the
revision to which rollback would revert the repository without
actually reverting it.
I wouldn't call it finished, and I'm not particularly happy about the
way this patch overrides the changelog opener. Nor have I tested it
with revlogv0. This patch is really a request for comments.
-------------- next part --------------
# HG changeset patch
# User Brendan Cully <brendan at kublai.com>
# Date 1207008092 25200
# Node ID ed1a5aa8e1721d9b977ad1694763dfff706ae1a2
# Parent 626a8e39684656e356c68fd178b255f6b9cb0ab2
Implement dry run for rollback
diff -r 626a8e396846 -r ed1a5aa8e172 mercurial/commands.py
--- a/mercurial/commands.py Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/commands.py Mon Mar 31 17:01:32 2008 -0700
@@ -2447,7 +2447,7 @@
finally:
del wlock
-def rollback(ui, repo):
+def rollback(ui, repo, **opts):
"""roll back the last transaction
This command should be used with care. There is only one level of
@@ -2473,7 +2473,15 @@
repository; for example an in-progress pull from the repository
may fail if a rollback is performed.
"""
- repo.rollback()
+ rbtip = repo.rollback(dryrun=opts.get('dry_run'))
+ if not rbtip:
+ return 1
+
+ rev = repo.changelog.rev(rbtip)
+ if opts.get('dry_run'):
+ ui.status('would roll back to revision %d\n' % rev)
+ else:
+ ui.note('rolled back to revision %d\n' % rev)
def root(ui, repo):
"""print the root (top) of the current working dir
@@ -3196,7 +3204,7 @@
('', 'no-backup', None, _('do not save backup copies of files')),
] + walkopts + dryrunopts,
_('hg revert [OPTION]... [-r REV] [NAME]...')),
- "rollback": (rollback, [], _('hg rollback')),
+ "rollback": (rollback, dryrunopts, _('hg rollback')),
"root": (root, [], _('hg root')),
"^serve":
(serve,
diff -r 626a8e396846 -r ed1a5aa8e172 mercurial/localrepo.py
--- a/mercurial/localrepo.py Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/localrepo.py Mon Mar 31 17:01:32 2008 -0700
@@ -608,12 +608,24 @@
finally:
del l
- def rollback(self):
+ def rollback(self, dryrun=False):
+ def szopener(opener, sz):
+ def o(*args, **kwargs):
+ kwargs['size'] = sz
+ return opener(*args, **kwargs)
+ return o
+
wlock = lock = None
try:
wlock = self.wlock()
lock = self.lock()
if os.path.exists(self.sjoin("undo")):
+ if dryrun:
+ files = transaction.parse(self.sjoin("undo"))
+ clo = files['00changelog.i']
+ opener = szopener(self.sopener, clo)
+ cl = changelog.changelog(opener)
+ return cl.tip()
self.ui.status(_("rolling back last transaction\n"))
transaction.rollback(self.sopener, self.sjoin("undo"))
util.rename(self.join("undo.dirstate"), self.join("dirstate"))
@@ -626,6 +638,7 @@
% util.tolocal(self.dirstate.branch()))
self.invalidate()
self.dirstate.invalidate()
+ return self.changelog.tip()
else:
self.ui.warn(_("no rollback information available\n"))
finally:
diff -r 626a8e396846 -r ed1a5aa8e172 mercurial/transaction.py
--- a/mercurial/transaction.py Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/transaction.py Mon Mar 31 17:01:32 2008 -0700
@@ -92,13 +92,16 @@
self.report(_("rollback completed\n"))
-def rollback(opener, file):
+def parse(file):
files = {}
for l in open(file).readlines():
f, o = l.split('\0')
- files[f] = o
+ files[f] = int(o)
+ return files
+
+def rollback(opener, file):
+ files = parse(file)
for f in files:
o = files[f]
- opener(f, "a").truncate(int(o))
+ opener(f, "a").truncate(o)
os.unlink(file)
-
diff -r 626a8e396846 -r ed1a5aa8e172 mercurial/util.py
--- a/mercurial/util.py Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/util.py Mon Mar 31 17:01:32 2008 -0700
@@ -751,9 +751,22 @@
def fstat(fp):
'''stat file object that may not have fileno method.'''
try:
- return os.fstat(fp.fileno())
+ sb = os.fstat(fp.fileno())
except AttributeError:
- return os.stat(fp.name)
+ sb = os.stat(fp.name)
+
+ if hasattr(fp, 'size'):
+ class sstat(object):
+ def __init__(self, sb, sz):
+ self._obj = sb
+ self.st_size = sz
+
+ def __getattr__(self, name):
+ return getattr(self._obj, name)
+
+ return sstat(sb, fp.size)
+
+ return sb
posixfile = file
@@ -1394,6 +1407,31 @@
makedirs(parent, mode)
makedirs(name, mode)
+class sizedfile(object):
+ "Wrap a file object to limit its apparent size"
+ def __init__(self, fp, size):
+ self._fp = fp
+ self.size = size
+
+ def __getattr__(self, name):
+ return getattr(self._fp, name)
+
+ def read(self, sz=None):
+ if sz is None:
+ sz = self.size
+ maxsz = self.size - self.tell()
+ if sz > maxsz:
+ sz = maxsz
+
+ return self._fp.read(sz)
+
+ def seek(self, offset, whence=0):
+ if whence == 2:
+ offset = offset + self.size
+ whence = 0
+
+ return self._fp.seek(offset, whence)
+
class opener(object):
"""Open files relative to a base directory
@@ -1419,7 +1457,7 @@
return
os.chmod(name, self.createmode & 0666)
- def __call__(self, path, mode="r", text=False, atomictemp=False):
+ def __call__(self, path, mode="r", text=False, atomictemp=False, size=None):
self.audit_path(path)
f = os.path.join(self.base, path)
@@ -1442,6 +1480,8 @@
fp = posixfile(f, mode)
if nlink == 0:
self._fixfilemode(f)
+ if size is not None:
+ fp = sizedfile(fp, size)
return fp
def symlink(self, src, dst):
More information about the Mercurial-devel
mailing list