summaryrefslogtreecommitdiff
path: root/usr/src/tools/onbld
diff options
context:
space:
mode:
authorRichard Lowe <richlowe@richlowe.net>2009-08-05 16:12:50 -0700
committerRichard Lowe <richlowe@richlowe.net>2009-08-05 16:12:50 -0700
commit0df7087fda4bb16f7e1cf07d1b90fcf070c19484 (patch)
tree184220de307cff74050f20dec20985ee38d647dc /usr/src/tools/onbld
parent2ab4ca4ba67b0dc870fbd57becdb9ea51d9b8663 (diff)
downloadillumos-gate-0df7087fda4bb16f7e1cf07d1b90fcf070c19484.tar.gz
6747190 Cadmium commands do not expand hgrc paths
6791858 Cadmium active list is incorrect if parent workspace contains no changesets 6831741 Many cadmium commands ignore -p/--parent
Diffstat (limited to 'usr/src/tools/onbld')
-rw-r--r--usr/src/tools/onbld/Scm/WorkSpace.py147
-rw-r--r--usr/src/tools/onbld/hgext/cdm.py129
2 files changed, 111 insertions, 165 deletions
diff --git a/usr/src/tools/onbld/Scm/WorkSpace.py b/usr/src/tools/onbld/Scm/WorkSpace.py
index 37f7c3db35..814415dc1c 100644
--- a/usr/src/tools/onbld/Scm/WorkSpace.py
+++ b/usr/src/tools/onbld/Scm/WorkSpace.py
@@ -440,70 +440,64 @@ class WorkSpace(object):
self.ui = self.repo.ui
self.name = self.repo.root
- parent = self.repo.ui.expandpath('default')
- if parent == 'default':
- parent = None
- self.parentrepo = parent
-
self.activecache = {}
self.outgoingcache = {}
def parent(self, spec=None):
- '''Return canonical workspace parent, either SPEC if passed,
- or default parent otherwise'''
- return spec or self.parentrepo
-
- def _localtip(self, bases, heads):
- '''Return a tuple (changectx, workingctx) representing the most
- representative head to act as the local tip.
+ '''Return the canonical workspace parent, either SPEC (which
+ will be expanded) if provided or the default parent
+ otherwise.'''
- If the working directory is modified, the changectx is its
- tipmost local parent (or tipmost parent, if neither is
- local), and the workingctx is non-null.
+ if spec:
+ return self.ui.expandpath(spec)
- If the working directory is clean, the workingctx is null.
- The changectx is the tip-most local head on the current branch.
- If this can't be determined for some reason (e.g., the parent
- repo is inacessible), changectx is the tip-most head on the
- current branch.
+ p = self.ui.expandpath('default')
+ if p == 'default':
+ return None
+ else:
+ return p
- If the workingctx is non-null it is the actual local tip (and would
- be the local tip in any generated ActiveList, for instance),
- the better parent revision is returned also to aid callers needing
- a real changeset to act as a surrogate for an uncommitted change.'''
+ def _localtip(self, outgoing, wctx):
+ '''Return the most representative changeset to act as the
+ localtip.
- def tipmost_of(nodes):
- return sorted(nodes, cmp=lambda x, y: cmp(x.rev(), y.rev()))[-1]
+ If the working directory is modified (has file changes, is a
+ merge, or has switched branches), this will be a workingctx.
- #
- # We need a full set of outgoing nodes such that we can limit
- # local branch heads to those which are outgoing
- #
- outnodes = self.repo.changelog.nodesbetween(bases, heads)[0]
- wctx = self.workingctx()
+ If the working directory is unmodified, this will be the most
+ recent (highest revision number) local (outgoing) head on the
+ current branch, if no heads are determined to be outgoing, it
+ will be the most recent head on the current branch.
+ '''
#
- # A modified working context is seen as a proto-branch, where
- # the 'heads' from our view are the parent revisions of that
- # context.
- # (and the working head is it)
+ # A modified working copy is seen as a proto-branch, and thus
+ # our only option as the local tip.
#
if (wctx.files() or len(wctx.parents()) > 1 or
wctx.branch() != wctx.parents()[0].branch()):
- heads = wctx.parents()
- else:
- heads = [self.repo.changectx(n) for n in heads]
- wctx = None
+ return wctx
+
+ heads = self.repo.heads(start=wctx.parents()[0].node())
+ headctxs = [self.repo.changectx(n) for n in heads]
+ localctxs = [c for c in headctxs if c.node() in outgoing]
+
+ ltip = sorted(localctxs or headctxs, key=lambda x: x.rev())[-1]
+
+ if len(heads) > 1:
+ self.ui.warn('The current branch has more than one head, '
+ 'using %s\n' % ltip.rev())
- localchoices = [n for n in heads if n.node() in outnodes]
- return (tipmost_of(localchoices or heads), wctx)
+ return ltip
- def _parenttip(self, localtip, parent=None):
- '''Find the closest approximation of the parents tip, as best
- as we can.
+ def _parenttip(self, heads, outgoing):
+ '''Return the highest-numbered, non-outgoing changeset that is
+ an ancestor of a changeset in heads.
- In parent-less workspaces returns our tip (given the best
- we can do is deal with uncommitted changes)'''
+ This is intended to find the most recent changeset on a given
+ branch that is shared between a parent and child workspace,
+ such that it can act as a stand-in for the parent workspace.
+ '''
def tipmost_shared(head, outnodes):
'''Return the tipmost node on the same branch as head that is not
@@ -514,15 +508,20 @@ class WorkSpace(object):
and return the first node we see in the iter phase that
was previously collected.
+ If no node is found (all revisions >= 0 are outgoing), the
+ only possible parenttip is the null node (node.nullid)
+ which is returned explicitly.
+
See the docstring of mercurial.cmdutil.walkchangerevs()
for the phased approach to the iterator returned. The
important part to note is that the 'add' phase gathers
nodes, which the 'iter' phase then iterates through.'''
+ opts = {'rev': ['%s:0' % head.rev()],
+ 'follow': True}
get = util.cachefunc(lambda r: self.repo.changectx(r).changeset())
changeiter = cmdutil.walkchangerevs(self.repo.ui, self.repo, [],
- get, {'rev': ['%s:0' % head],
- 'follow': True})[0]
+ get, opts)[0]
seen = []
for st, rev, fns in changeiter:
n = self.repo.changelog.node(rev)
@@ -532,22 +531,10 @@ class WorkSpace(object):
elif st == 'iter':
if n in seen:
return rev
- return None
-
- tipctx, wctx = localtip
- parent = self.parent(parent)
- outgoing = None
-
- if parent:
- outgoing = self.findoutgoing(parent)
-
- if wctx:
- possible_branches = wctx.parents()
- else:
- possible_branches = [tipctx]
+ return self.repo.changelog.rev(node.nullid)
- nodes = self.repo.changelog.nodesbetween(outgoing)[0]
- ptips = map(lambda x: tipmost_shared(x.rev(), nodes), possible_branches)
+ nodes = set(outgoing)
+ ptips = map(lambda x: tipmost_shared(x, nodes), heads)
return self.repo.changectx(sorted(ptips)[-1])
def status(self, base=None, head=None):
@@ -614,30 +601,26 @@ class WorkSpace(object):
if parent:
outgoing = self.findoutgoing(parent)
+ outnodes = self.repo.changelog.nodesbetween(outgoing)[0]
else:
outgoing = [] # No parent, no outgoing nodes
+ outnodes = []
- branchheads = self.repo.heads(start=self.repo.dirstate.parents()[0])
- ourhead, workinghead = self._localtip(outgoing, branchheads)
+ localtip = self._localtip(outnodes, self.workingctx())
- if len(branchheads) > 1:
- self.ui.warn('The current branch has more than one head, '
- 'using %s\n' % ourhead.rev())
-
- if workinghead:
- parents = workinghead.parents()
- ctxs = [self.repo.changectx(n) for n in
- self.repo.changelog.nodesbetween(outgoing,
- [h.node() for h in
- parents])[0]]
- ctxs.append(workinghead)
+ if localtip.rev() is None:
+ heads = localtip.parents()
else:
- ctxs = [self.repo.changectx(n) for n in
- self.repo.changelog.nodesbetween(outgoing,
- [ourhead.node()])[0]]
+ heads = [localtip]
+
+ ctxs = [self.repo.changectx(n) for n in
+ self.repo.changelog.nodesbetween(outgoing,
+ [h.node() for h in heads])[0]]
+
+ if localtip.rev() is None:
+ ctxs.append(localtip)
- act = ActiveList(self, self._parenttip((ourhead, workinghead), parent),
- ctxs)
+ act = ActiveList(self, self._parenttip(heads, outnodes), ctxs)
self.activecache[parent] = act
return act
diff --git a/usr/src/tools/onbld/hgext/cdm.py b/usr/src/tools/onbld/hgext/cdm.py
index aa1cd42f49..ef31854218 100644
--- a/usr/src/tools/onbld/hgext/cdm.py
+++ b/usr/src/tools/onbld/hgext/cdm.py
@@ -75,47 +75,22 @@ def yes_no(ui, msg, default):
return False
-def _buildfilelist(repo, args):
- '''build a list of files in which we're interested
+def buildfilelist(ws, parent, files):
+ '''Build a list of files in which we're interested.
- If no files are specified, then we'll default to using
- the entire active list.
+ If no files are specified take files from the active list relative
+ to 'parent'.
- Returns a dictionary, wherein the keys are cwd-relative file paths,
- and the values (when present) are entries from the active list.
- Instead of warning the user explicitly about files not in the active
- list, we'll attempt to do checks on them.'''
+ Return a list of 2-tuples the first element being a path relative
+ to the current directory and the second an entry from the active
+ list, or None if an explicit file list was given.'''
- fdict = {}
-
- #
- # If the user specified files on the command line, we'll only check
- # those files. We won't pull the active list at all. That means we
- # won't be smart about skipping deleted files and such, so the user
- # needs to be smart enough to not explicitly specify a nonexistent
- # file path. Which seems reasonable.
- #
- if args:
- for f in args:
- fdict[f] = None
-
- #
- # Otherwise, if no files were listed explicitly, we assume that the
- # checks should be run on all files in the active list. So we determine
- # it here.
- #
- # Tracking the file paths is a slight optimization, in that multiple
- # check functions won't need to derive it themselves. This also dovetails
- # nicely with the expectation that explicitly specified files will be
- # ${CWD}-relative paths, so the fdict keyspace will be consistent either
- # way.
- #
+ if files:
+ return [(path, None) for path in sorted(files)]
else:
- active = wslist[repo].active()
- for e in sorted(active):
- fdict[wslist[repo].filepath(e.name)] = e
-
- return fdict
+ active = ws.active(parent=parent)
+ return [(ws.filepath(e.name), e) for e in sorted(active)]
+buildfilelist = util.cachefunc(buildfilelist)
def not_check(repo, cmd):
@@ -303,16 +278,14 @@ def cdm_cddlchk(ui, repo, *args, **opts):
See http://www.opensolaris.org/os/community/on/devref_toc/devref_7/#7_2_3_nonformatting_considerations
for more info.'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
-
- ui.write('CDDL block check:\n')
-
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'cddlchk')
lenient = True
ret = 0
- exclude = not_check(repo, 'cddlchk')
+ ui.write('CDDL block check:\n')
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif (e or opts.get('honour_nots')) and exclude(f):
@@ -336,14 +309,13 @@ def cdm_mapfilechk(ui, repo, *args, **opts):
header comment directing the reader to the document containing
Solaris object versioning rules (README.mapfile).'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'mapfilechk')
+ ret = 0
ui.write('Mapfile comment check:\n')
- ret = 0
- exclude = not_check(repo, 'mapfilechk')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif f.find('mapfile') == -1:
@@ -366,14 +338,13 @@ def cdm_copyright(ui, repo, *args, **opts):
See http://www.opensolaris.org/os/project/muskoka/on_dev/golden_rules.txt
for more info.'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'copyright')
+ ret = 0
ui.write('Copyright check:\n')
- ret = 0
- exclude = not_check(repo, 'copyright')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif (e or opts.get('honour_nots')) and exclude(f):
@@ -389,14 +360,13 @@ def cdm_copyright(ui, repo, *args, **opts):
def cdm_hdrchk(ui, repo, *args, **opts):
'''check active header files conform to O/N rules'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'hdrchk')
+ ret = 0
ui.write('Header format check:\n')
- ret = 0
- exclude = not_check(repo, 'hdrchk')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif not f.endswith('.h'):
@@ -416,14 +386,13 @@ def cdm_cstyle(ui, repo, *args, **opts):
See http://opensolaris.org/os/community/documentation/getting_started_docs/cstyle.ms.pdf'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'cstyle')
+ ret = 0
ui.write('C style check:\n')
- ret = 0
- exclude = not_check(repo, 'cstyle')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif not (f.endswith('.c') or f.endswith('.h')):
@@ -443,14 +412,13 @@ def cdm_cstyle(ui, repo, *args, **opts):
def cdm_jstyle(ui, repo, *args, **opts):
'check active Java source files for common stylistic errors'
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'jstyle')
+ ret = 0
ui.write('Java style check:\n')
- ret = 0
- exclude = not_check(repo, 'jstyle')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif not f.endswith('.java'):
@@ -468,14 +436,13 @@ def cdm_jstyle(ui, repo, *args, **opts):
def cdm_permchk(ui, repo, *args, **opts):
'''check active files permission - warn +x (execute) mode'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'permchk')
+ exeFiles = []
ui.write('File permission check:\n')
- exeFiles = []
- exclude = not_check(repo, 'permchk')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif (e or opts.get('honour_nots')) and exclude(f):
@@ -606,14 +573,13 @@ def cdm_rtichk(ui, repo, **opts):
def cdm_keywords(ui, repo, *args, **opts):
'''check source files do not contain SCCS keywords'''
- filelist = opts.get('filelist') or _buildfilelist(repo, args)
+ filelist = buildfilelist(wslist[repo], opts.get('parent'), args)
+ exclude = not_check(repo, 'keywords')
+ ret = 0
ui.write('Keywords check:\n')
- ret = 0
- exclude = not_check(repo, 'keywords')
-
- for f, e in filelist.iteritems():
+ for f, e in filelist:
if e and e.is_removed():
continue
elif (e or opts.get('honour_nots')) and exclude(f):
@@ -671,20 +637,17 @@ def run_checks(ws, cmds, *args, **opts):
ret = 0
- flist = _buildfilelist(ws.repo, args)
-
for cmd in cmds:
name = cmd.func_name.split('_')[1]
if not ws.ui.configbool('cdm', name, True):
ws.ui.status('Skipping %s check...\n' % name)
else:
ws.ui.pushbuffer()
+ result = cmd(ws.ui, ws.repo, honour_nots=True, *args, **opts)
+ output = ws.ui.popbuffer()
- result = cmd(ws.ui, ws.repo, filelist=flist,
- honour_nots=True, *args, **opts)
ret |= result
- output = ws.ui.popbuffer()
if not ws.ui.quiet or result != 0:
ws.ui.write(output, '\n')
return ret