外部熊

欢迎。本教程将教您如何使用 @external_bear_wrap 修饰器,以便用Python以外的语言编写熊。

备注

本教程假定您已经了解基础知识。如果您是新手,请参阅 Writing Native Bears 部分。

如果您计划创建使用现有工具(也称为Linter)的熊,请参阅 Linter Bears 部分。

这为什么有用呢?

Coala是一个伟大的独立于语言的静电分析工具,用户可以在其中编写自己的静电分析例程。

使用户能够写入外部 bears 这意味着他们可以用自己喜欢的语言编写自己的静电分析例程。

这是怎么回事?

通过使用 @external_bear_wrap 您将通过JSON字符串将所有必要的数据(文件名、行、设置)发送到外部可执行文件 stdin 。之后,分析将在您的可执行文件中进行,该可执行文件可以用 字面意思 任何语言都行。最后,您将不得不提供 Results 通过标准输出在JSON字符串中。

在本教程中,我们将通过2个例子来创建一个非常简单的熊。第一个示例将使用 编译的 语言, C++ ,这将创建一个独立的二进制文件,而在第二个示例中,我们将查看 JS 那需要 node 以便从浏览器中耗尽。

外部熊生成工具

如果您确实不想编写任何Python代码,可以使用以下工具 herecoala-bears-create ,这将为您创建包装器。我们将使用

$ coala-bears-create -ext

以便为熊生成包装纸。

用C++编写一只熊

本教程将创建的熊将检查是否有 科拉 用大写字母拼写的 C 因为这是一个人犯的可怕的错误。

  1. 创建一个新目录并使其成为您的当前工作目录。

  2. coala-bears-create 如上所述,为了为我们的 C++ 熊。用您创建的目录的路径回答第一个问题(因为它应该是当前目录,您可以选择默认值并点击 Enter

  3. 最重要的问题是关于可执行文件名和熊名的问题。使用 coalaCheckBear 对于熊的名字和 coalaCheck_cpp 作为可执行文件名称。

  4. 问题的睡觉对本教程并不重要(语言、开发者姓名和联系信息、许可证等),您可以使用默认值。当系统提示您 settings 回答 no (默认)。脚本运行完毕后,您的当前目录中应该有2个文件: coalaCheckBear.py (包装纸)和 coalaCheckBearTest.py .

  5. 本教程不会重点介绍测试,因此暂时忽略第二个文件。包装器应该类似于下面给出的挡路代码。为了便于解释,一些代码已被清除。

    备注

    这个 LICENSE 指定的仅适用于python代码。您可以按照您认为合适的方式许可您的可执行文件。

    import os
    
    from coalib.bearlib.abstractions.ExternalBearWrap import (
        external_bear_wrap)
    
    
    @external_bear_wrap(executable='coalaCheck_cpp',
                     settings={})
    class coalaCheckBear:
        """
        Checks for coala written with uppercase 'C'
        """
        LANGUAGES = {'All'}
        REQUIREMENTS = {''}
        AUTHORS = {'Me'}
        AUTHORS_EMAILS = {'me@mail.com'}
        LICENSE = 'AGPL'
    
        @staticmethod
        def create_arguments():
            return ()
    
  6. 由于输入将是JSON字符串,因此需要某种JSON类。Nlohmann的JSON库( https://github.com/nlohmann/json )是一个很好的选择,因为它易于集成,并在本教程中使用。

  7. 创造 coalaCheck.cpp 并从测试输入开始。nlohmann的JSON库最好的地方是您可以直接从stdin解析JSON,如下所示:

    #include <iostream>
    
    #include "json.hpp"
    
    using json = nlohmann::json;
    using namespace std;
    
    json in;
    
    int main() {
    
        cin >> in;
    
        cout << in;
    
        return 0;
    }
    
  8. 创建一个 Makefile 。JSON库需要C++11,因此示例 Makefile 看起来像这样:

    build: coalaCheck.cpp
        g++ -std=c++11 -o coalaCheck_cpp coalaCheck.cpp
    
  9. 通过为其提供一个JSON字符串来编译和测试二进制文件。它应该将JSON字符串打印回 stdout .

  10. 阅读有关输入使用的JSON规范的信息 (The JSON Spec )。文件名位于 in["filename"] 行的列表可以在以下位置找到 in["file"] .

  11. 创建一个结果添加函数,还有一个init函数被证明对于初始化输出json非常有用。

    #include <iostream>
    #include <string>
    
    #include "json.hpp"
    
    using json = nlohmann::json;
    using namespace std;
    
    json in;
    json out;
    string origin;
    
    void init_results(string bear_name) {
        origin = bear_name;
        out["results"] = json::array({});
    }
    
    void add_result(string message, int line, int column, int severity) {
        json result = {
            {"origin", origin},
            {"message", message},
            {"affected_code", json::array({{
                {"file", in["filename"]},
                {"start", {
                    {"column", column},
                    {"file", in["filename"]},
                    {"line", line}
                }},
                {"end", {
                    {"column", column+6},
                    {"file", in["filename"]},
                    {"line", line}
                }}
            }})},
            {"severity", severity}
        };
        out["results"] += result;
    }
    
    int main() {
    
        cin >> in;
    
        init_results("coalaCheckBear");
    
        cout << out;
        return 0;
    }
    

    备注

    这个 C++ 运算符和语法不太适合JSON操作,但nlohmann的JSON lib使其尽可能简单。

  12. 遍历各行并检查 "coala" 大写的 "C" . 使用 stringfind 功能如下:

    #include <iostream>
    #include <string>
    
    #include "json.hpp"
    
    using json = nlohmann::json;
    using namespace std;
    
    json in;
    json out;
    string origin;
    
    void init_results(string bear_name) {
        origin = bear_name;
        out["results"] = json::array({});
    }
    
    void add_result(string message, int line, int column, int severity) {
        json result = {
            {"origin", origin},
            {"message", message},
            {"affected_code", json::array({{
                {"file", in["filename"]},
                {"start", {
                    {"column", column},
                    {"file", in["filename"]},
                    {"line", line}
                }},
                {"end", {
                    {"column", column+6},
                    {"file", in["filename"]},
                    {"line", line}
                }}
            }})},
            {"severity", severity}
        };
        out["results"] += result;
    }
    
    int main() {
    
        cin >> in;
    
        init_results("coalaCheckBear");
    
        int i = 0;
        for (auto it=in["file"].begin(); it !=in["file"].end(); it++) {
            i++;
            string line = *it;
            size_t found = line.find("Coala");
            while (found != string::npos) {
                add_result("Did you mean 'coala'?", i, found, 2);
                found = line.find("Coala", found+1);
            }
        }
    
        cout << out;
    
        return 0;
    }
    
  13. 生成可执行文件后,必须将其添加到 PATH 环境变量。可以修改包装器并为其提供完整路径。将当前目录添加到 PATH 像这样:

    $ export PATH=$PATH:$PWD
    

    最后一步是测试一切是否工作正常。这是本教程中使用的测试文件( testfile

  14. 通过运行以下命令执行Bear:

    $ coala -d . -b coalaCheckBear -f testfile
    

备注

如果您跑过 coala 在不修改文件的情况下,Coala会尝试将其缓存不止一次。为了避免这种行为,请添加 --flush-cache 在命令的末尾。

用Javascript和Node编写熊

本教程的这一部分将演示如何使用需要另一个二进制文件(例如,python、bash、node)运行的脚本创建外部Bear。

  1. coala-bears-create -ext 但是供应 node 作为可执行文件名。

    备注

    本教程使用 node v6.2.2 。它应该也适用于旧版本,但我们建议您更新。

    当需要另一个二进制文件来运行源代码时, create_arguments 方法就派上用场了。

  2. 将源代码文件作为参数添加到 create_arguments 方法(以便该命令变为 node coalaCheck.js

    这个 create_arguments 方法返回一个元组,因此如果只添加了一个参数,则必须在末尾使用逗号(例如 (one_item,)

    备注

    这个 LICENSE 指定的仅适用于python代码。您可以按照您认为合适的方式许可您的可执行文件。

    import os
    
    from coalib.bearlib.abstractions.ExternalBearWrap import (
        external_bear_wrap)
    
    
    @external_bear_wrap(executable='node',
                        settings={})
    class coalaCheckBear:
        """
        Checks for coala written with uppercase 'C'
        """
        LANGUAGES = {'All'}
        REQUIREMENTS = {'node'}
        AUTHORS = {'Me'}
        AUTHORS_EMAILS = {'me@mail.com'}
        LICENSE = 'AGPL'
    
        @staticmethod
        def create_arguments():
            return ('coalaCheck.js',)
    
  3. 创造 coalaCheck.js 并添加基本I/O处理。

    var input = "";
    
    console.log = (msg) => {
        process.stdout.write(`${msg}\n`);
    };
    
    process.stdin.setEncoding('utf8');
    
    process.stdin.on('readable', () => {
        var chunk = process.stdin.read();
        if (chunk !== null) {
            input += chunk;
        }
    });
    
    process.stdin.on('end', () => {
        input = JSON.parse(input);
        console.log(JSON.stringify(input));
    });
    
  4. 可以通过运行以下命令测试I/O node coalaCheck.js 并在标准输入中提供有效的JSON字符串。

  5. 添加init和add result函数。

    var out = {};
    var origin;
    
    init_results = (bear_name) => {
        origin = bear_name;
        out["results"] = [];
    };
    
    add_result = (message, line, column, severity) => {
        var result = {
            "origin": origin,
            "message": message,
            "affected_code": [{
                 "file": input["filename"],
                 "start": {
                     "column": column,
                     "file": input["filename"],
                     "line": line
                 },
                 "end": {
                     "column": column+6,
                     "file": input["filename"],
                     "line": line
                 }
            }],
            "severity": severity
        };
        out["results"].push(result)
    };
    
  6. 遍历各行并检查 "coala" 用大写字母拼写的 "C" 。最终源应如下所示:

    var input = "";
    var out = {};
    var origin;
    
    console.log = (msg) => {
        process.stdout.write(`${msg}\n`);
    };
    
    init_results = (bear_name) => {
        origin = bear_name;
        out["results"] = [];
    };
    
    add_result = (message, line, column, severity) => {
        var result = {
            "origin": origin,
            "message": message,
            "affected_code": [{
                 "file": input["filename"],
                 "start": {
                     "column": column,
                     "file": input["filename"],
                     "line": line
                 },
                 "end": {
                     "column": column+6,
                     "file": input["filename"],
                     "line": line
                 }
            }],
            "severity": severity
        };
        out["results"].push(result)
    };
    
    process.stdin.setEncoding('utf8');
    
    process.stdin.on('readable', () => {
        var chunk = process.stdin.read();
        if (chunk !== null) {
            input += chunk;
        }
    });
    
    process.stdin.on('end', () => {
        input = JSON.parse(input);
        init_results("coalaCheckBear");
        for (i in input["file"]) {
            var line = input["file"][i];
            var found = line.indexOf("Coala");
            while (found != -1) {
                add_result("Did you mean 'coala'?",
                           parseInt(i)+1, found+1, 2);
                found = line.indexOf("Coala", found+1)
            }
        }
        console.log(JSON.stringify(out));
    });
    

要运行此Bear,不需要将源代码添加到路径,因为正在运行的二进制文件是 node. Although there is a problem: the argument supplied will be looked up only in the current directory. To fix this you can add the full path of the .js file in the argument list. In this case just run the bear from the same directory as coalaCheck.js. The code for this example can be found here .

JSON规范

Coala将通过stdin以JSON字符串的形式向您发送数据,并且可执行文件必须通过stdout提供JSON字符串。规格如下:

  • 输入JSON规范

类型

描述

文件名

STR

正在分析的文件的名称

文件

列表

行列表形式的文件内容

设置

obj

设置为键:值对

  • 输出JSON规范

类型

描述

结果

列表

结果清单

起源

STR

通常是熊的名字

消息

STR

要向用户显示的消息

affected_code

列表

包含SourceRange对象

文件

STR

文件的名称

开始

obj

受影响代码的起始位置

文件

STR

文件的名称

线

利息

行号

利息

列号

结束

obj

受影响代码的结束位置

文件

STR

文件的名称

线

利息

行号

利息

列号

严重程度

利息

结果的严重程度(0-2)

debug_msg

STR

要在调试日志中显示的消息

additional_info

STR

要显示的其他信息

备注

输出的JSON规范与 coala --json 用途。如果你迷路了,你可以跑 coala --json 在一个文件上并检查结果。