--- a/doc/hgrc.5.txt Fri Dec 14 16:47:41 2007 +0100
+++ b/doc/hgrc.5.txt Mon Dec 17 13:45:30 2007 +0100
@@ -281,7 +281,7 @@
commit to proceed. Non-zero status will cause the commit to fail.
Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
preoutgoing;;
- Run before computing changes to send from the local repository to
+ Run before collecting changes to send from the local repository to
another. Non-zero status will cause failure. This lets you
prevent pull over http or ssh. Also prevents against local pull,
push (outbound) or bundle commands, but not effective, since you
--- a/mercurial/commands.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/commands.py Mon Dec 17 13:45:30 2007 +0100
@@ -2029,6 +2029,7 @@
forget.append(abs)
continue
reason = _('has been marked for add (use -f to force removal)')
+ exact = 1 # force the message
elif abs not in repo.dirstate:
reason = _('is not managed')
elif opts['after'] and not exact and abs not in deleted:
--- a/mercurial/demandimport.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/demandimport.py Mon Dec 17 13:45:30 2007 +0100
@@ -67,7 +67,7 @@
return "<proxied module '%s'>" % self._data[0]
return "<unloaded module '%s'>" % self._data[0]
def __call__(self, *args, **kwargs):
- raise TypeError("'unloaded module' object is not callable")
+ raise TypeError("%s object is not callable" % repr(self))
def __getattribute__(self, attr):
if attr in ('_data', '_extend', '_load', '_module'):
return object.__getattribute__(self, attr)
--- a/mercurial/dispatch.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/dispatch.py Mon Dec 17 13:45:30 2007 +0100
@@ -133,6 +133,8 @@
except util.Abort, inst:
ui.warn(_("abort: %s\n") % inst)
+ except MemoryError:
+ ui.warn(_("abort: out of memory\n"))
except SystemExit, inst:
# Commands shouldn't sys.exit directly, but give a return code.
# Just in case catch this and and pass exit code to caller.
--- a/mercurial/fancyopts.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/fancyopts.py Mon Dec 17 13:45:30 2007 +0100
@@ -1,35 +1,74 @@
import getopt
def fancyopts(args, options, state):
- long = []
- short = ''
- map = {}
- dt = {}
+ """
+ read args, parse options, and store options in state
+
+ each option is a tuple of:
+
+ short option or ''
+ long option
+ default value
+ description
+
+ option types include:
+
+ boolean or none - option sets variable in state to true
+ string - parameter string is stored in state
+ list - parameter string is added to a list
+ integer - parameter strings is stored as int
+ function - call function with parameter
- for s, l, d, c in options:
- pl = l.replace('-', '_')
- map['-'+s] = map['--'+l] = pl
- if isinstance(d, list):
- state[pl] = d[:]
+ non-option args are returned
+ """
+ namelist = []
+ shortlist = ''
+ argmap = {}
+ defmap = {}
+
+ for short, name, default, comment in options:
+ # convert opts to getopt format
+ oname = name
+ name = name.replace('-', '_')
+
+ argmap['-' + short] = argmap['--' + oname] = name
+ defmap[name] = default
+
+ # copy defaults to state
+ if isinstance(default, list):
+ state[name] = default[:]
+ elif callable(default):
+ print "whoa", name, default
+ state[name] = None
else:
- state[pl] = d
- dt[pl] = type(d)
- if (d is not None and d is not True and d is not False and
- not callable(d)):
- if s: s += ':'
- if l: l += '='
- if s: short = short + s
- if l: long.append(l)
+ state[name] = default
- opts, args = getopt.getopt(args, short, long)
+ # does it take a parameter?
+ if not (default is None or default is True or default is False):
+ if short: short += ':'
+ if oname: oname += '='
+ if short:
+ shortlist += short
+ if name:
+ namelist.append(oname)
+
+ # parse arguments
+ opts, args = getopt.getopt(args, shortlist, namelist)
- for opt, arg in opts:
- if dt[map[opt]] is type(fancyopts): state[map[opt]](state, map[opt], arg)
- elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
- elif dt[map[opt]] is type(''): state[map[opt]] = arg
- elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
- elif dt[map[opt]] is type(None): state[map[opt]] = True
- elif dt[map[opt]] is type(False): state[map[opt]] = True
+ # transfer result to state
+ for opt, val in opts:
+ name = argmap[opt]
+ t = type(defmap[name])
+ if t is type(fancyopts):
+ state[name] = defmap[name](val)
+ elif t is type(1):
+ state[name] = int(val)
+ elif t is type(''):
+ state[name] = val
+ elif t is type([]):
+ state[name].append(val)
+ elif t is type(None) or t is type(False):
+ state[name] = True
+ # return unparsed args
return args
-
--- a/mercurial/hg.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/hg.py Mon Dec 17 13:45:30 2007 +0100
@@ -280,13 +280,13 @@
# len(pl)==1, otherwise _merge.update() would have raised util.Abort:
repo.ui.status(_(" hg update %s\n hg update %s\n")
% (pl[0].rev(), repo.changectx(node).rev()))
- return stats[3]
+ return stats[3] > 0
def clean(repo, node, show_stats=True):
"""forcibly switch the working directory to node, clobbering changes"""
stats = _merge.update(repo, node, False, True, None)
if show_stats: _showstats(repo, stats)
- return stats[3]
+ return stats[3] > 0
def merge(repo, node, force=None, remind=True):
"""branch merge with node, resolving changes"""
@@ -301,11 +301,11 @@
% (pl[0].rev(), pl[1].rev()))
elif remind:
repo.ui.status(_("(branch merge, don't forget to commit)\n"))
- return stats[3]
+ return stats[3] > 0
def revert(repo, node, choose):
"""revert changes to revision in node without updating dirstate"""
- return _merge.update(repo, node, False, True, choose)[3]
+ return _merge.update(repo, node, False, True, choose)[3] > 0
def verify(repo):
"""verify the consistency of a repository"""
--- a/mercurial/ignore.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/ignore.py Mon Dec 17 13:45:30 2007 +0100
@@ -6,18 +6,21 @@
# of the GNU General Public License, incorporated herein by reference.
from i18n import _
-import util
+import util, re
+
+_commentre = None
def _parselines(fp):
for line in fp:
- if not line.endswith('\n'):
- line += '\n'
- escape = False
- for i in xrange(len(line)):
- if escape: escape = False
- elif line[i] == '\\': escape = True
- elif line[i] == '#': break
- line = line[:i].rstrip()
+ if "#" in line:
+ global _commentre
+ if not _commentre:
+ _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
+ # remove comments prefixed by an even number of escapes
+ line = _commentre.sub(r'\1', line)
+ # fixup properly escaped comments that survived the above
+ line = line.replace("\\#", "#")
+ line = line.rstrip()
if line:
yield line
--- a/mercurial/localrepo.py Fri Dec 14 16:47:41 2007 +0100
+++ b/mercurial/localrepo.py Mon Dec 17 13:45:30 2007 +0100
@@ -661,6 +661,7 @@
match=util.always, force=False, force_editor=False,
p1=None, p2=None, extra={}, empty_ok=False):
wlock = lock = tr = None
+ valid = 0 # don't save the dirstate if this isn't set
try:
commit = []
remove = []
@@ -747,6 +748,9 @@
if old_exec != new_exec or old_link != new_link:
changed.append(f)
m1.set(f, new_exec, new_link)
+ if use_dirstate:
+ self.dirstate.normal(f)
+
except (OSError, IOError):
if use_dirstate:
self.ui.warn(_("trouble committing %s!\n") % f)
@@ -817,14 +821,15 @@
if use_dirstate or update_dirstate:
self.dirstate.setparents(n)
if use_dirstate:
- for f in new:
- self.dirstate.normal(f)
for f in removed:
self.dirstate.forget(f)
+ valid = 1 # our dirstate updates are complete
self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
return n
finally:
+ if not valid: # don't save our updated dirstate
+ self.dirstate.invalidate()
del tr, lock, wlock
def walk(self, node=None, files=[], match=util.always, badmatch=None):