text: #!/usr/bin/env python
  # -*- encoding: utf-8 -*-
  """
          Wonderful linting script by jtriley @ https://github.com/jtriley/StarCluster
  
          :copyright: (c) Justin Riley <justin.t.riley@gmail.com>
          :license: LGPL
  """
  import os
  import re
  import ast
  import sys
  import glob
  import subprocess
  
  import pep8
  from pyflakes import checker
  
  
  def check(codeString, filename):
      """Check the Python source given by C{codeString} for flakes.
  
      @param codeString: The Python source to check.
      @type codeString: C{str}
  
      @param filename: The name of the file the source came from, used to report
          errors.
      @type filename: C{str}
  
      @return: The number of warnings emitted.
      @rtype: C{int}
      """
      # First, compile into an AST and handle syntax errors.
      try:
          tree = compile(codeString, filename, "exec", ast.PyCF_ONLY_AST)
      except SyntaxError, value:
          msg = value.args[0]
  
          (lineno, offset, text) = value.lineno, value.offset, value.text
  
          # If there's an encoding problem with the file, the text is None.
          if text is None:
              # Avoid using msg, since for the only known case, it contains a
              # bogus message that claims the encoding the file declared was
              # unknown.
              print >> sys.stderr, "%s: problem decoding source" % (filename, )
          else:
              line = text.splitlines()[-1]
  
              if offset is not None:
                  offset = offset - (len(text) - len(line))
  
              print >> sys.stderr, '%s:%d: %s' % (filename, lineno, msg)
              print >> sys.stderr, line
  
              if offset is not None:
                  print >> sys.stderr, " " * offset, "^"
  
          return 1
      else:
          # Okay, it's syntactically valid.  Now check it.
          w = checker.Checker(tree, filename)
          lines = codeString.split('\n')
          messages = [message for message in w.messages
                      if lines[message.lineno - 1].find('pyflakes:ignore') < 0]
          messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
          for warning in messages:
              print warning
          return len(messages)
  
  
  def checkPath(filename):
      """Check the given path, printing out any warnings detected.
  
      @return: the number of warnings printed
      """
      try:
          return check(file(filename, 'U').read() + '\n', filename)
      except IOError, msg:
          print >> sys.stderr, "%s: %s" % (filename, msg.args[1])
          return 1
  
  
  def matches_file(file_name, match_files):
      return any(re.compile(match_file).match(file_name) for match_file in
                 match_files)
  
  
  def check_files(files, check):
      clean = True
      print check['start_msg']
      for file_name in files:
          if not matches_file(file_name, check.get('match_files', [])):
              continue
          if matches_file(file_name, check.get('ignore_files', [])):
              continue
          print 'checking file: %s' % file_name
          process = subprocess.Popen(check['command'] % file_name,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE, shell=True)
          out, err = process.communicate()
          output = out + err
          if output:
              output_lines = ['%s: %s' % (file_name, line) for line in
                              (out + err).splitlines()]
              print '\n'.join(output_lines)
          if process.returncode != 0:
              clean = False
      if not clean:
          raise Exception("ERROR: checks failed on some source files")
  
  
  def find_py_files(path):
      for cfile in glob.glob(os.path.join(path, '*')):
          if os.path.isdir(cfile):
              for py in find_py_files(cfile):
                  yield py
          if cfile.endswith('.py'):
              yield cfile
  
  
  def check_pyflakes(files):
      print(">>> Running pyflakes...")
      clean = True
      for pyfile in files:
          if checkPath(pyfile) != 0:
              clean = False
      if not clean:
          raise Exception("ERROR: pyflakes failed on some source files")
  
  
  def check_pep8(files):
      print(">>> Running pep8...")
      sg = pep8.StyleGuide(parse_argv=False, config_file=False)
      sg.options.repeat = True
      sg.options.show_pep8 = True
      report = sg.check_files(files)
      if report.total_errors:
          raise Exception("ERROR: pep8 failed on some source files")
  
  
  def main(git_index=False, filetypes=['.py']):
      files = []
      if git_index:
          p = subprocess.Popen(['git', 'status', '--porcelain'],
                               stdout=subprocess.PIPE)
          out, err = p.communicate()
          modified = re.compile('^(?:MM|M|A)(\s+)(?P<name>.*)')
          for line in out.splitlines():
              match = modified.match(line)
              if match:
                  f = match.group('name')
                  if filetypes:
                      if f.endswith(tuple(filetypes)):
                          files.append(f)
                  else:
                      files.append(f)
      else:
          src = os.path.join(os.path.dirname(__file__), 'lmb')
          files = list(find_py_files(src))
      if not files:
          return
      try:
          check_pyflakes(files)
          check_pep8(files)
          print(">>> Clean!")
      except Exception, e:
          print
          print(e)
          print("ERROR: please fix the errors and re-run this script")
          sys.exit(1)
  
  if __name__ == '__main__':
      git_index = '--git-index' in sys.argv
      main(git_index=git_index)
  