##// END OF EJS Templates
store: explain "aux.foo" versus "foo.aux" in doc of _auxencode()
store: explain "aux.foo" versus "foo.aux" in doc of _auxencode()

File last commit:

r17551:a7b3fdaf default
r17569:e9af2134 default
Show More
bookmarks.py
284 lines | 8.8 KiB | text/x-python | PythonLexer
Matt Mackall
bookmarks: move basic io to core
r13350 # Mercurial bookmark support code
#
# Copyright 2008 David Soria Parra <dsp@php.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from mercurial.i18n import _
Alexander Solovyov
remove unused imports and variables
r14064 from mercurial.node import hex
Pierre-Yves David
bookmark: take successors into account when updating (issue3561)...
r17551 from mercurial import encoding, error, util, obsolete, phases
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 import errno, os
Matt Mackall
bookmarks: move basic io to core
r13350
David Soria Parra
bookmarks: forbid \0 \r \n : in bookmark names (BC)...
r13425 def valid(mark):
for c in (':', '\0', '\n', '\r'):
if c in mark:
return False
return True
Matt Mackall
bookmarks: move read methods to core
r13351 def read(repo):
'''Parse .hg/bookmarks file and return a dictionary
Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
in the .hg/bookmarks file.
Read the file and return a (name=>nodeid) dictionary
'''
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 bookmarks = {}
Matt Mackall
bookmarks: move read methods to core
r13351 try:
for line in repo.opener('bookmarks'):
Pierre-Yves David
bookmarks: more robust parsing of bookmarks file
r14845 line = line.strip()
Matt Mackall
bookmarks: simplify warning code
r14848 if not line:
continue
Pierre-Yves David
bookmarks: more robust parsing of bookmarks file
r14845 if ' ' not in line:
Matt Mackall
bookmarks: simplify warning code
r14848 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
Pierre-Yves David
bookmarks: more robust parsing of bookmarks file
r14845 continue
Matt Mackall
bookmarks: drop superfluous strip
r14847 sha, refspec = line.split(' ', 1)
Matt Mackall
bookmarks: move read methods to core
r13351 refspec = encoding.tolocal(refspec)
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 try:
bookmarks[refspec] = repo.changelog.lookup(sha)
Matt Mackall
bookmarks: catch the proper exception for missing revisions...
r16573 except LookupError:
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 pass
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
Matt Mackall
bookmarks: move read methods to core
r13351 return bookmarks
def readcurrent(repo):
'''Get the current bookmark
If we use gittishsh branches we have a current bookmark that
we are on. This function returns the name of the bookmark. It
is stored in .hg/bookmarks.current
'''
mark = None
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 try:
Matt Mackall
bookmarks: move read methods to core
r13351 file = repo.opener('bookmarks.current')
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 except IOError, inst:
if inst.errno != errno.ENOENT:
raise
return None
try:
Mads Kiilerich
fix wording and not-completely-trivial spelling errors and bad docstrings
r17425 # No readline() in osutil.posixfile, reading everything is cheap
David Soria Parra
bookmarks: read current bookmark as utf-8 and convert it to local
r13381 mark = encoding.tolocal((file.readlines() or [''])[0])
Benoit Boissinot
bookmarks: discard current bookmark if absent from the bookmarks (issue2692)...
r13627 if mark == '' or mark not in repo._bookmarks:
Matt Mackall
bookmarks: move read methods to core
r13351 mark = None
Benoit Boissinot
bookmarks: be more restrictive in our Exception catching
r14027 finally:
Matt Mackall
bookmarks: move read methods to core
r13351 file.close()
return mark
Matt Mackall
bookmarks: move basic io to core
r13350 def write(repo):
'''Write bookmarks
Write the given bookmark => hash dictionary to the .hg/bookmarks file
in a format equal to those of localtags.
We also store a backup of the previous state in undo.bookmarks that
can be copied back on rollback.
'''
refs = repo._bookmarks
if repo._bookmarkcurrent not in refs:
setcurrent(repo, None)
David Soria Parra
bookmarks: forbid \0 \r \n : in bookmark names (BC)...
r13425 for mark in refs.keys():
if not valid(mark):
raise util.Abort(_("bookmark '%s' contains illegal "
"character" % mark))
Matt Mackall
bookmarks: backout locking change in 12dea4d998ec...
r15908 wlock = repo.wlock()
Matt Mackall
bookmarks: move basic io to core
r13350 try:
David Soria Parra
bookmarks: forbid \0 \r \n : in bookmark names (BC)...
r13425
Matt Mackall
bookmarks: move basic io to core
r13350 file = repo.opener('bookmarks', 'w', atomictemp=True)
for refspec, node in refs.iteritems():
file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 file.close()
Matt Mackall
bookmarks: move basic io to core
r13350
# touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
try:
os.utime(repo.sjoin('00changelog.i'), None)
except OSError:
pass
finally:
Matt Mackall
bookmarks: backout locking change in 12dea4d998ec...
r15908 wlock.release()
Matt Mackall
bookmarks: move basic io to core
r13350
def setcurrent(repo, mark):
'''Set the name of the bookmark that we are currently on
Set the name of the bookmark that we are on (hg update <bookmark>).
The name is recorded in .hg/bookmarks.current
'''
current = repo._bookmarkcurrent
if current == mark:
return
David Soria Parra
bookmarks: remove API limitation in setcurrent...
r13647 if mark not in repo._bookmarks:
Matt Mackall
bookmarks: move basic io to core
r13350 mark = ''
David Soria Parra
bookmarks: forbid \0 \r \n : in bookmark names (BC)...
r13425 if not valid(mark):
raise util.Abort(_("bookmark '%s' contains illegal "
"character" % mark))
Matt Mackall
bookmarks: backout locking change in 12dea4d998ec...
r15908 wlock = repo.wlock()
Matt Mackall
bookmarks: move basic io to core
r13350 try:
file = repo.opener('bookmarks.current', 'w', atomictemp=True)
LUO Zheng
bookmarks: recognize the current bookmark when the local encoding isn't UTF-8...
r14559 file.write(encoding.fromlocal(mark))
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 file.close()
Matt Mackall
bookmarks: move basic io to core
r13350 finally:
Matt Mackall
bookmarks: backout locking change in 12dea4d998ec...
r15908 wlock.release()
Matt Mackall
bookmarks: move basic io to core
r13350 repo._bookmarkcurrent = mark
Matt Mackall
bookmarks: move update into core
r13352
Idan Kamara
update: delete bookmarks.current when explicitly updating to a rev (issue3276)
r16191 def unsetcurrent(repo):
wlock = repo.wlock()
try:
Gilles Moris
bookmarks: restore python 2.4 compatibility...
r16194 try:
util.unlink(repo.join('bookmarks.current'))
repo._bookmarkcurrent = None
except OSError, inst:
if inst.errno != errno.ENOENT:
raise
Idan Kamara
update: delete bookmarks.current when explicitly updating to a rev (issue3276)
r16191 finally:
wlock.release()
David Soria Parra
bundle: update current bookmark to most recent revision on current branch...
r13663 def updatecurrentbookmark(repo, oldnode, curbranch):
try:
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 return update(repo, oldnode, repo.branchtip(curbranch))
except error.RepoLookupError:
David Soria Parra
bundle: update current bookmark to most recent revision on current branch...
r13663 if curbranch == "default": # no default branch!
Kevin Bullock
bookmarks: update and updatecurrentbookmark return status...
r15621 return update(repo, oldnode, repo.lookup("tip"))
David Soria Parra
bundle: update current bookmark to most recent revision on current branch...
r13663 else:
raise util.Abort(_("branch %s not found") % curbranch)
Matt Mackall
bookmarks: move update into core
r13352 def update(repo, parents, node):
marks = repo._bookmarks
update = False
David Soria Parra
bookmarks: delete divergent bookmarks on merge
r16706 cur = repo._bookmarkcurrent
if not cur:
return False
toupdate = [b for b in marks if b.split('@', 1)[0] == cur.split('@', 1)[0]]
for mark in toupdate:
if mark and marks[mark] in parents:
old = repo[marks[mark]]
new = repo[node]
if new in old.descendants() and mark == cur:
marks[cur] = new.node()
update = True
if mark != cur:
del marks[mark]
Matt Mackall
bookmarks: move update into core
r13352 if update:
Augie Fackler
bookmarks: delegate writing to the repo just like reading...
r15237 repo._writebookmarks(marks)
Kevin Bullock
bookmarks: update and updatecurrentbookmark return status...
r15621 return update
Matt Mackall
bookmarks: move pushkey functions into core
r13353
def listbookmarks(repo):
# We may try to list bookmarks on a repo type that does not
# support it (e.g., statichttprepository).
Augie Fackler
bookmarks: use getattr instead of hasattr
r14946 marks = getattr(repo, '_bookmarks', {})
Matt Mackall
bookmarks: move pushkey functions into core
r13353
d = {}
Augie Fackler
bookmarks: use getattr instead of hasattr
r14946 for k, v in marks.iteritems():
Matt Mackall
bookmarks: shadow divergent bookmarks of foo with foo@n
r15613 # don't expose local divergent bookmarks
Kevin Bullock
bookmarks: clone non-divergent bookmarks with @ in them
r16276 if '@' not in k or k.endswith('@'):
Matt Mackall
bookmarks: shadow divergent bookmarks of foo with foo@n
r15613 d[k] = hex(v)
Matt Mackall
bookmarks: move pushkey functions into core
r13353 return d
def pushbookmark(repo, key, old, new):
Matt Mackall
bookmarks: backout locking change in 12dea4d998ec...
r15908 w = repo.wlock()
Matt Mackall
bookmarks: move pushkey functions into core
r13353 try:
marks = repo._bookmarks
if hex(marks.get(key, '')) != old:
return False
if new == '':
del marks[key]
else:
if new not in repo:
return False
marks[key] = repo[new].node()
write(repo)
return True
finally:
Matt Mackall
bookmarks: backout locking change in 12dea4d998ec...
r15908 w.release()
Matt Mackall
bookmarks: move diff to core
r13354
Matt Mackall
bookmarks: mark divergent bookmarks with book@pathalias when source in [paths]
r15614 def updatefromremote(ui, repo, remote, path):
David Soria Parra
bookmarks: separate bookmarks update code from localrepo's pull....
r13646 ui.debug("checking for updated bookmarks\n")
rb = remote.listkeys('bookmarks')
changed = False
for k in rb.keys():
if k in repo._bookmarks:
nr, nl = rb[k], repo._bookmarks[k]
if nr in repo:
cr = repo[nr]
cl = repo[nl]
if cl.rev() >= cr.rev():
continue
Pierre-Yves David
bookmarks: extract valid destination logic in a dedicated function...
r17550 if validdest(repo, cl, cr):
David Soria Parra
bookmarks: separate bookmarks update code from localrepo's pull....
r13646 repo._bookmarks[k] = cr.node()
changed = True
ui.status(_("updating bookmark %s\n") % k)
else:
Matt Mackall
bookmarks: mark divergent bookmarks with book@pathalias when source in [paths]
r15614 # find a unique @ suffix
Matt Mackall
bookmarks: shadow divergent bookmarks of foo with foo@n
r15613 for x in range(1, 100):
n = '%s@%d' % (k, x)
if n not in repo._bookmarks:
break
Matt Mackall
bookmarks: mark divergent bookmarks with book@pathalias when source in [paths]
r15614 # try to use an @pathalias suffix
# if an @pathalias already exists, we overwrite (update) it
for p, u in ui.configitems("paths"):
if path == u:
n = '%s@%s' % (k, p)
Matt Mackall
bookmarks: shadow divergent bookmarks of foo with foo@n
r15613 repo._bookmarks[n] = cr.node()
changed = True
ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
Levi Bard
bookmarks: pull new bookmarks from remote by default (BC)
r16697 elif rb[k] in repo:
# add remote bookmarks for changes we already have
repo._bookmarks[k] = repo[rb[k]].node()
changed = True
ui.status(_("adding remote bookmark %s\n") % k)
Matt Mackall
bookmarks: shadow divergent bookmarks of foo with foo@n
r15613
David Soria Parra
bookmarks: separate bookmarks update code from localrepo's pull....
r13646 if changed:
write(repo)
Matt Mackall
bookmarks: move diff to core
r13354 def diff(ui, repo, remote):
ui.status(_("searching for changed bookmarks\n"))
lmarks = repo.listkeys('bookmarks')
rmarks = remote.listkeys('bookmarks')
diff = sorted(set(rmarks) - set(lmarks))
for k in diff:
David Soria Parra
bookmarks: respect --debug during incoming/outgoing
r15984 mark = ui.debugflag and rmarks[k] or rmarks[k][:12]
ui.write(" %-25s %s\n" % (k, mark))
Matt Mackall
bookmarks: move diff to core
r13354
if len(diff) <= 0:
ui.status(_("no changed bookmarks found\n"))
return 1
return 0
Pierre-Yves David
bookmarks: extract valid destination logic in a dedicated function...
r17550
def validdest(repo, old, new):
"""Is the new bookmark destination a valid update from the old one"""
Pierre-Yves David
bookmark: take successors into account when updating (issue3561)...
r17551 if old == new:
# Old == new -> nothing to update.
validdests = ()
elif not old:
# old is nullrev, anything is valid.
# (new != nullrev has been excluded by the previous check)
validdests = (new,)
elif repo.obsstore:
# We only need this complicated logic if there is obsolescence
# XXX will probably deserve an optimised rset.
validdests = set([old])
plen = -1
# compute the whole set of successors or descendants
while len(validdests) != plen:
plen = len(validdests)
succs = set(c.node() for c in validdests)
for c in validdests:
if c.phase() > phases.public:
# obsolescence marker does not apply to public changeset
succs.update(obsolete.anysuccessors(repo.obsstore,
c.node()))
validdests = set(repo.set('%ln::', succs))
validdests.remove(old)
else:
validdests = old.descendants()
return new in validdests