外部熊¶
欢迎。本教程将教您如何使用 @external_bear_wrap
修饰器,以便用Python以外的语言编写熊。
备注
本教程假定您已经了解基础知识。如果您是新手,请参阅 Writing Native Bears 部分。
如果您计划创建使用现有工具(也称为Linter)的熊,请参阅 Linter Bears 部分。
这为什么有用呢?¶
Coala是一个伟大的独立于语言的静电分析工具,用户可以在其中编写自己的静电分析例程。
使用户能够写入外部 bears
这意味着他们可以用自己喜欢的语言编写自己的静电分析例程。
这是怎么回事?¶
通过使用 @external_bear_wrap
您将通过JSON字符串将所有必要的数据(文件名、行、设置)发送到外部可执行文件 stdin
。之后,分析将在您的可执行文件中进行,该可执行文件可以用 字面意思 任何语言都行。最后,您将不得不提供 Results
通过标准输出在JSON字符串中。
在本教程中,我们将通过2个例子来创建一个非常简单的熊。第一个示例将使用 编译的 语言, C++
,这将创建一个独立的二进制文件,而在第二个示例中,我们将查看 JS
那需要 node
以便从浏览器中耗尽。
外部熊生成工具¶
如果您确实不想编写任何Python代码,可以使用以下工具 here , coala-bears-create
,这将为您创建包装器。我们将使用
$ coala-bears-create -ext
以便为熊生成包装纸。
用C++编写一只熊¶
本教程将创建的熊将检查是否有 科拉 用大写字母拼写的 C
因为这是一个人犯的可怕的错误。
创建一个新目录并使其成为您的当前工作目录。
跑
coala-bears-create
如上所述,为了为我们的C++
熊。用您创建的目录的路径回答第一个问题(因为它应该是当前目录,您可以选择默认值并点击Enter
)最重要的问题是关于可执行文件名和熊名的问题。使用
coalaCheckBear
对于熊的名字和coalaCheck_cpp
作为可执行文件名称。问题的睡觉对本教程并不重要(语言、开发者姓名和联系信息、许可证等),您可以使用默认值。当系统提示您
settings
回答no
(默认)。脚本运行完毕后,您的当前目录中应该有2个文件:coalaCheckBear.py
(包装纸)和coalaCheckBearTest.py
.本教程不会重点介绍测试,因此暂时忽略第二个文件。包装器应该类似于下面给出的挡路代码。为了便于解释,一些代码已被清除。
备注
这个
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 ()
由于输入将是JSON字符串,因此需要某种JSON类。Nlohmann的JSON库( https://github.com/nlohmann/json )是一个很好的选择,因为它易于集成,并在本教程中使用。
创造
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; }
创建一个
Makefile
。JSON库需要C++11,因此示例Makefile
看起来像这样:build: coalaCheck.cpp g++ -std=c++11 -o coalaCheck_cpp coalaCheck.cpp
通过为其提供一个JSON字符串来编译和测试二进制文件。它应该将JSON字符串打印回
stdout
.阅读有关输入使用的JSON规范的信息 (The JSON Spec )。文件名位于
in["filename"]
行的列表可以在以下位置找到in["file"]
.创建一个结果添加函数,还有一个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使其尽可能简单。遍历各行并检查
"coala"
大写的"C"
. 使用string
的find
功能如下:#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; }
生成可执行文件后,必须将其添加到
PATH
环境变量。可以修改包装器并为其提供完整路径。将当前目录添加到PATH
像这样:$ export PATH=$PATH:$PWD
最后一步是测试一切是否工作正常。这是本教程中使用的测试文件( testfile )
通过运行以下命令执行Bear:
$ coala -d . -b coalaCheckBear -f testfile
备注
如果您跑过 coala
在不修改文件的情况下,Coala会尝试将其缓存不止一次。为了避免这种行为,请添加 --flush-cache
在命令的末尾。
用Javascript和Node编写熊¶
本教程的这一部分将演示如何使用需要另一个二进制文件(例如,python、bash、node)运行的脚本创建外部Bear。
跑
coala-bears-create -ext
但是供应node
作为可执行文件名。备注
本教程使用
node v6.2.2
。它应该也适用于旧版本,但我们建议您更新。当需要另一个二进制文件来运行源代码时,
create_arguments
方法就派上用场了。将源代码文件作为参数添加到
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',)
创造
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)); });
可以通过运行以下命令测试I/O
node coalaCheck.js
并在标准输入中提供有效的JSON字符串。添加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) };
遍历各行并检查
"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
在一个文件上并检查结果。