示例#1
0
 def _buildResult(self, resultDict, leadingWS):
     """Convert a pycompile.py output resultDict to a KoILintResult.
     
     A pycompile.py dict looks like this:
         {'description': 'SyntaxError: invalid syntax',
          'filename': 'foo.py',
          'lineno': 1,
          'offset': 8, # may be None
          'severity': 'ERROR',
          'text': 'asdf = \n'}
     """
     r = KoLintResult()
     r.description = resultDict["description"]
     if leadingWS:
         resultDict['lineno'] -= 1
         if resultDict['text'].startswith(leadingWS):
             resultDict['text'] = resultDict['text'][len(leadingWS):]
     if resultDict["offset"] is not None:
         if leadingWS:
             actualLineOffset = len(leadingWS)
             if resultDict['offset'] >= actualLineOffset:
                 resultDict['offset'] -= actualLineOffset
         r.description += " (at column %d)" % resultDict["offset"]
     r.lineStart = resultDict['lineno']
     r.lineEnd = resultDict['lineno']
     # Would be nice to actually underline from teh given offset, but
     # then have to be smart abouve how far after that to underline.
     r.columnStart = 1
     r.columnEnd = len(resultDict['text'])
     if resultDict['severity'] == "ERROR":
         r.severity = r.SEV_ERROR
     elif resultDict['severity'] == "WARNING":
         r.severity = r.SEV_WARNING
     return r
示例#2
0
 def _createAddResult(self, results, datalines, errorType, lineNo, desc, numDots):
     # build lint result object
     result = KoLintResult()
     if lineNo >= len(datalines):
         lineNo = len(datalines) - 1
         # if the error is on the last line, work back to the last
         # character of the first nonblank line so we can display
         # the error somewhere
         while lineNo >= 0 and not datalines[lineNo]:
             lineNo -= 1
         if lineNo < 0:
             return
         result.columnEnd = len(datalines[lineNo - 1]) + 1
         result.columnStart = 1
         lineNo += 1
     else:
         if numDots is None:
             result.columnStart = 1
         else:
             result.columnStart = numDots + 1
         result.columnEnd = result.columnStart + 1
     result.lineStart = lineNo
     result.lineEnd = lineNo
     if (errorType.lower().find('warning') >= 0):
         result.severity = result.SEV_WARNING
     else:
         result.severity = result.SEV_ERROR
     # This always results in a lint result spanning a single
     # character, which, given the squiggly reporting scheme is
     # almost invisible. Workaround: set the result to be the
     # whole line and append the column number to the description.
     result.description = "%s: %s (on column %d)" % (errorType,desc,result.columnStart)
     result.columnStart = 1
     result.columnEnd = len(datalines[lineNo-1])+1
     results.addResult(result)
示例#3
0
 def _buildResult(self, resultDict, leadingWS):
     """Convert a pycompile.py output resultDict to a KoILintResult.
     
     A pycompile.py dict looks like this:
         {'description': 'SyntaxError: invalid syntax',
          'filename': 'foo.py',
          'lineno': 1,
          'offset': 8, # may be None
          'severity': 'ERROR',
          'text': 'asdf = \n'}
     """
     r = KoLintResult()
     r.description = resultDict["description"]
     if leadingWS:
         resultDict['lineno'] -= 1
         if resultDict['text'].startswith(leadingWS):
             resultDict['text'] = resultDict['text'][len(leadingWS):]
     if resultDict["offset"] is not None:
         if leadingWS:
             actualLineOffset = len(leadingWS)
             if resultDict['offset'] >= actualLineOffset:
                 resultDict['offset'] -= actualLineOffset
         r.description += " (at column %d)" % resultDict["offset"]
     r.lineStart = resultDict['lineno']
     r.lineEnd = resultDict['lineno']
     # Would be nice to actually underline from teh given offset, but
     # then have to be smart abouve how far after that to underline.
     r.columnStart = 1
     r.columnEnd = len(resultDict['text'])
     if resultDict['severity'] == "ERROR":
         r.severity = r.SEV_ERROR
     elif resultDict['severity'] == "WARNING":
         r.severity = r.SEV_WARNING
     return r
示例#4
0
 def _createAddResult(self, results, datalines, errorType, lineNo, desc, numDots):
     # build lint result object
     result = KoLintResult()
     if lineNo >= len(datalines):
         lineNo = len(datalines) - 1
         # if the error is on the last line, work back to the last
         # character of the first nonblank line so we can display
         # the error somewhere
         while lineNo >= 0 and not datalines[lineNo]:
             lineNo -= 1
         if lineNo < 0:
             return
         result.columnEnd = len(datalines[lineNo - 1]) + 1
         result.columnStart = 1
         lineNo += 1
     else:
         if numDots is None:
             result.columnStart = 1
         else:
             result.columnStart = numDots + 1
         result.columnEnd = result.columnStart + 1
     result.lineStart = lineNo
     result.lineEnd = lineNo
     if (errorType.lower().find('warning') >= 0):
         result.severity = result.SEV_WARNING
     else:
         result.severity = result.SEV_ERROR
     # This always results in a lint result spanning a single
     # character, which, given the squiggly reporting scheme is
     # almost invisible. Workaround: set the result to be the
     # whole line and append the column number to the description.
     result.description = "%s: %s (on column %d)" % (errorType,desc,result.columnStart)
     result.columnStart = 1
     result.columnEnd = len(datalines[lineNo-1])+1
     results.addResult(result)
    def lint_with_text(self, request, text):
        if not text.strip():
            return None
        cwd = request.cwd
        env = koprocessutils.getUserEnv()
        settingsDir = env.get("DJANGO_SETTINGS_MODULE", None)
        if not settingsDir:
            settingsDir = self._getSettingsDir(cwd)
        if settingsDir:
            # Save the current buffer to a temporary file.
            tmpFileName = tempfile.mktemp()
            fout = open(tmpFileName, 'wb')
            try:
                fout.write(text)
                fout.close()

                #XXX: How to tell whether we're using Python or Python3?
                prefName = "pythonExtraPaths"
                pythonPath =  request.prefset.getString(prefName, "")
                pythonPathEnv = env.get("PYTHONPATH", "")
                if pythonPathEnv:
                    if pythonPath:
                        pythonPath += os.pathsep + pythonPathEnv
                    else:
                        pythonPath = pythonPathEnv
                if pythonPath:
                    if sys.platform.startswith("win"):
                        pythonPath = pythonPath.replace('\\', '/')
                    env["PYTHONPATH"] = pythonPath
                elif env.has_key("PYTHONPATH"):
                    del env["PYTHONPATH"]

                results = koLintResults()
                pythonExe = self._pythonInfo.getExecutableFromDocument(request.koDoc)
                argv = [pythonExe, self._djangoLinterPath,
                        tmpFileName, settingsDir]
                p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None)
                output, error = p.communicate()
                #log.debug("Django output: output:[%s], error:[%s]", output, error)
                retval = p.returncode
            finally:
                os.unlink(tmpFileName)
            if retval == 1:
                if error:
                    results.addResult(self._buildResult(text, error))
                else:
                    results.addResult(self._buildResult(text, "Unexpected error"))
        else:
            result = KoLintResult()
            result.lineStart = 1
            result.lineEnd = 1
            result.columnStart = 1
            result.columnEnd = 1 + len(text.splitlines(1)[0])
            result.description = "Can't find settings.py for this Django file"
            result.encodedDescription = result.description
            result.severity = result.SEV_ERROR
            results = koLintResults()
            results.addResult(result)
        return results
    def lint_with_text(self, request, text):
        if not text.strip():
            return None
        cwd = request.cwd
        env = koprocessutils.getUserEnv()
        settingsDir = env.get("DJANGO_SETTINGS_MODULE", None)
        if not settingsDir:
            settingsDir = self._getSettingsDir(cwd)
        if settingsDir:
            # Save the current buffer to a temporary file.
            tmpFileName = tempfile.mktemp()
            fout = open(tmpFileName, 'wb')
            try:
                fout.write(text)
                fout.close()

                #XXX: How to tell whether we're using Python or Python3?
                prefName = "pythonExtraPaths"
                pythonPath =  request.prefset.getString(prefName, "")
                pythonPathEnv = env.get("PYTHONPATH", "")
                if pythonPathEnv:
                    if pythonPath:
                        pythonPath += os.pathsep + pythonPathEnv
                    else:
                        pythonPath = pythonPathEnv
                if pythonPath:
                    if sys.platform.startswith("win"):
                        pythonPath = pythonPath.replace('\\', '/')
                    env["PYTHONPATH"] = pythonPath
                elif env.has_key("PYTHONPATH"):
                    del env["PYTHONPATH"]

                results = koLintResults()
                pythonExe = self._pythonInfo.getExecutableFromDocument(request.koDoc)
                argv = [pythonExe, self._djangoLinterPath,
                        tmpFileName, settingsDir]
                p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None)
                output, error = p.communicate()
                #log.debug("Django output: output:[%s], error:[%s]", output, error)
                retval = p.returncode
            finally:
                os.unlink(tmpFileName)
            if retval == 1:
                if error:
                    results.addResult(self._buildResult(text, error))
                else:
                    results.addResult(self._buildResult(text, "Unexpected error"))
        else:
            result = KoLintResult()
            result.lineStart = 1
            result.lineEnd = 1
            result.columnStart = 1
            result.columnEnd = 1 + len(text.splitlines(1)[0])
            result.description = "Can't find settings.py for this Django file"
            result.encodedDescription = result.description
            result.severity = result.SEV_ERROR
            results = koLintResults()
            results.addResult(result)
        return results
示例#7
0
    def _addMixedEOLWarnings(self, results, content, expectedEOL):
        """Add lint results (at the WARNING level) for each line that has
        an unexpected EOL.
        
            "results" in a koILintResults to which to add mixed EOL results.
            "content" is the content to analyze
            "expectedEOL" is the currently configured EOL for the document,
                this must be on of the EOL_LF, EOL_CR, EOL_CRLF constants.
        """
        import eollib
        mixedEOLs = eollib.getMixedEOLLineNumbers(content, expectedEOL)
        if not mixedEOLs:
            return

        def collapseContinuousLineNumbers(lineNos):
            """Return a collapsed group of continuous line numbers."""
            results = []
            start = -10
            last = -10
            for lineNo in lineNos:
                if lineNo == last + 1:
                    pass
                else:
                    if start >= 0:
                        results.append((start, last))
                    start = lineNo
                last = lineNo
            if start >= 0:
                results.append((start, last))
            return results

        # Add a warning lint result for each such line.
        expectedEOLStr = eollib.eol2eolPref[expectedEOL]
        lines = content.splitlines(1)
        # For performance reasons, we collapse groups of continuous line
        # numbers into the one line result - bug 92733.
        for lineStart, lineEnd in collapseContinuousLineNumbers(mixedEOLs):
            r = KoLintResult()
            r.description = "This line does not end with the expected "\
                            "EOL: '%s' (select View | View EOL Markers)"\
                            % expectedEOLStr
            r.lineStart = lineStart + 1
            r.lineEnd = lineEnd + 1
            r.columnStart = 1
            r.columnEnd = len(lines[lineEnd]) + 1
            r.severity = r.SEV_WARNING
            results.addResult(r)
示例#8
0
    def _addMixedEOLWarnings(self, results, content, expectedEOL):
        """Add lint results (at the WARNING level) for each line that has
        an unexpected EOL.
        
            "results" in a koILintResults to which to add mixed EOL results.
            "content" is the content to analyze
            "expectedEOL" is the currently configured EOL for the document,
                this must be on of the EOL_LF, EOL_CR, EOL_CRLF constants.
        """
        import eollib
        mixedEOLs = eollib.getMixedEOLLineNumbers(content, expectedEOL)
        if not mixedEOLs:
            return

        def collapseContinuousLineNumbers(lineNos):
            """Return a collapsed group of continuous line numbers."""
            results = []
            start = -10
            last = -10
            for lineNo in lineNos:
                if lineNo == last+1:
                    pass
                else:
                    if start >= 0:
                        results.append((start, last))
                    start = lineNo
                last = lineNo
            if start >= 0:
                results.append((start, last))
            return results

        # Add a warning lint result for each such line.
        expectedEOLStr = eollib.eol2eolPref[expectedEOL]
        lines = content.splitlines(1)
        # For performance reasons, we collapse groups of continuous line
        # numbers into the one line result - bug 92733.
        for lineStart, lineEnd in collapseContinuousLineNumbers(mixedEOLs):
            r = KoLintResult()
            r.description = "This line does not end with the expected "\
                            "EOL: '%s' (select View | View EOL Markers)"\
                            % expectedEOLStr
            r.lineStart = lineStart+1
            r.lineEnd = lineEnd+1
            r.columnStart = 1
            r.columnEnd = len(lines[lineEnd]) + 1
            r.severity = r.SEV_WARNING
            results.addResult(r)
示例#9
0
            indeces.append(index)
            offset = index + 1
        log.debug("encoding errors at indeces %s", indeces)

        results = koLintResults()
        lines = content.splitlines(1)  # keep line terminators
        offset = 0  # the current offset in the document
        for i in range(len(lines)):
            line = lines[i]
            while indeces and indeces[0] < offset + len(line):
                index = indeces.pop(0)  # this index is on this line
                r = KoLintResult()
                r.description = "This character cannot be represented with "\
                                "the current encoding: '%s'"\
                                % encoding.python_encoding_name
                r.lineStart = i + 1
                r.lineEnd = i + 1
                r.columnStart = index - offset + 1
                r.columnEnd = r.columnStart + 1
                log.debug("encoding error: index=%d: %d,%d-%d,%d", index,
                          r.lineStart, r.columnStart, r.lineEnd, r.columnEnd)
                r.severity = r.SEV_ERROR
                results.addResult(r)
            if not indeces:
                break
            offset += len(line)
        else:
            raise ValueError("Did not find line and column for one or "
                             "more indeces in content: %s" % indeces)

        return results
示例#10
0
            indeces.append(index)
            offset = index + 1
        log.debug("encoding errors at indeces %s", indeces)
            
        results = koLintResults()
        lines = content.splitlines(1) # keep line terminators
        offset = 0 # the current offset in the document
        for i in range(len(lines)):
            line = lines[i]
            while indeces and indeces[0] < offset + len(line):
                index = indeces.pop(0) # this index is on this line
                r = KoLintResult()
                r.description = "This character cannot be represented with "\
                                "the current encoding: '%s'"\
                                % encoding.python_encoding_name
                r.lineStart = i+1
                r.lineEnd = i+1
                r.columnStart = index - offset + 1
                r.columnEnd = r.columnStart + 1
                log.debug("encoding error: index=%d: %d,%d-%d,%d", index,
                          r.lineStart, r.columnStart, r.lineEnd, r.columnEnd)
                r.severity = r.SEV_ERROR
                results.addResult(r)
            if not indeces:
                break
            offset += len(line)
        else:
            raise ValueError("Did not find line and column for one or "
                             "more indeces in content: %s" % indeces)

        return results
示例#11
0
    def _TclPro_lint(self, lInput, lOutput):
        # TclPro output has the following header info:
        ###################
        #TclPro -- Version 1.4.1
        #Copyright (C) Ajuba Solutions 1998-2001. All rights reserved.
        #This product is registered to: <user name>
        #
        #scanning: <filename>
        #checking: <filename>
        #<filename>:<lineNo> (<errorName>) <errorText>
        #<commandWithError>
        #<caret at col in command where error is>
        #[repeat above three until no more errors]
        ###################
        # The 'checking' line exists when the -onepass option isn't used
        i = 1
        lastCol = -1
        lastLine = -1
        results = koLintResults()
        numLines = len(lOutput)
        while i < numLines:
            match = re.search(self._tclProRe, lOutput[i])
            if not match:
                # We expect the first few lines to not match, while we
                # skip the header lines
                i += 1
                # But if too many lines aren't matching, then we must have
                # unrecognizable input
                if i > 8:
                    log.warn("couldn't recognize Tcl linter output format")
                    break
                continue
            if i+2 >= numLines:
                log.error("unexpected return data format: short data")
                return
            cmd = lOutput[i+1].rstrip()
            col = lOutput[i+2].find('^')
            if col == -1:
                if i+3 == numLines:
                    log.error("unexpected return data format: short data")
                    return
                col = lOutput[i+3].find('^')
                if col == -1:
                    log.warn("No column indicator following line %d:%r", i, lOutput[i])
                    i += 1
                    continue
                cmd = lOutput[i+2].rstrip()
                parseLineOffset = 1
            else:
                parseLineOffset = 0
            lineNo = match.group(1)
            # lInput is zero-based, whereas text display lines start at one,
            # so we adjust lineNo down one here.
            lineNo = int(lineNo) - 1
            if lineNo != lastLine:
                lastLine = lineNo
                lastCol = 0

            if col == -1:
                col = len(lInput[lineNo].rstrip())
            startCol = lInput[lineNo].find(cmd, lastCol)
            if startCol == -1:
                # It's possible that we are throwing multiple warnings on
                # the same command.  Let's check again, starting at col 0.
                # If something was found, ignore multiple warnings in the
                # same line, otherwise log a problem
                if lastCol == 0 or \
                   lInput[lineNo].find(cmd, 0) == -1:
                    # Looks like we can't figure something out...
                    log.debug('undecipherable lint output: %s,%s "%s" in "%s" last %s' \
                              % (lineNo+1, col, cmd, lInput[lineNo], lastCol))
                i += parseLineOffset + 3
                continue

            #print 'TclLint: %s,%s "%s" in "%s"' \
            #      % (lineNo+1, startCol, cmd, lInput[lineNo])

            result = KoLintResult()
            msg = match.group(2)
            result.description = match.group(3).strip()
            result.lineStart = lineNo+1
            # All our warnings stay on one line
            result.lineEnd = result.lineStart
            cmdLen = len(cmd)
            if msg.startswith("warn") or msg.startswith("nonPort"):
                result.severity = result.SEV_WARNING
                # In the warning case, go to the next char that we think
                # ends the word (not precise), starting at the caret.
                endCol = col
                while endCol < cmdLen and cmd[endCol] not in endWordSet:
                    # might want to handle \ escapes
                    endCol += 1
                # readjust for where the command started
                endCol += startCol
                # and bump up the startCol to where the caret indicated
                startCol += col
            else:
                result.severity = result.SEV_ERROR
                # In the error case, highlight the entire command
                # The linter should only give one error per command
                endCol = startCol + cmdLen
            # Adjust by 1 as columns start at 1 for the text display
            result.columnStart = startCol + 1
            result.columnEnd = endCol + 1
            results.addResult(result)

            # Set lastCol to properly handle multiple similar code-blocks
            # with errors on the same line.
            lastCol = startCol+1
            i += 3
            # end while
        return results
def PerlWarnsToLintResults(warns, perlfilename, actualFileName, perlcode):
    perllines = perlcode.split('\n')

    # preprocess the perl warnings
    #   - copy up '(Missing semicolon on previous line?)' to previous line
    #   - remove 'perlfilename'
    #XXX it would be nice to find all hints and copy them up
    newwarns = []
    for line in warns:
        # get rid if eols
        line = line[:-1]

        # handle multi-line string literals
        if newwarns and newwarns[-1] and newwarns[-1][-1] == "\r":
            #XXX we should print an EOL symbol
            newwarns[-1] = newwarns[-1][:-1] + '\r' + line
        ## this code is not handling hints correctly. In any case, hints make
        ## the error messages too long for the status bar
        #elif line.find('(Missing semicolon on previous line?)') != -1:
        #      newwarns[-1] = newwarns[-1] + " " + line[1:]
        else:
            newline = line
            newwarns.append(newline)
    warns = newwarns

    results = []
    if type(perlfilename) == unicode:
        perlfilename = perlfilename.encode('utf-8')
    escPerlName = re.escape(perlfilename)
    # Fix bug 96303 (again): Replace any runs of non-ascii characters with unescaped '.*'
    # The other parts of the filename do get escaped.
    perlfilename_ascii_parts = re.split(r'([^\x00-\x7f]+)', perlfilename)
    escaped_even_parts = [
        re.escape(part) for part in perlfilename_ascii_parts[0::2]
    ]
    escPerlName = ".*?".join(escaped_even_parts)
    warnRe = re.compile(
        r'(?P<description>.*) at %s line (?P<lineNum>\d+)(?P<hint>.*)' %
        escPerlName)
    successRe = re.compile(r'%s syntax OK' % escPerlName)
    compilationFailedRe = re.compile(r'Compilation failed in require at %s' %
                                     escPerlName)
    compilationErrorsRe = re.compile(r'%s had compilation errors\.' %
                                     escPerlName)
    beginFailedRe = re.compile(r'BEGIN failed--compilation aborted')

    pendingLines = []
    sawSyntaxOK = False
    sawSyntaxBad = False
    for warn in warns:
        if successRe.match(warn):
            sawSyntaxOK = True
            continue
        match = warnRe.search(warn)
        if match:
            if compilationFailedRe.match(warn) or beginFailedRe.match(
                    warn) or compilationErrorsRe.match(warn):
                sawSyntaxBad = True
                if results:
                    # Don't bother displaying this
                    continue
            lineNum = int(match.group('lineNum'))
            varName = match.groupdict().get('varName', None)
            lr = KoLintResult()

            lr.description = _combineTextParts(
                pendingLines,
                match.group('description') + match.group('hint')).replace(
                    perlfilename, actualFileName)
            pendingLines = []
            while lr.description.endswith("\n"):
                lr.description = lr.description[:-1]

            lr.lineStart = lineNum
            lr.lineEnd = lineNum
            if varName:
                lr.columnStart = perllines[lr.lineStart - 1].find(varName) + 1
                if lr.columnStart == -1:
                    lr.columnEnd = -1
                else:
                    lr.columnEnd = lr.columnStart + len(varName) + 1
            else:
                lr.columnStart = 1
                lr.columnEnd = len(perllines[lr.lineStart - 1]) + 1
            results.append(lr)
        else:
            pendingLines.append(warn)
    if pendingLines and results:
        results[-1].description = _combineTextParts(
            pendingLines,
            results[-1].description).replace(perlfilename, actualFileName)


# XXX
#
# Whatever is caught by the next else block is (according to Aaron) additional information
# re: the last error.  It should be added to the lint warning, but isn't because the
# status bar display isn't smart enough and it looks ugly.
#  Todo: 1) add the extra info to the lint description (possibly add a new attribute to LintResults
#           with this 'metadata'
#        2) Update the status bar display and tooltip display to display the right info.
#  I'm commenting this block out because log.warn's impact speed. --david
#
#        else:
#            if not (successRe.search(warn) or failureRe.search(warn)):
#                log.warn("Skipping Perl warning: %r", warn)

# under some conditions, Perl will spit out messages after the
# "syntax Ok", so check the entire output.

    if results:
        if sawSyntaxOK and not sawSyntaxBad:
            severity = KoLintResult.SEV_WARNING
        elif sawSyntaxBad and not sawSyntaxOK:
            severity = KoLintResult.SEV_ERROR
        elif successRe.search("\n".join(warns)):
            severity = KoLintResult.SEV_WARNING
        else:
            severity = KoLintResult.SEV_ERROR
    lintResults = koLintResults()
    for lr in results:
        lr.severity = severity
        lintResults.addResult(lr)

    return lintResults
示例#13
0
    def lint_with_text(self, request, text):
        if not text.strip():
            return None
        cwd = request.cwd
        env = koprocessutils.getUserEnv()
        settingsDir = env.get("DJANGO_SETTINGS_MODULE", None)
        if not settingsDir:
            # Django wants to do something like "import project.settings", which
            # means "project/settings.py" needs to exist. First, try to find it.
            settingsDir = self._getSettingsDir(cwd)
            # Ultimately, Komodo's Django linter (djangoLinter.py) sets the
            # DJANGO_SETTINGS_MODULE env variable to be the basename of
            # "settingsDir", which needs to be a module in the PYTHONPATH (which
            # the linter will append the dirname of "settingsDir" to). Append
            # ".settings" so when Django tries to do something like
            # "import project.settings", it will behave as expected.
            settingsDir += ".settings"
        if settingsDir:
            # Save the current buffer to a temporary file.
            tmpFileName = tempfile.mktemp()
            fout = open(tmpFileName, 'wb')
            try:
                fout.write(text)
                fout.close()

                #XXX: How to tell whether we're using Python or Python3?
                prefName = "pythonExtraPaths"
                pythonPath = request.prefset.getString(prefName, "")
                pythonPathEnv = env.get("PYTHONPATH", "")
                if pythonPathEnv:
                    if pythonPath:
                        pythonPath += os.pathsep + pythonPathEnv
                    else:
                        pythonPath = pythonPathEnv
                if pythonPath:
                    if sys.platform.startswith("win"):
                        pythonPath = pythonPath.replace('\\', '/')
                    env["PYTHONPATH"] = pythonPath
                elif env.has_key("PYTHONPATH"):
                    del env["PYTHONPATH"]

                # First try to use Python2 to run the django linter. If django
                # is not found, use Python3 instead.
                results = koLintResults()
                pythonExe = self._pythonInfo.getExecutableFromDocument(
                    request.koDoc)
                djangoLinterPath = self._djangoLinterPath
                if pythonExe:
                    p = process.ProcessOpen([pythonExe, "-c", "import django"],
                                            env=env,
                                            stdin=None)
                    output, error = p.communicate()
                    #log.debug("Django output: output:[%s], error:[%s]", output, error)
                    if error.find('ImportError:') >= 0 and \
                       self._python3Info.getExecutableFromDocument(request.koDoc):
                        pythonExe = self._python3Info.getExecutableFromDocument(
                            request.koDoc)
                        djangoLinterPath = self._djangoLinter3Path
                else:
                    pythonExe = self._python3Info.getExecutableFromDocument(
                        request.koDoc)
                    djangoLinterPath = self._djangoLinter3Path
                #log.debug("pythonExe = " + pythonExe)
                #log.debug("djangoLinterPath = " + djangoLinterPath)
                argv = [pythonExe, djangoLinterPath, tmpFileName, settingsDir]
                p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None)
                output, error = p.communicate()
                retval = p.returncode
                #log.debug("Django output: output:[%s], error:[%s], retval:%d", output, error)
            finally:
                os.unlink(tmpFileName)
            if error:
                results.addResult(self._buildResult(text, error))
            elif retval != 0:
                results.addResult(self._buildResult(text, "Unexpected error"))
        else:
            result = KoLintResult()
            result.lineStart = 1
            result.lineEnd = 1
            result.columnStart = 1
            result.columnEnd = 1 + len(text.splitlines(1)[0])
            result.description = "Can't find settings.py for this Django file"
            result.encodedDescription = result.description
            result.severity = result.SEV_ERROR
            results = koLintResults()
            results.addResult(result)
        return results
示例#14
0
def PerlWarnsToLintResults(warns, perlfilename, actualFileName, perlcode):
    perllines = perlcode.split('\n')

    # preprocess the perl warnings
    #   - copy up '(Missing semicolon on previous line?)' to previous line
    #   - remove 'perlfilename'
    #XXX it would be nice to find all hints and copy them up
    newwarns = []
    for line in warns:
        # get rid if eols
        line = line[:-1]
        
        # handle multi-line string literals
        if newwarns and newwarns[-1] and newwarns[-1][-1] == "\r" :
            #XXX we should print an EOL symbol
            newwarns[-1] = newwarns[-1][:-1] + '\r' + line
        ## this code is not handling hints correctly. In any case, hints make
        ## the error messages too long for the status bar
        #elif line.find('(Missing semicolon on previous line?)') != -1:
        #      newwarns[-1] = newwarns[-1] + " " + line[1:]
        else:
            newline = line
            newwarns.append(newline)
    warns = newwarns

    results = []
    if type(perlfilename) == unicode:
        perlfilename = perlfilename.encode('utf-8')
    escPerlName = re.escape(perlfilename)
    # Fix bug 96303 (again): Replace any runs of non-ascii characters with unescaped '.*'
    # The other parts of the filename do get escaped.
    perlfilename_ascii_parts = re.split(r'([^\x00-\x7f]+)', perlfilename)
    escaped_even_parts = [re.escape(part) for part in perlfilename_ascii_parts[0::2]]
    escPerlName = ".*?".join(escaped_even_parts)
    warnRe = re.compile(r'(?P<description>.*) at %s line (?P<lineNum>\d+)(?P<hint>.*)' % escPerlName)
    successRe = re.compile(r'%s syntax OK' % escPerlName)
    compilationFailedRe = re.compile(r'Compilation failed in require at %s' % escPerlName)
    compilationErrorsRe = re.compile(r'%s had compilation errors\.' % escPerlName)
    beginFailedRe = re.compile(r'BEGIN failed--compilation aborted')

    pendingLines = []
    sawSyntaxOK = False
    sawSyntaxBad = False
    for warn in warns:
        if successRe.match(warn):
            sawSyntaxOK = True
            continue
        match = warnRe.search(warn)
        if match:
            if compilationFailedRe.match(warn) or beginFailedRe.match(warn) or compilationErrorsRe.match(warn):
                sawSyntaxBad = True
                if results:
                    # Don't bother displaying this
                    continue
            lineNum = int(match.group('lineNum'))
            varName = match.groupdict().get('varName', None)
            lr = KoLintResult()
            
            lr.description = _combineTextParts(pendingLines, match.group('description') + match.group('hint')).replace(perlfilename, actualFileName)
            pendingLines = []
            while lr.description.endswith("\n"):
                lr.description = lr.description[:-1]
                
            lr.lineStart = lineNum 
            lr.lineEnd = lineNum
            if varName:
                lr.columnStart = perllines[lr.lineStart-1].find(varName) + 1
                if lr.columnStart == -1:
                    lr.columnEnd = -1
                else:
                    lr.columnEnd = lr.columnStart + len(varName) + 1
            else:
                lr.columnStart = 1
                lr.columnEnd = len(perllines[lr.lineStart-1]) + 1
            results.append(lr)
        else:
            pendingLines.append(warn)
    if pendingLines and results:
        results[-1].description = _combineTextParts(pendingLines, results[-1].description).replace(perlfilename, actualFileName)

# XXX
#
# Whatever is caught by the next else block is (according to Aaron) additional information
# re: the last error.  It should be added to the lint warning, but isn't because the
# status bar display isn't smart enough and it looks ugly.
#  Todo: 1) add the extra info to the lint description (possibly add a new attribute to LintResults
#           with this 'metadata'
#        2) Update the status bar display and tooltip display to display the right info.
#  I'm commenting this block out because log.warn's impact speed. --david
#        
#        else:
#            if not (successRe.search(warn) or failureRe.search(warn)):
#                log.warn("Skipping Perl warning: %r", warn)


    # under some conditions, Perl will spit out messages after the
    # "syntax Ok", so check the entire output.
    
    if results:
        if sawSyntaxOK and not sawSyntaxBad:
            severity = KoLintResult.SEV_WARNING
        elif sawSyntaxBad and not sawSyntaxOK:
            severity = KoLintResult.SEV_ERROR
        elif successRe.search("\n".join(warns)):
            severity = KoLintResult.SEV_WARNING
        else:
            severity = KoLintResult.SEV_ERROR
    lintResults = koLintResults()
    for lr in results:
        lr.severity = severity
        lintResults.addResult(lr)

    return lintResults
示例#15
0
    def _TclPro_lint(self, lInput, lOutput):
        # TclPro output has the following header info:
        ###################
        #TclPro -- Version 1.4.1
        #Copyright (C) Ajuba Solutions 1998-2001. All rights reserved.
        #This product is registered to: <user name>
        #
        #scanning: <filename>
        #checking: <filename>
        #<filename>:<lineNo> (<errorName>) <errorText>
        #<commandWithError>
        #<caret at col in command where error is>
        #[repeat above three until no more errors]
        ###################
        # The 'checking' line exists when the -onepass option isn't used
        i = 1
        lastCol = -1
        lastLine = -1
        results = koLintResults()
        numLines = len(lOutput)
        while i < numLines:
            match = re.search(self._tclProRe, lOutput[i])
            if not match:
                # We expect the first few lines to not match, while we
                # skip the header lines
                i += 1
                # But if too many lines aren't matching, then we must have
                # unrecognizable input
                if i > 8:
                    log.warn("couldn't recognize Tcl linter output format")
                    break
                continue
            if i+2 >= numLines:
                log.error("unexpected return data format: short data")
                return
            cmd = lOutput[i+1].rstrip()
            col = lOutput[i+2].find('^')
            if col == -1:
                if i+3 == numLines:
                    log.error("unexpected return data format: short data")
                    return
                col = lOutput[i+3].find('^')
                if col == -1:
                    log.warn("No column indicator following line %d:%r", i, lOutput[i])
                    i += 1
                    continue
                cmd = lOutput[i+2].rstrip()
                parseLineOffset = 1
            else:
                parseLineOffset = 0
            lineNo = match.group(1)
            # lInput is zero-based, whereas text display lines start at one,
            # so we adjust lineNo down one here.
            lineNo = int(lineNo) - 1
            if lineNo != lastLine:
                lastLine = lineNo
                lastCol = 0

            if col == -1:
                col = len(lInput[lineNo].rstrip())
            startCol = lInput[lineNo].find(cmd, lastCol)
            if startCol == -1:
                # It's possible that we are throwing multiple warnings on
                # the same command.  Let's check again, starting at col 0.
                # If something was found, ignore multiple warnings in the
                # same line, otherwise log a problem
                if lastCol == 0 or \
                   lInput[lineNo].find(cmd, 0) == -1:
                    # Looks like we can't figure something out...
                    log.debug('undecipherable lint output: %s,%s "%s" in "%s" last %s' \
                              % (lineNo+1, col, cmd, lInput[lineNo], lastCol))
                i += parseLineOffset + 3
                continue

            #print 'TclLint: %s,%s "%s" in "%s"' \
            #      % (lineNo+1, startCol, cmd, lInput[lineNo])

            result = KoLintResult()
            msg = match.group(2)
            result.description = match.group(3).strip()
            result.lineStart = lineNo+1
            # All our warnings stay on one line
            result.lineEnd = result.lineStart
            cmdLen = len(cmd)
            if msg.startswith("warn") or msg.startswith("nonPort"):
                result.severity = result.SEV_WARNING
                # In the warning case, go to the next char that we think
                # ends the word (not precise), starting at the caret.
                endCol = col
                while endCol < cmdLen and cmd[endCol] not in endWordSet:
                    # might want to handle \ escapes
                    endCol += 1
                # readjust for where the command started
                endCol += startCol
                # and bump up the startCol to where the caret indicated
                startCol += col
            else:
                result.severity = result.SEV_ERROR
                # In the error case, highlight the entire command
                # The linter should only give one error per command
                endCol = startCol + cmdLen
            # Adjust by 1 as columns start at 1 for the text display
            result.columnStart = startCol + 1
            result.columnEnd = endCol + 1
            results.addResult(result)

            # Set lastCol to properly handle multiple similar code-blocks
            # with errors on the same line.
            lastCol = startCol+1
            i += 3
            # end while
        return results
    def lint_with_text(self, request, text):
        if not text.strip():
            return None
        cwd = request.cwd
        env = koprocessutils.getUserEnv()
        settingsDir = env.get("DJANGO_SETTINGS_MODULE", None)
        if not settingsDir:
            # Django wants to do something like "import project.settings", which
            # means "project/settings.py" needs to exist. First, try to find it.
            settingsDir = self._getSettingsDir(cwd)
            # Ultimately, Komodo's Django linter (djangoLinter.py) sets the
            # DJANGO_SETTINGS_MODULE env variable to be the basename of
            # "settingsDir", which needs to be a module in the PYTHONPATH (which
            # the linter will append the dirname of "settingsDir" to). Append
            # ".settings" so when Django tries to do something like
            # "import project.settings", it will behave as expected.
            settingsDir += ".settings"
        if settingsDir:
            # Save the current buffer to a temporary file.
            tmpFileName = tempfile.mktemp()
            fout = open(tmpFileName, 'wb')
            try:
                fout.write(text)
                fout.close()

                #XXX: How to tell whether we're using Python or Python3?
                prefName = "pythonExtraPaths"
                pythonPath =  request.prefset.getString(prefName, "")
                pythonPathEnv = env.get("PYTHONPATH", "")
                if pythonPathEnv:
                    if pythonPath:
                        pythonPath += os.pathsep + pythonPathEnv
                    else:
                        pythonPath = pythonPathEnv
                if pythonPath:
                    if sys.platform.startswith("win"):
                        pythonPath = pythonPath.replace('\\', '/')
                    env["PYTHONPATH"] = pythonPath
                elif env.has_key("PYTHONPATH"):
                    del env["PYTHONPATH"]

                # First try to use Python2 to run the django linter. If django
                # is not found, use Python3 instead.
                results = koLintResults()
                pythonExe = self._pythonInfo.getExecutableFromDocument(request.koDoc)
                djangoLinterPath = self._djangoLinterPath
                if pythonExe:
                    p = process.ProcessOpen([pythonExe, "-c", "import django"], env=env, stdin=None)
                    output, error = p.communicate()
                    #log.debug("Django output: output:[%s], error:[%s]", output, error)
                    if error.find('ImportError:') >= 0 and \
                       self._python3Info.getExecutableFromDocument(request.koDoc):
                        pythonExe = self._python3Info.getExecutableFromDocument(request.koDoc)
                        djangoLinterPath = self._djangoLinter3Path
                else:
                    pythonExe = self._python3Info.getExecutableFromDocument(request.koDoc)
                    djangoLinterPath = self._djangoLinter3Path
                #log.debug("pythonExe = " + pythonExe)
                #log.debug("djangoLinterPath = " + djangoLinterPath)
                argv = [pythonExe, djangoLinterPath,
                        tmpFileName, settingsDir]
                p = process.ProcessOpen(argv, cwd=cwd, env=env, stdin=None)
                output, error = p.communicate()
                retval = p.returncode
                #log.debug("Django output: output:[%s], error:[%s], retval:%d", output, error)
            finally:
                os.unlink(tmpFileName)
            if error:
                results.addResult(self._buildResult(text, error))
            elif retval != 0:
                results.addResult(self._buildResult(text, "Unexpected error"))
        else:
            result = KoLintResult()
            result.lineStart = 1
            result.lineEnd = 1
            result.columnStart = 1
            result.columnEnd = 1 + len(text.splitlines(1)[0])
            result.description = "Can't find settings.py for this Django file"
            result.encodedDescription = result.description
            result.severity = result.SEV_ERROR
            results = koLintResults()
            results.addResult(result)
        return results