def __init__(self, ui, path, bundlename): self._tempparent = None try: localrepo.localrepository.__init__(self, ui, path) except error.RepoError: self._tempparent = tempfile.mkdtemp() localrepo.instance(ui, self._tempparent, 1) localrepo.localrepository.__init__(self, ui, self._tempparent) self.ui.setconfig('phases', 'publish', False) if path: self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename else: self._url = 'bundle:' + bundlename self.tempfile = None f = util.posixfile(bundlename, "rb") self.bundle = changegroup.readbundle(f, bundlename) if self.bundle.compressed(): fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg10un", dir=self.path) self.tempfile = temp fptemp = os.fdopen(fdtemp, 'wb') try: fptemp.write("HG10UN") while True: chunk = self.bundle.read(2**18) if not chunk: break fptemp.write(chunk) finally: fptemp.close() f = util.posixfile(self.tempfile, "rb") self.bundle = changegroup.readbundle(f, bundlename) # dict with the mapping 'filename' -> position in the bundle self.bundlefilespos = {}
def unbundle(repo, proto, heads): their_heads = decodelist(heads) def check_heads(): heads = repo.heads() heads_hash = util.sha1(''.join(sorted(heads))).digest() return (their_heads == ['force'] or their_heads == heads or their_heads == ['hashed', heads_hash]) proto.redirect() # fail early if possible if not check_heads(): return pusherr('unsynced changes') # write bundle data to temporary file because it can be big fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-') fp = os.fdopen(fd, 'wb+') r = 0 try: proto.getfile(fp) lock = repo.lock() try: if not check_heads(): # someone else committed/pushed/unbundled while we # were transferring data return pusherr('unsynced changes') # push can proceed fp.seek(0) gen = changegroupmod.readbundle(fp, None) try: r = repo.addchangegroup(gen, 'serve', proto._client(), lock=lock) except util.Abort, inst: sys.stderr.write("abort: %s\n" % inst) finally: lock.release() return pushres(r) finally: fp.close() os.unlink(tempname)
def unbundle(repo, proto, heads): their_heads = decodelist(heads) def check_heads(): heads = repo.heads() heads_hash = util.sha1(''.join(sorted(heads))).digest() return (their_heads == ['force'] or their_heads == heads or their_heads == ['hashed', heads_hash]) proto.redirect() # fail early if possible if not check_heads(): return pusherr('repository changed while preparing changes - ' 'please try again') # write bundle data to temporary file because it can be big fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-') fp = os.fdopen(fd, 'wb+') r = 0 try: proto.getfile(fp) lock = repo.lock() try: if not check_heads(): # someone else committed/pushed/unbundled while we # were transferring data return pusherr('repository changed while uploading changes - ' 'please try again') # push can proceed fp.seek(0) gen = changegroupmod.readbundle(fp, None) try: r = repo.addchangegroup(gen, 'serve', proto._client()) except util.Abort, inst: sys.stderr.write("abort: %s\n" % inst) finally: lock.release() return pushres(r) finally: fp.close() os.unlink(tempname)
def unbundle(repo, proto, heads): their_heads = decodelist(heads) def check_heads(): heads = repo.heads() return their_heads == ["force"] or their_heads == heads proto.redirect() # fail early if possible if not check_heads(): return pusherr("unsynced changes") # write bundle data to temporary file because it can be big fd, tempname = tempfile.mkstemp(prefix="hg-unbundle-") fp = os.fdopen(fd, "wb+") r = 0 try: proto.getfile(fp) lock = repo.lock() try: if not check_heads(): # someone else committed/pushed/unbundled while we # were transferring data return pusherr("unsynced changes") # push can proceed fp.seek(0) gen = changegroupmod.readbundle(fp, None) try: r = repo.addchangegroup(gen, "serve", proto._client(), lock=lock) except util.Abort, inst: sys.stderr.write("abort: %s\n" % inst) finally: lock.release() return pushres(r) finally: fp.close() os.unlink(tempname)
def strip(ui, repo, node, backup="all"): cl = repo.changelog # TODO delete the undo files, and handle undo of merge sets striprev = cl.rev(node) # Some revisions with rev > striprev may not be descendants of striprev. # We have to find these revisions and put them in a bundle, so that # we can restore them after the truncations. # To create the bundle we use repo.changegroupsubset which requires # the list of heads and bases of the set of interesting revisions. # (head = revision in the set that has no descendant in the set; # base = revision in the set that has no ancestor in the set) tostrip = set((striprev,)) saveheads = set() savebases = [] for r in xrange(striprev + 1, len(cl)): parents = cl.parentrevs(r) if parents[0] in tostrip or parents[1] in tostrip: # r is a descendant of striprev tostrip.add(r) # if this is a merge and one of the parents does not descend # from striprev, mark that parent as a savehead. if parents[1] != nullrev: for p in parents: if p not in tostrip and p > striprev: saveheads.add(p) else: # if no parents of this revision will be stripped, mark it as # a savebase if parents[0] < striprev and parents[1] < striprev: savebases.append(cl.node(r)) saveheads.difference_update(parents) saveheads.add(r) saveheads = [cl.node(r) for r in saveheads] files = _collectfiles(repo, striprev) extranodes = _collectextranodes(repo, files, striprev) # create a changegroup for all the branches we need to keep if backup == "all": _bundle(repo, [node], cl.heads(), node, 'backup') if saveheads or extranodes: chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', extranodes) mfst = repo.manifest tr = repo.transaction() offset = len(tr.entries) tr.startgroup() cl.strip(striprev, tr) mfst.strip(striprev, tr) for fn in files: repo.file(fn).strip(striprev, tr) tr.endgroup() try: for i in xrange(offset, len(tr.entries)): file, troffset, ignore = tr.entries[i] repo.sopener(file, 'a').truncate(troffset) tr.close() except: tr.abort() raise if saveheads or extranodes: ui.status(_("adding branch\n")) f = open(chgrpfile, "rb") gen = changegroup.readbundle(f, chgrpfile) repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True) f.close() if backup != "strip": os.unlink(chgrpfile) repo.destroyed()
def strip(ui, repo, node, backup="all"): cl = repo.changelog # TODO delete the undo files, and handle undo of merge sets striprev = cl.rev(node) keeppartialbundle = backup == 'strip' # Some revisions with rev > striprev may not be descendants of striprev. # We have to find these revisions and put them in a bundle, so that # we can restore them after the truncations. # To create the bundle we use repo.changegroupsubset which requires # the list of heads and bases of the set of interesting revisions. # (head = revision in the set that has no descendant in the set; # base = revision in the set that has no ancestor in the set) tostrip = set((striprev, )) saveheads = set() savebases = [] for r in xrange(striprev + 1, len(cl)): parents = cl.parentrevs(r) if parents[0] in tostrip or parents[1] in tostrip: # r is a descendant of striprev tostrip.add(r) # if this is a merge and one of the parents does not descend # from striprev, mark that parent as a savehead. if parents[1] != nullrev: for p in parents: if p not in tostrip and p > striprev: saveheads.add(p) else: # if no parents of this revision will be stripped, mark it as # a savebase if parents[0] < striprev and parents[1] < striprev: savebases.append(cl.node(r)) saveheads.difference_update(parents) saveheads.add(r) bm = repo._bookmarks updatebm = [] for m in bm: rev = repo[bm[m]].rev() if rev in tostrip: updatebm.append(m) saveheads = [cl.node(r) for r in saveheads] files = _collectfiles(repo, striprev) extranodes = _collectextranodes(repo, files, striprev) # create a changegroup for all the branches we need to keep backupfile = None if backup == "all": backupfile = _bundle(repo, [node], cl.heads(), node, 'backup') repo.ui.status(_("saved backup bundle to %s\n") % backupfile) if saveheads or extranodes: # do not compress partial bundle if we remove it from disk later chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', extranodes=extranodes, compress=keeppartialbundle) mfst = repo.manifest tr = repo.transaction("strip") offset = len(tr.entries) try: tr.startgroup() cl.strip(striprev, tr) mfst.strip(striprev, tr) for fn in files: repo.file(fn).strip(striprev, tr) tr.endgroup() try: for i in xrange(offset, len(tr.entries)): file, troffset, ignore = tr.entries[i] repo.sopener(file, 'a').truncate(troffset) tr.close() except: tr.abort() raise if saveheads or extranodes: ui.note(_("adding branch\n")) f = open(chgrpfile, "rb") gen = changegroup.readbundle(f, chgrpfile) if not repo.ui.verbose: # silence internal shuffling chatter repo.ui.pushbuffer() repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True) if not repo.ui.verbose: repo.ui.popbuffer() f.close() if not keeppartialbundle: os.unlink(chgrpfile) for m in updatebm: bm[m] = repo['.'].node() bookmarks.write(repo) except: if backupfile: ui.warn( _("strip failed, full bundle stored in '%s'\n") % backupfile) elif saveheads: ui.warn( _("strip failed, partial bundle stored in '%s'\n") % chgrpfile) raise repo.destroyed()
def strip(ui, repo, node, backup="all"): cl = repo.changelog # TODO delete the undo files, and handle undo of merge sets pp = cl.parents(node) striprev = cl.rev(node) # Some revisions with rev > striprev may not be descendants of striprev. # We have to find these revisions and put them in a bundle, so that # we can restore them after the truncations. # To create the bundle we use repo.changegroupsubset which requires # the list of heads and bases of the set of interesting revisions. # (head = revision in the set that has no descendant in the set; # base = revision in the set that has no ancestor in the set) tostrip = {striprev: 1} saveheads = {} savebases = [] for r in xrange(striprev + 1, cl.count()): parents = cl.parentrevs(r) if parents[0] in tostrip or parents[1] in tostrip: # r is a descendant of striprev tostrip[r] = 1 # if this is a merge and one of the parents does not descend # from striprev, mark that parent as a savehead. if parents[1] != nullrev: for p in parents: if p not in tostrip and p > striprev: saveheads[p] = 1 else: # if no parents of this revision will be stripped, mark it as # a savebase if parents[0] < striprev and parents[1] < striprev: savebases.append(cl.node(r)) for p in parents: if p in saveheads: del saveheads[p] saveheads[r] = 1 saveheads = [cl.node(r) for r in saveheads] files = _collectfiles(repo, striprev) extranodes = _collectextranodes(repo, files, striprev) # create a changegroup for all the branches we need to keep if backup == "all": _bundle(repo, [node], cl.heads(), node, 'backup') if saveheads or extranodes: chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', extranodes) cl.strip(striprev) repo.manifest.strip(striprev) for name in files: f = repo.file(name) f.strip(striprev) if saveheads or extranodes: ui.status("adding branch\n") f = open(chgrpfile, "rb") gen = changegroup.readbundle(f, chgrpfile) repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True) f.close() if backup != "strip": os.unlink(chgrpfile)
def strip(ui, repo, node, backup="all"): cl = repo.changelog # TODO delete the undo files, and handle undo of merge sets striprev = cl.rev(node) # Some revisions with rev > striprev may not be descendants of striprev. # We have to find these revisions and put them in a bundle, so that # we can restore them after the truncations. # To create the bundle we use repo.changegroupsubset which requires # the list of heads and bases of the set of interesting revisions. # (head = revision in the set that has no descendant in the set; # base = revision in the set that has no ancestor in the set) tostrip = {striprev: 1} saveheads = {} savebases = [] for r in xrange(striprev + 1, len(cl)): parents = cl.parentrevs(r) if parents[0] in tostrip or parents[1] in tostrip: # r is a descendant of striprev tostrip[r] = 1 # if this is a merge and one of the parents does not descend # from striprev, mark that parent as a savehead. if parents[1] != nullrev: for p in parents: if p not in tostrip and p > striprev: saveheads[p] = 1 else: # if no parents of this revision will be stripped, mark it as # a savebase if parents[0] < striprev and parents[1] < striprev: savebases.append(cl.node(r)) for p in parents: if p in saveheads: del saveheads[p] saveheads[r] = 1 saveheads = [cl.node(r) for r in saveheads] files = _collectfiles(repo, striprev) extranodes = _collectextranodes(repo, files, striprev) # create a changegroup for all the branches we need to keep if backup == "all": _bundle(repo, [node], cl.heads(), node, 'backup') if saveheads or extranodes: chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', extranodes) cl.strip(striprev) repo.manifest.strip(striprev) for name in files: f = repo.file(name) f.strip(striprev) if saveheads or extranodes: ui.status(_("adding branch\n")) f = open(chgrpfile, "rb") gen = changegroup.readbundle(f, chgrpfile) repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True) f.close() if backup != "strip": os.unlink(chgrpfile)
def strip(ui, repo, node, backup="all"): cl = repo.changelog # TODO delete the undo files, and handle undo of merge sets striprev = cl.rev(node) keeppartialbundle = backup == 'strip' # Some revisions with rev > striprev may not be descendants of striprev. # We have to find these revisions and put them in a bundle, so that # we can restore them after the truncations. # To create the bundle we use repo.changegroupsubset which requires # the list of heads and bases of the set of interesting revisions. # (head = revision in the set that has no descendant in the set; # base = revision in the set that has no ancestor in the set) tostrip = set((striprev,)) saveheads = set() savebases = [] for r in xrange(striprev + 1, len(cl)): parents = cl.parentrevs(r) if parents[0] in tostrip or parents[1] in tostrip: # r is a descendant of striprev tostrip.add(r) # if this is a merge and one of the parents does not descend # from striprev, mark that parent as a savehead. if parents[1] != nullrev: for p in parents: if p not in tostrip and p > striprev: saveheads.add(p) else: # if no parents of this revision will be stripped, mark it as # a savebase if parents[0] < striprev and parents[1] < striprev: savebases.append(cl.node(r)) saveheads.difference_update(parents) saveheads.add(r) bm = repo._bookmarks updatebm = [] for m in bm: rev = repo[bm[m]].rev() if rev in tostrip: updatebm.append(m) saveheads = [cl.node(r) for r in saveheads] files = _collectfiles(repo, striprev) extranodes = _collectextranodes(repo, files, striprev) # create a changegroup for all the branches we need to keep backupfile = None if backup == "all": backupfile = _bundle(repo, [node], cl.heads(), node, 'backup') repo.ui.status(_("saved backup bundle to %s\n") % backupfile) if saveheads or extranodes: # do not compress partial bundle if we remove it from disk later chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', extranodes=extranodes, compress=keeppartialbundle) mfst = repo.manifest tr = repo.transaction("strip") offset = len(tr.entries) try: tr.startgroup() cl.strip(striprev, tr) mfst.strip(striprev, tr) for fn in files: repo.file(fn).strip(striprev, tr) tr.endgroup() try: for i in xrange(offset, len(tr.entries)): file, troffset, ignore = tr.entries[i] repo.sopener(file, 'a').truncate(troffset) tr.close() except: tr.abort() raise if saveheads or extranodes: ui.note(_("adding branch\n")) f = open(chgrpfile, "rb") gen = changegroup.readbundle(f, chgrpfile) if not repo.ui.verbose: # silence internal shuffling chatter repo.ui.pushbuffer() repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True) if not repo.ui.verbose: repo.ui.popbuffer() f.close() if not keeppartialbundle: os.unlink(chgrpfile) for m in updatebm: bm[m] = repo['.'].node() bookmarks.write(repo) except: if backupfile: ui.warn(_("strip failed, full bundle stored in '%s'\n") % backupfile) elif saveheads: ui.warn(_("strip failed, partial bundle stored in '%s'\n") % chgrpfile) raise repo.destroyed()