##// END OF EJS Templates
localrepo: use changelog.hasnode instead of self.__contains__...
localrepo: use changelog.hasnode instead of self.__contains__ Before this patch, releasing the store lock implies the actions below, when the transaction is aborted: 1. "commithook()" scheduled in "localrepository.commit()" is invoked 2. "changectx.__init__()" is invoked via "self.__contains__()" 3. specified ID is examined against "repo.dirstate.p1()" 4. validation function is invoked in "dirstate.p1()" In subsequent patches, "dirstate.invalidate()" invocations for discarding changes are replaced with "dirstateguard", but discarding changes by "dirstateguard" is executed after releasing the store lock: resources are acquired in "wlock => dirstateguard => store lock" order, and are released in reverse order. This may cause that "dirstate.p1()" still refers to the changeset to be rolled-back at (4) above: pushing multiple patches by "hg qpush" is a typical case. When releasing the store lock, such changesets are: - not contained in "repo.changelog", if it is reloaded from ".hg/00changelog.i", as that file was already truncated by "transaction.abort()" - still contained in it, otherwise (this "dirty read" problem is discussed in "Transaction Plan" http://mercurial.selenic.com/wiki/TransactionPlan) Validation function shows "unknown working parent" warning in the former case, but reloading "repo.changelog" depends on the timestamp of ".hg/00changelog.i". This causes occasional test failures. In the case of scheduled "commithook()", it just wants to examine whether "node ID" of committed changeset is still valid or not. Other examinations implied in "changectx.__init__()" are meaningless. To avoid showing the "unknown working parent" warning irregularly, this patch uses "changelog.hasnode()" instead of "node in self" to examine existence of committed changeset.

File last commit:

r21794:753af9ee default
r24992:7df090c9 default
Show More
fancyopts.py
123 lines | 3.5 KiB | text/x-python | PythonLexer
# fancyopts.py - better command line parsing
#
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
import getopt
import util
from i18n import _
def gnugetopt(args, options, longoptions):
"""Parse options mostly like getopt.gnu_getopt.
This is different from getopt.gnu_getopt in that an argument of - will
become an argument of - instead of vanishing completely.
"""
extraargs = []
if '--' in args:
stopindex = args.index('--')
extraargs = args[stopindex + 1:]
args = args[:stopindex]
opts, parseargs = getopt.getopt(args, options, longoptions)
args = []
while parseargs:
arg = parseargs.pop(0)
if arg and arg[0] == '-' and len(arg) > 1:
parseargs.insert(0, arg)
topts, newparseargs = getopt.getopt(parseargs, options, longoptions)
opts = opts + topts
parseargs = newparseargs
else:
args.append(arg)
args.extend(extraargs)
return opts, args
def fancyopts(args, options, state, gnu=False):
"""
read args, parse options, and store options in state
each option is a tuple of:
short option or ''
long option
default value
description
option value label(optional)
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
non-option args are returned
"""
namelist = []
shortlist = ''
argmap = {}
defmap = {}
for option in options:
if len(option) == 5:
short, name, default, comment, dummy = option
else:
short, name, default, comment = option
# 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):
state[name] = None
else:
state[name] = default
# 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
if gnu:
parse = gnugetopt
else:
parse = getopt.getopt
opts, args = parse(args, shortlist, namelist)
# 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):
try:
state[name] = int(val)
except ValueError:
raise util.Abort(_('invalid value %r for option %s, '
'expected int') % (val, opt))
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