github.phpd.cn/thought-machine/please@v12.2.0+incompatible/tools/misc/ci_lint.py (about)

     1  #!/usr/bin/env python3
     2  """Implements a bunch of linters on the repo's source.
     3  
     4  Some specific things are run as plz tests (e.g. lint_builtin_rules_test)
     5  but this covers more nebulous things like linters as part of the CI build.
     6  
     7  Should be run from the repo root.
     8  """
     9  
    10  import os
    11  import subprocess
    12  import sys
    13  from concurrent import futures
    14  from itertools import groupby
    15  
    16  
    17  # Dir names that are always blacklisted.
    18  BLACKLISTED_DIRS = {'plz-out', 'test', 'test_data', 'third_party'}
    19  # Count of packages linted so far and total to do
    20  done = 0
    21  total = 0
    22  
    23  
    24  class Linter:
    25  
    26      def __init__(self, root):
    27          all_go_files = [(d, f) for d, f in self.find_go_files(root)]
    28          self.by_dir = [[os.path.join(d, f[1]) for f in files]
    29                         for d, files in groupby(all_go_files, key=lambda x: x[0])]
    30          self.done = 0
    31          self.write('Linting... 0 / %d done', len(self.by_dir))
    32  
    33      def write(self, msg, args, overwrite=False):
    34          if sys.stderr.isatty() and not os.environ.get('CI'):
    35              if overwrite:
    36                  sys.stderr.write('\033[1G')
    37              sys.stderr.write(msg % args)
    38              sys.stderr.flush()
    39  
    40      def reset_line(self):
    41          if sys.stderr.isatty() and not os.environ.get('CI'):
    42              sys.stderr.write('\033[1G')
    43  
    44      def find_go_files(self, root):
    45          for dirname, dirs, files in os.walk(root):
    46              # Excludes github.com, gopkg.in, etc.
    47              dirs[:] = [d for d in dirs if '.' not in d and d not in BLACKLISTED_DIRS]
    48              yield from [(dirname[2:], file) for file in files
    49                          if file.endswith('.go') and not file.endswith('.bindata.go')]
    50  
    51      def run_linters(self, files):
    52          try:
    53              # There are two cases of "possible misuse of unsafe.Pointer" in the parser.
    54              # We *think* our usage is legit although of course it would be nice to fix
    55              # the warnings regardless. For now we disable it to get linting of the rest
    56              # of the package.
    57              subprocess.check_call(['go', 'tool', 'vet', '-unsafeptr=false', '-structtags=false'] + files)
    58              subprocess.check_call(['golint', '-set_exit_status'] + files)
    59              return True
    60          except subprocess.CalledProcessError:
    61              return False
    62          finally:
    63              self.done += 1
    64              self.write('Linting... %d / %d done', (self.done, len(self.by_dir)), overwrite=True)
    65  
    66  
    67  def main():
    68      linter = Linter('.')
    69      with futures.ThreadPoolExecutor(max_workers=6) as executor:
    70          if not all(executor.map(linter.run_linters, linter.by_dir)):
    71              linter.reset_line()
    72              sys.exit('Some linters failed')
    73          linter.reset_line()
    74  
    75  
    76  if __name__ == '__main__':
    77      main()