Пример #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
    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
Пример #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 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
Пример #5
0
    def parse(self, filepath, cwd=None):
        results = koLintResults()

        entries = []
        cmd = [self.xpcshell_exe, self.csslint_filepath, filepath]
        stdout = None

        # We only need the stdout result.
        try:
            p = process.ProcessOpen(cmd,
                                    cwd=cwd,
                                    env=self._setLDLibraryPath(),
                                    stdin=None)
            stdout, stderr = p.communicate()
            entries = json.loads(stdout or "[]")
        except:
            log.exception("Problem running xcshell: %r\n,output:%r\n", cmd,
                          stdout)
            return results

        for entry in entries:
            # Convert to Komodo lint result object.
            #print 'entry: %r' % (entry, )
            results.addResult(
                KoLintResult(description=entry.get('description', ''),
                             severity=entry.get('severity', 1),
                             lineStart=entry.get('lineStart', 0),
                             lineEnd=entry.get('lineEnd', -1),
                             columnStart=entry.get('columnStart', 0),
                             columnEnd=entry.get('columnEnd', 0)))

        return results
Пример #6
0
    def _parseWarnings(self, warntext, text, leadingWS):
        """Parse out warnings from the text like the following and return
        a list of KoLintResult's.

        Example output:
            t.py:3: SyntaxWarning: import * only allowed at module level
              def foo():
            t.py:1: DeprecationWarning: the regex module is deprecated; please use the re module
              import regex
        Also sometimes get lines like this:
            t.py: Token Error: ('EOF in multi-line string', (3, 6))
        Note that this is picked up in the SyntaxError processing so we can
        skip that here for now.
        """
        textlines = text.splitlines(1)
        if leadingWS:
            del textlines[0]
        warningRe = re.compile("^(?P<fname>.*?):(?P<line>\d+): (?P<desc>.*)$")
        results = koLintResults()
        for line in warntext.splitlines():
            match = warningRe.match(line)
            if match:
                # Ignore lines that don't match this, e.g. "  def foo():"
                r = KoLintResult()
                lineNo = int(match.group('line'))
                if leadingWS:
                    lineNo -= 1
                koLintResult.createAddResult(results, textlines,
                                             r.SEV_WARNING, lineNo,
                                             match.group('desc'), leadingWS)
        return results
Пример #7
0
 def lint_with_text(self, request, text):
     if self._fmt_cmd_start is None:
         return
     cwd = request.cwd or None
     results = koLintResults()
     tmpfilename = tempfile.mktemp() + ".go"
     fout = open(tmpfilename, 'wb')
     fout.write(text)
     fout.close()
     cmd = self._fmt_cmd_start + [tmpfilename]
     env = koprocessutils.getUserEnv()
     bad_keys = []
     for k, v in env.items():
         if not isinstance(v, (str, unicode)):
             bad_keys.append(k)
     for k in bad_keys:
         del env[k]
     try:
         p = process.ProcessOpen(cmd, cwd=cwd, env=env, stdin=None)
         stdout, stderr = p.communicate()
         if not stderr:
             return results
     except:
         log.exception("Failed to run %s, cwd %r", cmd, cwd)
         return results
     finally:
         os.unlink(tmpfilename)
     errLines = stderr.splitlines(0) # Don't need the newlines.
     textLines = text.splitlines(0)
     for line in errLines:
         m = self._ptn_err.match(line)
         if m:
             fname = m.group(1)
             if tmpfilename not in fname:
                 continue
             lineNo = int(m.group(2))
             columnStart = int(m.group(3))
             desc = m.group(4)
             m1 = self._problem_token.search(desc)
             if m1:
                 columnEnd = columnStart + len(m1.group(1))
             else:
                 columnEnd = columnStart + 1
             result = KoLintResult(description=desc,
                                    severity=SEV_ERROR,
                                    lineStart=lineNo,
                                    lineEnd=lineNo,
                                    columnStart=columnStart,
                                    columnEnd=columnEnd)
             results.addResult(result)
     return results
    def _buildResult(self, text, message):
        inputLines = text.splitlines()
        r = KoLintResult()
        r.severity = r.SEV_ERROR
        r.description = message
        m = re.compile(r'TemplateSyntaxError:\s*(.*)\n').match(message)
        if m:
            message = m.group(1)
            for errorType in self._simple_matchers:
                if errorType in message:
                    if self._do_simple_matcher(
                            self._simple_matchers[errorType], text, r):
                        return r
            for raw_ptn in self._contextual_matchers:
                if not self._compiled_ptns.has_key(raw_ptn):
                    self._compiled_ptns[raw_ptn] = re.compile(raw_ptn)
                ptn = self._compiled_ptns[raw_ptn]
                m = ptn.search(message)
                if m:
                    if self._do_contextual_matcher(
                            self._contextual_matchers[raw_ptn], m.group(1),
                            text, r):
                        return r
            if self._test_for_duplicate_extends(message, text, r):
                return r

            # Special-case contextual pattern has two parts
            m = re.compile(
                r"Could not parse the remainder: '(.*?)' from '(.*?)'").search(
                    message)
            if m:
                part2 = m.group(1)
                part1 = m.group(2)[:-1 * len(part2)]
                ptn = r'%s(%%s)' % (re.escape(part1), )
                res = self._do_contextual_matcher(ptn, part2, text, r)
                if res:
                    return r
        # Let the Unclosed Block Tag message fall through, and highlight
        # last line, since we don't know which open-tag it's referring to
        # Underline the last line for all other unrecognized syntax errors.

        r.columnStart = 1
        problemLineIdx = len(inputLines) - 1
        while problemLineIdx >= 0 and not inputLines[problemLineIdx].strip():
            problemLineIdx -= 1
        if problemLineIdx == -1:
            r.lineStart = r.lineEnd = 1
            r.columnEnd = 1
        else:
            r.lineStart = r.lineEnd = problemLineIdx + 1
            r.columnEnd = len(inputLines[problemLineIdx])
        return r
Пример #9
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)
Пример #10
0
 def _createAddResult(self, results, textlines, errorLines, severity):
     for line in errorLines:
         m = self.warnLinePtn.match(line)
         if m:
             lineNo = int(m.group(2))
             desc = "pyflakes: %s" % (m.group(3), )
             targetLine = textlines[lineNo - 1]
             columnEnd = len(targetLine) + 1
             result = KoLintResult(description=desc,
                                   severity=severity,
                                   lineStart=lineNo,
                                   lineEnd=lineNo,
                                   columnStart=1,
                                   columnEnd=columnEnd)
             results.addResult(result)
Пример #11
0
 def lint_with_text(self, request, text):  #pylint: disable=R0201
     textlines = text.splitlines()
     results = CSSLinter().lint(text, request.koDoc.language)
     lintResults = koLintResults()
     for r in results:
         if r.line_start is None:
             createAddResult(lintResults, textlines, r.status + 1,
                             len(textlines) - 1, r.message)
         else:
             result = KoLintResult(description=r.message,
                                   severity=r.status + 1,
                                   lineStart=r.line_start,
                                   lineEnd=r.line_end,
                                   columnStart=r.col_start + 1,
                                   columnEnd=r.col_end + 1)
             lintResults.addResult(result)
     return lintResults
Пример #12
0
    def _buildResult(self, text, message, filename=None):
        r = KoLintResult()
        r.severity = r.SEV_ERROR
        r.description = message
        
        m = re.match('./(.+\.go):(\d+): (.*)', message)
        if m:
            lint_message_file, line_no, error_message = m.groups()
            if lint_message_file != filename:
                r.description = message
                return r
            line_no = int(line_no)
            line_contents = text.splitlines()[int(line_no)-1].rstrip()
            r.description = error_message
            r.lineStart = r.lineEnd = line_no
            r.columnStart = len(line_contents) - len(line_contents.strip()) + 1
            r.columnEnd = len(line_contents) + 1

        return r
Пример #13
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)
Пример #14
0
    def _buildResult(self, text, message):
        inputLines = text.splitlines()
        r = KoLintResult()
        r.severity = r.SEV_ERROR
        r.description = message
        m = re.compile(r'TemplateSyntaxError:\s*(.*)\n').match(message)
        if m:
            message = m.group(1)
            for errorType in self._simple_matchers:
                if errorType in message:
                    if self._do_simple_matcher(
                        self._simple_matchers[errorType],
                            text, r):
                        return r
            for raw_ptn in self._contextual_matchers:
                if raw_ptn not in self._compiled_ptns:
                    self._compiled_ptns[raw_ptn] = re.compile(raw_ptn)
                ptn = self._compiled_ptns[raw_ptn]
                m = ptn.search(message)
                if m:
                    if self._do_contextual_matcher(self._contextual_matchers[raw_ptn], m.group(1), text, r):
                        return r
            if self._test_for_duplicate_extends(message, text, r):
                return r

            # Special-case contextual pattern has two parts
            m = re.compile(
                r"Could not parse the remainder: '(.*?)' from '(.*?)'").search(message)
            if m:
                part2 = m.group(1)
                part1 = m.group(2)[:-1 * len(part2)]
                ptn = r'%s(%%s)' % (re.escape(part1),)
                res = self._do_contextual_matcher(ptn, part2, text, r)
                if res:
                    return r
        # Let the Unclosed Block Tag message fall through, and highlight
        # last line, since we don't know which open-tag it's referring to
        # Underline the last line for all other unrecognized syntax errors.

        r.columnStart = 1
        problemLineIdx = len(inputLines) - 1
        while problemLineIdx >= 0 and not inputLines[problemLineIdx].strip():
            problemLineIdx -= 1
        if problemLineIdx == -1:
            r.lineStart = r.lineEnd = 1
            r.columnEnd = 1
        else:
            r.lineStart = r.lineEnd = problemLineIdx + 1
            r.columnEnd = len(inputLines[problemLineIdx])
        return r
Пример #15
0
    def parse(self, filepath, cwd=None, text=None):
        results = koLintResults()

        entries = []
        cmd = [self.xpcshell_exe, self.csslint_filepath, filepath]
        stdout = None

        # We only need the stdout result.
        try:
            p = process.ProcessOpen(cmd,
                                    cwd=cwd,
                                    env=self._setEnv(),
                                    stdin=None)
            stdout, stderr = p.communicate()
            entries = json.loads(stdout or "[]")
        except:
            log.exception("Problem running xcshell: %r\n,output:%r\n", cmd,
                          stdout)
            return results

        lines = text.split('\n')

        for entry in entries:
            # Convert to Komodo lint result object.
            #print 'entry: %r' % (entry, )
            line_start = entry.get('lineStart', 0)
            column_start = entry.get('columnStart', 0)
            column_end = entry.get('columnEnd', 0)
            if column_start + 1 == column_end:
                word = re.search('\\w+$',
                                 lines[line_start - 1][0:column_end - 1])
                if word:
                    column_start = word.start() + 1
            results.addResult(
                KoLintResult(description=entry.get('description', ''),
                             severity=entry.get('severity', 1),
                             lineStart=line_start,
                             lineEnd=entry.get('lineEnd', -1),
                             columnStart=column_start,
                             columnEnd=column_end))

        return results
Пример #16
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
Пример #17
0
def _errorResult(description):
    r = KoLintResult()
    r.severity = r.SEV_ERROR
    r.description = description
    return r
Пример #18
0
        while 1:
            index = encodedString.find('?', offset)
            if index == -1:
                break
            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:
Пример #19
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 _fixPerlPart(self, text):
     parts = self._masonMatcher.findall(text)
     if not parts:
         return "", []
     i = 0
     lim = len(parts)
     perlTextParts = []
     masonLintResults = []
     eols = ("\n", "\r\n")
     
     # states
     currTags = []
     perlTags = ('init', 'perl', 'once') # drop code for other tags.
     lineNo = i
     while i < lim:
         part = parts[i]
         if part in eols:
             perlTextParts.append(part)
         elif part.startswith("%") and (i == 0 or parts[i - 1].endswith("\n")):
             m = self._perlLineRE.match(part)
             if not m:
                 perlTextParts.append(self._spaceOutNonNewlines(part))
             else:
                 perlTextParts.append(self._spaceOutNonNewlines(m.group(1)))
                 perlTextParts.append(m.group(2))
         elif part.startswith("<"):
             m = self._blockTagRE.match(part)
             if m:
                 payload = m.group(2)
                 if m.group(1):
                     unexpectedEndTag = None
                     if currTags:
                         currTag = currTags[-1]
                         if currTag == payload:
                             currTags.pop()
                         else:
                             # Recover by removing everything up to and including the tag
                             unexpectedEndTag = currTags[-1]
                             for idx in range(len(currTags) - 1, -1, -1):
                                 if currTags[idx] == payload:
                                     del currTags[idx:-1]
                                     break
                     else:
                         unexpectedEndTag = "not in a tag block"
                     if unexpectedEndTag is not None:
                         lr = KoLintResult()
                         lr.lineStart = lr.lineEnd = lineNo + 1
                         lr.columnStart = 1
                         lr.columnEnd = 1 + len(text.splitlines()[lineNo])
                         if unexpectedEndTag == "not in a tag block":
                             lr.description = "Got end tag %s, not in a tag" % part
                         else:
                             lr.description = "Expected </%%%s>, got %s" % (
                                 unexpectedEndTag, part)
                         lr.encodedDescription = lr.description
                         lr.severity = lr.SEV_WARNING
                         masonLintResults.append(lr)
                 else:
                     currTags.append(payload)
                 perlTextParts.append(self._spaceOutNonNewlines(part))
             else:
                 m = self._exprRE.match(part)
                 if not m:
                     perlTextParts.append(self._spaceOutNonNewlines(part))
                 else:
                     perlTextParts.append(self._spaceOutNonNewlines(m.group(1)))
                     payload = m.group(2)
                     if payload.startswith("#"):
                         perlTextParts.append(payload) # One big comment
                     elif "|" not in payload:
                         perlTextParts.append("print " + payload + ";");
                     else:
                         # Filters aren't perl syntax, so punt
                         perlTextParts.append(self._spaceOutNonNewlines(m.group(2)))
                     perlTextParts.append(self._spaceOutNonNewlines(m.group(3)))
         else:
             # We only copy things out under certain circumstances
             if not currTags or currTags[-1] not in perlTags:
                 perlTextParts.append(self._spaceOutNonNewlines(part))
             else:
                 perlTextParts.append(part)
         i += 1
         lineNo += part.count("\n")
     return "".join(perlTextParts), masonLintResults
Пример #21
0
 while 1:
     index = encodedString.find('?', offset)
     if index == -1:
         break
     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:
Пример #22
0
class KoEsLintLinter(object):
    _com_interfaces_ = [Ci.koILinter]
    _reg_clsid_ = "{00CEDD2B-BE9E-4FD6-A9DE-5405B5B4503D}"
    _reg_contractid_ = "@addons.defman.me/koEsLintLinter;1"
    _reg_categories_ = [("category-komodo-linter", 'JavaScript&type=eslint'),
                        ("category-komodo-linter", 'Node.js&type=eslint'),
                        ("category-komodo-linter", 'JSX&type=eslint')]

    def __init__(self, ):
        self.project = Cc["@activestate.com/koPartService;1"].getService(
            Ci.koIPartService)

    def lint(self, request):
        text = request.content.encode(request.encoding.python_encoding_name)
        return self.lint_with_text(request, text)

    def lint_with_text(self, request, text):
        if not request.prefset.getBoolean("lint_eslint_enabled", False):
            log.debug("EsLint: not enabled")
            return

        is_project = False
        cwd = None
        cmd = []
        config = None

        if self.project.currentProject is not None:
            is_project = True
            cwd = self.project.currentProject.liveDirectory
            log.debug("EsLint: using current project directory")
        else:
            cwd = request.cwd
        log.debug("EsLint: cwd = %s" % (cwd))

        # priority:
        # 1 - node_modules's eslint
        # 2 - eslint binary set by user [fallback]
        # 3 - eslint binary found on $PATH [fallback]
        if "win" in sys.platform:
            eslint = os.path.join(cwd, 'node_modules/.bin/eslint.cmd')
        else:
            eslint = os.path.join(cwd, 'node_modules/.bin/eslint')
        if not os.path.exists(eslint):
            log.debug("EsLint: {} does not exist".format(eslint))
            eslint = request.prefset.getString('eslint_binary', '')
            if not os.path.exists(eslint):
                log.debug("EsLint: eslint executable is not set/not found")
                try:
                    eslint = which.which('eslint')
                    log.debug("EsLint: eslint executable found on $PATH")
                except which.WhichError:
                    log.debug(
                        "EsLint: eslint executable is not found on $PATH")
                    return
            else:
                log.debug("EsLint: eslint executable is set by the user")

        if cwd is not None:
            # priority:
            # 1 - user config in the cwd
            # 2 - user config set by user [fallback]
            for file_format in ['js', 'yml', 'json']:
                config = os.path.join(cwd, '.eslintrc.{}'.format(file_format))
                log.debug(config)
                if os.path.exists(config):
                    break
            if not os.path.exists(config):
                config = request.prefset.getString('eslint_config', '')
        else:
            log.debug("EsLint: cwd is empty")
            return
        if config and os.path.isfile(config):
            cmd = [
                eslint, '--no-color', '--format', 'json', '--config', config
            ]
        else:
            log.info("EsLint: .eslintrc is not found")
            return

        cmd += ['--stdin', '--stdin-filename', request.koDoc.file.encodedPath]

        log.debug("EsLint: command = %s" % (" ".join(cmd)))
        log.debug("EsLint: text = %s" % text)

        env = koprocessutils.getUserEnv()
        cwd = cwd or None
        p = process.ProcessOpen(cmd, cwd=cwd, env=env, stdin=process.PIPE)
        stdout, stderr = p.communicate(input=text)

        results = koLintResults()
        try:
            log.debug("EsLint: stdout = %s" % stdout)
            log.debug("EsLint: stderr = %s" % stderr)
            data = json.loads(stdout)[0]['messages']
        except Exception, e:
            log.warn('Failed to parse the eslint output!')
            log.warn('The output was: {}'.format(stdout))
            return

        for message in data:
            line = message['line']
            column = message['column']
            try:
                column_end = message['endColumn']
            except:
                if column > 1:
                    column -= 1
                column_end = column + 1
            try:
                line_end = message['endLine']
            except:
                line_end = line
            if message['severity'] == 2:
                severity = SEV_ERROR
            elif message['severity'] == 1:
                severity = SEV_WARNING
            else:
                severity = SEV_INFO
            if message['ruleId'] != None:
                description = "%s: %s" % (message['ruleId'],
                                          message['message'])
            else:
                description = message['message']
            result = KoLintResult(description=description,
                                  severity=severity,
                                  lineStart=line,
                                  lineEnd=line_end,
                                  columnStart=column,
                                  columnEnd=column_end)
            results.addResult(result)
        return results
Пример #23
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
Пример #24
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
Пример #25
0
    def _fixPerlPart(self, text):
        parts = self._masonMatcher.findall(text)
        if not parts:
            return "", []
        i = 0
        lim = len(parts)
        perlTextParts = []
        masonLintResults = []
        eols = ("\n", "\r\n")

        # states
        currTags = []
        perlTags = ('init', 'perl', 'once')  # drop code for other tags.
        lineNo = i
        while i < lim:
            part = parts[i]
            if part in eols:
                perlTextParts.append(part)
            elif part.startswith("%") and (i == 0
                                           or parts[i - 1].endswith("\n")):
                m = self._perlLineRE.match(part)
                if not m:
                    perlTextParts.append(self._spaceOutNonNewlines(part))
                else:
                    perlTextParts.append(self._spaceOutNonNewlines(m.group(1)))
                    perlTextParts.append(m.group(2))
            elif part.startswith("<"):
                m = self._blockTagRE.match(part)
                if m:
                    payload = m.group(2)
                    if m.group(1):
                        unexpectedEndTag = None
                        if currTags:
                            currTag = currTags[-1]
                            if currTag == payload:
                                currTags.pop()
                            else:
                                # Recover by removing everything up to and including the tag
                                unexpectedEndTag = currTags[-1]
                                for idx in range(len(currTags) - 1, -1, -1):
                                    if currTags[idx] == payload:
                                        del currTags[idx:-1]
                                        break
                        else:
                            unexpectedEndTag = "not in a tag block"
                        if unexpectedEndTag is not None:
                            lr = KoLintResult()
                            lr.lineStart = lr.lineEnd = lineNo + 1
                            lr.columnStart = 1
                            lr.columnEnd = 1 + len(text.splitlines()[lineNo])
                            if unexpectedEndTag == "not in a tag block":
                                lr.description = "Got end tag %s, not in a tag" % part
                            else:
                                lr.description = "Expected </%%%s>, got %s" % (
                                    unexpectedEndTag, part)
                            lr.encodedDescription = lr.description
                            lr.severity = lr.SEV_WARNING
                            masonLintResults.append(lr)
                    else:
                        currTags.append(payload)
                    perlTextParts.append(self._spaceOutNonNewlines(part))
                else:
                    m = self._exprRE.match(part)
                    if not m:
                        perlTextParts.append(self._spaceOutNonNewlines(part))
                    else:
                        perlTextParts.append(
                            self._spaceOutNonNewlines(m.group(1)))
                        payload = m.group(2)
                        if payload.startswith("#"):
                            perlTextParts.append(payload)  # One big comment
                        elif "|" not in payload:
                            perlTextParts.append("print " + payload + ";")
                        else:
                            # Filters aren't perl syntax, so punt
                            perlTextParts.append(
                                self._spaceOutNonNewlines(m.group(2)))
                        perlTextParts.append(
                            self._spaceOutNonNewlines(m.group(3)))
            else:
                # We only copy things out under certain circumstances
                if not currTags or currTags[-1] not in perlTags:
                    perlTextParts.append(self._spaceOutNonNewlines(part))
                else:
                    perlTextParts.append(part)
            i += 1
            lineNo += part.count("\n")
        return "".join(perlTextParts), masonLintResults
Пример #26
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
Пример #27
0
    def _jslint_with_text(self, request, text, prefSwitchName, prefOptionsName):
        if not text:
            #log.debug("<< no text")
            return
        prefset = request.prefset
        if not prefset.getBooleanPref(prefSwitchName):
            return
        jsfilename, isMacro, datalines = self._make_tempfile_from_text(request, text)
        jsInterp = self._get_js_interp_path()
        jsLintDir = os.path.join(self.koDirs.supportDir, "lint", "javascript")
        jsLintApp = os.path.join(jsLintDir, "lintWrapper.js")
        jsLintBasename = None
        if prefSwitchName == "lintWithJSLint":
            appName = "jslint"
        else:
            appName = "jshint"
        try:
            customJSLint = prefset.getStringPref(appName + "_linter_chooser")
            if customJSLint == "specific":
                p = prefset.getStringPref(appName + "_linter_specific")
                if p and os.path.exists(p):
                    jsLintDir = os.path.dirname(p) + "/"
                    jsLintBasename = os.path.basename(p)
        except:
            log.exception("Problem finding the custom lintjs file")
        options = prefset.getStringPref(prefOptionsName).strip()
        # Lint the temp file, the jsInterp options are described here:
        # https://developer.mozilla.org/en/Introduction_to_the_JavaScript_shell
        cmd = [jsInterp, jsLintApp, "--include=" + jsLintDir]
        if jsLintBasename:
            if prefSwitchName == "lintWithJSLint":
                cmd.append("--jslint-basename=" + jsLintBasename)
            else:
                cmd.append("--jshint-basename=" + jsLintBasename)
        elif prefSwitchName == "lintWithJSHint":
            cmd.append("--jshint")
        if options:
            # Drop empty parts.
            otherParts = [s for s in re.compile(r'\s+').split(options)]
            cmd += [s for s in re.compile(r'\s+').split(options)]
        if request.koDoc.language == "Node.js":
            if not "node=" in options:
                cmd.append("node=1")
        if (prefSwitchName == "lintWithJSHint"
            and not self.strict_option_re.match(options)
            and 'globalstrict=' not in options):
            # jshint tests options.strict !== false, otherwise strict is on
            # Other options are tested as simply !options.strict
            cmd.append('strict=false')

        fd = open(jsfilename)
        cwd = request.cwd or None
        # We only need the stderr result.
        try:
            p = process.ProcessOpen(cmd, cwd=cwd, env=self._setLDLibraryPath(), stdin=fd)
            stdout, stderr = p.communicate()
            if stderr:
                log.warn("Error in jslint/jshint: stderr: %s, command was: %s",
                         stderr, cmd)
            #log.debug("jslint(%s): stdout: %s, stderr: %s", prefSwitchName, stdout, stderr)
            warnLines = stdout.splitlines() # Don't need the newlines.
            i = 0
            outputStart = "++++JSLINT OUTPUT:"
            while i < len(warnLines):
                if outputStart in warnLines[i]:
                    warnLines = warnLines[i + 1:]
                    break
                i += 1
        except:
            log.exception("Problem running GenericJSLinter")
        finally:
            try:
                fd.close()
            except:
                log.error("Problem closing file des(%s)", jsfilename)
            try:
                os.unlink(jsfilename)
            except:
                log.error("Problem deleting file des(%s)", jsfilename)
                
        # 'jslint' error reports come in this form:
        # jslint error: at line \d+ column \d+: explanation
        results = koLintResults()
        msgRe = re.compile("^jslint error: at line (?P<lineNo>\d+) column (?P<columnNo>\d+):\s*(?P<desc>.*?)$")
        numDataLines = len(datalines)
        if len(warnLines) % 2 == 1:
            warnLines.append("")
        for i in range(0, len(warnLines), 2):
            msgLine = warnLines[i]
            evidenceLine = warnLines[i + 1]
            m = msgRe.match(msgLine)
            if m:
                lineNo = int(m.group("lineNo"))
                #columnNo = int(m.group("columnNo"))
                # build lint result object
                result = KoLintResult()
                evidenceLineNo = lineNo
                if evidenceLineNo >= numDataLines:
                    evidenceLineNo = numDataLines - 1
                if evidenceLine in datalines[evidenceLineNo]:
                    lineNo = evidenceLineNo
                    pass
                elif evidenceLineNo > 0 and evidenceLine in datalines[evidenceLineNo - 1]:
                    lineNo = evidenceLineNo - 1
                elif lineNo >= numDataLines:
                    lineNo = numDataLines - 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
                if len(datalines[lineNo]) == 0:
                    while lineNo > 0 and len(datalines[lineNo - 1]) == 0:
                        lineNo -= 1
                result.columnStart =  1
                result.columnEnd = len(datalines[lineNo]) + 1
                result.lineStart = result.lineEnd = lineNo + 1
                result.severity = result.SEV_WARNING
                result.description = m.group("desc")
                results.addResult(result)

        return results
Пример #28
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)
Пример #29
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)
Пример #30
0
    def _jslint_with_text(self, request, text, prefSwitchName,
                          prefOptionsName):
        if not text:
            #log.debug("<< no text")
            return
        prefset = request.prefset
        if not prefset.getBooleanPref(prefSwitchName):
            return
        jsfilename, isMacro, datalines = self._make_tempfile_from_text(
            request, text)
        jsInterp = self._get_js_interp_path()
        jsLintDir = os.path.join(self.koDirs.supportDir, "lint", "javascript")
        jsLintApp = os.path.join(jsLintDir, "lintWrapper.js")
        jsLintBasename = None
        if prefSwitchName == "lintWithJSLint":
            appName = "jslint"
        else:
            appName = "jshint"
        try:
            customJSLint = prefset.getStringPref(appName + "_linter_chooser")
            if customJSLint == "specific":
                p = prefset.getStringPref(appName + "_linter_specific")
                if p and os.path.exists(p):
                    jsLintDir = os.path.dirname(p) + "/"
                    jsLintBasename = os.path.basename(p)
        except:
            log.exception("Problem finding the custom lintjs file")
        options = prefset.getStringPref(prefOptionsName).strip()
        # Lint the temp file, the jsInterp options are described here:
        # https://developer.mozilla.org/en/Introduction_to_the_JavaScript_shell
        cmd = [jsInterp, jsLintApp, "--include=" + jsLintDir]
        if jsLintBasename:
            if prefSwitchName == "lintWithJSLint":
                cmd.append("--jslint-basename=" + jsLintBasename)
            else:
                cmd.append("--jshint-basename=" + jsLintBasename)
        elif prefSwitchName == "lintWithJSHint":
            cmd.append("--jshint")
        if options:
            # Drop empty parts.
            otherParts = [s for s in re.compile(r'\s+').split(options)]
            cmd += [s for s in re.compile(r'\s+').split(options)]
        if request.koDoc.language == "Node.js":
            if not "node=" in options:
                cmd.append("node=1")
        if (prefSwitchName == "lintWithJSHint"
                and not self.strict_option_re.match(options)
                and 'globalstrict=' not in options):
            # jshint tests options.strict !== false, otherwise strict is on
            # Other options are tested as simply !options.strict
            cmd.append('strict=false')

        fd = open(jsfilename)
        cwd = request.cwd or None
        # We only need the stderr result.
        try:
            p = process.ProcessOpen(cmd,
                                    cwd=cwd,
                                    env=self._setLDLibraryPath(),
                                    stdin=fd)
            stdout, stderr = p.communicate()
            if stderr:
                log.warn("Error in jslint/jshint: stderr: %s, command was: %s",
                         stderr, cmd)
            #log.debug("jslint(%s): stdout: %s, stderr: %s", prefSwitchName, stdout, stderr)
            warnLines = stdout.splitlines()  # Don't need the newlines.
            i = 0
            outputStart = "++++JSLINT OUTPUT:"
            while i < len(warnLines):
                if outputStart in warnLines[i]:
                    warnLines = warnLines[i + 1:]
                    break
                i += 1
        except:
            log.exception("Problem running GenericJSLinter")
        finally:
            try:
                fd.close()
            except:
                log.error("Problem closing file des(%s)", jsfilename)
            try:
                os.unlink(jsfilename)
            except:
                log.error("Problem deleting file des(%s)", jsfilename)

        # 'jslint' error reports come in this form:
        # jslint error: at line \d+ column \d+: explanation
        results = koLintResults()
        msgRe = re.compile(
            "^jslint error: at line (?P<lineNo>\d+) column (?P<columnNo>\d+):\s*(?P<desc>.*?)$"
        )
        numDataLines = len(datalines)
        if len(warnLines) % 2 == 1:
            warnLines.append("")
        for i in range(0, len(warnLines), 2):
            msgLine = warnLines[i]
            evidenceLine = warnLines[i + 1]
            m = msgRe.match(msgLine)
            if m:
                lineNo = int(m.group("lineNo"))
                #columnNo = int(m.group("columnNo"))
                # build lint result object
                result = KoLintResult()
                evidenceLineNo = lineNo
                if evidenceLineNo >= numDataLines:
                    evidenceLineNo = numDataLines - 1
                if evidenceLine in datalines[evidenceLineNo]:
                    lineNo = evidenceLineNo
                    pass
                elif evidenceLineNo > 0 and evidenceLine in datalines[
                        evidenceLineNo - 1]:
                    lineNo = evidenceLineNo - 1
                elif lineNo >= numDataLines:
                    lineNo = numDataLines - 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
                if len(datalines[lineNo]) == 0:
                    while lineNo > 0 and len(datalines[lineNo - 1]) == 0:
                        lineNo -= 1
                result.columnStart = 1
                result.columnEnd = len(datalines[lineNo]) + 1
                result.lineStart = result.lineEnd = lineNo + 1
                result.severity = result.SEV_WARNING
                result.description = m.group("desc")
                results.addResult(result)

        return results
Пример #31
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