hgweb: show as same parents as "hg parents -r REV FILE" in pages for file
Before this patch, "parents" in pages for file doesn't show as same
parents as "hg parents -r REV FILE", when the specified file is not
modified in the specified revision.
For example, it is assumed that revision A, B and D change file "f".
changelog (A) ---> (B) ---> (C) ---> (D)
filelog "f" (x) ---> (y) ------------> (z)
"/file/D/f" invokes "webutil.parents()" with filectx(z) gotten from
changectx(D), and it returns changectx(B). This is as same result as
"hg parents -r D f".
In the other hand, "/file/C/f" invokes "webutil.parents()" with
filectx(y') gotten from changectx(C), and it returns changectx(A),
because filectx(y') is linked to changectx(B), and works like
filectx(y) in some cases.
In this case, revision B is hidden from users browsing file "f" in
revision C.
This patch shows as same parents as "hg parents -r REV FILE" in pages
for file, by making "webutil.parents()" return:
- "linkrev()"-ed revision only, if:
- specified context instance is "filectx" (because
"webutil.parents()" is invoked with changectx, too), and
- (1) the revision from which filectx is gotten and (2) the one to
which filectx is linked are different from each other
- revision gotten from "ctx.parents()", otherwise
# 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 getattr(default, '__call__', False):
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