##// END OF EJS Templates
hg qrecord -- like record, but for mq...
hg qrecord -- like record, but for mq I'm a former Darcs user, and I've discovered that it is very convenient to actually perform development using MQ first, and only when the patches are 'ready' move them to project's history in stone. Usually I work on some topic, temporarily forgetting about any version control, and just do coding, experimenting, debugging, etc. After some time, I approach a moment, where my work should actually go to patches/commits, and here is the problem:: As it is now, there is no way to put part of the changes into one patch, and another part of the changes into second patch. This works, but only when changes are touching separate files, and for semantically different changes touching the same file(s) there is now pretty way to put them into separate patches. For some time, I've tolerated the pain to run vim patches/... and move hunks between files by hand, but I think this affects my productivity badly. So, here is the first step towards untiing the problem: Let's use 'hg qrecord' for mq, like we use 'hg record' for usual commits!

File last commit:

r5814:dd5a501c default
r5830:c32d41af default
Show More
localrepo.py
2030 lines | 75.7 KiB | text/x-python | PythonLexer
mpm@selenic.com
Break apart hg.py...
r1089 # localrepo.py - read/write repository class for mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
mpm@selenic.com
Break apart hg.py...
r1089 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
mpm@selenic.com
localrepo: more import/namespace tidying
r1100 from node import *
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Matt Mackall
restructure changelog file appending...
r4261 import repo, changegroup
Matt Mackall
Use a weakref for recursive transactions
r4916 import changelog, dirstate, filelog, manifest, context, weakref
Matt Mackall
remove unneeded imports of mdiff
r5175 import re, lock, transaction, tempfile, stat, errno, ui
Matt Mackall
hooks: separate hook code into a separate module
r4622 import os, revlog, time, util, extensions, hook
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
add support for streaming clone....
r2612 class localrepository(repo.repository):
Bryan O'Sullivan
Turn capabilities into a mutable set, instead of a fixed tuple.
r5258 capabilities = util.set(('lookup', 'changegroupsubset'))
Benoit Boissinot
switch to the .hg/store layout, fix the tests
r3853 supported = ('revlogv1', 'store')
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
Thomas Arendsen Hein
Create local ui object per repository, so .hg/hgrc don't get mixed....
r1839 def __init__(self, parentui, path=None, create=0):
Vadim Gelfer
add support for streaming clone....
r2612 repo.repository.__init__(self)
Benoit Boissinot
move code around
r3850 self.root = os.path.realpath(path)
Alexis S. L. Carvalho
Save an absolute path in repo.path...
r4170 self.path = os.path.join(self.root, ".hg")
Benoit Boissinot
move code around
r3850 self.origroot = path
self.opener = util.opener(self.path)
self.wopener = util.opener(self.root)
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
localrepo: move the repo creation code, fail if the repo exists
r3035 if not os.path.isdir(self.path):
if create:
if not os.path.exists(path):
os.mkdir(path)
os.mkdir(self.path)
Alexis S. L. Carvalho
small fixes for the parent patch...
r4166 requirements = ["revlogv1"]
if parentui.configbool('format', 'usestore', True):
Matt Mackall
Allow disabling store format to work with absurdly long filenames
r4163 os.mkdir(os.path.join(self.path, "store"))
Alexis S. L. Carvalho
small fixes for the parent patch...
r4166 requirements.append("store")
# create an invalid changelog
self.opener("00changelog.i", "a").write(
'\0\0\0\2' # represents revlogv2
' dummy changelog to prevent using the old repo layout'
)
Benoit Boissinot
add "requires" file to the repo, specifying the requirements
r3851 reqfile = self.opener("requires", "w")
for r in requirements:
reqfile.write("%s\n" % r)
reqfile.close()
Benoit Boissinot
localrepo: move the repo creation code, fail if the repo exists
r3035 else:
raise repo.RepoError(_("repository %s not found") % path)
elif create:
raise repo.RepoError(_("repository %s already exists") % path)
Benoit Boissinot
add "requires" file to the repo, specifying the requirements
r3851 else:
# find requirements
try:
requirements = self.opener("requires").read().splitlines()
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
requirements = []
# check them
for r in requirements:
if r not in self.supported:
raise repo.RepoError(_("requirement '%s' not supported") % r)
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
move code around
r3850 # setup store
Benoit Boissinot
switch to the .hg/store layout, fix the tests
r3853 if "store" in requirements:
self.encodefn = util.encodefilename
self.decodefn = util.decodefilename
self.spath = os.path.join(self.path, "store")
else:
self.encodefn = lambda x: x
self.decodefn = lambda x: x
self.spath = self.path
Bryan O'Sullivan
Make audit_path more stringent....
r5158 self.sopener = util.encodedopener(util.opener(self.spath),
self.encodefn)
Benoit Boissinot
move code around
r3850
Thomas Arendsen Hein
Create local ui object per repository, so .hg/hgrc don't get mixed....
r1839 self.ui = ui.ui(parentui=parentui)
mason@suse.com
Implement revlogng....
r2072 try:
self.ui.readconfig(self.join("hgrc"), self.root)
Matt Mackall
extensions: kill ui readhooks...
r4618 extensions.loadall(self.ui)
mason@suse.com
Implement revlogng....
r2072 except IOError:
pass
mpm@selenic.com
Break apart hg.py...
r1089 self.tagscache = None
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 self._tagstypecache = None
Matt Mackall
Add branchtags function with cache...
r3417 self.branchcache = None
mpm@selenic.com
Break apart hg.py...
r1089 self.nodetagscache = None
Matt Mackall
unify encode/decode filter routines
r4004 self.filterpats = {}
Matt Mackall
Use a weakref for recursive transactions
r4916 self._transref = self._lockref = self._wlockref = None
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
localrepo: demand-load changeset, manifest, and dirstate
r4559 def __getattr__(self, name):
if name == 'changelog':
self.changelog = changelog.changelog(self.sopener)
self.sopener.defversion = self.changelog.version
return self.changelog
if name == 'manifest':
self.changelog
self.manifest = manifest.manifest(self.sopener)
return self.manifest
if name == 'dirstate':
self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
return self.dirstate
else:
raise AttributeError, name
Vadim Gelfer
support hooks written in python....
r2155
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 def url(self):
return 'file:' + self.root
Vadim Gelfer
make hook code nicer....
r1718 def hook(self, name, throw=False, **args):
Matt Mackall
hooks: separate hook code into a separate module
r4622 return hook.hook(self.ui, self, name, throw, **args)
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
move most of tag code to localrepository class.
r2601 tag_disallowed = ':\r\n'
Brendan Cully
Export extra in _tag so convert can set the branch of a tag
r4864 def _tag(self, name, node, message, local, user, date, parent=None,
extra={}):
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 use_dirstate = parent is None
for c in self.tag_disallowed:
if c in name:
raise util.Abort(_('%r cannot be used in a tag name') % c)
self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932 def writetag(fp, name, munge, prevtags):
if prevtags and prevtags[-1] != '\n':
fp.write('\n')
fp.write('%s %s\n' % (hex(node), munge and munge(name) or name))
fp.close()
Thomas Arendsen Hein
Remove trailing spaces
r5081
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932 prevtags = ''
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 if local:
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932 try:
fp = self.opener('localtags', 'r+')
except IOError, err:
fp = self.opener('localtags', 'a')
else:
prevtags = fp.read()
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 # local tags are stored in the current charset
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932 writetag(fp, name, None, prevtags)
John Coomes
hg tag: run tag hook just once
r5801 self.hook('tag', node=hex(node), tag=name, local=local)
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 return
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932 if use_dirstate:
try:
fp = self.wfile('.hgtags', 'rb+')
except IOError, err:
fp = self.wfile('.hgtags', 'ab')
else:
prevtags = fp.read()
else:
try:
prevtags = self.filectx('.hgtags', parent).data()
except revlog.LookupError:
pass
fp = self.wfile('.hgtags', 'wb')
Brendan Cully
Do not lose previous tags when adding a tag in raw mode
r5211 if prevtags:
fp.write(prevtags)
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 # committed tags are stored in UTF-8
Bryan O'Sullivan
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)...
r4932 writetag(fp, name, util.fromlocal, prevtags)
Matt Mackall
dirstate: add __contains__ and make __getitem__ more useful...
r4906 if use_dirstate and '.hgtags' not in self.dirstate:
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 self.add(['.hgtags'])
Brendan Cully
Export extra in _tag so convert can set the branch of a tag
r4864 tagnode = self.commit(['.hgtags'], message, user, date, p1=parent,
extra=extra)
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118
self.hook('tag', node=hex(node), tag=name, local=local)
return tagnode
Matt Mackall
tag: shorten hash in default commit message...
r2967 def tag(self, name, node, message, local, user, date):
Vadim Gelfer
move most of tag code to localrepository class.
r2601 '''tag a revision with a symbolic name.
if local is True, the tag is stored in a per-repository file.
otherwise, it is stored in the .hgtags file, and a new
changeset is committed with the change.
keyword arguments:
local: whether to store tag in non-version-controlled file
(default False)
message: commit message to use if committing
user: name of user to use if committing
date: date tuple to use if committing'''
Vadim Gelfer
remove localrepository.changes....
r2875 for x in self.status()[:5]:
Vadim Gelfer
move most of tag code to localrepository class.
r2601 if '.hgtags' in x:
raise util.Abort(_('working copy of .hgtags is changed '
'(please commit .hgtags manually)'))
Brendan Cully
Break core of repo.tag into dirstate/hook-free repo._tag for convert-repo
r4118 self._tag(name, node, message, local, user, date)
Vadim Gelfer
move most of tag code to localrepository class.
r2601
mpm@selenic.com
Break apart hg.py...
r1089 def tags(self):
'''return a mapping of tag to node'''
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 if self.tagscache:
return self.tagscache
Matt Mackall
Make the tags algorithm smarter
r4211 globaltags = {}
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 tagtypes = {}
mpm@selenic.com
Break apart hg.py...
r1089
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 def readtags(lines, fn, tagtype):
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 filetags = {}
count = 0
def warn(msg):
self.ui.warn(_("%s, line %s: %s\n") % (fn, count, msg))
for l in lines:
count += 1
if not l:
continue
Benoit Boissinot
add checking for invalid entries in tag files...
r1986 s = l.split(" ", 1)
if len(s) != 2:
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 warn(_("cannot parse entry"))
continue
Benoit Boissinot
add checking for invalid entries in tag files...
r1986 node, key = s
Matt Mackall
Handle transcoding of tags
r3772 key = util.tolocal(key.strip()) # stored in UTF-8
Benoit Boissinot
add checking for invalid entries in tag files...
r1986 try:
bin_n = bin(node)
except TypeError:
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 warn(_("node '%s' is not well formed") % node)
continue
Benoit Boissinot
add checking for invalid entries in tag files...
r1986 if bin_n not in self.changelog.nodemap:
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 warn(_("tag '%s' refers to unknown node") % key)
continue
Matt Mackall
Make the tags algorithm smarter
r4211
Matt Mackall
tags: fix abababa case, with test case
r4266 h = []
Matt Mackall
Make the tags algorithm smarter
r4211 if key in filetags:
n, h = filetags[key]
Matt Mackall
tags: fix abababa case, with test case
r4266 h.append(n)
Matt Mackall
Make the tags algorithm smarter
r4211 filetags[key] = (bin_n, h)
Benoit Boissinot
add checking for invalid entries in tag files...
r1986
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 for k, nh in filetags.items():
Matt Mackall
Make the tags algorithm smarter
r4211 if k not in globaltags:
globaltags[k] = nh
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 tagtypes[k] = tagtype
Matt Mackall
Make the tags algorithm smarter
r4211 continue
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657
Matt Mackall
Make the tags algorithm smarter
r4211 # we prefer the global tag if:
# it supercedes us OR
# mutual supercedes and it has a higher rank
# otherwise we win because we're tip-most
an, ah = nh
bn, bh = globaltags[k]
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 if (bn != an and an in bh and
(bn not in ah or len(bh) > len(ah))):
Matt Mackall
Make the tags algorithm smarter
r4211 an = bn
Alexis S. L. Carvalho
use .extend instead of .append in readtags
r4482 ah.extend([n for n in bh if n not in ah])
Matt Mackall
Make the tags algorithm smarter
r4211 globaltags[k] = an, ah
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 tagtypes[k] = tagtype
Matt Mackall
Make the tags algorithm smarter
r4211
# read the tags file from each head, ending with the tip
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 f = None
for rev, node, fnode in self._hgtagsnodes():
f = (f and f.filectx(fnode) or
self.filectx('.hgtags', fileid=fnode))
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 readtags(f.data().splitlines(), f, "global")
Matt Mackall
Minor tags optimization
r3456
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 try:
data = util.fromlocal(self.opener("localtags").read())
# localtags are stored in the local character set
# while the internal tag table is stored in UTF-8
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 readtags(data.splitlines(), "localtags", "local")
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 except IOError:
pass
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Make the tags algorithm smarter
r4211 self.tagscache = {}
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 self._tagstypecache = {}
Matt Mackall
Make the tags algorithm smarter
r4211 for k,nh in globaltags.items():
n = nh[0]
Matt Mackall
tags: add --remove
r4213 if n != nullid:
self.tagscache[k] = n
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 self._tagstypecache[k] = tagtypes[k]
Matt Mackall
Refactor tags code to prepare for improving the algorithm
r4210 self.tagscache['tip'] = self.changelog.tip()
mpm@selenic.com
Break apart hg.py...
r1089
return self.tagscache
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 def tagtype(self, tagname):
'''
return the type of the given tag. result can be:
'local' : a local tag
'global' : a global tag
None : tag does not exist
'''
self.tags()
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 return self._tagstypecache.get(tagname)
Alexis S. L. Carvalho
Correct optimization from 3464f5e77f34; add a test....
r3577 def _hgtagsnodes(self):
heads = self.heads()
heads.reverse()
last = {}
ret = []
for node in heads:
c = self.changectx(node)
rev = c.rev()
try:
fnode = c.filenode('.hgtags')
Brendan Cully
Add revlog.LookupError exception, and use it instead of RevlogError....
r3930 except revlog.LookupError:
Alexis S. L. Carvalho
Correct optimization from 3464f5e77f34; add a test....
r3577 continue
ret.append((rev, node, fnode))
if fnode in last:
ret[last[fnode]] = None
last[fnode] = len(ret) - 1
return [item for item in ret if item]
mpm@selenic.com
Break apart hg.py...
r1089 def tagslist(self):
'''return a list of tags ordered by revision'''
l = []
for t, n in self.tags().items():
try:
r = self.changelog.rev(n)
except:
r = -2 # sort to the beginning of the list if unknown
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 l.append((r, t, n))
mpm@selenic.com
Break apart hg.py...
r1089 l.sort()
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 return [(t, n) for r, t, n in l]
mpm@selenic.com
Break apart hg.py...
r1089
def nodetags(self, node):
'''return the tags associated with a node'''
if not self.nodetagscache:
self.nodetagscache = {}
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 for t, n in self.tags().items():
self.nodetagscache.setdefault(n, []).append(t)
mpm@selenic.com
Break apart hg.py...
r1089 return self.nodetagscache.get(node, [])
Alexis S. L. Carvalho
fix encoding conversion of branch names when mq is loaded
r3826 def _branchtags(self):
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491 partial, last, lrev = self._readbranchcache()
tiprev = self.changelog.count() - 1
if lrev != tiprev:
self._updatebranchcache(partial, lrev+1, tiprev+1)
self._writebranchcache(partial, self.changelog.tip(), tiprev)
Alexis S. L. Carvalho
fix encoding conversion of branch names when mq is loaded
r3826 return partial
def branchtags(self):
if self.branchcache is not None:
return self.branchcache
self.branchcache = {} # avoid recursion in changectx
partial = self._branchtags()
Matt Mackall
Handle transcoding of branch names
r3773 # the branch cache is stored on disk as UTF-8, but in the local
# charset internally
for k, v in partial.items():
self.branchcache[util.tolocal(k)] = v
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491 return self.branchcache
def _readbranchcache(self):
partial = {}
Matt Mackall
Add branchtags function with cache...
r3417 try:
Matt Mackall
Move branches.cache to branch.cache...
r4177 f = self.opener("branch.cache")
Alexis S. L. Carvalho
don't use readline() to read branches.cache...
r3668 lines = f.read().split('\n')
f.close()
Matt Mackall
branch.cache: silently ignore I/O and OS errors
r4415 except (IOError, OSError):
return {}, nullid, nullrev
try:
Thomas Arendsen Hein
Store empty (default) branch in branch cache, too....
r4167 last, lrev = lines.pop(0).split(" ", 1)
Matt Mackall
Add branchtags function with cache...
r3417 last, lrev = bin(last), int(lrev)
Alexis S. L. Carvalho
Ignore all errors while parsing the branch cache.
r3761 if not (lrev < self.changelog.count() and
self.changelog.node(lrev) == last): # sanity check
# invalidate the cache
raise ValueError('Invalid branch cache: unknown tip')
for l in lines:
if not l: continue
Thomas Arendsen Hein
Store empty (default) branch in branch cache, too....
r4167 node, label = l.split(" ", 1)
partial[label.strip()] = bin(node)
Alexis S. L. Carvalho
Ignore all errors while parsing the branch cache.
r3761 except (KeyboardInterrupt, util.SignalInterrupt):
raise
except Exception, inst:
if self.ui.debugflag:
self.ui.warn(str(inst), '\n')
partial, last, lrev = {}, nullid, nullrev
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491 return partial, last, lrev
Matt Mackall
Add branchtags function with cache...
r3417
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491 def _writebranchcache(self, branches, tip, tiprev):
Matt Mackall
If we can't write the branch cache, fail quietly.
r3452 try:
Alexis S. L. Carvalho
use atomictemp files to write branch.cache
r4329 f = self.opener("branch.cache", "w", atomictemp=True)
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491 f.write("%s %s\n" % (hex(tip), tiprev))
for label, node in branches.iteritems():
Matt Mackall
If we can't write the branch cache, fail quietly.
r3452 f.write("%s %s\n" % (hex(node), label))
Alexis S. L. Carvalho
use atomictemp files to write branch.cache
r4329 f.rename()
Matt Mackall
branch.cache: silently ignore I/O and OS errors
r4415 except (IOError, OSError):
Matt Mackall
If we can't write the branch cache, fail quietly.
r3452 pass
Matt Mackall
Add branchtags function with cache...
r3417
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491 def _updatebranchcache(self, partial, start, end):
for r in xrange(start, end):
c = self.changectx(r)
b = c.branch()
Thomas Arendsen Hein
Store empty (default) branch in branch cache, too....
r4167 partial[b] = c.node()
Alexis S. L. Carvalho
Split branchtags into two additional functions....
r3491
mpm@selenic.com
Break apart hg.py...
r1089 def lookup(self, key):
Matt Mackall
Make lookup aware of branch labels...
r3418 if key == '.':
Thomas Arendsen Hein
Issue a warning if "-r ." is used with two working directory parents....
r4510 key, second = self.dirstate.parents()
Matt Mackall
Make lookup aware of branch labels...
r3418 if key == nullid:
raise repo.RepoError(_("no revision checked out"))
Thomas Arendsen Hein
Issue a warning if "-r ." is used with two working directory parents....
r4510 if second != nullid:
self.ui.warn(_("warning: working directory has two parents, "
"tag '.' uses the first\n"))
Brendan Cully
Add "null" pseudo-tag pointing to nullid
r3801 elif key == 'null':
return nullid
Matt Mackall
Only look up tags and branches as a last resort
r3453 n = self.changelog._match(key)
if n:
return n
Matt Mackall
Make lookup aware of branch labels...
r3418 if key in self.tags():
mpm@selenic.com
Break apart hg.py...
r1089 return self.tags()[key]
Matt Mackall
Make lookup aware of branch labels...
r3418 if key in self.branchtags():
return self.branchtags()[key]
Matt Mackall
Only look up tags and branches as a last resort
r3453 n = self.changelog._partialmatch(key)
if n:
return n
Matt Mackall
Use a weakref for recursive transactions
r4916 try:
if len(key) == 20:
key = hex(key)
except:
pass
Matt Mackall
Only look up tags and branches as a last resort
r3453 raise repo.RepoError(_("unknown revision '%s'") % key)
mpm@selenic.com
Break apart hg.py...
r1089
def dev(self):
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 return os.lstat(self.path).st_dev
mpm@selenic.com
Break apart hg.py...
r1089
def local(self):
mpm@selenic.com
Separate out old-http support...
r1101 return True
mpm@selenic.com
Break apart hg.py...
r1089
def join(self, f):
return os.path.join(self.path, f)
Matt Mackall
localrepo: add separate methods for manipulating repository data...
r3457 def sjoin(self, f):
Benoit Boissinot
switch to the .hg/store layout, fix the tests
r3853 f = self.encodefn(f)
Benoit Boissinot
introduce localrepo.spath for the store path, sopener fixes
r3791 return os.path.join(self.spath, f)
Matt Mackall
localrepo: add separate methods for manipulating repository data...
r3457
mpm@selenic.com
Break apart hg.py...
r1089 def wjoin(self, f):
return os.path.join(self.root, f)
def file(self, f):
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 if f[0] == '/':
f = f[1:]
Matt Mackall
revlog: simplify revlog version handling...
r4258 return filelog.filelog(self.sopener, f)
mpm@selenic.com
Break apart hg.py...
r1089
Brendan Cully
Move defaultrev into changectx...
r3132 def changectx(self, changeid=None):
Matt Mackall
Add context helper functions to localrepo
r2564 return context.changectx(self, changeid)
Matt Mackall
merge: use new working context object in update
r3218 def workingctx(self):
return context.workingctx(self)
Matt Mackall
Add localrepo.parents to get parent changectxs.
r3163 def parents(self, changeid=None):
'''
get list of changectxs for parents of changeid or working directory
'''
if changeid is None:
pl = self.dirstate.parents()
else:
n = self.changelog.lookup(changeid)
pl = self.changelog.parents(n)
Matt Mackall
localrepo.parents: return null context for no parents
r3164 if pl[1] == nullid:
return [self.changectx(pl[0])]
return [self.changectx(pl[0]), self.changectx(pl[1])]
Matt Mackall
Add localrepo.parents to get parent changectxs.
r3163
Matt Mackall
Add context helper functions to localrepo
r2564 def filectx(self, path, changeid=None, fileid=None):
"""changeid can be a changeset revision, node, or tag.
fileid can be a file revision or node."""
return context.filectx(self, path, changeid, fileid)
mpm@selenic.com
Break apart hg.py...
r1089 def getcwd(self):
return self.dirstate.getcwd()
Alexis S. L. Carvalho
Add dirstate.pathto and localrepo.pathto....
r4525 def pathto(self, f, cwd=None):
return self.dirstate.pathto(f, cwd)
mpm@selenic.com
Break apart hg.py...
r1089 def wfile(self, f, mode='r'):
return self.wopener(f, mode)
Alexis S. L. Carvalho
use os.path.islink instead of util.is_link; remove util.is_link
r4275 def _link(self, f):
return os.path.islink(self.wjoin(f))
Matt Mackall
unify encode/decode filter routines
r4004 def _filter(self, filter, filename, data):
if filter not in self.filterpats:
mpm@selenic.com
Add file encoding/decoding support
r1258 l = []
Matt Mackall
unify encode/decode filter routines
r4004 for pat, cmd in self.ui.configitems(filter):
Benoit Boissinot
fix the call to util.matcher (the args should be (reporoot, cwd, ...))
r1947 mf = util.matcher(self.root, "", [pat], [], [])[1]
mpm@selenic.com
Add file encoding/decoding support
r1258 l.append((mf, cmd))
Matt Mackall
unify encode/decode filter routines
r4004 self.filterpats[filter] = l
mpm@selenic.com
Add file encoding/decoding support
r1258
Matt Mackall
unify encode/decode filter routines
r4004 for mf, cmd in self.filterpats[filter]:
mpm@selenic.com
Add file encoding/decoding support
r1258 if mf(filename):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
mpm@selenic.com
Add file encoding/decoding support
r1258 data = util.filter(data, cmd)
break
return data
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
unify encode/decode filter routines
r4004 def wread(self, filename):
if self._link(filename):
data = os.readlink(self.wjoin(filename))
else:
data = self.wopener(filename, 'r').read()
return self._filter("encode", filename, data)
mpm@selenic.com
Add file encoding/decoding support
r1258
Matt Mackall
symlinks: add flags param to wwrite...
r4006 def wwrite(self, filename, data, flags):
Matt Mackall
unify encode/decode filter routines
r4004 data = self._filter("decode", filename, data)
Matt Mackall
wwrite: simplify with util.set_flags...
r5703 try:
os.unlink(self.wjoin(filename))
except OSError:
pass
self.wopener(filename, 'w').write(data)
util.set_flags(self.wjoin(filename), flags)
mpm@selenic.com
Add file encoding/decoding support
r1258
Matt Mackall
replace filehandle version of wwrite with wwritedata
r4005 def wwritedata(self, filename, data):
return self._filter("decode", filename, data)
mpm@selenic.com
Break apart hg.py...
r1089
def transaction(self):
Matt Mackall
Use a weakref for recursive transactions
r4916 if self._transref and self._transref():
return self._transref().nest()
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806
Thomas Arendsen Hein
Renamed localrepo.undo() to rollback() and talk about "rollback information".
r2362 # save dirstate for rollback
mpm@selenic.com
Break apart hg.py...
r1089 try:
ds = self.opener("dirstate").read()
except IOError:
ds = ""
self.opener("journal.dirstate", "w").write(ds)
Alexandre Vassalotti
restore branch after rollback (issue 902)
r5814 self.opener("journal.branch", "w").write(self.dirstate.branch())
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
localrepo: change aftertrans to be independant of the store path
r3790 renames = [(self.sjoin("journal"), self.sjoin("undo")),
Alexandre Vassalotti
restore branch after rollback (issue 902)
r5814 (self.join("journal.dirstate"), self.join("undo.dirstate")),
(self.join("journal.branch"), self.join("undo.branch"))]
Matt Mackall
localrepo: add separate methods for manipulating repository data...
r3457 tr = transaction.transaction(self.ui.warn, self.sopener,
self.sjoin("journal"),
Benoit Boissinot
localrepo: change aftertrans to be independant of the store path
r3790 aftertrans(renames))
Matt Mackall
Use a weakref for recursive transactions
r4916 self._transref = weakref.ref(tr)
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806 return tr
mpm@selenic.com
Break apart hg.py...
r1089
def recover(self):
Benoit Boissinot
fix warnings from pychecker (unused variables and shadowing)
r1749 l = self.lock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
if os.path.exists(self.sjoin("journal")):
self.ui.status(_("rolling back interrupted transaction\n"))
transaction.rollback(self.sopener, self.sjoin("journal"))
self.invalidate()
return True
else:
self.ui.warn(_("no interrupted transaction available\n"))
return False
finally:
del l
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def rollback(self):
wlock = lock = None
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
mason@suse.com
Allow callers to pass in the dirstate lock in most localrepo.py funcs....
r1712 wlock = self.wlock()
Eric Hopper
Fix hg import --exact bug that hangs hg on failure.
r4438 lock = self.lock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if os.path.exists(self.sjoin("undo")):
self.ui.status(_("rolling back last transaction\n"))
transaction.rollback(self.sopener, self.sjoin("undo"))
util.rename(self.join("undo.dirstate"), self.join("dirstate"))
Alexandre Vassalotti
restore branch after rollback (issue 902)
r5814 branch = self.opener("undo.branch").read()
self.dirstate.setbranch(branch)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.invalidate()
self.dirstate.invalidate()
else:
self.ui.warn(_("no rollback information available\n"))
finally:
Alexis S. L. Carvalho
del transaction before lock before wlock...
r5053 del lock, wlock
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
localrepo and dirstate: rename reload to invalidate...
r4613 def invalidate(self):
for a in "changelog manifest".split():
if hasattr(self, a):
self.__delattr__(a)
Benoit Boissinot
revalidate revlog data after locking the repo (issue132)
r1784 self.tagscache = None
Osku Salerma
Properly check tag's existence as a local/global tag when removing it.
r5657 self._tagstypecache = None
Benoit Boissinot
revalidate revlog data after locking the repo (issue132)
r1784 self.nodetagscache = None
Matt Mackall
rename and simplify do_lock
r4913 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
mpm@selenic.com
Break apart hg.py...
r1089 try:
Matt Mackall
localrepo: add separate methods for manipulating repository data...
r3457 l = lock.lock(lockname, 0, releasefn, desc=desc)
Benoit Boissinot
add localrepo.wlock for protecting the dirstate...
r1531 except lock.LockHeld, inst:
if not wait:
Vadim Gelfer
fix backtrace printed when cannot get lock....
r2016 raise
Thomas Arendsen Hein
Corrected "waiting for lock on repository FOO held by BAR" message....
r3688 self.ui.warn(_("waiting for lock on %s held by %r\n") %
(desc, inst.locker))
Vadim Gelfer
fix backtrace printed when cannot get lock....
r2016 # default to 600 seconds timeout
Matt Mackall
localrepo: add separate methods for manipulating repository data...
r3457 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
Vadim Gelfer
fix backtrace printed when cannot get lock....
r2016 releasefn, desc=desc)
Benoit Boissinot
localrepo: refactor the locking functions
r1751 if acquirefn:
acquirefn()
return l
Matt Mackall
repo locks: use True/False
r4914 def lock(self, wait=True):
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 if self._lockref and self._lockref():
return self._lockref()
l = self._lock(self.sjoin("lock"), wait, None, self.invalidate,
_('repository %s') % self.origroot)
self._lockref = weakref.ref(l)
return l
Benoit Boissinot
localrepo: refactor the locking functions
r1751
Matt Mackall
repo locks: use True/False
r4914 def wlock(self, wait=True):
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 if self._wlockref and self._wlockref():
return self._wlockref()
Benoit Boissinot
add localrepo.wlock for protecting the dirstate...
r1531
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 l = self._lock(self.join("wlock"), wait, self.dirstate.write,
self.dirstate.invalidate, _('working directory of %s') %
self.origroot)
self._wlockref = weakref.ref(l)
return l
Benoit Boissinot
add localrepo.wlock for protecting the dirstate...
r1531
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 def filecommit(self, fn, manifest1, manifest2, linkrev, tr, changelist):
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 """
Matt Mackall
commit: unify file-level commit code
r3294 commit an individual file as part of a larger transaction
"""
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292
Matt Mackall
commit: unify file-level commit code
r3294 t = self.wread(fn)
fl = self.file(fn)
fp1 = manifest1.get(fn, nullid)
fp2 = manifest2.get(fn, nullid)
Matt Mackall
Refactor excessive merge detection, add test
r1716
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 meta = {}
Matt Mackall
commit: unify file-level commit code
r3294 cp = self.dirstate.copied(fn)
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 if cp:
Alexis S. L. Carvalho
filecommit: don't forget the local parent on a merge with a local rename
r4058 # Mark the new revision of this file as a copy of another
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516 # file. This copy data will effectively act as a parent
# of this new revision. If this is a merge, the first
Alexis S. L. Carvalho
filecommit: don't forget the local parent on a merge with a local rename
r4058 # parent will be the nullid (meaning "look up the copy data")
# and the second one will be the other parent. For example:
#
# 0 --- 1 --- 3 rev1 changes file foo
# \ / rev2 renames foo to bar and changes it
# \- 2 -/ rev3 should have bar with all changes and
# should record that bar descends from
# bar in rev2 and foo in rev1
#
# this allows this merge to succeed:
#
# 0 --- 1 --- 3 rev4 reverts the content change from rev2
# \ / merging rev3 and rev4 should use bar@rev2
# \- 2 --- 4 as the merge base
#
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 meta["copy"] = cp
if not manifest2: # not a branch merge
meta["copyrev"] = hex(manifest1.get(cp, nullid))
fp2 = nullid
elif fp2 != nullid: # copied on remote side
meta["copyrev"] = hex(manifest1.get(cp, nullid))
Matt Mackall
merge: handle directory renames...
r3733 elif fp1 != nullid: # copied on local side, reversed
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 meta["copyrev"] = hex(manifest2.get(cp))
Alexis S. L. Carvalho
filecommit: don't forget the local parent on a merge with a local rename
r4058 fp2 = fp1
Alexis S. L. Carvalho
correctly record file-level history when the local side renames a directory
r5229 elif cp in manifest2: # directory rename on local side
meta["copyrev"] = hex(manifest2[cp])
else: # directory rename on remote side
Matt Mackall
merge: handle directory renames...
r3733 meta["copyrev"] = hex(manifest1.get(cp, nullid))
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 self.ui.debug(_(" %s: copy %s:%s\n") %
Matt Mackall
commit: unify file-level commit code
r3294 (fn, cp, meta["copyrev"]))
Matt Mackall
merge: remember rename copies and parents properly on commit...
r3292 fp1 = nullid
elif fp2 != nullid:
Matt Mackall
Refactor excessive merge detection, add test
r1716 # is one parent an ancestor of the other?
Matt Mackall
commit: unify file-level commit code
r3294 fpa = fl.ancestor(fp1, fp2)
Matt Mackall
Refactor excessive merge detection, add test
r1716 if fpa == fp1:
fp1, fp2 = fp2, nullid
elif fpa == fp2:
fp2 = nullid
Alexis S. L. Carvalho
Avoid extra filelogs entries....
r4531 # is the file unmodified from the parent? report existing entry
Alexis S. L. Carvalho
Fix theoretical issue in filecommit....
r5228 if fp2 == nullid and not fl.cmp(fp1, t) and not meta:
Alexis S. L. Carvalho
Avoid extra filelogs entries....
r4531 return fp1
Matt Mackall
Refactor excessive merge detection, add test
r1716
Matt Mackall
commit: unify file-level commit code
r3294 changelist.append(fn)
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 return fl.add(t, meta, tr, linkrev, fp1, fp2)
Matt Mackall
Refactor excessive merge detection, add test
r1716
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def rawcommit(self, files, text, user, date, p1=None, p2=None, extra={}):
Benoit Boissinot
localrepo: factor commit and rawcommit...
r3621 if p1 is None:
p1, p2 = self.dirstate.parents()
return self.commit(files=files, text=text, user=user, date=date,
Bryan O'Sullivan
localrepository: allow rawcommit to commit with an empty message
r5041 p1=p1, p2=p2, extra=extra, empty_ok=True)
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 def commit(self, files=None, text="", user=None, date=None,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 match=util.always, force=False, force_editor=False,
Bryan O'Sullivan
localrepository: allow rawcommit to commit with an empty message
r5041 p1=None, p2=None, extra={}, empty_ok=False):
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 wlock = lock = tr = None
Matt Mackall
commit: avoid losing edits during commit...
r5637 valid = 0 # don't save the dirstate if this isn't set
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
commit = []
remove = []
changed = []
use_dirstate = (p1 is None) # not rawcommit
extra = extra.copy()
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if use_dirstate:
if files:
for f in files:
s = self.dirstate[f]
if s in 'nma':
commit.append(f)
elif s == 'r':
remove.append(f)
else:
self.ui.warn(_("%s not tracked!\n") % f)
else:
changes = self.status(match=match)[:5]
modified, added, removed, deleted, unknown = changes
commit = modified + added
remove = removed
Benoit Boissinot
localrepo: factor commit and rawcommit...
r3621 else:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 commit = files
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if use_dirstate:
p1, p2 = self.dirstate.parents()
update_dirstate = True
else:
p1, p2 = p1, p2 or nullid
update_dirstate = (self.dirstate.parents()[0] == p1)
Benoit Boissinot
localrepo: factor commit and rawcommit...
r3621
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
m1 = self.manifest.read(c1[0]).copy()
m2 = self.manifest.read(c2[0])
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if use_dirstate:
branchname = self.workingctx().branch()
try:
branchname = branchname.decode('UTF-8').encode('UTF-8')
except UnicodeDecodeError:
raise util.Abort(_('branch name not in UTF-8!'))
else:
branchname = ""
Matt Mackall
Add branch support to commit
r3419
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if use_dirstate:
oldname = c1[5].get("branch") # stored in UTF-8
if (not commit and not remove and not force and p2 == nullid
and branchname == oldname):
self.ui.status(_("nothing changed\n"))
return None
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 xp1 = hex(p1)
if p2 == nullid: xp2 = ''
else: xp2 = hex(p2)
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
mpm@selenic.com
Break apart hg.py...
r1089
mason@suse.com
Allow callers to pass in the dirstate lock in most localrepo.py funcs....
r1712 wlock = self.wlock()
mason@suse.com
Allow repo lock to be passed in to localrepo.commit for performance
r1807 lock = self.lock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 tr = self.transaction()
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 trp = weakref.proxy(tr)
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # check in files
new = {}
linkrev = self.changelog.count()
commit.sort()
is_exec = util.execfunc(self.root, m1.execf)
is_link = util.linkfunc(self.root, m1.linkf)
for f in commit:
self.ui.note(f + "\n")
try:
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 new[f] = self.filecommit(f, m1, m2, linkrev, trp, changed)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 new_exec = is_exec(f)
new_link = is_link(f)
Alexis S. L. Carvalho
Merge with crew-stable.
r5249 if ((not changed or changed[-1] != f) and
m2.get(f) != new[f]):
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # mention the file in the changelog if some
# flag changed, even if there was no content
# change.
old_exec = m1.execf(f)
old_link = m1.linkf(f)
if old_exec != new_exec or old_link != new_link:
changed.append(f)
m1.set(f, new_exec, new_link)
Matt Mackall
commit: avoid losing edits during commit...
r5637 if use_dirstate:
self.dirstate.normal(f)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 except (OSError, IOError):
if use_dirstate:
self.ui.warn(_("trouble committing %s!\n") % f)
raise
else:
remove.append(f)
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # update manifest
m1.update(new)
remove.sort()
removed = []
Benoit Boissinot
localrepo.commit: little cleanups...
r3620
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 for f in remove:
if f in m1:
del m1[f]
removed.append(f)
elif f in m2:
removed.append(f)
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 mn = self.manifest.add(m1, trp, linkrev, c1[0], c2[0],
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 (new, removed))
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # add changeset
new = new.keys()
new.sort()
Alexis S. L. Carvalho
Revert almost all of 5be434785317; add a test...
r3675
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 user = user or self.ui.username()
Bryan O'Sullivan
localrepository: allow rawcommit to commit with an empty message
r5041 if (not empty_ok and not text) or force_editor:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 edittext = []
if text:
edittext.append(text)
edittext.append("")
Thomas Arendsen Hein
Clarify some messages during commit:...
r5757 edittext.append(_("HG: Enter commit message."
" Lines beginning with 'HG:' are removed."))
Patrick Mezard
Prompt for a commit message in editor, improve error message
r5754 edittext.append("HG: --")
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 edittext.append("HG: user: %s" % user)
if p2 != nullid:
edittext.append("HG: branch merge")
if branchname:
Thomas Arendsen Hein
Clarify some messages during commit:...
r5757 edittext.append("HG: branch '%s'" % util.tolocal(branchname))
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 edittext.extend(["HG: changed %s" % f for f in changed])
edittext.extend(["HG: removed %s" % f for f in removed])
if not changed and not remove:
edittext.append("HG: no files changed")
edittext.append("")
# run editor in the repository root
olddir = os.getcwd()
os.chdir(self.root)
text = self.ui.edit("\n".join(edittext), user)
os.chdir(olddir)
mpm@selenic.com
Break apart hg.py...
r1089
Simon 'corecode' Schubert
Add branch name to editor text.
r4020 if branchname:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 extra["branch"] = branchname
mpm@selenic.com
Break apart hg.py...
r1089
Bryan O'Sullivan
localrepo.commit: only munge comment text if committing via dirstate
r5023 if use_dirstate:
lines = [line.rstrip() for line in text.rstrip().splitlines()]
while lines and not lines[0]:
del lines[0]
if not lines:
Thomas Arendsen Hein
Clarify some messages during commit:...
r5757 raise util.Abort(_("empty commit message"))
Bryan O'Sullivan
localrepo.commit: only munge comment text if committing via dirstate
r5023 text = '\n'.join(lines)
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 n = self.changelog.add(mn, changed + removed, text, trp, p1, p2,
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 user, date, extra)
self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
parent2=xp2)
tr.close()
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if self.branchcache and "branch" in extra:
self.branchcache[util.tolocal(extra["branch"])] = n
Simon 'corecode' Schubert
When committing, record the changeset in the branchcache.
r4019
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if use_dirstate or update_dirstate:
self.dirstate.setparents(n)
if use_dirstate:
for f in removed:
self.dirstate.forget(f)
Matt Mackall
commit: avoid losing edits during commit...
r5637 valid = 1 # our dirstate updates are complete
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
return n
finally:
Matt Mackall
commit: avoid losing edits during commit...
r5637 if not valid: # don't save our updated dirstate
self.dirstate.invalidate()
Alexis S. L. Carvalho
del transaction before lock before wlock...
r5053 del tr, lock, wlock
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
rewrite revert command. fix issues 93, 123, 147....
r2029 def walk(self, node=None, files=[], match=util.always, badmatch=None):
Matt Mackall
improve walk docstrings
r3532 '''
walk recursively through the directory tree or a given
changeset, finding all files matched by the match
function
results are yielded in a tuple (src, filename), where src
is one of:
'f' the file was found in the directory tree
'm' the file was only in the dirstate and not in the tree
'b' file was not found and matched badmatch
'''
mpm@selenic.com
Break apart hg.py...
r1089 if node:
Benoit Boissinot
fix the cat command...
r1582 fdict = dict.fromkeys(files)
Alexis S. L. Carvalho
change locate to use relglobs by default...
r4195 # for dirstate.walk, files=['.'] means "walk the whole tree".
# follow that here, too
fdict.pop('.', None)
Alexis S. L. Carvalho
localrepo.walk: if we're walking a specific revision, sort the files...
r4194 mdict = self.manifest.read(self.changelog.read(node)[0])
mfiles = mdict.keys()
mfiles.sort()
for fn in mfiles:
Benoit Boissinot
fix incorrect warning when walking on a particular rev...
r3019 for ffn in fdict:
# match if the file is the exact name or a directory
if ffn == fn or fn.startswith("%s/" % ffn):
del fdict[ffn]
break
Benoit Boissinot
fix the cat command...
r1582 if match(fn):
yield 'm', fn
Alexis S. L. Carvalho
localrepo.walk: if we're walking a specific revision, sort the files...
r4194 ffiles = fdict.keys()
ffiles.sort()
for fn in ffiles:
Vadim Gelfer
rewrite revert command. fix issues 93, 123, 147....
r2029 if badmatch and badmatch(fn):
if match(fn):
yield 'b', fn
else:
Alexis S. L. Carvalho
Add dirstate.pathto and localrepo.pathto....
r4525 self.ui.warn(_('%s: No such file in rev %s\n')
% (self.pathto(fn), short(node)))
mpm@selenic.com
Break apart hg.py...
r1089 else:
Vadim Gelfer
small changes to revert command....
r2042 for src, fn in self.dirstate.walk(files, match, badmatch=badmatch):
mpm@selenic.com
Break apart hg.py...
r1089 yield src, fn
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 def status(self, node1=None, node2=None, files=[], match=util.always,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 list_ignored=False, list_clean=False):
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 """return status of files between two nodes or node and working directory
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616
If node1 is None, use the first dirstate parent instead.
If node2 is None, compare node1 with working directory.
"""
mpm@selenic.com
Break apart hg.py...
r1089
Alexis S. L. Carvalho
localrepo.status: fcmp gets a getnode function instead of the manifest
r4160 def fcmp(fn, getnode):
mpm@selenic.com
Break apart hg.py...
r1089 t1 = self.wread(fn)
Alexis S. L. Carvalho
localrepo.status: fcmp gets a getnode function instead of the manifest
r4160 return self.file(fn).cmp(getnode(fn), t1)
mpm@selenic.com
Break apart hg.py...
r1089
def mfmatches(node):
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 change = self.changelog.read(node)
Benoit Boissinot
fix localrepo.status when dealing with x-bit changes
r3322 mf = self.manifest.read(change[0]).copy()
mpm@selenic.com
Break apart hg.py...
r1089 for fn in mf.keys():
if not match(fn):
del mf[fn]
return mf
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 modified, added, removed, deleted, unknown = [], [], [], [], []
ignored, clean = [], []
Chris Mason
Fix cold cache diff performance...
r2474 compareworking = False
Chris Mason
Fix localrepo.changes() Correctly decide if we are diffing the working dir
r2491 if not node1 or (not node2 and node1 == self.dirstate.parents()[0]):
Chris Mason
Fix cold cache diff performance...
r2474 compareworking = True
if not compareworking:
Alexis S. L. Carvalho
speed up hg log --debug...
r1802 # read the manifest from node1 before the manifest from node2,
# so that we'll hit the manifest cache if we're going through
# all the revisions in parent->child order.
mf1 = mfmatches(node1)
mpm@selenic.com
Break apart hg.py...
r1089 # are we comparing the working directory?
if not node2:
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 (lookup, modified, added, removed, deleted, unknown,
ignored, clean) = self.dirstate.status(files, match,
list_ignored, list_clean)
mpm@selenic.com
Break apart hg.py...
r1089
# are we comparing working dir against its parent?
Chris Mason
Fix cold cache diff performance...
r2474 if compareworking:
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 if lookup:
Matt Mackall
simplify dirstate fixups in repo.status()
r4912 fixup = []
mpm@selenic.com
Break apart hg.py...
r1089 # do a full compare of any files that might have changed
Matt Mackall
use context for part of localrepo status
r4910 ctx = self.changectx()
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 for f in lookup:
Matt Mackall
use context for part of localrepo status
r4910 if f not in ctx or ctx[f].cmp(self.wread(f)):
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 modified.append(f)
Alexis S. L. Carvalho
localrepo.status: detect clean files even when the mtime has changed
r2961 else:
Matt Mackall
simplify dirstate fixups in repo.status()
r4912 fixup.append(f)
Alexis S. L. Carvalho
localrepo.status: only append stuff to the clean list if list_clean is true...
r4579 if list_clean:
clean.append(f)
Matt Mackall
simplify dirstate fixups in repo.status()
r4912
# update dirstate for files that are actually clean
if fixup:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 wlock = None
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 try:
wlock = self.wlock(False)
except lock.LockException:
pass
Bryan O'Sullivan
localrepository.status: only acquire wlock if actually needed....
r4372 if wlock:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 for f in fixup:
self.dirstate.normal(f)
finally:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 del wlock
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 else:
# we are comparing working dir against non-parent
# generate a pseudo-manifest for the working dir
Benoit Boissinot
fix localrepo.status when dealing with x-bit changes
r3322 # XXX: create it in dirstate.py ?
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 mf2 = mfmatches(self.dirstate.parents()[0])
Matt Mackall
exec: add execfunc to simplify exec flag support on non-exec filesystems
r3996 is_exec = util.execfunc(self.root, mf2.execf)
Matt Mackall
symlinks: use is_link wherever is_exec is used
r4002 is_link = util.linkfunc(self.root, mf2.linkf)
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 for f in lookup + modified + added:
mf2[f] = ""
Matt Mackall
symlinks: use is_link wherever is_exec is used
r4002 mf2.set(f, is_exec(f), is_link(f))
Thomas Arendsen Hein
Make localrepo.changes() internally distinguish between removed and deleted.
r1617 for f in removed:
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 if f in mf2:
del mf2[f]
Bryan O'Sullivan
localrepository.status: only acquire wlock if actually needed....
r4372
mpm@selenic.com
Break apart hg.py...
r1089 else:
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 # we are comparing two revisions
mf2 = mfmatches(node2)
mpm@selenic.com
Break apart hg.py...
r1089
Chris Mason
Fix cold cache diff performance...
r2474 if not compareworking:
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 # flush lists from dirstate before comparing manifests
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 modified, added, clean = [], [], []
mpm@selenic.com
Break apart hg.py...
r1089
Chris Mason
Fix cold cache diff performance...
r2474 # make sure to sort the files so we talk to the disk in a
# reasonable order
mf2keys = mf2.keys()
mf2keys.sort()
Alexis S. L. Carvalho
localrepo.status: fcmp gets a getnode function instead of the manifest
r4160 getnode = lambda fn: mf1.get(fn, nullid)
Chris Mason
Fix cold cache diff performance...
r2474 for fn in mf2keys:
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 if mf1.has_key(fn):
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 if (mf1.flags(fn) != mf2.flags(fn) or
(mf1[fn] != mf2[fn] and
(mf2[fn] != "" or fcmp(fn, getnode)))):
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 modified.append(fn)
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 elif list_clean:
clean.append(fn)
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 del mf1[fn]
else:
added.append(fn)
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Make localrepo.changes() internally distinguish between removed and deleted.
r1617 removed = mf1.keys()
Thomas Arendsen Hein
Cleaned up localrepo.changes()
r1616 # sort and return results:
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 for l in modified, added, removed, deleted, unknown, ignored, clean:
mpm@selenic.com
Break apart hg.py...
r1089 l.sort()
Vadim Gelfer
status: add -c (clean) and -A (all files) options...
r2661 return (modified, added, removed, deleted, unknown, ignored, clean)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def add(self, list):
wlock = self.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
Patrick Mezard
commands: add exits(1) if a specified file cannot be added (issue 891)
r5688 rejected = []
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415 for f in list:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 p = self.wjoin(f)
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415 try:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 st = os.lstat(p)
except:
self.ui.warn(_("%s does not exist!\n") % f)
Patrick Mezard
commands: add exits(1) if a specified file cannot be added (issue 891)
r5688 rejected.append(f)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 continue
if st.st_size > 10000000:
self.ui.warn(_("%s: files over 10MB may cause memory and"
" performance problems\n"
"(use 'hg revert %s' to unadd the file)\n")
% (f, f))
if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
self.ui.warn(_("%s not added: only files and symlinks "
"supported currently\n") % f)
Patrick Mezard
commands: add exits(1) if a specified file cannot be added (issue 891)
r5688 rejected.append(p)
Benoit Boissinot
abort when adding a file in merged state
r5206 elif self.dirstate[f] in 'amn':
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.ui.warn(_("%s already tracked!\n") % f)
Benoit Boissinot
make hg add of a removed file unremove the file...
r5207 elif self.dirstate[f] == 'r':
Alexis S. L. Carvalho
merge: forcefully mark files that we get from the second parent as dirty...
r5210 self.dirstate.normallookup(f)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 else:
self.dirstate.add(f)
Patrick Mezard
commands: add exits(1) if a specified file cannot be added (issue 891)
r5688 return rejected
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 finally:
del wlock
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def forget(self, list):
wlock = self.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
for f in list:
if self.dirstate[f] != 'a':
self.ui.warn(_("%s not added!\n") % f)
else:
self.dirstate.forget(f)
finally:
del wlock
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def remove(self, list, unlink=False):
wlock = None
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
if unlink:
for f in list:
try:
util.unlink(self.wjoin(f))
except OSError, inst:
if inst.errno != errno.ENOENT:
raise
mason@suse.com
Allow callers to pass in the dirstate lock in most localrepo.py funcs....
r1712 wlock = self.wlock()
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415 for f in list:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if unlink and os.path.exists(self.wjoin(f)):
self.ui.warn(_("%s still exists!\n") % f)
elif self.dirstate[f] == 'a':
self.dirstate.forget(f)
elif f not in self.dirstate:
self.ui.warn(_("%s not tracked!\n") % f)
else:
self.dirstate.remove(f)
finally:
del wlock
Benoit Boissinot
revert added and removed files to their normal state before reverting...
r1447
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def undelete(self, list):
wlock = None
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
Patrick Mezard
Merge with crew-stable
r5323 manifests = [self.manifest.read(self.changelog.read(p)[0])
for p in self.dirstate.parents() if p != nullid]
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 wlock = self.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 for f in list:
if self.dirstate[f] != 'r':
self.ui.warn("%s not removed!\n" % f)
else:
Patrick Mezard
Merge with crew-stable
r5323 m = f in manifests[0] and manifests[0] or manifests[1]
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 t = self.file(f).read(m[f])
self.wwrite(f, t, m.flags(f))
self.dirstate.normal(f)
finally:
del wlock
Benoit Boissinot
revert added and removed files to their normal state before reverting...
r1447
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def copy(self, source, dest):
wlock = None
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
p = self.wjoin(dest)
if not (os.path.exists(p) or os.path.islink(p)):
self.ui.warn(_("%s does not exist!\n") % dest)
elif not (os.path.isfile(p) or os.path.islink(p)):
self.ui.warn(_("copy failed: %s is not a file or a "
"symbolic link\n") % dest)
else:
mason@suse.com
Allow callers to pass in the dirstate lock in most localrepo.py funcs....
r1712 wlock = self.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if dest not in self.dirstate:
self.dirstate.add(dest)
self.dirstate.copy(source, dest)
finally:
del wlock
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Fixes to "hg heads -r FOO":...
r1551 def heads(self, start=None):
Benoit Boissinot
add a -r/--rev option to heads to show only heads descendant from rev
r1550 heads = self.changelog.heads(start)
# sort the output in rev descending order
heads = [(-self.changelog.rev(h), h) for h in heads]
heads.sort()
return [n for (r, n) in heads]
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
Add option to heads to show only heads for current branch.
r4648 def branchheads(self, branch, start=None):
branches = self.branchtags()
if branch not in branches:
return []
# The basic algorithm is this:
#
# Start from the branch tip since there are no later revisions that can
# possibly be in this branch, and the tip is a guaranteed head.
#
# Remember the tip's parents as the first ancestors, since these by
# definition are not heads.
#
# Step backwards from the brach tip through all the revisions. We are
# guaranteed by the rules of Mercurial that we will now be visiting the
# nodes in reverse topological order (children before parents).
#
# If a revision is one of the ancestors of a head then we can toss it
# out of the ancestors set (we've already found it and won't be
# visiting it again) and put its parents in the ancestors set.
#
# Otherwise, if a revision is in the branch it's another head, since it
# wasn't in the ancestor list of an existing head. So add it to the
# head list, and add its parents to the ancestor list.
#
# If it is not in the branch ignore it.
#
# Once we have a list of heads, use nodesbetween to filter out all the
# heads that cannot be reached from startrev. There may be a more
# efficient way to do this as part of the previous algorithm.
set = util.set
heads = [self.changelog.rev(branches[branch])]
# Don't care if ancestors contains nullrev or not.
ancestors = set(self.changelog.parentrevs(heads[0]))
for rev in xrange(heads[0] - 1, nullrev, -1):
if rev in ancestors:
ancestors.update(self.changelog.parentrevs(rev))
ancestors.remove(rev)
elif self.changectx(rev).branch() == branch:
heads.append(rev)
ancestors.update(self.changelog.parentrevs(rev))
heads = [self.changelog.node(rev) for rev in heads]
if start is not None:
heads = self.changelog.nodesbetween([start], heads)[2]
return heads
mpm@selenic.com
Break apart hg.py...
r1089 def branches(self, nodes):
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 if not nodes:
nodes = [self.changelog.tip()]
mpm@selenic.com
Break apart hg.py...
r1089 b = []
for n in nodes:
t = n
Benoit Boissinot
n is always 'True', we can only stop the loop with the break statement
r2345 while 1:
mpm@selenic.com
Break apart hg.py...
r1089 p = self.changelog.parents(n)
if p[1] != nullid or p[0] == nullid:
b.append((t, n, p[0], p[1]))
break
n = p[0]
return b
def between(self, pairs):
r = []
for top, bottom in pairs:
n, l, i = top, [], 0
f = 1
while n != bottom:
p = self.changelog.parents(n)[0]
if i == f:
l.append(n)
f = f * 2
n = p
i += 1
r.append(l)
return r
Vadim Gelfer
add -f/--force to pull, incoming, outgoing, to work on unrelated repo....
r1959 def findincoming(self, remote, base=None, heads=None, force=False):
Benoit Boissinot
document and fix findincoming...
r2339 """Return list of roots of the subsets of missing nodes from remote
If base dict is specified, assume that these nodes and their parents
exist on the remote side and that no child of a node of base exists
in both remote and self.
Furthermore base will be updated to include the nodes that exists
in self and remote but no children exists in self and remote.
If a list of heads is specified, return only nodes which are heads
or ancestors of these heads.
All the ancestors of base are in self and in remote.
All the descendants of the list returned are missing in self.
(and so we know that the rest of the nodes are missing in remote, see
outgoing)
"""
mpm@selenic.com
Break apart hg.py...
r1089 m = self.changelog.nodemap
search = []
fetch = {}
seen = {}
seenbranch = {}
if base == None:
base = {}
Matt Mackall
Move empty local repo logic for pull into findincoming...
r2108 if not heads:
heads = remote.heads()
if self.changelog.tip() == nullid:
Benoit Boissinot
document and fix findincoming...
r2339 base[nullid] = 1
Matt Mackall
Move empty local repo logic for pull into findincoming...
r2108 if heads != [nullid]:
return [nullid]
return []
mpm@selenic.com
Break apart hg.py...
r1089 # assume we're closer to the tip than the root
# and start by examining the heads
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.status(_("searching for changes\n"))
mpm@selenic.com
Break apart hg.py...
r1089
unknown = []
for h in heads:
if h not in m:
unknown.append(h)
else:
base[h] = 1
if not unknown:
Benoit Boissinot
findincoming should return an iterable
r1895 return []
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
document and fix findincoming...
r2339 req = dict.fromkeys(unknown)
mpm@selenic.com
Break apart hg.py...
r1089 reqcnt = 0
# search through remote branches
# a 'branch' here is a linear segment of history, with four parts:
# head, root, first parent, second parent
# (a branch always has two parents (or none) by definition)
unknown = remote.branches(unknown)
while unknown:
r = []
while unknown:
n = unknown.pop(0)
if n[0] in seen:
continue
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 self.ui.debug(_("examining %s:%s\n")
% (short(n[0]), short(n[1])))
Benoit Boissinot
document and fix findincoming...
r2339 if n[0] == nullid: # found the end of the branch
pass
elif n in seenbranch:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("branch already found\n"))
mpm@selenic.com
Break apart hg.py...
r1089 continue
Benoit Boissinot
document and fix findincoming...
r2339 elif n[1] and n[1] in m: # do we know the base?
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("found incomplete branch %s:%s\n")
mpm@selenic.com
Break apart hg.py...
r1089 % (short(n[0]), short(n[1])))
search.append(n) # schedule branch range for scanning
seenbranch[n] = 1
else:
if n[1] not in seen and n[1] not in fetch:
if n[2] in m and n[3] in m:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("found new changeset %s\n") %
mpm@selenic.com
Break apart hg.py...
r1089 short(n[1]))
fetch[n[1]] = 1 # earliest unknown
Benoit Boissinot
document and fix findincoming...
r2339 for p in n[2:4]:
if p in m:
base[p] = 1 # latest known
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
document and fix findincoming...
r2339 for p in n[2:4]:
if p not in req and p not in m:
r.append(p)
req[p] = 1
mpm@selenic.com
Break apart hg.py...
r1089 seen[n[0]] = 1
if r:
reqcnt += 1
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("request %d: %s\n") %
mpm@selenic.com
Break apart hg.py...
r1089 (reqcnt, " ".join(map(short, r))))
Benoit Boissinot
use xrange instead of range
r3473 for p in xrange(0, len(r), 10):
mpm@selenic.com
Break apart hg.py...
r1089 for b in remote.branches(r[p:p+10]):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("received %s:%s\n") %
mpm@selenic.com
Break apart hg.py...
r1089 (short(b[0]), short(b[1])))
Benoit Boissinot
document and fix findincoming...
r2339 unknown.append(b)
mpm@selenic.com
Break apart hg.py...
r1089
# do binary search on the branches we found
while search:
n = search.pop(0)
reqcnt += 1
l = remote.between([(n[0], n[1])])[0]
l.append(n[1])
p = n[0]
f = 1
for i in l:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("narrowing %d:%d %s\n") % (f, len(l), short(i)))
mpm@selenic.com
Break apart hg.py...
r1089 if i in m:
if f <= 2:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("found new branch changeset %s\n") %
mpm@selenic.com
Break apart hg.py...
r1089 short(p))
fetch[p] = 1
base[i] = 1
else:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("narrowed branch search to %s:%s\n")
mpm@selenic.com
Break apart hg.py...
r1089 % (short(p), short(i)))
search.append((p, i))
break
p, f = i, f * 2
# sanity check our fetch list
for f in fetch.keys():
if f in m:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise repo.RepoError(_("already have changeset ") + short(f[:4]))
mpm@selenic.com
Break apart hg.py...
r1089
if base.keys() == [nullid]:
Vadim Gelfer
add -f/--force to pull, incoming, outgoing, to work on unrelated repo....
r1959 if force:
self.ui.warn(_("warning: repository is unrelated\n"))
else:
raise util.Abort(_("repository is unrelated"))
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Demote a pull note to a debug message
r2965 self.ui.debug(_("found new changesets starting at ") +
mpm@selenic.com
Break apart hg.py...
r1089 " ".join([short(f) for f in fetch]) + "\n")
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("%d total queries\n") % reqcnt)
mpm@selenic.com
Break apart hg.py...
r1089
return fetch.keys()
Vadim Gelfer
add -f/--force to pull, incoming, outgoing, to work on unrelated repo....
r1959 def findoutgoing(self, remote, base=None, heads=None, force=False):
Thomas Arendsen Hein
Fix hg push and hg push -r sometimes creating new heads without --force....
r2021 """Return list of nodes that are roots of subsets not in remote
If base dict is specified, assume that these nodes and their parents
exist on the remote side.
If a list of heads is specified, return only nodes which are heads
or ancestors of these heads, and return a second element which
contains all remote heads which get new children.
"""
mpm@selenic.com
Break apart hg.py...
r1089 if base == None:
base = {}
Vadim Gelfer
add -f/--force to pull, incoming, outgoing, to work on unrelated repo....
r1959 self.findincoming(remote, base, heads, force=force)
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("common changesets up to ")
mpm@selenic.com
Break apart hg.py...
r1089 + " ".join(map(short, base.keys())) + "\n")
remain = dict.fromkeys(self.changelog.nodemap)
# prune everything remote has from the tree
del remain[nullid]
remove = base.keys()
while remove:
n = remove.pop(0)
if n in remain:
del remain[n]
for p in self.changelog.parents(n):
remove.append(p)
# find every node whose parents have been pruned
subset = []
Thomas Arendsen Hein
Fix hg push and hg push -r sometimes creating new heads without --force....
r2021 # find every remote head that will get new children
updated_heads = {}
mpm@selenic.com
Break apart hg.py...
r1089 for n in remain:
p1, p2 = self.changelog.parents(n)
if p1 not in remain and p2 not in remain:
subset.append(n)
Thomas Arendsen Hein
Fix hg push and hg push -r sometimes creating new heads without --force....
r2021 if heads:
if p1 in heads:
updated_heads[p1] = True
if p2 in heads:
updated_heads[p2] = True
mpm@selenic.com
Break apart hg.py...
r1089
# this is the set of all roots we have to push
Thomas Arendsen Hein
Fix hg push and hg push -r sometimes creating new heads without --force....
r2021 if heads:
return subset, updated_heads.keys()
else:
return subset
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def pull(self, remote, heads=None, force=False):
lock = self.lock()
Vadim Gelfer
fetch: hold lock and wlock across all operations
r2827 try:
Alexis S. L. Carvalho
pull -r: pass the revisions as the heads argument of findincoming...
r5221 fetch = self.findincoming(remote, heads=heads, force=force)
Vadim Gelfer
fetch: hold lock and wlock across all operations
r2827 if fetch == [nullid]:
self.ui.status(_("requesting all changes\n"))
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
fetch: hold lock and wlock across all operations
r2827 if not fetch:
self.ui.status(_("no changes found\n"))
return 0
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
fetch: hold lock and wlock across all operations
r2827 if heads is None:
cg = remote.changegroup(fetch, 'pull')
else:
Eric Hopper
Stop erroring out pull -r and clone -r if repository isn't local.
r3448 if 'changegroupsubset' not in remote.capabilities:
raise util.Abort(_("Partial pull cannot be done because other repository doesn't support changegroupsubset."))
Vadim Gelfer
fetch: hold lock and wlock across all operations
r2827 cg = remote.changegroupsubset(fetch, heads, 'pull')
return self.addchangegroup(cg, 'pull', remote.url())
finally:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 del lock
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
add an optional argument to push only the specified revisions (push -r)
r1781 def push(self, remote, force=False, revs=None):
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 # there are two ways to push to remote repo:
#
# addchangegroup assumes local user can lock remote
# repo (local filesystem, old ssh servers).
#
# unbundle assumes local user cannot lock remote repo (new ssh
# servers, http servers).
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
add support for streaming clone....
r2612 if remote.capable('unbundle'):
Vadim Gelfer
localrepository.push: propagate return value
r2463 return self.push_unbundle(remote, force, revs)
return self.push_addchangegroup(remote, force, revs)
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
def prepush(self, remote, force, revs):
mpm@selenic.com
Break apart hg.py...
r1089 base = {}
Thomas Arendsen Hein
Fix hg push and hg push -r sometimes creating new heads without --force....
r2021 remote_heads = remote.heads()
inc = self.findincoming(remote, base, remote_heads, force=force)
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Fix hg push and hg push -r sometimes creating new heads without --force....
r2021 update, updated_heads = self.findoutgoing(remote, base, remote_heads)
Benoit Boissinot
add an optional argument to push only the specified revisions (push -r)
r1781 if revs is not None:
msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
else:
bases, heads = update, self.changelog.heads()
if not bases:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.status(_("no changes found\n"))
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 return None, 1
mpm@selenic.com
Break apart hg.py...
r1089 elif not force:
Matt Mackall
correct remote heads test in prepush
r3684 # check if we're creating new remote heads
# to be a remote head after push, node must be either
# - unknown locally
# - a local outgoing head descended from update
# - a remote head that's known locally and not
# ancestral to an outgoing head
warn = 0
if remote_heads == [nullid]:
warn = 0
elif not revs and len(heads) > len(remote_heads):
warn = 1
else:
newheads = list(heads)
for r in remote_heads:
if r in self.changelog.nodemap:
Benoit Boissinot
fix calculation of new heads added during push with -r...
r3923 desc = self.changelog.heads(r, heads)
Matt Mackall
correct remote heads test in prepush
r3684 l = [h for h in heads if h in desc]
if not l:
newheads.append(r)
else:
newheads.append(r)
if len(newheads) > len(remote_heads):
warn = 1
if warn:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.warn(_("abort: push creates new remote branches!\n"))
self.ui.status(_("(did you forget to merge?"
" use push -f to force)\n"))
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 return None, 1
Matt Mackall
correct remote heads test in prepush
r3684 elif inc:
self.ui.warn(_("note: unsynced remote changes!\n"))
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
reorder tests in prepush...
r3682
Benoit Boissinot
add an optional argument to push only the specified revisions (push -r)
r1781 if revs is None:
Benoit Boissinot
merge with crew
r1782 cg = self.changegroup(update, 'push')
Benoit Boissinot
add an optional argument to push only the specified revisions (push -r)
r1781 else:
Benoit Boissinot
merge with crew
r1782 cg = self.changegroupsubset(update, revs, 'push')
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 return cg, remote_heads
def push_addchangegroup(self, remote, force, revs):
lock = remote.lock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
ret = self.prepush(remote, force, revs)
if ret[0] is not None:
cg, remote_heads = ret
return remote.addchangegroup(cg, 'push', self.url())
return ret[1]
finally:
del lock
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
def push_unbundle(self, remote, force, revs):
# local repo finds heads on server, finds out what revs it
# must push. once revs transferred, if server finds it has
# different heads (someone else won commit/push race), server
# aborts.
ret = self.prepush(remote, force, revs)
if ret[0] is not None:
cg, remote_heads = ret
if force: remote_heads = ['force']
return remote.unbundle(cg, remote_heads, 'push')
return ret[1]
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Show number of changesets written to bundle files by default (issue569)...
r5763 def changegroupinfo(self, nodes, source):
if self.ui.verbose or source == 'bundle':
self.ui.status(_("%d changesets found\n") % len(nodes))
Thomas Arendsen Hein
Show number (-v) and list (--debug) of changesets with bundle/pull/push etc.
r3513 if self.ui.debugflag:
self.ui.debug(_("List of changesets:\n"))
for node in nodes:
self.ui.debug("%s\n" % hex(node))
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736 def changegroupsubset(self, bases, heads, source):
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 """This function generates a changegroup consisting of all the nodes
that are descendents of any of the bases, and ancestors of any of
the heads.
It is fairly complex as determining which filenodes and which
manifest nodes need to be included for the changeset to be complete
is non-trivial.
Another wrinkle is doing the reverse, figuring out which changeset in
the changegroup a particular filenode or manifestnode belongs to."""
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736 self.hook('preoutgoing', throw=True, source=source)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Set up some initial variables
# Make it easy to refer to self.changelog
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 cl = self.changelog
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # msng is short for missing - compute the list of changesets in this
# changegroup.
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
Thomas Arendsen Hein
Show number of changesets written to bundle files by default (issue569)...
r5763 self.changegroupinfo(msng_cl_lst, source)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Some bases may turn out to be superfluous, and some heads may be
# too. nodesbetween will return the minimal set of bases and heads
# necessary to re-create the changegroup.
# Known heads are the list of heads that it is assumed the recipient
# of this changegroup will know about.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 knownheads = {}
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # We assume that all parents of bases are known heads.
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 for n in bases:
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 for p in cl.parents(n):
if p != nullid:
knownheads[p] = 1
knownheads = knownheads.keys()
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 if knownheads:
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Now that we know what heads are known, we can compute which
# changesets are known. The recipient must know about all
# changesets required to reach the known heads from the null
# changeset.
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 has_cl_set, junk, junk = cl.nodesbetween(None, knownheads)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 junk = None
# Transform the list into an ersatz set.
Eric Hopper
Fixed silly bug involving a non-existent variable.
r1464 has_cl_set = dict.fromkeys(has_cl_set)
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 else:
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # If there were no known heads, the recipient cannot be assumed to
# know about any changesets.
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 has_cl_set = {}
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Make it easy to refer to self.manifest
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 mnfst = self.manifest
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # We don't know which manifests are missing yet
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 msng_mnfst_set = {}
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Nor do we know which filenodes are missing.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 msng_filenode_set = {}
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 junk = mnfst.index[mnfst.count() - 1] # Get around a bug in lazyindex
junk = None
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # A changeset always belongs to itself, so the changenode lookup
# function for a changenode is identity.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def identity(x):
return x
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # A function generating function. Sets up an environment for the
# inner function.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def cmp_by_rev_func(revlog):
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Compare two nodes by their revision number in the environment's
# revision history. Since the revision number both represents the
# most efficient order to read the nodes in, and represents a
# topological sorting of the nodes, this function is often useful.
def cmp_by_rev(a, b):
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 return cmp(revlog.rev(a), revlog.rev(b))
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 return cmp_by_rev
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # If we determine that a particular file or manifest node must be a
# node that the recipient of the changegroup will already have, we can
# also assume the recipient will have all the parents. This function
# prunes them from the set of missing nodes.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def prune_parents(revlog, hasset, msngset):
haslst = hasset.keys()
haslst.sort(cmp_by_rev_func(revlog))
for node in haslst:
parentlst = [p for p in revlog.parents(node) if p != nullid]
while parentlst:
n = parentlst.pop()
if n not in hasset:
hasset[n] = 1
p = [p for p in revlog.parents(n) if p != nullid]
parentlst.extend(p)
for n in hasset:
msngset.pop(n, None)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # This is a function generating function used to set up an environment
# for the inner function to execute in.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def manifest_and_file_collector(changedfileset):
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # This is an information gathering function that gathers
# information from each changeset node that goes out as part of
# the changegroup. The information gathered is a list of which
# manifest nodes are potentially required (the recipient may
# already have them) and total list of all files which were
# changed in any changeset in the changegroup.
#
# We also remember the first changenode we saw any manifest
# referenced by so we can later determine which changenode 'owns'
# the manifest.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def collect_manifests_and_files(clnode):
c = cl.read(clnode)
for f in c[3]:
# This is to make sure we only have one instance of each
# filename string for each filename.
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 changedfileset.setdefault(f, f)
msng_mnfst_set.setdefault(c[0], clnode)
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 return collect_manifests_and_files
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Figure out which manifest nodes (of the ones we think might be part
# of the changegroup) the recipient must know about and remove them
# from the changegroup.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def prune_manifests():
has_mnfst_set = {}
for n in msng_mnfst_set:
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # If a 'missing' manifest thinks it belongs to a changenode
# the recipient is assumed to have, obviously the recipient
# must have that manifest.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 linknode = cl.node(mnfst.linkrev(n))
if linknode in has_cl_set:
has_mnfst_set[n] = 1
prune_parents(mnfst, has_mnfst_set, msng_mnfst_set)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Use the information collected in collect_manifests_and_files to say
# which changenode any manifestnode belongs to.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def lookup_manifest_link(mnfstnode):
return msng_mnfst_set[mnfstnode]
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # A function generating function that sets up the initial environment
# the inner function.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def filenode_collector(changedfiles):
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 next_rev = [0]
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # This gathers information from each manifestnode included in the
# changegroup about which filenodes the manifest node references
# so we can include those in the changegroup too.
#
# It also remembers which changenode each filenode belongs to. It
# does this by assuming the a filenode belongs to the changenode
# the first manifest that references it belongs to.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def collect_msng_filenodes(mnfstnode):
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 r = mnfst.rev(mnfstnode)
if r == next_rev[0]:
# If the last rev we looked at was the one just previous,
# we only need to see a diff.
Matt Mackall
remove unneeded imports of mdiff
r5175 deltamf = mnfst.readdelta(mnfstnode)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # For each line in the delta
Matt Mackall
remove unneeded imports of mdiff
r5175 for f, fnode in deltamf.items():
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 f = changedfiles.get(f, None)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # And if the file is in the list of files we care
# about.
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 if f is not None:
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Get the changenode this manifest belongs to
clnode = msng_mnfst_set[mnfstnode]
# Create the set of filenodes for the file if
# there isn't one already.
ndset = msng_filenode_set.setdefault(f, {})
# And set the filenode's changelog node to the
# manifest's if it hasn't been set already.
ndset.setdefault(fnode, clnode)
else:
# Otherwise we need a full manifest.
m = mnfst.read(mnfstnode)
# For every file in we care about.
for f in changedfiles:
fnode = m.get(f, None)
# If it's in the manifest
if fnode is not None:
# See comments above.
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 clnode = msng_mnfst_set[mnfstnode]
ndset = msng_filenode_set.setdefault(f, {})
ndset.setdefault(fnode, clnode)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Remember the revision we hope to see next.
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 next_rev[0] = r + 1
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 return collect_msng_filenodes
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # We have a list of filenodes we think we need for a file, lets remove
# all those we now the recipient must have.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def prune_filenodes(f, filerevlog):
msngset = msng_filenode_set[f]
hasset = {}
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # If a 'missing' filenode thinks it belongs to a changenode we
# assume the recipient must have, then the recipient must have
# that filenode.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 for n in msngset:
clnode = cl.node(filerevlog.linkrev(n))
if clnode in has_cl_set:
hasset[n] = 1
prune_parents(filerevlog, hasset, msngset)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # A function generator function that sets up the a context for the
# inner function.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def lookup_filenode_link_func(fname):
msngset = msng_filenode_set[fname]
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Lookup the changenode the filenode belongs to.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def lookup_filenode_link(fnode):
return msngset[fnode]
return lookup_filenode_link
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Now that we have all theses utility functions to help out and
# logically divide up the task, generate the group.
mpm@selenic.com
Break apart hg.py...
r1089 def gengroup():
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # The set of changed files starts empty.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 changedfiles = {}
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Create a changenode group generator that will call our functions
# back to lookup the owning changenode and collect information.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 group = cl.group(msng_cl_lst, identity,
manifest_and_file_collector(changedfiles))
for chnk in group:
yield chnk
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466
# The list of manifests has been collected by the generator
# calling our functions back.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 prune_manifests()
msng_mnfst_lst = msng_mnfst_set.keys()
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Sort the manifestnodes by revision number.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 msng_mnfst_lst.sort(cmp_by_rev_func(mnfst))
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Create a generator for the manifestnodes that calls our lookup
# and data collection functions back.
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 group = mnfst.group(msng_mnfst_lst, lookup_manifest_link,
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 filenode_collector(changedfiles))
for chnk in group:
yield chnk
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466
# These are no longer needed, dereference and toss the memory for
# them.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 msng_mnfst_lst = None
msng_mnfst_set.clear()
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466
Eric Hopper
Optimizing manifest reads in changegroupsubset by using deltas.
r1462 changedfiles = changedfiles.keys()
changedfiles.sort()
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Go through all our files in order sorted by name.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 for fname in changedfiles:
filerevlog = self.file(fname)
Matt Mackall
push/pull: abort if we try to visit a missing or empty revlog
r5543 if filerevlog.count() == 0:
Matt Mackall
fix spelling error
r5666 raise util.Abort(_("empty or missing revlog for %s") % fname)
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Toss out the filenodes that the recipient isn't really
# missing.
Eric Hopper
This fixes a bug that Chris Mason found. As for a test case, I can't...
r1630 if msng_filenode_set.has_key(fname):
prune_filenodes(fname, filerevlog)
msng_filenode_lst = msng_filenode_set[fname].keys()
else:
msng_filenode_lst = []
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # If any filenodes are left, generate the group for them,
# otherwise don't bother.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 if len(msng_filenode_lst) > 0:
Matt Mackall
changegroup: avoid large copies...
r5368 yield changegroup.chunkheader(len(fname))
yield fname
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Sort the filenodes by their revision #
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 msng_filenode_lst.sort(cmp_by_rev_func(filerevlog))
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Create a group generator and only pass in a changenode
# lookup function as we need to collect no information
# from filenodes.
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 group = filerevlog.group(msng_filenode_lst,
Eric Hopper
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
r1460 lookup_filenode_link_func(fname))
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 for chnk in group:
yield chnk
Eric Hopper
This fixes a bug that Chris Mason found. As for a test case, I can't...
r1630 if msng_filenode_set.has_key(fname):
# Don't need this anymore, toss it to free memory.
del msng_filenode_set[fname]
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 # Signal that no more groups are left.
Thomas Arendsen Hein
make incoming work via ssh (issue139); move chunk code into separate module....
r1981 yield changegroup.closechunk()
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
fix a NameError in changegroupsubset
r2150 if msng_cl_lst:
Vincent Danjean
allow to pull from an empty repo without getting a backtrace
r2149 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 return util.chunkbuffer(gengroup())
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736 def changegroup(self, basenodes, source):
Eric Hopper
Added a lot of comments to changegroupsubset.
r1466 """Generate a changegroup of all nodes that we have that a recipient
doesn't.
This is much easier than the previous function as we can assume that
the recipient has any changenode we aren't sending them."""
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736
self.hook('preoutgoing', throw=True, source=source)
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 cl = self.changelog
nodes = cl.nodesbetween(basenodes, None)[0]
revset = dict.fromkeys([cl.rev(n) for n in nodes])
Thomas Arendsen Hein
Show number of changesets written to bundle files by default (issue569)...
r5763 self.changegroupinfo(nodes, source)
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458
def identity(x):
return x
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 def gennodelst(revlog):
for r in xrange(0, revlog.count()):
n = revlog.node(r)
if revlog.linkrev(n) in revset:
yield n
def changed_file_collector(changedfileset):
def collect_changed_files(clnode):
c = cl.read(clnode)
for fname in c[3]:
changedfileset[fname] = 1
return collect_changed_files
def lookuprevlink_func(revlog):
def lookuprevlink(n):
return cl.node(revlog.linkrev(n))
return lookuprevlink
def gengroup():
mpm@selenic.com
Break apart hg.py...
r1089 # construct a list of all changed files
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 changedfiles = {}
for chnk in cl.group(nodes, identity,
changed_file_collector(changedfiles)):
yield chnk
changedfiles = changedfiles.keys()
changedfiles.sort()
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 mnfst = self.manifest
nodeiter = gennodelst(mnfst)
for chnk in mnfst.group(nodeiter, lookuprevlink_func(mnfst)):
yield chnk
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 for fname in changedfiles:
filerevlog = self.file(fname)
Matt Mackall
push/pull: abort if we try to visit a missing or empty revlog
r5543 if filerevlog.count() == 0:
Matt Mackall
fix spelling error
r5666 raise util.Abort(_("empty or missing revlog for %s") % fname)
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 nodeiter = gennodelst(filerevlog)
nodeiter = list(nodeiter)
if nodeiter:
Matt Mackall
changegroup: avoid large copies...
r5368 yield changegroup.chunkheader(len(fname))
yield fname
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 lookup = lookuprevlink_func(filerevlog)
for chnk in filerevlog.group(nodeiter, lookup):
yield chnk
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
make incoming work via ssh (issue139); move chunk code into separate module....
r1981 yield changegroup.closechunk()
Matt Mackall
Don't die calling outgoing hook if we have no changesets
r2107
if nodes:
self.hook('outgoing', node=hex(nodes[0]), source=source)
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
This changes the revlog.group and re-implements the localrepo.changeroup...
r1458 return util.chunkbuffer(gengroup())
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 def addchangegroup(self, source, srctype, url):
Vadim Gelfer
add merge command. means same thing as "update -m"....
r2019 """add changegroup to repo.
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Don't report an error when closing heads during local push (issue387)
r3803 return values:
- nothing changed or no source: 0
- more heads than before: 1+added heads (2..n)
- less heads than before: -1-removed heads (-2..-n)
- number of heads stays the same: 1
"""
mpm@selenic.com
Break apart hg.py...
r1089 def csmap(x):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("add changeset %s\n") % short(x))
Vadim Gelfer
fix race in localrepo.addchangegroup....
r1998 return cl.count()
mpm@selenic.com
Break apart hg.py...
r1089
def revmap(x):
Vadim Gelfer
fix race in localrepo.addchangegroup....
r1998 return cl.rev(x)
mpm@selenic.com
Break apart hg.py...
r1089
Thomas Arendsen Hein
Cleanup of indentation, spacing, newlines, strings and line length
r1615 if not source:
Vadim Gelfer
add merge command. means same thing as "update -m"....
r2019 return 0
Vadim Gelfer
add prechangegroup and pretxnchangegroup hooks....
r1730
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 self.hook('prechangegroup', throw=True, source=srctype, url=url)
Vadim Gelfer
add prechangegroup and pretxnchangegroup hooks....
r1730
mpm@selenic.com
Break apart hg.py...
r1089 changesets = files = revisions = 0
Benoit Boissinot
remove appendfile for the manifest when adding a changegroup...
r2395 # write changelog data to temp files so concurrent readers will not see
# inconsistent view
Matt Mackall
restructure changelog file appending...
r4261 cl = self.changelog
cl.delayupdate()
oldheads = len(cl.heads())
Vadim Gelfer
fix race in localrepo.addchangegroup....
r1998
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 tr = self.transaction()
try:
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 trp = weakref.proxy(tr)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # pull off the changeset group
self.ui.status(_("adding changesets\n"))
cor = cl.count() - 1
chunkiter = changegroup.chunkiter(source)
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 if cl.addgroup(chunkiter, csmap, trp, 1) is None:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 raise util.Abort(_("received changelog group is empty"))
cnr = cl.count() - 1
changesets = cnr - cor
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # pull off the manifest group
self.ui.status(_("adding manifests\n"))
chunkiter = changegroup.chunkiter(source)
# no need to check for empty manifest group here:
# if the result of the merge of 1 and 2 is the same in 3 and 4,
# no new manifest will be created and the manifest group will
# be empty during the pull
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 self.manifest.addgroup(chunkiter, revmap, trp)
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # process the files
self.ui.status(_("adding file changes\n"))
while 1:
f = changegroup.getchunk(source)
if not f:
break
self.ui.debug(_("adding %s revisions\n") % f)
fl = self.file(f)
o = fl.count()
chunkiter = changegroup.chunkiter(source)
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 if fl.addgroup(chunkiter, revmap, trp) is None:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 raise util.Abort(_("received file revlog group is empty"))
revisions += fl.count() - o
files += 1
# make changelog see real files again
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 cl.finalize(trp)
Vadim Gelfer
fix race in localrepo.addchangegroup....
r1998
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 newheads = len(self.changelog.heads())
heads = ""
if oldheads and newheads != oldheads:
heads = _(" (%+d heads)") % (newheads - oldheads)
Vadim Gelfer
fix race in localrepo.addchangegroup....
r1998
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.ui.status(_("added %d changesets"
" with %d changes to %d files%s\n")
% (changesets, revisions, files, heads))
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if changesets > 0:
self.hook('pretxnchangegroup', throw=True,
node=hex(self.changelog.node(cor+1)), source=srctype,
url=url)
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 tr.close()
finally:
del tr
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
Fix traceback when nothing was added during unbundle...
r1375 if changesets > 0:
Vadim Gelfer
changegroup hooks: add source to hook parameters
r2229 self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 source=srctype, url=url)
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(cor + 1, cnr + 1):
Vadim Gelfer
changegroup hooks: add source to hook parameters
r2229 self.hook("incoming", node=hex(self.changelog.node(i)),
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 source=srctype, url=url)
mpm@selenic.com
Hook fixups...
r1316
Thomas Arendsen Hein
Don't report an error when closing heads during local push (issue387)
r3803 # never return 0 here:
if newheads < oldheads:
return newheads - oldheads - 1
else:
return newheads - oldheads + 1
Vadim Gelfer
add merge command. means same thing as "update -m"....
r2019
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
add support for streaming clone....
r2612 def stream_in(self, remote):
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 fp = remote.stream_out()
Thomas Arendsen Hein
New UnexpectedOutput exception to catch server errors in localrepo.stream_in...
r3564 l = fp.readline()
try:
resp = int(l)
except ValueError:
raise util.UnexpectedOutput(
_('Unexpected response from remote server:'), l)
Thomas Arendsen Hein
Handle locking exceptions if streaming clone can't lock the repo. (Issue324)
r3687 if resp == 1:
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 raise util.Abort(_('operation forbidden by server'))
Thomas Arendsen Hein
Handle locking exceptions if streaming clone can't lock the repo. (Issue324)
r3687 elif resp == 2:
raise util.Abort(_('locking the remote repository failed'))
elif resp != 0:
raise util.Abort(_('the server sent an unknown error code'))
Vadim Gelfer
add support for streaming clone....
r2612 self.ui.status(_('streaming all changes\n'))
Thomas Arendsen Hein
New UnexpectedOutput exception to catch server errors in localrepo.stream_in...
r3564 l = fp.readline()
try:
total_files, total_bytes = map(int, l.split(' ', 1))
except ValueError, TypeError:
raise util.UnexpectedOutput(
_('Unexpected response from remote server:'), l)
Vadim Gelfer
add support for streaming clone....
r2612 self.ui.status(_('%d files to transfer, %s of data\n') %
(total_files, util.bytecount(total_bytes)))
start = time.time()
for i in xrange(total_files):
Benoit Boissinot
add a comment about '\n' and '\r' and streaming clone
r3720 # XXX doesn't support '\n' or '\r' in filenames
Thomas Arendsen Hein
New UnexpectedOutput exception to catch server errors in localrepo.stream_in...
r3564 l = fp.readline()
try:
name, size = l.split('\0', 1)
size = int(size)
except ValueError, TypeError:
raise util.UnexpectedOutput(
_('Unexpected response from remote server:'), l)
Vadim Gelfer
add support for streaming clone....
r2612 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
Matt Mackall
localrepo: add separate methods for manipulating repository data...
r3457 ofp = self.sopener(name, 'w')
Vadim Gelfer
add support for streaming clone....
r2612 for chunk in util.filechunkiter(fp, limit=size):
ofp.write(chunk)
ofp.close()
elapsed = time.time() - start
Patrick Mezard
localrepo: stream_in may raise ZeroDivisionError with nul float elapsed argument.
r4128 if elapsed <= 0:
elapsed = 0.001
Vadim Gelfer
add support for streaming clone....
r2612 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
(util.bytecount(total_bytes), elapsed,
util.bytecount(total_bytes / elapsed)))
Matt Mackall
localrepo and dirstate: rename reload to invalidate...
r4613 self.invalidate()
Vadim Gelfer
add support for streaming clone....
r2612 return len(self.heads()) + 1
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
clone: do not make streaming default. add --stream option instead.
r2613 def clone(self, remote, heads=[], stream=False):
Vadim Gelfer
add support for streaming clone....
r2612 '''clone remote repository.
Matt Mackall
hg verify: more consistency checking between changesets and manifests
r1382
Vadim Gelfer
add support for streaming clone....
r2612 keyword arguments:
heads: list of revs to clone (forces use of pull)
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 stream: use streaming clone if possible'''
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 # now, all clients that can request uncompressed clones can
# read repo formats supported by all servers that can serve
# them.
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
add support for streaming clone....
r2612 # if revlog format changes, client will have to check version
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 # and format flags on "stream" capability, and use
# uncompressed only if compatible.
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
clone: do not make streaming default. add --stream option instead.
r2613 if stream and not heads and remote.capable('stream'):
Vadim Gelfer
add support for streaming clone....
r2612 return self.stream_in(remote)
return self.pull(remote, heads)
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806
# used to avoid circular references so destructors work
Benoit Boissinot
localrepo: change aftertrans to be independant of the store path
r3790 def aftertrans(files):
renamefiles = [tuple(t) for t in files]
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806 def a():
Benoit Boissinot
localrepo: change aftertrans to be independant of the store path
r3790 for src, dest in renamefiles:
util.rename(src, dest)
mason@suse.com
Automatic nesting into running transactions in the same repository....
r1806 return a
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 def instance(ui, path, create):
return localrepository(ui, util.drop_scheme('file', path), create)
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 def islocal(path):
return True