##// END OF EJS Templates
strip: make repair.strip transactional to avoid repository corruption...
strip: make repair.strip transactional to avoid repository corruption Uses a transaction instance from the local repository to journal the truncation of revlog files, such that if a strip only partially completes, hg recover will be able to finish the truncate of all the files. The potential unbundling of changes that have been backed up to be restored later will, in case of an error, have to be unbundled manually. The difference is that it will be possible to recover the repository state so the unbundle can actually succeed.

File last commit:

r7873:4a4c7f6a default
r8073:e8a28556 default
Show More
bundlerepo.py
298 lines | 10.9 KiB | text/x-python | PythonLexer
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 """
bundlerepo.py - repository class for viewing uncompressed bundles
This provides a read-only repository interface to bundles as if
they were part of the actual repository.
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
"""
Peter Arrenbrecht
cleanup: drop unused imports
r7873 from node import nullid
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Benoit Allard
add support for HG10GZ bundles to bundlerepo.bundlerevlog()
r6569 import changegroup, util, os, struct, bz2, zlib, tempfile, shutil, mdiff
Peter Arrenbrecht
cleanup: drop unused imports
r7873 import localrepo, changelog, manifest, filelog, revlog, error
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 class bundlerevlog(revlog.revlog):
Matt Mackall
revlog: don't pass datafile as an argument
r4257 def __init__(self, opener, indexfile, bundlefile,
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 linkmapper=None):
# How it works:
# to retrieve a revision, we need to know the offset of
# the revision in the bundlefile (an opened file).
#
# We store this offset in the index (start), to differentiate a
# rev in the bundle and from a rev in the revlog, we check
# len(index[r]). If the tuple is bigger than 7, it is a bundle
# (it is bigger since we store the node to which the delta is)
#
Matt Mackall
revlog: don't pass datafile as an argument
r4257 revlog.revlog.__init__(self, opener, indexfile)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 self.bundlefile = bundlefile
mason@suse.com
Fix bundle repos to use an index tuple consistent with revlogng...
r2074 self.basemap = {}
Thomas Arendsen Hein
make incoming work via ssh (issue139); move chunk code into separate module....
r1981 def chunkpositer():
for chunk in changegroup.chunkiter(bundlefile):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 pos = bundlefile.tell()
Thomas Arendsen Hein
make incoming work via ssh (issue139); move chunk code into separate module....
r1981 yield chunk, pos - len(chunk)
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 n = len(self)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 prev = None
Thomas Arendsen Hein
make incoming work via ssh (issue139); move chunk code into separate module....
r1981 for chunk, start in chunkpositer():
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 size = len(chunk)
if size < 80:
Martin Geisler
i18n: mark strings for translation in Mercurial
r6953 raise util.Abort(_("invalid changegroup"))
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 start += 80
size -= 80
node, p1, p2, cs = struct.unpack("20s20s20s20s", chunk[:80])
if node in self.nodemap:
prev = node
continue
for p in (p1, p2):
if not p in self.nodemap:
Matt Mackall
errors: move revlog errors...
r7633 raise error.LookupError(p1, self.indexfile,
_("unknown parent"))
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 if linkmapper is None:
link = n
else:
link = linkmapper(cs)
if not prev:
prev = p1
Benoit Boissinot
fix bundlerepo broken by 4205f626dc05...
r5167 # start, size, full unc. size, base (unused), link, p1, p2, node
e = (revlog.offset_type(start, 0), size, -1, -1, link,
Matt Mackall
revlog: add a magic null revision to our index...
r4979 self.rev(p1), self.rev(p2), node)
mason@suse.com
Fix bundle repos to use an index tuple consistent with revlogng...
r2074 self.basemap[n] = prev
Matt Mackall
revlog: add a magic null revision to our index...
r4979 self.index.insert(-1, e)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 self.nodemap[node] = n
prev = node
n += 1
def bundle(self, rev):
"""is rev from the bundle"""
if rev < 0:
return False
mason@suse.com
Fix bundle repos to use an index tuple consistent with revlogng...
r2074 return rev in self.basemap
def bundlebase(self, rev): return self.basemap[rev]
Benoit Boissinot
fix errors spotted by pychecker (mostly scope problems)
r2256 def chunk(self, rev, df=None, cachelen=4096):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 # Warning: in case of bundle, the diff is against bundlebase,
# not against rev - 1
# XXX: could use some caching
if not self.bundle(rev):
Matt Mackall
revlog: speed up chunkcache...
r4988 return revlog.revlog.chunk(self, rev, df)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 self.bundlefile.seek(self.start(rev))
return self.bundlefile.read(self.length(rev))
def revdiff(self, rev1, rev2):
"""return or calculate a delta between two revisions"""
if self.bundle(rev1) and self.bundle(rev2):
# hot path for bundle
revb = self.rev(self.bundlebase(rev2))
if revb == rev1:
return self.chunk(rev2)
elif not self.bundle(rev1) and not self.bundle(rev2):
Benoit Boissinot
bundlerepo: it was meant to be revdiff() instead of chunk()
r4028 return revlog.revlog.revdiff(self, rev1, rev2)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Matt Mackall
revlog: eliminate diff and patches functions...
r4989 return mdiff.textdiff(self.revision(self.node(rev1)),
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 self.revision(self.node(rev2)))
def revision(self, node):
"""return an uncompressed revision of a given"""
if node == nullid: return ""
text = None
chain = []
iter_node = node
rev = self.rev(iter_node)
# reconstruct the revision if it is from a changegroup
while self.bundle(rev):
Matt Mackall
revlog: mark cache private
r4984 if self._cache and self._cache[0] == iter_node:
text = self._cache[2]
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 break
chain.append(rev)
iter_node = self.bundlebase(rev)
rev = self.rev(iter_node)
if text is None:
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 text = revlog.revlog.revision(self, iter_node)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
while chain:
delta = self.chunk(chain.pop())
Matt Mackall
revlog: eliminate diff and patches functions...
r4989 text = mdiff.patches(text, [delta])
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
p1, p2 = self.parents(node)
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 if node != revlog.hash(text, p1, p2):
Matt Mackall
errors: move revlog errors...
r7633 raise error.RevlogError(_("integrity check failed on %s:%d")
Benoit Boissinot
indent: fix alignment
r2257 % (self.datafile, self.rev(node)))
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Matt Mackall
revlog: mark cache private
r4984 self._cache = (node, self.rev(node), text)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 return text
def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
raise NotImplementedError
Peter Arrenbrecht
drop superfluous param from revlog.addgroup()
r6647 def addgroup(self, revs, linkmapper, transaction):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 raise NotImplementedError
def strip(self, rev, minlink):
raise NotImplementedError
def checksize(self):
raise NotImplementedError
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 class bundlechangelog(bundlerevlog, changelog.changelog):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 def __init__(self, opener, bundlefile):
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 changelog.changelog.__init__(self, opener)
Matt Mackall
revlog: don't pass datafile as an argument
r4257 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 class bundlemanifest(bundlerevlog, manifest.manifest):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 def __init__(self, opener, bundlefile, linkmapper):
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 manifest.manifest.__init__(self, opener)
Matt Mackall
revlog: don't pass datafile as an argument
r4257 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile,
linkmapper)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 class bundlefilelog(bundlerevlog, filelog.filelog):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 def __init__(self, opener, path, bundlefile, linkmapper):
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 filelog.filelog.__init__(self, opener, path)
Matt Mackall
revlog: don't pass datafile as an argument
r4257 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile,
linkmapper)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Benoit Boissinot
bundlerepo: remove relative import, fix a comment
r1946 class bundlerepository(localrepo.localrepository):
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 def __init__(self, ui, path, bundlename):
John Mulligan
Add ability to directly clone from all-history bundles...
r6314 self._tempparent = None
try:
localrepo.localrepository.__init__(self, ui, path)
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
John Mulligan
Add ability to directly clone from all-history bundles...
r6314 self._tempparent = tempfile.mkdtemp()
Peter Arrenbrecht
cleanup: drop unused imports
r7873 localrepo.instance(ui,self._tempparent,1)
John Mulligan
Add ability to directly clone from all-history bundles...
r6314 localrepo.localrepository.__init__(self, ui, self._tempparent)
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673
Peter Arrenbrecht
bundlerepo: fix inconsistency of parsed and internal name (issue #821)
r6129 if path:
self._url = 'bundle:' + path + '+' + bundlename
else:
self._url = 'bundle:' + bundlename
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673
Benoit Boissinot
add support for compressed bundle repositories...
r2273 self.tempfile = None
self.bundlefile = open(bundlename, "rb")
Benoit Boissinot
use HG10UN header for uncompressed bundle...
r1980 header = self.bundlefile.read(6)
if not header.startswith("HG"):
raise util.Abort(_("%s: not a Mercurial bundle file") % bundlename)
elif not header.startswith("HG10"):
raise util.Abort(_("%s: unknown bundle version") % bundlename)
Benoit Allard
add support for HG10GZ bundles to bundlerepo.bundlerevlog()
r6569 elif (header == "HG10BZ") or (header == "HG10GZ"):
Benoit Boissinot
add support for compressed bundle repositories...
r2273 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-",
suffix=".hg10un", dir=self.path)
self.tempfile = temp
fptemp = os.fdopen(fdtemp, 'wb')
def generator(f):
Benoit Allard
add support for HG10GZ bundles to bundlerepo.bundlerevlog()
r6569 if header == "HG10BZ":
zd = bz2.BZ2Decompressor()
zd.decompress("BZ")
elif header == "HG10GZ":
zd = zlib.decompressobj()
Benoit Boissinot
add support for compressed bundle repositories...
r2273 for chunk in f:
yield zd.decompress(chunk)
gen = generator(util.filechunkiter(self.bundlefile, 4096))
try:
fptemp.write("HG10UN")
for chunk in gen:
fptemp.write(chunk)
finally:
fptemp.close()
self.bundlefile.close()
self.bundlefile = open(self.tempfile, "rb")
# seek right after the header
self.bundlefile.seek(6)
Benoit Boissinot
use HG10UN header for uncompressed bundle...
r1980 elif header == "HG10UN":
Benoit Boissinot
add support for compressed bundle repositories...
r2273 # nothing to do
Benoit Boissinot
use HG10UN header for uncompressed bundle...
r1980 pass
else:
raise util.Abort(_("%s: unknown bundle compression type")
% bundlename)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 # dict with the mapping 'filename' -> position in the bundle
self.bundlefilespos = {}
Brendan Cully
Make bundlerepo lazier...
r5262
def __getattr__(self, name):
if name == 'changelog':
self.changelog = bundlechangelog(self.sopener, self.bundlefile)
Brendan Cully
bundle: fix up lazy reads
r5263 self.manstart = self.bundlefile.tell()
Brendan Cully
Make bundlerepo lazier...
r5262 return self.changelog
Dirkjan Ochtman
bundlerepo doesn't really have a dirstate, throw AttributeError if requested
r7435 elif name == 'manifest':
Brendan Cully
bundle: fix up lazy reads
r5263 self.bundlefile.seek(self.manstart)
Brendan Cully
Make bundlerepo lazier...
r5262 self.manifest = bundlemanifest(self.sopener, self.bundlefile,
self.changelog.rev)
self.filestart = self.bundlefile.tell()
return self.manifest
Dirkjan Ochtman
bundlerepo doesn't really have a dirstate, throw AttributeError if requested
r7435 elif name == 'manstart':
Brendan Cully
bundle: fix up lazy reads
r5263 self.changelog
return self.manstart
Dirkjan Ochtman
bundlerepo doesn't really have a dirstate, throw AttributeError if requested
r7435 elif name == 'filestart':
Brendan Cully
bundle: fix up lazy reads
r5263 self.manifest
return self.filestart
Dirkjan Ochtman
bundlerepo doesn't really have a dirstate, throw AttributeError if requested
r7435 else:
Matt Mackall
bundlerepo: reintroduce dirstate
r7853 return localrepo.localrepository.__getattr__(self, name)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 def url(self):
return self._url
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 def file(self, f):
Brendan Cully
Make bundlerepo lazier...
r5262 if not self.bundlefilespos:
self.bundlefile.seek(self.filestart)
while 1:
chunk = changegroup.getchunk(self.bundlefile)
if not chunk:
break
self.bundlefilespos[chunk] = self.bundlefile.tell()
for c in changegroup.chunkiter(self.bundlefile):
pass
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 if f[0] == '/':
f = f[1:]
if f in self.bundlefilespos:
self.bundlefile.seek(self.bundlefilespos[f])
Benoit Boissinot
introduce localrepo.spath for the store path, sopener fixes
r3791 return bundlefilelog(self.sopener, f, self.bundlefile,
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942 self.changelog.rev)
else:
Benoit Boissinot
introduce localrepo.spath for the store path, sopener fixes
r3791 return filelog.filelog(self.sopener, f)
Benoit Boissinot
add bundlerepo.py: a read-only repo that can use uncompressed bundles...
r1942
Thomas Arendsen Hein
imported patch /home/thomas/fix-incoming-abortion4.patch
r1971 def close(self):
"""Close assigned bundle file immediately."""
self.bundlefile.close()
Benoit Boissinot
add support for compressed bundle repositories...
r2273
def __del__(self):
Alexis S. L. Carvalho
bundlerepo: avoid exception in __del__ when the bundle doesn't exist...
r3429 bundlefile = getattr(self, 'bundlefile', None)
if bundlefile and not bundlefile.closed:
bundlefile.close()
tempfile = getattr(self, 'tempfile', None)
if tempfile is not None:
os.unlink(tempfile)
John Mulligan
Add ability to directly clone from all-history bundles...
r6314 if self._tempparent:
shutil.rmtree(self._tempparent, True)
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740
Matt Mackall
clone: use cancopy
r6315 def cancopy(self):
return False
Dirkjan Ochtman
bundlerepo doesn't really have a dirstate, throw AttributeError if requested
r7435 def getcwd(self):
return os.getcwd() # always outside the repo
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 def instance(ui, path, create):
if create:
raise util.Abort(_('cannot create new bundle repository'))
Peter Arrenbrecht
Fix income/pull with bundle and -R (issue 820)....
r5664 parentpath = ui.config("bundle", "mainreporoot", "")
if parentpath:
# Try to make the full path relative so we get a nice, short URL.
# In particular, we don't want temp dir names in test outputs.
cwd = os.getcwd()
if parentpath == cwd:
parentpath = ''
else:
cwd = os.path.join(cwd,'')
if parentpath.startswith(cwd):
parentpath = parentpath[len(cwd):]
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 path = util.drop_scheme('file', path)
if path.startswith('bundle:'):
path = util.drop_scheme('bundle', path)
s = path.split("+", 1)
if len(s) == 1:
Peter Arrenbrecht
Fix income/pull with bundle and -R (issue 820)....
r5664 repopath, bundlename = parentpath, s[0]
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 else:
repopath, bundlename = s
else:
Peter Arrenbrecht
Fix income/pull with bundle and -R (issue 820)....
r5664 repopath, bundlename = parentpath, path
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 return bundlerepository(ui, repopath, bundlename)