mirror of
https://gitee.com/openharmony/napi_generator
synced 2024-11-23 08:20:01 +00:00
add native gen tool
Signed-off-by: gou-jingjing <goujingjing@kaihong.com>
This commit is contained in:
parent
f730eed763
commit
bea45c4e7b
5
OAT.xml
5
OAT.xml
@ -56,8 +56,8 @@ Note:If the text contains special characters, please escape them according to th
|
|||||||
<licensefile></licensefile>
|
<licensefile></licensefile>
|
||||||
<policylist>
|
<policylist>
|
||||||
<policy name="projectPolicy" desc="">
|
<policy name="projectPolicy" desc="">
|
||||||
<policyitem type="copyright" name="Copyright (c) 2024 Shenzhen Kaihong Digital" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
<policyitem type="copyright" name="Copyright (c) 2024 Shenzhen Kaihong Digital" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||||
<policyitem type="copyright" name="Copyright (c) 2023 Shenzhen Kaihong Digital" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
<policyitem type="copyright" name="Copyright (c) 2023 Shenzhen Kaihong Digital" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||||
<policyitem type="copyright" name="Copyright (c) 2022 Shenzhen Kaihong Digital" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
<policyitem type="copyright" name="Copyright (c) 2022 Shenzhen Kaihong Digital" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||||
<policyitem type="copyright" name="Copyright (c) 2022 Guangzhou Digitalchina Information Technology Co., Ltd." path=".*" desc=""/>
|
<policyitem type="copyright" name="Copyright (c) 2022 Guangzhou Digitalchina Information Technology Co., Ltd." path=".*" desc=""/>
|
||||||
</policy>
|
</policy>
|
||||||
@ -65,6 +65,7 @@ Note:If the text contains special characters, please escape them according to th
|
|||||||
<filefilterlist>
|
<filefilterlist>
|
||||||
<filefilter name="defaultFilter" desc="Files not to check">
|
<filefilter name="defaultFilter" desc="Files not to check">
|
||||||
<filteritem type="filename" name="*.mp4" desc="mp4 files"/>
|
<filteritem type="filename" name="*.mp4" desc="mp4 files"/>
|
||||||
|
<filteritem type="filename" name="*.py" desc="python files"/>
|
||||||
<filteritem type="filepath" name="src/generator/src/com/sk/dialog/.*." desc=""/>
|
<filteritem type="filepath" name="src/generator/src/com/sk/dialog/.*." desc=""/>
|
||||||
<filteritem type="filepath" name="napi_IntelliJ_plugin/generator/src/com/sk/dialog/.*." desc=""/>
|
<filteritem type="filepath" name="napi_IntelliJ_plugin/generator/src/com/sk/dialog/.*." desc=""/>
|
||||||
<filteritem type="filepath" name="test/storytest/test.py" desc="GPL or BSD license"/>
|
<filteritem type="filepath" name="test/storytest/test.py" desc="GPL or BSD license"/>
|
||||||
|
@ -18,13 +18,27 @@ Native生成工具支持两种入口,分别是命令行、IntelliJ插件,使
|
|||||||
2.在命令行使用 以下命令运行脚本
|
2.在命令行使用 以下命令运行脚本
|
||||||
|
|
||||||
```
|
```
|
||||||
node ./tool/commandLine/src/main.js 接口文件路径
|
node ./tool/commandLine/src/main.js -f 接口文件路径
|
||||||
```
|
```
|
||||||
|
|
||||||
|
其中,参数详情如下:
|
||||||
|
|
||||||
|
-f, 待转换的.h文件;
|
||||||
|
|
||||||
|
-t, 可选参数,工程目录下测试用例文件Ability.test.ets文件路径,默认路径为.h文件所在工程目录下的
|
||||||
|
|
||||||
|
Ability.test.ets文件路径;
|
||||||
|
|
||||||
|
-i, 可选参数,工程目录下ts声明文件index.s.ts文件路径,默认路径为.h文件所在工程目录下的
|
||||||
|
|
||||||
|
index.d.ts文件路径;
|
||||||
|
|
||||||
|
-o, 可选参数,工程目录下生成的.cpp文件所在文件夹路径,若该目录下不存在.cpp文件则会创建test.cpp文件,默认路径为.h所在工程目录./src/main/cpp路径下;
|
||||||
|
|
||||||
例如:
|
例如:
|
||||||
|
|
||||||
```
|
```
|
||||||
node ./tool/commandLine/src/main.js E:\napi_generator_aboutTest\napi_240329\napi_generator\examples\napitutorials\entry\src\main\cpp\test.h
|
node ./tool/commandLine/src/main.js -f E:\napi_generator_aboutTest\napi_240329\napi_generator\examples\napitutorials\entry\src\main\cpp\test.h
|
||||||
```
|
```
|
||||||
|
|
||||||
3.运行成功后命令行会打印出 Generate success,并在./entry/src/main/cpp会生成test.cpp文件,其中是接口napi层模板;在./entry/src/main/cpp/types/libentry/index.d.ts文件中会追加写入生成的ts接口;在./entrysrc/ohosTest/ets/test/Ability.test.ets生成接口测试代码模板。用户根据自身需求在test.cpp中增加业务代码,并在Ability.test.ets中增加合适断言之后,即可连接开发板并运行测试用例测试验证生成napi代码是否正确。例如:
|
3.运行成功后命令行会打印出 Generate success,并在./entry/src/main/cpp会生成test.cpp文件,其中是接口napi层模板;在./entry/src/main/cpp/types/libentry/index.d.ts文件中会追加写入生成的ts接口;在./entrysrc/ohosTest/ets/test/Ability.test.ets生成接口测试代码模板。用户根据自身需求在test.cpp中增加业务代码,并在Ability.test.ets中增加合适断言之后,即可连接开发板并运行测试用例测试验证生成napi代码是否正确。例如:
|
||||||
@ -38,7 +52,7 @@ res = value0 + value1;
|
|||||||
在Ability.test.ets文件中增加断言:
|
在Ability.test.ets文件中增加断言:
|
||||||
|
|
||||||
```
|
```
|
||||||
expect(result).assertEqual(2.3+3.2)
|
expect(result).assertEqual(2+3)
|
||||||
```
|
```
|
||||||
|
|
||||||
连接开发板,运行Ability.test.ets中的测试用例:
|
连接开发板,运行Ability.test.ets中的测试用例:
|
||||||
|
35
examples/napitutorials/tool/commandLine/src/function.json
Normal file
35
examples/napitutorials/tool/commandLine/src/function.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"directFunction": {
|
||||||
|
"indexTemplete": "export const %s:(%s) => %s;\n",
|
||||||
|
"cppFuncTemplete": "#include \"napi/native_api.h\"\n[include_replace]\n\n[body_replace]\n\nEXTERN_C_START\nstatic napi_value Init(napi_env env, napi_value exports)\n{\n napi_property_descriptor desc[] = {\n [init_replace]\n};\nnapi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);\nreturn exports;\n}\nEXTERN_C_END\n\nstatic napi_module demoModule = {\n .nm_version = 1,\n .nm_flags = 0,\n .nm_filename = nullptr,\n .nm_register_func = Init,\n .nm_modname = \"entry\",\n .nm_priv = ((void*)0),\n .reserved = { 0 },\n};\n\nextern \"C\" __attribute__((constructor)) void RegisterEntryModule(void)\n{\n napi_module_register(&demoModule);\n}",
|
||||||
|
"cppFuncDetails": {
|
||||||
|
"funcInitTemplete": "{ \"%s\" , nullptr, %s, nullptr, nullptr, nullptr, napi_default, nullptr },",
|
||||||
|
"funcBodyTemplete": "static napi_value [funcName](napi_env env, napi_callback_info info)\n{\n[func_getParam_replace]\n [func_return_replace]\n }\n",
|
||||||
|
"funcGetParamTemplete" : "size_t requireArgc = [param_length];\n size_t argc = [param_length];\n napi_value args[[param_length]] = {nullptr};\n napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);\n [getParam_replace]\n ",
|
||||||
|
"funcReturnTemplete" : "[return_type_define]\n // Todo\n // eg. res = value0 + value1;\n napi_value result;\n [return_replace]\n return result;\n",
|
||||||
|
"paramGenTemplete": " napi_valuetype valuetype%s;\n napi_typeof(env, args[%s], &valuetype%s);\n %s value%s;\n [getParam_replace]",
|
||||||
|
"funcParamType": {
|
||||||
|
"int32_t": "napi_get_value_int32(env, args[%s], &value%s);\n",
|
||||||
|
"int64_t": "napi_get_value_int64(env, args[%s], &value%s);\n",
|
||||||
|
"uint32_t": "napi_get_value_uint32(env, args[%s], &value%s);\n",
|
||||||
|
"int": "",
|
||||||
|
"double": "napi_get_value_double(env, args[%s], &value%s);\n",
|
||||||
|
"bool": "napi_get_value_bool(env, args[%s], &value%s);\n",
|
||||||
|
"string": "char buf[1024];\n size_t results;\n napi_get_value_string_utf8(env, args[%s], buf, 1024, &results);\n value%s = buf;\n"
|
||||||
|
},
|
||||||
|
"funcReturnType": {
|
||||||
|
"int32_t": "napi_create_int32(env, res, &result);\n",
|
||||||
|
"int64_t": "napi_create_int64(env, res, &result);\n",
|
||||||
|
"uint32_t": "napi_create_uint32(env, res, &result);\n",
|
||||||
|
"int": "",
|
||||||
|
"size_t": "",
|
||||||
|
"double": "napi_create_double(env, res, &result);\n",
|
||||||
|
"bool": "napi_get_boolean(env, res, &result);\n",
|
||||||
|
"string": "napi_create_string_utf8(env, res, NAPI_AUTO_LENGTH, &result);\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"abilityTestTemplete": "it('assertContain_[random_number]', 0, () => {\n // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.\n hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');\n\n [func_direct_testCase]\n\n // Defines a variety of assertion methods, which are used to declare expected boolean conditions.\n // 断言 如:expect(result).assertEqual(2+3)\n })\n"
|
||||||
|
},
|
||||||
|
"asyncFunction": {
|
||||||
|
}
|
||||||
|
}
|
@ -14,11 +14,47 @@
|
|||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const stdio = require("stdio");
|
||||||
const main = require("./TsGen/tsMain");
|
const main = require("./TsGen/tsMain");
|
||||||
|
|
||||||
|
let ops = stdio.getopt({
|
||||||
|
// 输入的.h文件路径,必填
|
||||||
|
'filename': { key: 'f', args: 1, description: ".h file", default: "" },
|
||||||
|
// 可选参数,可设置默认值
|
||||||
|
'testFilename': { key: 't', args: 1, description: "Ability.test.ets file", default: "" },
|
||||||
|
'indexFilename': { key: 'i', args: 1, description: "index.d.ts file", default: "" },
|
||||||
|
'outCppPath': { key: 'o', args: 1, description: ".cpp dir path", default: "" },
|
||||||
|
});
|
||||||
|
|
||||||
// 获取命令行参数 .h文件路径
|
// 获取命令行参数 .h文件路径
|
||||||
const filePath = process.argv[2] || '';
|
let filePath = ops.filename
|
||||||
let out = './entry/src/main/cpp/types/libentry/'
|
let testFilePath = ops.testFilename
|
||||||
|
let tsFilePath = ops.indexFilename
|
||||||
|
let cppFilePath = ops.outCppPath
|
||||||
|
// 读取文件内容 判断参数是否为空
|
||||||
|
if (filePath !== '') {
|
||||||
|
let fileDir = path.resolve(filePath, '..');
|
||||||
|
let indexFile = findIndexDTS(fileDir);
|
||||||
|
// 若用户没有提供路径 则程序提供默认路径
|
||||||
|
if (!tsFilePath) {
|
||||||
|
tsFilePath = indexFile
|
||||||
|
}
|
||||||
|
if (!testFilePath) {
|
||||||
|
let rootPath = path.resolve(indexFile, '..', '..', '..', '..', '..');
|
||||||
|
testFilePath = path.join(rootPath, 'ohosTest/ets/test/Ability.test.ets');
|
||||||
|
}
|
||||||
|
if(!cppFilePath) {
|
||||||
|
let rootPath = path.resolve(indexFile, '..', '..', '..');
|
||||||
|
cppFilePath = path.join(rootPath, 'test.cpp');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info("filePath: " + filePath)
|
||||||
|
console.info("testFilePath: " + testFilePath)
|
||||||
|
console.info("tsFilePath: " + tsFilePath)
|
||||||
|
console.info("cppFilePath: " + cppFilePath)
|
||||||
|
main.doGenerate(filePath, testFilePath, tsFilePath, cppFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 这个函数接收一个目录的绝对路径作为参数
|
// 这个函数接收一个目录的绝对路径作为参数
|
||||||
function findIndexDTS(currentDir) {
|
function findIndexDTS(currentDir) {
|
||||||
@ -47,12 +83,3 @@ function findIndexDTS(currentDir) {
|
|||||||
console.log('index.d.ts not found in any checked directory.');
|
console.log('index.d.ts not found in any checked directory.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取文件内容
|
|
||||||
if (filePath !== '') {
|
|
||||||
let fileDir = path.resolve(filePath, '..');
|
|
||||||
let out = findIndexDTS(fileDir);
|
|
||||||
if (out !== null) {
|
|
||||||
main.doGenerate(filePath, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,66 +12,17 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
// const { paramGenerate } = require("./param_generate");
|
|
||||||
// const { returnGenerate } = require("./return_generate");
|
|
||||||
const { NapiLog } = require("../tools/NapiLog");
|
const { NapiLog } = require("../tools/NapiLog");
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
|
const fs = require("fs");
|
||||||
const { writeFile } = require("../tools/tool");
|
const { writeFile } = require("../tools/tool");
|
||||||
const re = require("../tools/re");
|
const re = require("../tools/re");
|
||||||
const LENGTH = 10;
|
const LENGTH = 10;
|
||||||
const TWO_DECIMAL = 2;
|
const TWO_DECIMAL = 2;
|
||||||
|
|
||||||
let cppTemplete = `
|
function generateDirectFunction(params, tsFuncName, cppFilePath, directFuncJson) {
|
||||||
#include "napi/native_api.h"
|
|
||||||
[include_replace]
|
|
||||||
static napi_value [funcName](napi_env env, napi_callback_info info)
|
|
||||||
{
|
|
||||||
[body_replace]
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERN_C_START
|
|
||||||
static napi_value Init(napi_env env, napi_value exports)
|
|
||||||
{
|
|
||||||
napi_property_descriptor desc[] = {
|
|
||||||
[init_replace]
|
|
||||||
};
|
|
||||||
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
|
|
||||||
return exports;
|
|
||||||
}
|
|
||||||
EXTERN_C_END
|
|
||||||
|
|
||||||
static napi_module demoModule = {
|
|
||||||
.nm_version = 1,
|
|
||||||
.nm_flags = 0,
|
|
||||||
.nm_filename = nullptr,
|
|
||||||
.nm_register_func = Init,
|
|
||||||
.nm_modname = "entry",
|
|
||||||
.nm_priv = ((void*)0),
|
|
||||||
.reserved = { 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
|
|
||||||
{
|
|
||||||
napi_module_register(&demoModule);
|
|
||||||
}`
|
|
||||||
|
|
||||||
let bodyTemplete = `
|
|
||||||
size_t requireArgc = [param_length];
|
|
||||||
size_t argc = [param_length];
|
|
||||||
napi_value args[[param_length]] = {nullptr};
|
|
||||||
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
|
|
||||||
[getParme_replace]
|
|
||||||
[return_type_define]
|
|
||||||
// Todo
|
|
||||||
// eg. res = value0 + value1;
|
|
||||||
napi_value result;
|
|
||||||
[return_replace]
|
|
||||||
return result;
|
|
||||||
`
|
|
||||||
|
|
||||||
// 暂不考虑interface情况
|
|
||||||
function generateDirectFunction(params, tsFuncName, indexPath) {
|
|
||||||
let funcInfo = {
|
let funcInfo = {
|
||||||
"name": "",
|
"name": "",
|
||||||
"params": [],
|
"params": [],
|
||||||
@ -83,16 +34,15 @@ function generateDirectFunction(params, tsFuncName, indexPath) {
|
|||||||
for(let i in includes) {
|
for(let i in includes) {
|
||||||
includes_replace += util.format('#include %s\n', includes[i])
|
includes_replace += util.format('#include %s\n', includes[i])
|
||||||
}
|
}
|
||||||
// console.info("includes_replace: " + includes_replace)
|
|
||||||
|
|
||||||
// 获取注册的方法名字 (只读取了一个方法 当前只支持一个方法的转换)
|
// 获取注册的方法名字 (只读取了一个方法 当前只支持一个方法的转换)
|
||||||
funcInfo.name = params.functions[0].name
|
funcInfo.name = params.functions[0].name
|
||||||
let funcName_replace = funcInfo.name.substring(0,1).toUpperCase() + funcInfo.name.substring(1,funcInfo.name.length)
|
let serialNum = tsFuncName.substring(0,6)
|
||||||
// console.info("funcName_replace: " + funcName_replace)
|
let funcName_replace = serialNum + funcInfo.name.substring(0,1).toUpperCase() + funcInfo.name.substring(1,funcInfo.name.length)
|
||||||
|
|
||||||
// 方法的注册
|
// 方法的注册
|
||||||
let init_replace = util.format('{ "%s" , nullptr, %s, nullptr, nullptr, nullptr, napi_default, nullptr }', tsFuncName, funcName_replace)
|
let initTemplete = directFuncJson.cppFuncDetails.funcInitTemplete
|
||||||
// console.info("init_replace: " + init_replace)
|
let init_replace = util.format(initTemplete, tsFuncName, funcName_replace)
|
||||||
|
|
||||||
// 分析方法
|
// 分析方法
|
||||||
funcInfo.retType = params.functions[0].rtnType
|
funcInfo.retType = params.functions[0].rtnType
|
||||||
@ -101,76 +51,115 @@ function generateDirectFunction(params, tsFuncName, indexPath) {
|
|||||||
let param = createParam(parseParams[i])
|
let param = createParam(parseParams[i])
|
||||||
funcInfo.params.push(param)
|
funcInfo.params.push(param)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成
|
// 生成
|
||||||
let paramGenTemplete = `
|
let paramGenTemplete = directFuncJson.cppFuncDetails.paramGenTemplete
|
||||||
napi_valuetype valuetype%s;
|
let funcParamType = directFuncJson.cppFuncDetails.funcParamType
|
||||||
napi_typeof(env, args[%s], &valuetype%s);
|
|
||||||
%s value%s;
|
|
||||||
[getParam_replace]
|
|
||||||
`
|
|
||||||
let paramGenResult = ''
|
let paramGenResult = ''
|
||||||
// napi 获取参数
|
// napi 获取参数
|
||||||
for(let i = 0; i < funcInfo.params.length; i++) {
|
for(let i = 0; i < funcInfo.params.length; i++) {
|
||||||
let paramGen = util.format(paramGenTemplete, i, i, i, funcInfo.params[i].type, i)
|
console.info("funcInfo.params[i].type.substring(0,10): " + funcInfo.params[i].type.substring(0,10))
|
||||||
if (funcInfo.params[i].type === 'double' || funcInfo.params[i].type === 'double_t' || funcInfo.params[i].type === 'float') {
|
let paramType = funcInfo.params[i].type === 'size_t'? 'int64_t': funcInfo.params[i].type
|
||||||
let getParam = util.format('napi_get_value_double(env, args[%s], &value%s);', i, i)
|
let paramGen = util.format(paramGenTemplete, i, i, i, paramType, i)
|
||||||
|
if (funcInfo.params[i].type === 'double') {
|
||||||
|
let getParam = util.format(funcParamType.double, i, i)
|
||||||
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
||||||
paramGenResult += paramGen;
|
paramGenResult += paramGen;
|
||||||
} else if (funcInfo.params[i].type === 'uint32_t') {
|
} else if (funcInfo.params[i].type === 'uint32_t') {
|
||||||
let getParam = util.format('napi_get_value_uint32(env, args[%s], &value%s);', i, i)
|
let getParam = util.format(funcParamType.uint32_t, i, i)
|
||||||
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
||||||
paramGenResult += paramGen;
|
paramGenResult += paramGen;
|
||||||
} else if (funcInfo.params[i].type === 'int32_t') {
|
} else if (funcInfo.params[i].type === 'int32_t') {
|
||||||
let getParam = util.format('napi_get_value_int32(env, args[%s], &value%s);', i, i)
|
let getParam = util.format(funcParamType.int32_t, i, i)
|
||||||
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
||||||
paramGenResult += paramGen;
|
paramGenResult += paramGen;
|
||||||
} else if (funcInfo.params[i].type === 'int64_t') {
|
} else if (funcInfo.params[i].type === 'int64_t' || funcInfo.params[i].type === 'size_t') {
|
||||||
let getParam = util.format('napi_get_value_int64_t(env, args[%s], &value%s);', i, i)
|
let getParam = util.format(funcParamType.int64_t, i, i)
|
||||||
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
||||||
paramGenResult += paramGen;
|
paramGenResult += paramGen;
|
||||||
} else if (funcInfo.params[i].type === 'bool') {
|
} else if (funcInfo.params[i].type === 'bool') {
|
||||||
let getParam = util.format('napi_get_value_bool(env, args[%s], &value%s);', i, i)
|
let getParam = util.format(funcParamType.bool, i, i)
|
||||||
|
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
||||||
|
paramGenResult += paramGen;
|
||||||
|
} else if (funcInfo.params[i].type === 'std::string' || funcInfo.params[i].type.substring(0,10) === 'const char') {
|
||||||
|
let getParam = util.format(funcParamType.string, i, i)
|
||||||
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
|
||||||
paramGenResult += paramGen;
|
paramGenResult += paramGen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.info("paramGenResult: " + paramGenResult)
|
|
||||||
// 返回值处理
|
// 返回值处理
|
||||||
let retGenResult = ''
|
let retGenResult = ''
|
||||||
|
let funcReturnType = directFuncJson.cppFuncDetails.funcReturnType
|
||||||
if (funcInfo.retType === 'uint32_t') {
|
if (funcInfo.retType === 'uint32_t') {
|
||||||
retGenResult = 'napi_create_uint32(env, res, &result);'
|
retGenResult = funcReturnType.uint32_t
|
||||||
} else if (funcInfo.retType === 'double' || funcInfo.retType === 'double_t' || funcInfo.retType === 'float') {
|
} else if (funcInfo.retType === 'double') {
|
||||||
retGenResult = 'napi_create_double(env, res, &result);'
|
retGenResult = funcReturnType.double
|
||||||
} else if (funcInfo.retType === 'int32_t') {
|
} else if (funcInfo.retType === 'int32_t') {
|
||||||
retGenResult = 'napi_create_int32(env, res, &result);'
|
retGenResult = funcReturnType.int32_t
|
||||||
} else if (funcInfo.retType === 'int64_t') {
|
} else if (funcInfo.retType === 'int64_t' || funcInfo.retType === 'size_t') {
|
||||||
retGenResult = 'napi_create_int64(env, res, &result);'
|
retGenResult = funcReturnType.int64_t
|
||||||
} else if (funcInfo.retType === 'bool') {
|
} else if (funcInfo.retType === 'bool') {
|
||||||
retGenResult = 'napi_get_boolean(env, res, &result);'
|
retGenResult = funcReturnType.bool
|
||||||
|
} else if (funcInfo.retType === 'std::string' || funcInfo.retType.substring(0,10) === 'const char') {
|
||||||
|
retGenResult = funcReturnType.string
|
||||||
}
|
}
|
||||||
// console.info("retGenResult: " + retGenResult)
|
|
||||||
|
|
||||||
let body_replace = replaceAll(bodyTemplete, '[param_length]', funcInfo.params.length)
|
let bodyTemplete = directFuncJson.cppFuncDetails.funcBodyTemplete
|
||||||
body_replace = replaceAll(body_replace, '[getParme_replace]', paramGenResult)
|
let body_replace = replaceAll(bodyTemplete, '[funcName]', funcName_replace)
|
||||||
if(funcInfo.retType !== 'void') {
|
let funcGetParamTemplete = directFuncJson.cppFuncDetails.funcGetParamTemplete
|
||||||
body_replace = replaceAll(body_replace, '[return_type_define]', funcInfo.retType + ' res;')
|
let genParam_replace = replaceAll(funcGetParamTemplete, '[param_length]', funcInfo.params.length)
|
||||||
|
genParam_replace = replaceAll(genParam_replace, '[getParam_replace]', paramGenResult)
|
||||||
|
if (funcInfo.params.length !== 0) {
|
||||||
|
body_replace = replaceAll(body_replace, '[func_getParam_replace]', genParam_replace)
|
||||||
} else {
|
} else {
|
||||||
body_replace = replaceAll(body_replace, '[return_type_define]', '')
|
body_replace = replaceAll(body_replace, '[func_getParam_replace]', '')
|
||||||
|
}
|
||||||
|
if(funcInfo.retType !== 'void') {
|
||||||
|
let returnType = funcInfo.retType === 'std::string'? 'const char *': funcInfo.retType
|
||||||
|
returnType = returnType === 'size_t'? 'int64_t': returnType
|
||||||
|
let funcReturnTemplete = directFuncJson.cppFuncDetails.funcReturnTemplete
|
||||||
|
let func_return_replace = replaceAll(funcReturnTemplete, '[return_type_define]', returnType + ' res;')
|
||||||
|
func_return_replace = replaceAll(func_return_replace, '[return_replace]', retGenResult)
|
||||||
|
body_replace = replaceAll(body_replace, '[func_return_replace]', func_return_replace)
|
||||||
|
} else {
|
||||||
|
body_replace = replaceAll(body_replace, '[func_return_replace]', '')
|
||||||
}
|
}
|
||||||
body_replace = replaceAll(body_replace, '[return_replace]', retGenResult)
|
body_replace = replaceAll(body_replace, '[return_replace]', retGenResult)
|
||||||
// console.info("body_replace: " + body_replace)
|
|
||||||
|
|
||||||
let cppContent = replaceAll(cppTemplete, '[include_replace]', includes_replace)
|
|
||||||
cppContent = replaceAll(cppContent, '[funcName]', funcName_replace)
|
|
||||||
cppContent = replaceAll(cppContent, '[body_replace]', body_replace)
|
|
||||||
cppContent = replaceAll(cppContent, '[init_replace]', init_replace)
|
|
||||||
// console.info("Last cppContent: " + cppContent)
|
|
||||||
|
|
||||||
// 将内容写入cpp文件
|
// 将内容写入cpp文件
|
||||||
let rootPath = path.resolve(indexPath, '..', '..', '..');
|
// 先判断cppFilePath是否存在,若存在则追加写入内容
|
||||||
let cppFilePath = path.join(rootPath, 'test.cpp');
|
if (fs.existsSync(cppFilePath)) {
|
||||||
// console.info("cppFilePath: " + cppFilePath)
|
// 读取cpp文件内容
|
||||||
writeFile(cppFilePath, cppContent)
|
const cppFileContent = fs.readFileSync(cppFilePath, 'utf8');
|
||||||
|
let includePosition = cppFileContent.indexOf('#include');
|
||||||
|
let includes = includes_replace.split('\n')
|
||||||
|
let newIncludes = ""
|
||||||
|
for (let i = 0; i < includes.length; i++) {
|
||||||
|
if (cppFileContent.indexOf(includes[i]) < 0) {
|
||||||
|
newIncludes += includes[i] + '\n'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let newCppFileContent = cppFileContent
|
||||||
|
if (newIncludes !== "") {
|
||||||
|
// 追加写入#include
|
||||||
|
newCppFileContent = newCppFileContent.slice(0, includePosition) + newIncludes + newCppFileContent.slice(includePosition);
|
||||||
|
}
|
||||||
|
// 追加写入方法体
|
||||||
|
let funcPosition = newCppFileContent.indexOf('EXTERN_C_START')
|
||||||
|
newCppFileContent = newCppFileContent.slice(0, funcPosition) + body_replace + newCppFileContent.slice(funcPosition);
|
||||||
|
|
||||||
|
// 追加写入 方法的初始化
|
||||||
|
let initPosition = newCppFileContent.indexOf('napi_property_descriptor desc[] = {') + 'napi_property_descriptor desc[] = {'.length;
|
||||||
|
newCppFileContent = newCppFileContent.slice(0, initPosition) + '\n ' + init_replace + newCppFileContent.slice(initPosition);
|
||||||
|
writeFile(cppFilePath, newCppFileContent)
|
||||||
|
} else {
|
||||||
|
let cppTemplete = directFuncJson.cppFuncTemplete
|
||||||
|
let cppContent = replaceAll(cppTemplete, '[include_replace]', includes_replace)
|
||||||
|
cppContent = replaceAll(cppContent, '[body_replace]', body_replace)
|
||||||
|
cppContent = replaceAll(cppContent, '[init_replace]', init_replace)
|
||||||
|
// 第一次生成
|
||||||
|
writeFile(cppFilePath, cppContent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceAll(s, sfrom, sto) {
|
function replaceAll(s, sfrom, sto) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -16,51 +16,11 @@ const { NapiLog } = require("../tools/NapiLog");
|
|||||||
const util = require('util');
|
const util = require('util');
|
||||||
const { writeFile, generateRandomInteger } = require("../tools/tool");
|
const { writeFile, generateRandomInteger } = require("../tools/tool");
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const fs = require("fs");
|
||||||
const LENGTH = 10;
|
const LENGTH = 10;
|
||||||
const TWO_DECIMAL = 2;
|
const TWO_DECIMAL = 2;
|
||||||
|
const SERIAL = 5;
|
||||||
let abilityTestTemplete = `
|
const MODTWO = 2;
|
||||||
import hilog from '@ohos.hilog';
|
|
||||||
import testNapi from 'libentry.so';
|
|
||||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
|
||||||
|
|
||||||
export default function abilityTest() {
|
|
||||||
describe('ActsAbilityTest', () => {
|
|
||||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
|
||||||
beforeAll(() => {
|
|
||||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
|
||||||
// This API supports only one parameter: preset action function.
|
|
||||||
})
|
|
||||||
beforeEach(() => {
|
|
||||||
// Presets an action, which is performed before each unit test case starts.
|
|
||||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
|
||||||
// This API supports only one parameter: preset action function.
|
|
||||||
})
|
|
||||||
afterEach(() => {
|
|
||||||
// Presets a clear action, which is performed after each unit test case ends.
|
|
||||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
|
||||||
// This API supports only one parameter: clear action function.
|
|
||||||
})
|
|
||||||
afterAll(() => {
|
|
||||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
|
||||||
// This API supports only one parameter: clear action function.
|
|
||||||
})
|
|
||||||
it('assertContain', 0, () => {
|
|
||||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
|
||||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
|
||||||
let a = 'abc';
|
|
||||||
let b = 'b';
|
|
||||||
|
|
||||||
[func_direct_testCase]
|
|
||||||
|
|
||||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
|
||||||
expect(a).assertContain(b);
|
|
||||||
expect(a).assertEqual(a);
|
|
||||||
// 断言 如:expect(result).assertEqual(2+3)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
// 随机生成浮点数值
|
// 随机生成浮点数值
|
||||||
function generateRandomArbitrary(min, max, fixed) {
|
function generateRandomArbitrary(min, max, fixed) {
|
||||||
@ -77,7 +37,20 @@ function generateRandomBoolValue() {
|
|||||||
return randomBool;
|
return randomBool;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateFuncTestCase(params, tsFuncName, indexPath) {
|
// 随机生成字符串
|
||||||
|
function generateRandomString(length) {
|
||||||
|
let result = '';
|
||||||
|
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
let charactersLength = characters.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateFuncTestCase(params, tsFuncName, testFilePath, directFuncJson) {
|
||||||
let funcInfo = {
|
let funcInfo = {
|
||||||
"name": "",
|
"name": "",
|
||||||
"params": [],
|
"params": [],
|
||||||
@ -92,7 +65,6 @@ function generateFuncTestCase(params, tsFuncName, indexPath) {
|
|||||||
funcInfo.retType = params.functions[0].rtnType
|
funcInfo.retType = params.functions[0].rtnType
|
||||||
let funcParamDefine = ''
|
let funcParamDefine = ''
|
||||||
let funcParamUse = ''
|
let funcParamUse = ''
|
||||||
// let funcParamExpect = ''
|
|
||||||
// 判断函数有几个参数,依次给参数赋值
|
// 判断函数有几个参数,依次给参数赋值
|
||||||
for(let i = 0; i < funcInfo.params.length; i++) {
|
for(let i = 0; i < funcInfo.params.length; i++) {
|
||||||
if (getTestType(funcInfo.params[i].type) === 'int') {
|
if (getTestType(funcInfo.params[i].type) === 'int') {
|
||||||
@ -104,6 +76,9 @@ function generateFuncTestCase(params, tsFuncName, indexPath) {
|
|||||||
} else if (getTestType(funcInfo.params[i].type) === 'bool') {
|
} else if (getTestType(funcInfo.params[i].type) === 'bool') {
|
||||||
funcParamDefine += util.format('let %s = %s\n', funcInfo.params[i].name, generateRandomBoolValue())
|
funcParamDefine += util.format('let %s = %s\n', funcInfo.params[i].name, generateRandomBoolValue())
|
||||||
funcParamUse += funcInfo.params[i].name + ', '
|
funcParamUse += funcInfo.params[i].name + ', '
|
||||||
|
} else if (getTestType(funcInfo.params[i].type) === 'string') {
|
||||||
|
funcParamDefine += util.format('let %s = "%s"\n', funcInfo.params[i].name, generateRandomString(LENGTH))
|
||||||
|
funcParamUse += funcInfo.params[i].name + ', '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 去除调用参数的最后一个','
|
// 去除调用参数的最后一个','
|
||||||
@ -114,17 +89,39 @@ function generateFuncTestCase(params, tsFuncName, indexPath) {
|
|||||||
// 加 hilog 打印
|
// 加 hilog 打印
|
||||||
let hilogContent = util.format('hilog.info(0x0000, "testTag", "Test NAPI %s: ", result);', tsFuncName)
|
let hilogContent = util.format('hilog.info(0x0000, "testTag", "Test NAPI %s: ", result);', tsFuncName)
|
||||||
let func_test_replace = funcParamDefine + callFunc + hilogContent
|
let func_test_replace = funcParamDefine + callFunc + hilogContent
|
||||||
|
let abilityTestTemplete = directFuncJson.abilityTestTemplete
|
||||||
|
// 替换random_number
|
||||||
|
let serialNum = tsFuncName.substring(0,SERIAL)
|
||||||
|
console.info("serialNum: " + serialNum)
|
||||||
let funcTestContent = replaceAll(abilityTestTemplete,'[func_direct_testCase]', func_test_replace)
|
let funcTestContent = replaceAll(abilityTestTemplete,'[func_direct_testCase]', func_test_replace)
|
||||||
|
funcTestContent = replaceAll(funcTestContent, '[random_number]', serialNum)
|
||||||
// let filePath = './entry/src/ohosTest/ets/test/Ability.test.ets'
|
//console.info("funcTestContent: " + funcTestContent)
|
||||||
// 将内容写入Ability.test.ets文件
|
// 将内容写入Ability.test.ets文件
|
||||||
// __dirname //当前文件的绝对路径
|
// 1.追加写入import模块 写在第一个import之前
|
||||||
// ../
|
// 2.追加写入测试用例
|
||||||
// let relativeFilePath = './entry/src/ohosTest/ets/test/Ability.test.ets'
|
|
||||||
let rootPath = path.resolve(indexPath, '..', '..', '..', '..', '..');
|
// writeFile(testFilePath, funcTestContent)
|
||||||
let filePath = path.join(rootPath, 'ohosTest/ets/test/Ability.test.ets');
|
|
||||||
// console.info("filePath: " + filePath)
|
const importContent = "import testNapi from 'libentry.so';"
|
||||||
writeFile(filePath, funcTestContent)
|
writeTestFile(testFilePath, importContent, funcTestContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeTestFile(filePath, importContent, funcTestContent) {
|
||||||
|
// 读取原本文件内容
|
||||||
|
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const importPosition = fileContent.indexOf('import ');
|
||||||
|
let newFileContent = fileContent;
|
||||||
|
// 判断是否有该import语句,没有则添加
|
||||||
|
if (fileContent.indexOf(importContent) < 0) {
|
||||||
|
const newImportStatement = importContent + '\n';
|
||||||
|
newFileContent = fileContent.slice(0, importPosition) + newImportStatement + fileContent.slice(importPosition);
|
||||||
|
}
|
||||||
|
// 追加写入测试用例
|
||||||
|
let testCasePosition = newFileContent.lastIndexOf('})\n}')
|
||||||
|
//console.info("testCasePosition: " + testCasePosition)
|
||||||
|
newFileContent = newFileContent.slice(0, testCasePosition) + funcTestContent + newFileContent.slice(testCasePosition);
|
||||||
|
|
||||||
|
writeFile(filePath, newFileContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceAll(s, sfrom, sto) {
|
function replaceAll(s, sfrom, sto) {
|
||||||
@ -135,20 +132,23 @@ function replaceAll(s, sfrom, sto) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTestType(type) {
|
function getTestType(type) {
|
||||||
if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' || type === 'int64_t' || type === 'int') {
|
if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' ||
|
||||||
|
type === 'int64_t' || type === 'int' || type === 'size_t') {
|
||||||
return 'int'
|
return 'int'
|
||||||
} else if (type === 'double_t' || type === 'double' || type === 'float') {
|
} else if (type === 'double_t' || type === 'double' || type === 'float') {
|
||||||
return 'float'
|
return 'float'
|
||||||
} else if (type === 'bool') {
|
} else if (type === 'bool') {
|
||||||
return 'bool'
|
return 'bool'
|
||||||
|
} else if (type === 'std::string' || type.substring(0,10) === 'const char') {
|
||||||
|
return 'string'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJsType(type) {
|
function getJsType(type) {
|
||||||
if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' || type === 'int64_t' ||
|
if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' || type === 'int64_t' ||
|
||||||
type === 'int' || type === 'double_t' || type === 'double' || type === 'float') {
|
type === 'int' || type === 'double_t' || type === 'double' || type === 'float' || type === 'size_t') {
|
||||||
return 'number'
|
return 'number'
|
||||||
} else if (type === 'const char *' || type === 'std::string') {
|
} else if (type.substring(0,10) === 'const char' || type === 'std::string') {
|
||||||
return 'string'
|
return 'string'
|
||||||
} else if (type === 'bool') {
|
} else if (type === 'bool') {
|
||||||
return 'boolean'
|
return 'boolean'
|
||||||
|
@ -13,58 +13,63 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const MOVE_EIGHTEEN = 18;
|
||||||
|
const MOVE_TWELVE = 12;
|
||||||
|
const MOVE_SIX = 6;
|
||||||
|
|
||||||
function utf8ArrayToStr(array) {
|
function utf8ArrayToStr(array) {
|
||||||
var out, i, len, c;
|
let char2, char3;
|
||||||
var char2, char3;
|
|
||||||
|
|
||||||
out = "";
|
let outStr = "";
|
||||||
len = array.length;
|
let len = array.length;
|
||||||
i = 0;
|
let i = 0;
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
c = array[i++];
|
let ch = array[i++];
|
||||||
switch (c >> 4) {
|
switch (ch >> 4) {
|
||||||
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
||||||
// 0xxxxxxx
|
// 0xxxxxxx
|
||||||
out += String.fromCharCode(c);
|
outStr += String.fromCharCode(ch);
|
||||||
break;
|
break;
|
||||||
case 12: case 13:
|
case 12: case 13:
|
||||||
// 110x xxxx 10xx xxxx
|
// 110x xxxx 10xx xxxx
|
||||||
char2 = array[i++];
|
char2 = array[i++];
|
||||||
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
|
outStr += String.fromCharCode(((ch & 0x1F) << 6) | (char2 & 0x3F));
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
// 1110 xxxx 10xx xxxx 10xx xxxx
|
// 1110 xxxx 10xx xxxx 10xx xxxx
|
||||||
char2 = array[i++];
|
char2 = array[i++];
|
||||||
char3 = array[i++];
|
char3 = array[i++];
|
||||||
out += String.fromCharCode(((c & 0x0F) << 12) |
|
outStr += String.fromCharCode(((ch & 0x0F) << 12) |
|
||||||
((char2 & 0x3F) << 6) |
|
((char2 & 0x3F) << 6) |
|
||||||
((char3 & 0x3F) << 0));
|
((char3 & 0x3F) << 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return outStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringToUint8Array(string, options = { stream: false }) {
|
function stringToUint8Array(string, option = { streamBool: false }) {
|
||||||
if (options.stream) {
|
if (option.streamBool) {
|
||||||
throw new Error(`Failed to encode: the 'stream' option is unsupported.`);
|
throw new Error(`Failed to encode: the 'streamBool' option is unsupported.`);
|
||||||
}
|
}
|
||||||
let pos = 0;
|
|
||||||
const len = string.length;
|
const len = string.length;
|
||||||
let at = 0; // output position
|
let position = 0;
|
||||||
let tlen = Math.max(32, len + (len >> 1) + 7); // 1.5x size
|
// output position
|
||||||
let target = new Uint8Array((tlen >> 3) << 3); // ... but at 8 byte offset
|
let atPos = 0;
|
||||||
|
// 1.5x size
|
||||||
|
let tlength = Math.max(32, len + (len >> 1) + 7);
|
||||||
|
// ... but atPos 8 byte offset
|
||||||
|
let target = new Uint8Array((tlength >> 3) << 3);
|
||||||
|
|
||||||
while (pos < len) {
|
while (position < len) {
|
||||||
let value = string.charCodeAt(pos++);
|
let value = string.charCodeAt(position++);
|
||||||
let isContinue = false;
|
let isContinue = false;
|
||||||
if (value >= 0xd800 && value <= 0xdbff) {
|
if (value >= 0xd800 && value <= 0xdbff) {
|
||||||
if (pos < len) {// high surrogate
|
if (position < len) {// high surrogate
|
||||||
const extra = string.charCodeAt(pos);
|
const extra = string.charCodeAt(position);
|
||||||
if ((extra & 0xfc00) === 0xdc00) {
|
if ((extra & 0xfc00) === 0xdc00) {
|
||||||
++pos;
|
++position;
|
||||||
value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
|
value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,42 +80,42 @@ function stringToUint8Array(string, options = { stream: false }) {
|
|||||||
|
|
||||||
if (!isContinue) {
|
if (!isContinue) {
|
||||||
// expand the buffer if we couldn't write 4 bytes
|
// expand the buffer if we couldn't write 4 bytes
|
||||||
if (at + 4 > target.length) {
|
if (atPos + 4 > target.length) {
|
||||||
tlen += 8; // minimum extra
|
tlength += 8; // minimum extra
|
||||||
tlen *= (1.0 + (pos / string.length) * 2); // take 2x the remaining
|
tlength *= (1.0 + (position / string.length) * 2); // take 2x the remaining
|
||||||
tlen = (tlen >> 3) << 3; // 8 byte offset
|
tlength = (tlength >> 3) << 3; // 8 byte offset
|
||||||
|
|
||||||
target = uint8Array(tlen, target);
|
target = uint8Array(tlength, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
let calculateResult = calculate(value, target, at)
|
let calculateResult = calculate(value, target, atPos)
|
||||||
isContinue = calculateResult[0]
|
isContinue = calculateResult[0]
|
||||||
target = calculateResult[1]
|
target = calculateResult[1]
|
||||||
at = calculateResult[2]
|
atPos = calculateResult[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return target.slice(0, at);
|
return target.slice(0, atPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculate(value, target, at) {
|
function calculate(val, target, at) {
|
||||||
let isContinue = false
|
let isContinue = false
|
||||||
if ((value & 0xffffff80) === 0) { // 1-byte
|
if ((val & 0xffffff80) === 0) { // 1-byte
|
||||||
target[at++] = value; // ASCII
|
target[at++] = val; // ASCII
|
||||||
isContinue = true;
|
isContinue = true;
|
||||||
} else if ((value & 0xfffff800) === 0) { // 2-byte
|
} else if ((val & 0xffe00000) === 0) { // 4-byte
|
||||||
target[at++] = ((value >> 6) & 0x1f) | 0xc0;
|
target[at++] = ((val >> MOVE_EIGHTEEN) & 0x07) | 0xf0;
|
||||||
} else if ((value & 0xffff0000) === 0) { // 3-byte
|
target[at++] = ((val >> MOVE_TWELVE) & 0x3f) | 0x80;
|
||||||
target[at++] = ((value >> 12) & 0x0f) | 0xe0;
|
target[at++] = ((val >> MOVE_SIX) & 0x3f) | 0x80;
|
||||||
target[at++] = ((value >> 6) & 0x3f) | 0x80;
|
} else if ((val & 0xffff0000) === 0) { // 3-byte
|
||||||
} else if ((value & 0xffe00000) === 0) { // 4-byte
|
target[at++] = ((val >> MOVE_TWELVE) & 0x0f) | 0xe0;
|
||||||
target[at++] = ((value >> 18) & 0x07) | 0xf0;
|
target[at++] = ((val >> MOVE_SIX) & 0x3f) | 0x80;
|
||||||
target[at++] = ((value >> 12) & 0x3f) | 0x80;
|
} else if ((val & 0xfffff800) === 0) { // 2-byte
|
||||||
target[at++] = ((value >> 6) & 0x3f) | 0x80;
|
target[at++] = ((val >> MOVE_SIX) & 0x1f) | 0xc0;
|
||||||
} else {
|
} else {
|
||||||
isContinue = true;
|
isContinue = true;
|
||||||
}
|
}
|
||||||
if (!isContinue) {
|
if (!isContinue) {
|
||||||
target[at++] = (value & 0x3f) | 0x80;
|
target[at++] = (val & 0x3f) | 0x80;
|
||||||
}
|
}
|
||||||
return [isContinue, target, at]
|
return [isContinue, target, at]
|
||||||
}
|
}
|
||||||
@ -135,7 +140,7 @@ function writeFile(fn, str) {
|
|||||||
fs.writeFileSync(fn, data);
|
fs.writeFileSync(fn, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendWriteFile(fn, str) {
|
function appendWriteFile(fn, str) {
|
||||||
fs.appendFile(fn, str, 'utf8', err => {
|
fs.appendFile(fn, str, 'utf8', err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -151,9 +156,21 @@ function generateRandomInteger(min, max) {
|
|||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Json文件内容
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function getJsonCfg(jsonFilePath) {
|
||||||
|
let jsonCfg = null; // json 配置文件
|
||||||
|
let jsonFile = fs.readFileSync(jsonFilePath, { encoding: "utf8" });
|
||||||
|
jsonCfg = JSON.parse(jsonFile);
|
||||||
|
return jsonCfg;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
readFile,
|
readFile,
|
||||||
writeFile,
|
writeFile,
|
||||||
appendWriteFile,
|
appendWriteFile,
|
||||||
generateRandomInteger
|
generateRandomInteger,
|
||||||
|
getJsonCfg
|
||||||
}
|
}
|
@ -18,15 +18,15 @@ function search(ss, data) {
|
|||||||
ss = replaceAll(ss, "\\.", "\\.")
|
ss = replaceAll(ss, "\\.", "\\.")
|
||||||
let reg = new RegExp(ss);
|
let reg = new RegExp(ss);
|
||||||
let tt = reg.exec(data);
|
let tt = reg.exec(data);
|
||||||
if (tt == null) return null;
|
if (tt === null || tt === undefined) return null;
|
||||||
let ret = { "regs": [] }
|
let ret = { "regs": [] }
|
||||||
for (let i = 0; i < tt.length; i++) {
|
for (let i = 0; i < tt.length; i++) {
|
||||||
let p = data.indexOf(tt[i]);
|
let p = data.indexOf(tt[i]);
|
||||||
if (tt[i] == null) {
|
if (tt[i] === null || tt[i] === undefined) {
|
||||||
ret["regs"].push([-1, -1])
|
ret.regs.push([-1, -1])
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret["regs"].push([p, p + tt[i].length])
|
ret.regs.push([p, p + tt[i].length])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ function search(ss, data) {
|
|||||||
|
|
||||||
function match(ss, data) {
|
function match(ss, data) {
|
||||||
let tt = search(ss, data)
|
let tt = search(ss, data)
|
||||||
if (tt != null && tt.regs[0][0] == 0) return tt;
|
if ((tt !== null && tt !== undefined) && tt.regs[0][0] === 0) return tt;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
const { NapiLog } = require("../tools/NapiLog");
|
const { NapiLog } = require("../tools/NapiLog");
|
||||||
const { writeFile, appendWriteFile, generateRandomInteger } = require("../tools/Tool");
|
const { writeFile, appendWriteFile, generateRandomInteger, getJsonCfg } = require("../tools/Tool");
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const re = require("../tools/re");
|
const re = require("../tools/re");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const os = require("os");
|
const os = require("os");
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
const readline = require('readline');
|
||||||
const { generateDirectFunction } = require('../napiGen/functionDirect')
|
const { generateDirectFunction } = require('../napiGen/functionDirect')
|
||||||
const { generateFuncTestCase } = require('../napiGen/functionDirectTest')
|
const { generateFuncTestCase } = require('../napiGen/functionDirectTest')
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ function isStringType(cType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isBoolType(cType) {
|
function isBoolType(cType) {
|
||||||
if (cType == 'bool') {
|
if (cType === 'bool') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -121,7 +122,6 @@ function getJsTypeFromC(cType, typeInfo) {
|
|||||||
}
|
}
|
||||||
let jsType = basicC2js(basicCtype)
|
let jsType = basicC2js(basicCtype)
|
||||||
if (typeInfo.array) {
|
if (typeInfo.array) {
|
||||||
// 替换原先的无用format
|
|
||||||
jsType = util.format("Array<%s>", jsType)
|
jsType = util.format("Array<%s>", jsType)
|
||||||
}
|
}
|
||||||
return jsType
|
return jsType
|
||||||
@ -176,8 +176,8 @@ function analyzeRootFunction(rootInfo, parseResult) {
|
|||||||
let parseFunctions = parseResult.functions
|
let parseFunctions = parseResult.functions
|
||||||
// console.info("parseFunctions: " + JSON.stringify(parseFunctions))
|
// console.info("parseFunctions: " + JSON.stringify(parseFunctions))
|
||||||
for(var i = 0; i < parseFunctions.length; ++i) {
|
for(var i = 0; i < parseFunctions.length; ++i) {
|
||||||
|
// 普通方法生成模板
|
||||||
let funcInfo = createFuncInfo(parseFunctions[i], false)
|
let funcInfo = createFuncInfo(parseFunctions[i], false)
|
||||||
|
|
||||||
rootInfo.functions.push(funcInfo)
|
rootInfo.functions.push(funcInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,52 +190,121 @@ function getTab(tabLv) {
|
|||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
|
|
||||||
function genFunction(func, tabLv, needDeclare = false) {
|
function genFunction(func, funcJson) {
|
||||||
let tab = getTab(tabLv)
|
|
||||||
let funcPrefix = func.isClassFunc ? "" : "function "
|
let funcPrefix = func.isClassFunc ? "" : "function "
|
||||||
let funcParams = ""
|
let funcParams = ""
|
||||||
for (var i = 0; i < func.params.length; ++i) {
|
for (var i = 0; i < func.params.length; ++i) {
|
||||||
funcParams += i > 0 ? ", " : ""
|
funcParams += i > 0 ? ", " : ""
|
||||||
funcParams += func.params[i].name + ": " + func.params[i].type
|
funcParams += func.params[i].name + ": " + func.params[i].type
|
||||||
}
|
}
|
||||||
let declareStr = needDeclare ? "declare " : ""
|
|
||||||
|
let indexTemplete = funcJson.directFunction.indexTemplete
|
||||||
tsFuncName = 'KH' + generateRandomInteger(MIN_RANDOM, MAX_RANDOM) + '_' + func.name
|
tsFuncName = 'KH' + generateRandomInteger(MIN_RANDOM, MAX_RANDOM) + '_' + func.name
|
||||||
return util.format("export const %s:(%s) => %s;\n", tsFuncName, funcParams, func.retType)
|
return util.format(indexTemplete, tsFuncName, funcParams, func.retType)
|
||||||
}
|
}
|
||||||
|
|
||||||
function genTsContent(rootInfo) {
|
function genTsContent(rootInfo, funcJson) {
|
||||||
let tsContent = rootInfo.needCallback ? "import { AsyncCallback, Callback } from './../basic';\n\n" : ""
|
let tsContent = rootInfo.needCallback ? "import { AsyncCallback, Callback } from './../basic';\n\n" : ""
|
||||||
|
|
||||||
for(var i = 0; i < rootInfo.functions.length; ++i) {
|
for(var i = 0; i < rootInfo.functions.length; ++i) {
|
||||||
tsContent += genFunction(rootInfo.functions[i], 0, true)
|
tsContent += genFunction(rootInfo.functions[i], funcJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tsContent
|
return tsContent
|
||||||
}
|
}
|
||||||
|
|
||||||
function doGenerate(hFilePath, destDir) {
|
function removeMarco(hFilePath, tempFilePath) {
|
||||||
let parseResult = parseFileAll(hFilePath)
|
// 创建读取文件的流
|
||||||
// console.info("parseResult: " + JSON.stringify(parseResult))
|
const fileStream = fs.createReadStream(hFilePath);
|
||||||
|
// 创建逐行读取的接口
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: fileStream,
|
||||||
|
crlfDelay: Infinity
|
||||||
|
});
|
||||||
|
// 存储处理后的文件内容
|
||||||
|
let processedContent = '';
|
||||||
|
// 逐行读取文件内容并处理
|
||||||
|
rl.on('line', (line) => {
|
||||||
|
let tt = re.match('[A-Z_]+\([A-Za-z_ *]+\)', line)
|
||||||
|
console.info("tt: " + JSON.stringify(tt))
|
||||||
|
if (tt) {
|
||||||
|
console.info("before line: " + line)
|
||||||
|
let removeContent = re.getReg(line, tt.regs[0])
|
||||||
|
line = line.substring(removeContent.length + 1, line.length)
|
||||||
|
let index = line.indexOf(') ')
|
||||||
|
console.info("index: " + index)
|
||||||
|
if (index >= 0) {
|
||||||
|
line = line.substring(0, index) + line.substring(index + 1, line.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processedContent += line + '\n';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 完成读取操作
|
||||||
|
rl.on('close', () => {
|
||||||
|
console.log("processedContent: " + processedContent);
|
||||||
|
writeFile(tempFilePath, processedContent)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doGenerate(hFilePath, testFilePath, tsFilePath, cppFilePath) {
|
||||||
|
let random = generateRandomInteger(MIN_RANDOM, MAX_RANDOM)
|
||||||
|
let tempFileName = '../temp_' + random + '.h'
|
||||||
|
let tempFilePath = path.join(hFilePath, tempFileName)
|
||||||
|
removeMarco(hFilePath, tempFilePath)
|
||||||
|
|
||||||
|
while(!fs.existsSync(tempFilePath)) {
|
||||||
|
await sleep(20); // 延迟 20 毫秒
|
||||||
|
}
|
||||||
|
const fileContent = fs.readFileSync(tempFilePath, 'utf8');
|
||||||
|
console.info("fileContent: " + fileContent)
|
||||||
|
|
||||||
|
let parseResult = parseFileAll(tempFilePath)
|
||||||
|
console.info("parseResult.functions: " + JSON.stringify(parseResult.functions))
|
||||||
|
|
||||||
let rootInfo = {
|
let rootInfo = {
|
||||||
"functions": [],
|
"functions": [],
|
||||||
"needCallback": false
|
"needCallback": false
|
||||||
}
|
}
|
||||||
|
// 普通方法生成一个模板模板
|
||||||
analyzeRootFunction(rootInfo, parseResult)
|
analyzeRootFunction(rootInfo, parseResult)
|
||||||
|
// 如果是class生成一个模板
|
||||||
|
// analyzeRootClass()
|
||||||
|
|
||||||
|
// 读取Json文件
|
||||||
|
let funcJsonPath = path.join(__dirname, '../function.json');
|
||||||
|
console.info("funcJsonPath: " + funcJsonPath)
|
||||||
|
let funcJson = getJsonCfg(funcJsonPath);
|
||||||
|
|
||||||
let hfileName = path.basename(hFilePath, ".h")
|
let hfileName = path.basename(hFilePath, ".h")
|
||||||
let tsFilePath = destDir
|
let tsContent = genTsContent(rootInfo, funcJson)
|
||||||
let tsContent = genTsContent(rootInfo)
|
|
||||||
console.info("tsContent: " + tsContent)
|
console.info("tsContent: " + tsContent)
|
||||||
appendWriteFile(tsFilePath, '\n' + tsContent)
|
appendWriteFile(tsFilePath, '\n' + tsContent)
|
||||||
|
|
||||||
// 调用napi转换的方法
|
// 调用napi转换的方法
|
||||||
generateDirectFunction(parseResult, tsFuncName, destDir)
|
generateDirectFunction(parseResult, tsFuncName, cppFilePath, funcJson.directFunction)
|
||||||
|
|
||||||
// 生成测试用例
|
// 生成测试用例
|
||||||
generateFuncTestCase(parseResult, tsFuncName, destDir)
|
generateFuncTestCase(parseResult, tsFuncName, testFilePath, funcJson.directFunction)
|
||||||
|
|
||||||
|
// 删除生成的中间文件
|
||||||
|
clearTmpFile(tempFilePath)
|
||||||
|
|
||||||
console.info('Generate success')
|
console.info('Generate success')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearTmpFile(filePath) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
doGenerate
|
doGenerate
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 工具代码框架介绍
|
## 工具代码框架介绍
|
||||||
|
|
||||||
native生成工具由由C++语法解释器和代码生成器两部分组成。C++语法解释器解析用户输入的.h文件内容,通过C++语法解析,将文件内容分解为类、方法、入参、成员属性等元素;代码生成器根据从语法解析器得到的这些元素,转换为对应的typescript语法的接口、方法、参数代码,生成.ts文件内容;同时通过语法解析器得到的元素,生成.h文件对应的napi框架代码和接口调用测试代码。
|
native生成工具由由C++语法解释器和代码生成器两部分组成。C++语法解释器解析用户输入的.h文件内容,通过C++语法解析,将文件内容分解为类、方法、入参、成员属性等元素;代码生成器根据从语法解析器得到的这些元素,转换为对应的typescript语法的接口、方法、参数代码,生成.ts文件内容;同时通过语法解析器得到的元素,生成.h文件对应的napi框架代码和接口调用测试代码。native生成工具支持命令行和IntelliJ插件,本文主要介绍IntellIJ插件。
|
||||||
|
|
||||||
## 工具开发
|
## 工具开发
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ res = value0 + value1;
|
|||||||
在Ability.test.ets文件中增加断言:
|
在Ability.test.ets文件中增加断言:
|
||||||
|
|
||||||
```
|
```
|
||||||
expect(result).assertEqual(2.3+3.2)
|
expect(result).assertEqual(2+3)
|
||||||
```
|
```
|
||||||
|
|
||||||
连接开发板,运行Ability.test.ets中的测试用例:
|
连接开发板,运行Ability.test.ets中的测试用例:
|
||||||
|
@ -31,6 +31,8 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目文件入口
|
* 项目文件入口
|
||||||
@ -40,8 +42,9 @@ import java.io.InputStreamReader;
|
|||||||
* @version: v1.0.0
|
* @version: v1.0.0
|
||||||
* @since 2024-03-29
|
* @since 2024-03-29
|
||||||
*/
|
*/
|
||||||
public class GenDTS extends AnAction {
|
public class GenDts extends AnAction {
|
||||||
private static final Logger LOG = Logger.getInstance(GenDTS.class);
|
private static final Logger LOG = Logger.getInstance(GenDts.class);
|
||||||
|
|
||||||
private boolean generateSuccess = true;
|
private boolean generateSuccess = true;
|
||||||
private String sErrorMessage = "";
|
private String sErrorMessage = "";
|
||||||
|
|
||||||
@ -58,10 +61,135 @@ public class GenDTS extends AnAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String destPath = file.getPath();
|
String destPath = file.getPath();
|
||||||
// 异步执行
|
|
||||||
runFun(destPath);
|
runFun(destPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(AnActionEvent event) {
|
||||||
|
// 根据所选文件名,判断是否显示生成菜单项
|
||||||
|
VirtualFile file = event.getData(PlatformDataKeys.VIRTUAL_FILE);
|
||||||
|
if (file == null) {
|
||||||
|
event.getPresentation().setEnabledAndVisible(false);
|
||||||
|
} else {
|
||||||
|
event.getPresentation().setEnabledAndVisible(patternFileName(file.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正则匹配所选文件名是否符合规范
|
||||||
|
*
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return boolean 是否匹配
|
||||||
|
*/
|
||||||
|
public static boolean patternFileName(String fileName) {
|
||||||
|
String pattern = "(([a-z_A-Z0-9]+).h)";
|
||||||
|
return Pattern.matches(pattern, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取生成成功结果文件。
|
||||||
|
*
|
||||||
|
* @param process 进程ID
|
||||||
|
*/
|
||||||
|
private void genResultLog(Process process) {
|
||||||
|
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getErrorStream(),
|
||||||
|
StandardCharsets.UTF_8));
|
||||||
|
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream(),
|
||||||
|
StandardCharsets.UTF_8));
|
||||||
|
String sErr = getErrorResult(stdError);
|
||||||
|
String sOut;
|
||||||
|
if (TextUtils.isEmpty(sErr)) {
|
||||||
|
sOut = genInputLog(stdInput);
|
||||||
|
if (!generateIsSuccess(sOut)) {
|
||||||
|
sErrorMessage = sOut;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
generateSuccess = false;
|
||||||
|
sErrorMessage = sErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取生成文本内容。
|
||||||
|
*
|
||||||
|
* @param stdInput input buff
|
||||||
|
* @return 返回当前输入框内容
|
||||||
|
*/
|
||||||
|
private String genInputLog(BufferedReader stdInput) {
|
||||||
|
StringBuilder sOut = new StringBuilder();
|
||||||
|
while (true) {
|
||||||
|
String sTmp;
|
||||||
|
try {
|
||||||
|
if ((sTmp = stdInput.readLine()) == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sOut.append(sTmp).append(getNewline());
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
LOG.error(" genResultLog stdInput error" + ioException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sOut.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取生成失败结果文件。
|
||||||
|
*
|
||||||
|
* @param stdError error buff
|
||||||
|
* @return ErrorResult
|
||||||
|
*/
|
||||||
|
private String getErrorResult(BufferedReader stdError) {
|
||||||
|
StringBuilder sErr = new StringBuilder();
|
||||||
|
while (true) {
|
||||||
|
String sTmp;
|
||||||
|
try {
|
||||||
|
if ((sTmp = stdError.readLine()) == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sErr.append(sTmp).append(getNewline());
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
LOG.error(" genResultLog stdInput error" + ioException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sErr.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取换行符
|
||||||
|
*
|
||||||
|
* @return 换行符
|
||||||
|
*/
|
||||||
|
public static String getNewline() {
|
||||||
|
return System.getProperty("line.separator");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean generateIsSuccess(String sOut) {
|
||||||
|
generateSuccess = sOut.contains("success") || TextUtils.isEmpty(sOut);
|
||||||
|
return generateSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StreamConsumer extends Thread {
|
||||||
|
InputStream is;
|
||||||
|
|
||||||
|
StreamConsumer(InputStream is) {
|
||||||
|
super.setName("StreamConsumer");
|
||||||
|
this.is = is;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
|
||||||
|
BufferedReader br = new BufferedReader(isr);
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
LOG.error("StreamConsumer" + line);
|
||||||
|
}
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
LOG.error("StreamConsumer io error" + ioException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean callExtProcess(String command) throws IOException, InterruptedException {
|
private boolean callExtProcess(String command) throws IOException, InterruptedException {
|
||||||
|
|
||||||
if (TextUtils.isEmpty(command)) {
|
if (TextUtils.isEmpty(command)) {
|
||||||
@ -69,40 +197,20 @@ public class GenDTS extends AnAction {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Process process = Runtime.getRuntime().exec(command);
|
Process process = Runtime.getRuntime().exec(command);
|
||||||
|
genResultLog(process);
|
||||||
// 读取输出流(正常输出)
|
StreamConsumer errConsumer = new StreamConsumer(process.getErrorStream());
|
||||||
new Thread(() -> {
|
StreamConsumer outputConsumer = new StreamConsumer(process.getInputStream());
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
errConsumer.start();
|
||||||
String line;
|
outputConsumer.start();
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
System.out.println(line);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
// 读取错误流(错误输出)
|
|
||||||
new Thread(() -> {
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
System.err.println(line);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
// 等待进程结束
|
|
||||||
int exitCode = process.waitFor();
|
|
||||||
System.out.println("Process exited with code: " + exitCode);
|
|
||||||
|
|
||||||
if (!generateSuccess) {
|
if (!generateSuccess) {
|
||||||
GenNotification.notifyMessage(null, sErrorMessage, "提示", NotificationType.ERROR);
|
GenNotification.notifyMessage(null, sErrorMessage, "提示", NotificationType.ERROR);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errConsumer.join();
|
||||||
|
outputConsumer.join();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +237,7 @@ public class GenDTS extends AnAction {
|
|||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
boolean isNewFile = file.createNewFile();
|
boolean isNewFile = file.createNewFile();
|
||||||
if (!isNewFile) {
|
if (!isNewFile) {
|
||||||
LOG.info("writeTmpFile createNewFile error");
|
LOG.info("writeTmpFile createNewFile error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FileOutputStream fw = new FileOutputStream(file);
|
FileOutputStream fw = new FileOutputStream(file);
|
||||||
@ -175,6 +283,7 @@ public class GenDTS extends AnAction {
|
|||||||
/**
|
/**
|
||||||
* 生成命令行指令
|
* 生成命令行指令
|
||||||
*
|
*
|
||||||
|
* @param hFilePath .h文件路径
|
||||||
* @return 返回命令行执行内容
|
* @return 返回命令行执行内容
|
||||||
*/
|
*/
|
||||||
private String genCommand(String hFilePath) {
|
private String genCommand(String hFilePath) {
|
||||||
@ -193,13 +302,15 @@ public class GenDTS extends AnAction {
|
|||||||
|
|
||||||
File file = new File(tmpDirFile);
|
File file = new File(tmpDirFile);
|
||||||
String command = file.toString();
|
String command = file.toString();
|
||||||
command += " " + hFilePath;
|
command += " -f " + hFilePath;
|
||||||
|
// 判断用户是否输入了 "-o"+cpp文件路径, "-i"+dts文件路径,"-t"+test文件路径 从界面获取
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行主程序入口
|
* 执行主程序入口
|
||||||
*
|
*
|
||||||
|
* @param hFilePath .h文件路径
|
||||||
* @return 执行状态
|
* @return 执行状态
|
||||||
*/
|
*/
|
||||||
public boolean runFun(String hFilePath) {
|
public boolean runFun(String hFilePath) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@ -13,6 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.sk.na.utils;
|
package com.sk.na.utils;
|
||||||
|
|
||||||
import com.intellij.notification.NotificationType;
|
import com.intellij.notification.NotificationType;
|
||||||
import com.intellij.notification.Notification;
|
import com.intellij.notification.Notification;
|
||||||
import com.intellij.notification.NotificationGroupManager;
|
import com.intellij.notification.NotificationGroupManager;
|
||||||
@ -20,13 +21,14 @@ import com.intellij.notification.NotificationGroup;
|
|||||||
import com.intellij.notification.Notifications;
|
import com.intellij.notification.Notifications;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知框
|
* 通知框
|
||||||
*
|
*
|
||||||
* @author: liulongc digitalchina.com
|
* @author: goujingjing
|
||||||
* @see: tool conversion plug-in
|
* @see: tool conversion plug-in
|
||||||
* @version: v1.0.0
|
* @version: v1.0.0
|
||||||
* @since 2022-05-27
|
* @since 2024-04-02
|
||||||
*/
|
*/
|
||||||
public class GenNotification {
|
public class GenNotification {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user