< prev index next >

./jcheck.py

Print this page
rev 105 : 7901298: jcheck should check that every file ends with exactly one newline
Summary: also remove trailing whitespace and ^L characters from jcheck.py because apparently jcheck.py itself isn't checked by jcheck


  69         _matchall = scmutil.matchall
  70     except ImportError:
  71         pass
  72 
  73 def repocompat(repo):
  74     # Modern mercurial versions use len(repo) and repo[cset_id]; enable those
  75     # operations with older versions.
  76     t = type(repo)
  77     if not getattr(t, '__len__', None):
  78         def repolen(self):
  79             return self.changelog.count()
  80         setattr(t, '__len__', repolen)
  81     if not getattr(t, '__getitem__', None):
  82         def repoitem(self, arg):
  83             return context.changectx(self, arg)
  84         setattr(t, '__getitem__', repoitem)
  85     # Similarly, use branchmap instead of branchtags; enable it if needed.
  86     if not getattr(t, 'branchmap', None):
  87         setattr(t, 'branchmap', t.branchtags)
  88 
  89 
  90 # Configuration-file parsing
  91 
  92 def load_conf(root):
  93     cf = { }
  94     fn = os.path.join(root, ".jcheck/conf")
  95     f = open(fn)
  96     try:
  97         prop_re = re.compile("\s*(\S+)\s*=\s*(\S+)\s*$")
  98         i = 0
  99         for ln in f.readlines():
 100             i = i + 1
 101             ln = ln.strip()
 102             if (ln.startswith("#")):
 103                 continue
 104             m = prop_re.match(ln)
 105             if not m:
 106                 raise util.Abort("%s:%d: Invalid configuration syntax: %s"
 107                                  % (fn, i, ln))
 108             cf[m.group(1)] = m.group(2)
 109     finally:
 110         f.close()
 111     for pn in ["project"]:
 112         if not cf.has_key(pn):
 113             raise util.Abort("%s: Missing property: %s" % (fn, pn))
 114     return cf
 115 
 116 
 117 # Author validation
 118 
 119 author_cache = { }                      ## Should really cache more permanently
 120 
 121 def validate_author(an, pn):
 122   if author_cache.has_key(an):
 123     return True
 124   u = ("http://db.openjdk.java.net/people/%s/projects/%s"
 125        % (urllib.quote(an), pn))
 126   f = None
 127   try:
 128       try:
 129           f = urllib2.urlopen(u)
 130       except urllib2.HTTPError, e:
 131           if e.code == 404:
 132               return False
 133           raise e
 134   finally:
 135       if f:
 136           f.close()
 137   author_cache[an] = True
 138   return True
 139 
 140 
 141 # Whitespace and comment validation
 142 
 143 badwhite_re = re.compile("(\t)|([ \t]$)|\r", re.MULTILINE)

 144 normext_re = re.compile(".*\.(java|c|h|cpp|hpp)$")
 145 
 146 tag_desc_re = re.compile("Added tag [^ ]+ for changeset [0-9a-f]{12}")
 147 tag_re = re.compile("tip$|jdk[4-9](u\d{1,3})?-b\d{2,3}$|hs\d\d(\.\d{1,2})?-b\d\d$")
 148 
 149 def badwhite_what(m):
 150     if m.group(1):
 151         return "Tab character"
 152     if m.group(2):
 153         return "Trailing whitespace"

 154     return "Carriage return (^M)"



 155 
 156 base_addr_pat = "[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}"
 157 addr_pat = ("(" + base_addr_pat + ")"
 158             + "|(([-_a-zA-Z0-9][-_ a-zA-Z0-9]+) +<" + base_addr_pat + ">)")
 159 
 160 bug_ident = re.compile("(([A-Z][A-Z0-9]+-)?[0-9]+):")
 161 bug_check = re.compile("([0-9]{7}): \S.*$")
 162 sum_ident = re.compile("Summary:")
 163 sum_check = re.compile("Summary: \S.*")
 164 rev_ident = re.compile("Reviewed-by:")
 165 rev_check = re.compile("Reviewed-by: (([a-z0-9]+)(, [a-z0-9]+)*$)")
 166 con_ident = re.compile("Contributed-by:")
 167 con_check = re.compile("Contributed-by: ((" + addr_pat + ")(, (" + addr_pat + "))*)$")
 168 
 169 def bug_validate(ch, ctx, m, pn):
 170     bs = m.group(1)
 171     if not (bs[0] in ['1','2','4','5','6','7','8']):
 172         ch.error(ctx, "Invalid bugid: %s" % bs)
 173     b = int(bs)
 174     if b in ch.cs_bugids:


 232     opts = { 'rev' : ['0:tip'] }
 233     try:
 234         nop = lambda c, fns: None
 235         iter = cmdutil.walkchangerevs(repo, _matchall(repo), opts, nop)
 236         for ctx in iter:
 237             addbugids(bugids, ctx)
 238     except (AttributeError, TypeError):
 239         # AttributeError:  matchall does not exist in hg < 1.1
 240         # TypeError:  walkchangerevs args differ in hg <= 1.3.1
 241         get = util.cachefunc(lambda r: repo.changectx(r).changeset())
 242         changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, [], get, opts)
 243         for st, rev, fns in changeiter:
 244             if st == 'add':
 245                 node = repo.changelog.node(rev)
 246                 addbugids(bugids, context.changectx(repo, node))
 247     if ui.debugflag:
 248         ui.debug("Bugids: %s\n" % bugids)
 249     return bugids
 250 
 251 
 252 
 253 # Black/white lists
 254 ## The black/white lists should really be in the database
 255 
 256 # Bogus yet historically-accepted changesets,
 257 # so that jcheck may evolve
 258 #
 259 changeset_whitelist = [
 260     '31000d79ec713de1e601dc16d74d726edd661ed5',
 261     'b7987d19f5122a9f169e568f935b7cdf1a2609f5',
 262     'c70a245cad3ad74602aa26b9d8e3d0472f7317c3',
 263     'e8e20316458c1cdb85d9733a2e357e438a76a859',
 264     'f68325221ce1efe94ab367400a49a8039d9b3db3',
 265     '4dfa5d67c44500155ce9ab1e00d0de21bdbb9ee6',
 266     '73a4d5be86497baf74c1fc194c9a0dd4e86d3a31', # jdk6/jdk6/jaxp bad comment
 267     'a25f15bfd04b46a302b6ca1a298c176344f432dd', # jdk6/jdk6/jdk  bad comment
 268     'bf87d5af43614d609a5251c43eea44c028500d02', # jdk6/jdk6/jdk  bad comment
 269     'd77434402021cebc4c25b452db18bbfd2d7ccda1', # jdk6/jdk6/jdk  bad comment
 270     '931e5f39e365a0d550d79148ff87a7f9e864d2e1', # hotspot dup bug id 7147064
 271     'd8abc90163a4b58db407a60cba331ab21c9977e7', # hotspot dup bug id 7147064
 272     '45849c62c298aa8426c9e67599e4e35793d8db13', # pubs executable files


 346     '3ecd3336c805978a37a933fbeca26c65fbe81432',
 347     # hsx/jdk7u/hotspot wrong bugid
 348     'f5d8e6d72e23d972db522f7ad4cd3b9b01085466',
 349     # jdk8/tl/jdk erroneous push 7152892
 350     'da4b0962ad1161dbd84e7daa0fdc706281c456a2',
 351     # jdk8/tl/jdk/test/closed erroneous push 7152892
 352     '1e69a1ce212c7c4c884f155dd123c936787db273',
 353     # jdk9/jdk9/closed bad tag
 354     '61fdebb503d79392536b8f502ae215022d1a1f1c',
 355     # jdk9/hs-rt/jdk/src/closed dup bugid 8034951
 356     'a19596796430761dde87bee9f6616480f1c93678',
 357     # jdk9/hs-rt/jdk/test/closed dup bugid 8034951
 358     'd2308c9714c94e87a0e60cda314746a5c17dbcc2',
 359     # jdk9/client/deploy erroneous push 8041798
 360     'fff4ff4fd6f031ab335b44842d69fd125297b5ab',
 361     ]
 362 
 363 # Path to file containing additional blacklisted changesets
 364 blacklist_file = '/oj/db/hg/blacklist'
 365 
 366 
 367 # Checker class
 368 
 369 class checker(object):
 370 
 371     def __init__(self, ui, repo, strict, lax):
 372         self.ui = ui
 373         self.repo = repo
 374         self.rv = Pass
 375         self.checks = [c for c in checker.__dict__ if c.startswith("c_")]
 376         self.checks.sort()
 377         self.summarized = False
 378         self.repo_bugids = [ ]
 379         self.cs_bugids = [ ]            # Bugids in current changeset
 380         self.cs_author = None           # Author of current changeset
 381         self.cs_reviewers = [ ]         # Reviewers of current changeset
 382         self.cs_contributor = None      # Contributor of current changeset
 383         self.strict = strict
 384         self.conf = load_conf(repo.root)
 385         self.whitespace_lax = lax and not strict
 386         if self.conf.get("whitespace") == "lax":
 387             self.whitespace_lax = True
 388         self.comments_lax = lax and not strict
 389         if self.conf.get("comments") == "lax":
 390             self.comments_lax = True
 391         self.tags_lax = lax and not strict


















 392         if self.conf.get("tags") == "lax":
 393             self.tags_lax = True
 394         self.bugids_allow_dups = self.conf.get("bugids") == "dup"
 395         self.bugids_lax = lax and not strict
 396         if self.conf.get("bugids") == "lax":
 397             self.bugids_lax = True
 398         self.bugids_ignore = False
 399         if self.conf.get("bugids") == "ignore":
 400             self.bugids_ignore = True
 401         if not self.bugids_ignore:
 402             # only identify bug ids if we are going to use them
 403             self.repo_bugids = repo_bugids(ui, repo)
 404         self.blacklist = dict.fromkeys(changeset_blacklist)
 405         self.read_blacklist(blacklist_file)
 406         # hg < 1.0 does not have localrepo.tagtype()
 407         self.tagtype = getattr(self.repo, 'tagtype', lambda k: 'global')
 408 
 409     def read_blacklist(self, fname):
 410         if not os.path.exists(fname):
 411             return


 429 
 430     def error(self, ctx, msg):
 431         if self.rv != Fail:
 432             self.ui.status("[jcheck %s %s]\n" % (_version, _date))
 433         if not self.summarized:
 434             if ctx:
 435                 self.summarize(ctx)
 436             else:
 437                 self.ui.status("\n")
 438             self.summarized = True
 439         self.ui.status(msg + "\n")
 440         self.rv = Fail
 441 
 442     def c_00_author(self, ctx):
 443         self.ui.debug("author: %s\n" % ctx.user())
 444         if not validate_author(ctx.user(), self.conf["project"]):
 445             self.error(ctx, "Invalid changeset author: %s" % ctx.user())
 446         self.cs_author = ctx.user()
 447 
 448     def c_01_comment(self, ctx):
 449         m = badwhite_re.search(ctx.description())
 450         if m:
 451             ln = ctx.description().count("\n", 0, m.start()) + 1
 452             self.error(ctx, "%s in comment (line %d)" % (badwhite_what(m), ln))
 453 
 454         if is_merge(self.repo, ctx.rev()):
 455             if ctx.description() != "Merge":
 456                 self.error(ctx, ("Invalid comment for merge changeset"
 457                                  + " (must be \"Merge\")"))
 458             return
 459 
 460         if tag_desc_re.match(ctx.description()):
 461             ## Should check tag itself
 462             return
 463 
 464         if ((ctx.rev() == 0 or (ctx.rev() == 1 and self.comments_lax))
 465             and ctx.user() == "duke"
 466             and ctx.description().startswith("Initial load")):
 467             return
 468 
 469         lns = ctx.description().splitlines()


 501                 self.error(ctx, "Too many %ss" % st.name)
 502 
 503         if not self.cs_contributor and [self.cs_author] == self.cs_reviewers:
 504             self.error(ctx, "Self-reviews not permitted")
 505         if not self.comments_lax:
 506             if (gi == 0 and n > 0):
 507                 self.error(ctx, "Incomplete comment: Missing bugid line")
 508             elif gi == 1 or (gi == 2 and n == 0):
 509                 self.error(ctx, "Incomplete comment: Missing reviewer attribution")
 510             if (i < len(lns)):
 511                 self.error(ctx, "Extraneous text in comment")
 512 
 513     def c_02_files(self, ctx):
 514         changes = self.repo.status(ctx.parents()[0].node(),
 515                                    ctx.node(), None)[:5]
 516         modified, added = changes[:2]
 517         # ## Skip files that were renamed but not modified
 518         files = modified + added
 519         if self.ui.debugflag:
 520             self.ui.debug("Checking files: %s\n" % ", ".join(files))




 521         for f in files:
 522             if ctx.rev() == 0:
 523                 ## This is loathsome
 524                 if f.startswith("test/java/rmi"): continue
 525                 if f.startswith("test/com/sun/javadoc/test"): continue
 526                 if f.startswith("docs/technotes/guides"): continue
 527             fx = ctx.filectx(f)
 528             if normext_re.match(f) and not self.whitespace_lax:
 529                 data = fx.data()
 530                 m = badwhite_re.search(data)
 531                 if m:
 532                     ln = data.count("\n", 0, m.start()) + 1
 533                     self.error(ctx, "%s:%d: %s" % (f, ln, badwhite_what(m)))
 534             ## check_file_header(self, fx, data)
 535             flags = fx.manifest().flags(f)
 536             if 'x' in flags:
 537                 self.error(ctx, "%s: Executable files not permitted" % f)
 538             if 'l' in flags:
 539                 self.error(ctx, "%s: Symbolic links not permitted" % f)
 540 




  69         _matchall = scmutil.matchall
  70     except ImportError:
  71         pass
  72 
  73 def repocompat(repo):
  74     # Modern mercurial versions use len(repo) and repo[cset_id]; enable those
  75     # operations with older versions.
  76     t = type(repo)
  77     if not getattr(t, '__len__', None):
  78         def repolen(self):
  79             return self.changelog.count()
  80         setattr(t, '__len__', repolen)
  81     if not getattr(t, '__getitem__', None):
  82         def repoitem(self, arg):
  83             return context.changectx(self, arg)
  84         setattr(t, '__getitem__', repoitem)
  85     # Similarly, use branchmap instead of branchtags; enable it if needed.
  86     if not getattr(t, 'branchmap', None):
  87         setattr(t, 'branchmap', t.branchtags)
  88 

  89 # Configuration-file parsing
  90 
  91 def load_conf(root):
  92     cf = { }
  93     fn = os.path.join(root, ".jcheck/conf")
  94     f = open(fn)
  95     try:
  96         prop_re = re.compile("\s*(\S+)\s*=\s*(\S+)\s*$")
  97         i = 0
  98         for ln in f.readlines():
  99             i = i + 1
 100             ln = ln.strip()
 101             if (ln.startswith("#")):
 102                 continue
 103             m = prop_re.match(ln)
 104             if not m:
 105                 raise util.Abort("%s:%d: Invalid configuration syntax: %s"
 106                                  % (fn, i, ln))
 107             cf[m.group(1)] = m.group(2)
 108     finally:
 109         f.close()
 110     for pn in ["project"]:
 111         if not cf.has_key(pn):
 112             raise util.Abort("%s: Missing property: %s" % (fn, pn))
 113     return cf
 114 

 115 # Author validation
 116 
 117 author_cache = { }                      ## Should really cache more permanently
 118 
 119 def validate_author(an, pn):
 120   if author_cache.has_key(an):
 121     return True
 122   u = ("http://db.openjdk.java.net/people/%s/projects/%s"
 123        % (urllib.quote(an), pn))
 124   f = None
 125   try:
 126       try:
 127           f = urllib2.urlopen(u)
 128       except urllib2.HTTPError, e:
 129           if e.code == 404:
 130               return False
 131           raise e
 132   finally:
 133       if f:
 134           f.close()
 135   author_cache[an] = True
 136   return True
 137 

 138 # Whitespace and comment validation
 139 
 140 badwhite_comment_re = re.compile("(\t)|([ \t]$)|(\r)", re.MULTILINE)
 141 badwhite_with_eof_re = re.compile("(\t)|([ \t]$)|(\r)|([^\n]\Z)|(\n\n+\Z)", re.MULTILINE)
 142 normext_re = re.compile(".*\.(java|c|h|cpp|hpp)$")
 143 
 144 tag_desc_re = re.compile("Added tag [^ ]+ for changeset [0-9a-f]{12}")
 145 tag_re = re.compile("tip$|jdk[4-9](u\d{1,3})?-b\d{2,3}$|hs\d\d(\.\d{1,2})?-b\d\d$")
 146 
 147 def badwhite_what(m):
 148     if m.group(1):
 149         return "Tab character"
 150     if m.group(2):
 151         return "Trailing whitespace"
 152     if m.group(3):
 153         return "Carriage return (^M)"
 154     if m.group(4):
 155         return "No newline (\\n) at the end of file"
 156     return "More than one newline (\\n) at the end of file"
 157 
 158 base_addr_pat = "[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}"
 159 addr_pat = ("(" + base_addr_pat + ")"
 160             + "|(([-_a-zA-Z0-9][-_ a-zA-Z0-9]+) +<" + base_addr_pat + ">)")
 161 
 162 bug_ident = re.compile("(([A-Z][A-Z0-9]+-)?[0-9]+):")
 163 bug_check = re.compile("([0-9]{7}): \S.*$")
 164 sum_ident = re.compile("Summary:")
 165 sum_check = re.compile("Summary: \S.*")
 166 rev_ident = re.compile("Reviewed-by:")
 167 rev_check = re.compile("Reviewed-by: (([a-z0-9]+)(, [a-z0-9]+)*$)")
 168 con_ident = re.compile("Contributed-by:")
 169 con_check = re.compile("Contributed-by: ((" + addr_pat + ")(, (" + addr_pat + "))*)$")
 170 
 171 def bug_validate(ch, ctx, m, pn):
 172     bs = m.group(1)
 173     if not (bs[0] in ['1','2','4','5','6','7','8']):
 174         ch.error(ctx, "Invalid bugid: %s" % bs)
 175     b = int(bs)
 176     if b in ch.cs_bugids:


 234     opts = { 'rev' : ['0:tip'] }
 235     try:
 236         nop = lambda c, fns: None
 237         iter = cmdutil.walkchangerevs(repo, _matchall(repo), opts, nop)
 238         for ctx in iter:
 239             addbugids(bugids, ctx)
 240     except (AttributeError, TypeError):
 241         # AttributeError:  matchall does not exist in hg < 1.1
 242         # TypeError:  walkchangerevs args differ in hg <= 1.3.1
 243         get = util.cachefunc(lambda r: repo.changectx(r).changeset())
 244         changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, [], get, opts)
 245         for st, rev, fns in changeiter:
 246             if st == 'add':
 247                 node = repo.changelog.node(rev)
 248                 addbugids(bugids, context.changectx(repo, node))
 249     if ui.debugflag:
 250         ui.debug("Bugids: %s\n" % bugids)
 251     return bugids
 252 
 253 

 254 # Black/white lists
 255 ## The black/white lists should really be in the database
 256 
 257 # Bogus yet historically-accepted changesets,
 258 # so that jcheck may evolve
 259 #
 260 changeset_whitelist = [
 261     '31000d79ec713de1e601dc16d74d726edd661ed5',
 262     'b7987d19f5122a9f169e568f935b7cdf1a2609f5',
 263     'c70a245cad3ad74602aa26b9d8e3d0472f7317c3',
 264     'e8e20316458c1cdb85d9733a2e357e438a76a859',
 265     'f68325221ce1efe94ab367400a49a8039d9b3db3',
 266     '4dfa5d67c44500155ce9ab1e00d0de21bdbb9ee6',
 267     '73a4d5be86497baf74c1fc194c9a0dd4e86d3a31', # jdk6/jdk6/jaxp bad comment
 268     'a25f15bfd04b46a302b6ca1a298c176344f432dd', # jdk6/jdk6/jdk  bad comment
 269     'bf87d5af43614d609a5251c43eea44c028500d02', # jdk6/jdk6/jdk  bad comment
 270     'd77434402021cebc4c25b452db18bbfd2d7ccda1', # jdk6/jdk6/jdk  bad comment
 271     '931e5f39e365a0d550d79148ff87a7f9e864d2e1', # hotspot dup bug id 7147064
 272     'd8abc90163a4b58db407a60cba331ab21c9977e7', # hotspot dup bug id 7147064
 273     '45849c62c298aa8426c9e67599e4e35793d8db13', # pubs executable files


 347     '3ecd3336c805978a37a933fbeca26c65fbe81432',
 348     # hsx/jdk7u/hotspot wrong bugid
 349     'f5d8e6d72e23d972db522f7ad4cd3b9b01085466',
 350     # jdk8/tl/jdk erroneous push 7152892
 351     'da4b0962ad1161dbd84e7daa0fdc706281c456a2',
 352     # jdk8/tl/jdk/test/closed erroneous push 7152892
 353     '1e69a1ce212c7c4c884f155dd123c936787db273',
 354     # jdk9/jdk9/closed bad tag
 355     '61fdebb503d79392536b8f502ae215022d1a1f1c',
 356     # jdk9/hs-rt/jdk/src/closed dup bugid 8034951
 357     'a19596796430761dde87bee9f6616480f1c93678',
 358     # jdk9/hs-rt/jdk/test/closed dup bugid 8034951
 359     'd2308c9714c94e87a0e60cda314746a5c17dbcc2',
 360     # jdk9/client/deploy erroneous push 8041798
 361     'fff4ff4fd6f031ab335b44842d69fd125297b5ab',
 362     ]
 363 
 364 # Path to file containing additional blacklisted changesets
 365 blacklist_file = '/oj/db/hg/blacklist'
 366 

 367 # Checker class
 368 
 369 class checker(object):
 370 
 371     def __init__(self, ui, repo, strict, lax):
 372         self.ui = ui
 373         self.repo = repo
 374         self.rv = Pass
 375         self.checks = [c for c in checker.__dict__ if c.startswith("c_")]
 376         self.checks.sort()
 377         self.summarized = False
 378         self.repo_bugids = [ ]
 379         self.cs_bugids = [ ]            # Bugids in current changeset
 380         self.cs_author = None           # Author of current changeset
 381         self.cs_reviewers = [ ]         # Reviewers of current changeset
 382         self.cs_contributor = None      # Contributor of current changeset
 383         self.strict = strict
 384         self.conf = load_conf(repo.root)
 385         self.whitespace_lax = lax and not strict
 386         if self.conf.get("whitespace") == "lax":
 387             self.whitespace_lax = True
 388         self.comments_lax = lax and not strict
 389         if self.conf.get("comments") == "lax":
 390             self.comments_lax = True
 391         self.tags_lax = lax and not strict
 392         # Test if we should check for a correct EOF (i.e. files end with exatly one '\n')
 393         # This behaviour is controlled by the 'check_eof' attribute in the conf file.
 394         # -1 means to not check for EOF at all.
 395         #  0 means to potentially check all the changes for a correct EOF.
 396         #    any other positive number is interpreted as the revision number or change-
 397         #    set ID from which on jcheck should start checking for a correct EOF.
 398         # If the 'check_eof' attribute is missing, '-1' (i.e. no EOF check) will be assumed.
 399         if self.conf.has_key("check_eof"):
 400             check_eof_cs = self.conf.get("check_eof")
 401             if not check_eof_cs.startswith("-"):
 402                 try:
 403                     self.check_eof = repo[check_eof_cs].rev()
 404                 except:
 405                     self.check_eof = -1
 406             else:
 407                 self.check_eof = -1
 408         else:
 409             self.check_eof = -1
 410         if self.conf.get("tags") == "lax":
 411             self.tags_lax = True
 412         self.bugids_allow_dups = self.conf.get("bugids") == "dup"
 413         self.bugids_lax = lax and not strict
 414         if self.conf.get("bugids") == "lax":
 415             self.bugids_lax = True
 416         self.bugids_ignore = False
 417         if self.conf.get("bugids") == "ignore":
 418             self.bugids_ignore = True
 419         if not self.bugids_ignore:
 420             # only identify bug ids if we are going to use them
 421             self.repo_bugids = repo_bugids(ui, repo)
 422         self.blacklist = dict.fromkeys(changeset_blacklist)
 423         self.read_blacklist(blacklist_file)
 424         # hg < 1.0 does not have localrepo.tagtype()
 425         self.tagtype = getattr(self.repo, 'tagtype', lambda k: 'global')
 426 
 427     def read_blacklist(self, fname):
 428         if not os.path.exists(fname):
 429             return


 447 
 448     def error(self, ctx, msg):
 449         if self.rv != Fail:
 450             self.ui.status("[jcheck %s %s]\n" % (_version, _date))
 451         if not self.summarized:
 452             if ctx:
 453                 self.summarize(ctx)
 454             else:
 455                 self.ui.status("\n")
 456             self.summarized = True
 457         self.ui.status(msg + "\n")
 458         self.rv = Fail
 459 
 460     def c_00_author(self, ctx):
 461         self.ui.debug("author: %s\n" % ctx.user())
 462         if not validate_author(ctx.user(), self.conf["project"]):
 463             self.error(ctx, "Invalid changeset author: %s" % ctx.user())
 464         self.cs_author = ctx.user()
 465 
 466     def c_01_comment(self, ctx):
 467         m = badwhite_comment_re.search(ctx.description())
 468         if m:
 469             ln = ctx.description().count("\n", 0, m.start()) + 1
 470             self.error(ctx, "%s in comment (line %d)" % (badwhite_what(m), ln))
 471 
 472         if is_merge(self.repo, ctx.rev()):
 473             if ctx.description() != "Merge":
 474                 self.error(ctx, ("Invalid comment for merge changeset"
 475                                  + " (must be \"Merge\")"))
 476             return
 477 
 478         if tag_desc_re.match(ctx.description()):
 479             ## Should check tag itself
 480             return
 481 
 482         if ((ctx.rev() == 0 or (ctx.rev() == 1 and self.comments_lax))
 483             and ctx.user() == "duke"
 484             and ctx.description().startswith("Initial load")):
 485             return
 486 
 487         lns = ctx.description().splitlines()


 519                 self.error(ctx, "Too many %ss" % st.name)
 520 
 521         if not self.cs_contributor and [self.cs_author] == self.cs_reviewers:
 522             self.error(ctx, "Self-reviews not permitted")
 523         if not self.comments_lax:
 524             if (gi == 0 and n > 0):
 525                 self.error(ctx, "Incomplete comment: Missing bugid line")
 526             elif gi == 1 or (gi == 2 and n == 0):
 527                 self.error(ctx, "Incomplete comment: Missing reviewer attribution")
 528             if (i < len(lns)):
 529                 self.error(ctx, "Extraneous text in comment")
 530 
 531     def c_02_files(self, ctx):
 532         changes = self.repo.status(ctx.parents()[0].node(),
 533                                    ctx.node(), None)[:5]
 534         modified, added = changes[:2]
 535         # ## Skip files that were renamed but not modified
 536         files = modified + added
 537         if self.ui.debugflag:
 538             self.ui.debug("Checking files: %s\n" % ", ".join(files))
 539         if self.check_eof != -1 and ctx.rev() >= self.check_eof:
 540             badwhite_re = badwhite_with_eof_re
 541         else:
 542             badwhite_re = badwhite_comment_re
 543         for f in files:
 544             if ctx.rev() == 0:
 545                 ## This is loathsome
 546                 if f.startswith("test/java/rmi"): continue
 547                 if f.startswith("test/com/sun/javadoc/test"): continue
 548                 if f.startswith("docs/technotes/guides"): continue
 549             fx = ctx.filectx(f)
 550             if normext_re.match(f) and not self.whitespace_lax:
 551                 data = fx.data()
 552                 m = badwhite_re.search(data)
 553                 if m:
 554                     ln = data.count("\n", 0, m.start()) + 1
 555                     self.error(ctx, "%s:%d: %s" % (f, ln, badwhite_what(m)))
 556             ## check_file_header(self, fx, data)
 557             flags = fx.manifest().flags(f)
 558             if 'x' in flags:
 559                 self.error(ctx, "%s: Executable files not permitted" % f)
 560             if 'l' in flags:
 561                 self.error(ctx, "%s: Symbolic links not permitted" % f)
 562 


< prev index next >