add tool plugin

Signed-off-by: gou-jingjing <goujingjing@kaihong.com>
This commit is contained in:
gou-jingjing 2024-04-01 10:39:08 +08:00
parent 3b95ea2266
commit ecde59653b
8 changed files with 532 additions and 0 deletions

View File

@ -0,0 +1,113 @@
# Native生成工具IntelliJ插件开发说明
## 工具代码框架介绍
native生成工具由由C++语法解释器和代码生成器两部分组成。C++语法解释器解析用户输入的.h文件内容通过C++语法解析将文件内容分解为类、方法、入参、成员属性等元素代码生成器根据从语法解析器得到的这些元素转换为对应的typescript语法的接口、方法、参数代码生成.ts文件内容同时通过语法解析器得到的元素生成.h文件对应的napi框架代码和接口调用测试代码。
## 工具开发
### IntelliJ 插件开发说明
#### 环境说明
系统建议Windows 10
#### 开发步骤
##### 环境准备
1.生成native_gen程序
1.1 安装typescript使用管理员身份在napi_generator/examples/napitutorials/tool/commandLine/src目录下执行命令
```
npm i typescript
```
1.2 安装stdio使用管理员身份在napi_generator/examples/napitutorials/tool/commandLine目录下执行命令
```
npm i stdio
```
1.3 安装pkg : 使用管理员身份在napi_generator/examples/napitutorials/tool/commandLine目录下执行命令
```
npm i -g pkg
```
1.4 打包三个版本 : 使用管理员身份执行命令:
```
pkg .
```
执行以上步骤后即可在napi_generator/examples/napitutorials/tool/commandLine目录下生成Windows、linux、mac系统下的可执行程序:
```
native_gen-win.exe、native_gen-linux、native_gen-macos
```
1.4.1可选步骤根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件可执行命令
```
pkg -t node14-win . -o napi_generator-win.exe
```
2.下载header_parser
下载header_parser/windows目录下的header_parser.exe(由于网络原因,可能会导致有的下载链接失效,因此提供了以下三个下载链接)。
[下载链接1](https://gitee.com/link?target=http%3A%2F%2Fftpkaihongdigi.i234.me%3A5000%2Fsharing%2FkBG1c7CvT)
[下载链接2](https://gitee.com/link?target=http%3A%2F%2Fftp.kaihong.com%3A5000%2Fsharing%2FkBG1c7CvT)
[下载链接3](https://gitee.com/link?target=http%3A%2F%2Fftp.kaihongdigi.com%3A5000%2Fsharing%2FkBG1c7CvT)
3.将生成的native_gen-win.exe可执行程序和下载的header_parser.exe拷贝到napi_generator/examples/napitutorials/tool/resources/cmds/win目录下。
4.下载并安装IDEA CommunityIntelliJ IDEA 2021.3.3 (Community Edition、JDK11配置好环境。IDEA Community版本可以左键单击以下链接下载。
[下载链接](https://gitee.com/link?target=https%3A%2F%2Fwww.jetbrains.com%2Fidea%2Fdownload%2F)
5.打开IDEA Community应用程序。 依次点击项目File>Open 选择napi_generator/examples/napitutorials/tool/plugin项目文件夹。
![img](../../../figures/IntelliJ_env_config_open_proj.png)
6.项目打开完成点击File>Project Structure,在出现的界面中点击Project,下图的SDK选择JDK 11Language level也选择版本11选择或者新建complier output目录为项目文件下的out目录。
![img](../../../figures/IntelliJ_env_proj_structure.png)
7.Project Settings > Modules 新建Modules。点击上方“-”删除原有的Modules然后点击“+”选择 New Module。
![img](../../../figures/IntelliJ_env_Proj_Module.png)
8.在New Module对话框中选择IntelliJ Platform Plugin。若Module SDK中无可选SDK请在Module SDK 下拉框中点击 Add IntelliJ Platform Plugin SDK 选择IDEA Community安装目录点击OK。
![img](../../../figures/IntelliJ_env_Proj_Module_New.png)
9.Content root选择~/napi_generator/hdc/ts/ts_IntelliJ_plugin文件夹module name填写generator。点击Finish若出现提示已存在是否覆盖的提示请点“Yes”完成配置。
![img](../../../figures/IntelliJ_env_module_root.png)
10.Modules配置完成后若在SDKs中无相应JDK和Plugin SDK,请点击+号分别添加 Add Java JDK和Add Intellij PlantForm Plugin SDK,Java JDK为java11的安装目录Plugin SDK为 IDEA Community 2021.3.3的安装目录。
![img](../../../figures/IntelliJ_env_config_SDKs.png)
11.若完成以上步骤配置点击OK完成配置。Rebuild项目若IDEA不能点击右上角的运行点击Plugin后下三角选择Edit Configurations...选项Run/Debug Configurations框中Use classpath of moudle选择generator点击ok等待安装完成。
![img](../../../figures/IntelliJ_env_configurations.png)
![img](../../../figures/IntelliJ_env_run_debug.png)
12.点击Intellij IDEA工具右上角Built Project按钮等待工程built完成。
![img](../../../figures/IntelliJ_env_built_pro.png)
13.在IDEA Community中依次点击Build>Prepare All Plugin Modules for development"jar包生成完成后在工具右下角提示jar包生成成功且包含jar包存放位置。
![img](../../../figures/IntelliJ_env_built_jar.png)
![img](../../../figures/IntelliJ_env_built_jar_success.png)

View File

@ -0,0 +1,61 @@
# Native接口生成工具IntelliJ插件使用说明
## 简介
Native生成工具支持两种入口分别是命令行、IntelliJ插件使用者可以根据自己的需要选择合适的工具。
## 工具介绍
通过Native生成工具使用者可以将已有的.h接口文件生成.d.ts文件并生成napi框架代码和接口测试代码。
## IntelliJ插件使用方法
### 依赖
系统建议Windows 10
开发工具DevEco Studio
### 使用指导
1.打开项目工程,以下以打开项目工程为例。
File->Open
选择napi_generator/examples/napitutorials工程后点击OK
2.安装插件File->Settings->Plugins->Installed->Install Plugin from Disk...选择编译生成的generator.jar安装成功之后重启IDE。
![](../../../figures/DevEco_step_pluginsOk.png)
![](../../../figures/DevEco_step_napiPlugins.png)
3.将待转换的.h文件放入该工程目录下任意位置例如将test.h文件放入./entry/src/main/cpp目录下。
4.选择.h文件,点击右键选择Generate Native Frame
![](../../../figures/DevEco_step_nativeGenerate.png)
3.运行成功后插件会弹出消息 Generate Native Successfully
![](../../../figures/DevEco_step_ts_ok.png)
并在./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代码是否正确。例如
在生成的test.cpp模板中 // Todo下增加一行
```
res = value0 + value1;
```
在Ability.test.ets文件中增加断言
```
expect(result).assertEqual(2.3+3.2)
```
连接开发板运行Ability.test.ets中的测试用例
![img](E:/napi_generator_aboutTest/napi_240329/napi_generator/examples/napitutorials/tool/figures/DevEco_env_run_Abilitytest.png)
![img](E:/napi_generator_aboutTest/napi_240329/napi_generator/examples/napitutorials/tool/figures/DevEco_env_Abilitytest_success.png)

View File

@ -0,0 +1,53 @@
<!--
Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<idea-plugin>
<id>com.sk.na</id>
<name>Native Generator</name>
<version>1.0.0</version>
<vendor url="http://kaihong.com/">深圳开鸿数字产业发展有限公司</vendor>
<!-- <description><![CDATA[-->
<!-- <h2>Introduction</h2>-->
<!-- <p>&nbsp;&nbsp;&nbsp;&nbsp;One-click generation of NAPI framework code, business code framework, GN file, etc. according to the ts (typescript) interface file in the user-specified path.<br/></p>-->
<!-- <p>&nbsp;&nbsp;&nbsp;&nbsp;When developing the interface between JS applications and NAPI, the developers of the underlying framework do not need to pay attention to the upper-level application conversion logic such as Nodejs syntax, data type conversion between C++ and JS, and only focus on the underlying business logic. Professional people do professional things. Thus, the development efficiency can be greatly improved</p>-->
<!-- <p><a href="https://gitee.com/openharmony/napi_generator">Sources on Gitee</a></p>-->
<!-- ]]>-->
<!-- </description>-->
<change-notes><![CDATA[
<h2>Features</h2>
]]>
</change-notes>
<idea-version since-build="211.0"/>
<depends>com.intellij.modules.platform</depends>
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<!-- <notificationGroup displayType="BALLOON" id="Generate.Result.Group"/>-->
<!-- <toolWindow id="Generator window" anchor="right" factoryClass="com.sk.dialog.ResutlToolWindowFactory" secondary="true"/>-->
<notificationGroup id="Generate.Result.Group"
displayType="STICKY_BALLOON"/>
</extensions>
<actions>
<!-- Add your actions here -->
<action id="NativeGenerate.gen" class="com.sk.na.ng.GenDTS" text="Generate Native Frame" description="generate cpp files">
<add-to-group group-id="ProjectViewPopupMenu" anchor="first"/>
</action>
</actions>
</idea-plugin>

View File

@ -0,0 +1,4 @@
# 目录说明
此目录用于存放napi_generator-linux可执行文件
[可执行文件下载](http://ftpkaihongdigi.i234.me:5000/fsdownload/PPVcNMgVv/2022-06-13)

View File

@ -0,0 +1,4 @@
# 目录说明
此目录用于存放napi_generator-macos可执行文件
[可执行文件下载](http://ftpkaihongdigi.i234.me:5000/fsdownload/PPVcNMgVv/2022-06-13)

View File

@ -0,0 +1,4 @@
# 目录说明
此目录用于存放napi_generator-win.exe可执行文件
[可执行文件下载](http://ftpkaihongdigi.i234.me:5000/fsdownload/PPVcNMgVv/2022-06-13)

View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sk.na.ng;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.sk.na.utils.GenNotification;
import org.apache.http.util.TextUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 项目文件入口
*
* @author: goujingjing
* @see: tool conversion plug-in
* @version: v1.0.0
* @since 2024-03-29
*/
public class GenDTS extends AnAction {
private static final Logger LOG = Logger.getInstance(GenDTS.class);
private boolean generateSuccess = true;
private String sErrorMessage = "";
@Override
public void actionPerformed(AnActionEvent anActionEvent) {
Project project = anActionEvent.getProject();
// 获取需要处理的.h文件绝对路径
VirtualFile file = anActionEvent.getData(PlatformDataKeys.VIRTUAL_FILE);
if (file == null) {
GenNotification.notifyMessage(project, "", "file is not exist", NotificationType.ERROR);
return;
}
if (project == null) {
return;
}
String destPath = file.getPath();
// 异步执行
runFun(destPath);
}
private boolean callExtProcess(String command) throws IOException, InterruptedException {
if (TextUtils.isEmpty(command)) {
GenNotification.notifyMessage(null, "执行命令文件为空", "空命令行提示", NotificationType.ERROR);
return false;
}
Process process = Runtime.getRuntime().exec(command);
// 读取输出流正常输出
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
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) {
GenNotification.notifyMessage(null, sErrorMessage, "提示", NotificationType.ERROR);
return false;
}
return true;
}
/**
* 赋值可执行文件权限
*
* @param execFn 可执行命令
* @throws IOException 打开文件异常
* @throws InterruptedException 中断异常
*/
private void executable(String execFn) throws IOException, InterruptedException {
callExtProcess("chmod a+x " + execFn);
}
/**
* 拷贝可执行文件到临时文件夹
*
* @param path 目标文件路径
* @param bs 字节内容
* @throws IOException exception
*/
private void writeTmpFile(String path, byte[] bs) throws IOException {
File file = new File(path);
if (!file.exists()) {
boolean isNewFile = file.createNewFile();
if (!isNewFile) {
LOG.info("writeTmpFile createNewFile error");
}
}
FileOutputStream fw = new FileOutputStream(file);
fw.write(bs, 0, bs.length);
fw.close();
}
/**
* 拷贝文件到本地临时目录
*
* @param fileName 文件名
*/
private void copyFileToLocalPath(String fileName) {
String sysName = System.getProperties().getProperty("os.name").toUpperCase();
String tmpDirFile = System.getProperty("java.io.tmpdir");
String execFn;
if (sysName.contains("WIN")) {
execFn = "cmds/win/" + fileName + ".exe";
tmpDirFile += fileName + ".exe";
} else if (sysName.contains("LINUX")) {
execFn = "cmds/linux/" + fileName;
tmpDirFile += fileName;
} else {
execFn = "cmds/mac/" + fileName;
tmpDirFile += fileName;
}
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(execFn)) {
if (inputStream == null) {
throw new IOException("exec File InputStream is Null");
}
byte[] bs = inputStream.readAllBytes();
writeTmpFile(tmpDirFile, bs);
if (sysName.contains("LINUX") || sysName.contains("MAC OS")) {
executable(tmpDirFile);
}
} catch (IOException | InterruptedException e) {
GenNotification.notifyMessage(null, e.getMessage(), "Can not Find File:" + execFn,
NotificationType.ERROR);
LOG.error(e);
}
}
/**
* 生成命令行指令
*
* @return 返回命令行执行内容
*/
private String genCommand(String hFilePath) {
String sysName = System.getProperties().getProperty("os.name").toUpperCase();
String tmpDirFile = System.getProperty("java.io.tmpdir");
if (sysName.contains("WIN")) {
copyFileToLocalPath("native_gen-win");
tmpDirFile += "native_gen-win.exe";
} else if (sysName.contains("LINUX")) {
copyFileToLocalPath("native_gen-linux");
tmpDirFile += "native_gen-linux";
} else {
copyFileToLocalPath("native_gen-macos");
tmpDirFile += "native_gen-macos";
}
File file = new File(tmpDirFile);
String command = file.toString();
command += " " + hFilePath;
return command;
}
/**
* 执行主程序入口
*
* @return 执行状态
*/
public boolean runFun(String hFilePath) {
copyFileToLocalPath("header_parser");
String command;
command = genCommand(hFilePath);
GenNotification.notifyMessage(null, command, "command",
NotificationType.INFORMATION);
try {
if (!TextUtils.isEmpty(command) && callExtProcess(command)) {
GenNotification.notifyMessage(null, "", "Generate Native Successfully",
NotificationType.INFORMATION);
return true;
}
} catch (IOException | InterruptedException ex) {
GenNotification.notifyMessage(null, "", "Command exec error",
NotificationType.ERROR);
LOG.error(ex);
}
return false;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sk.na.utils;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationGroupManager;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.Notifications;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
/**
* 通知框
*
* @author: liulongc digitalchina.com
* @see: tool conversion plug-in
* @version: v1.0.0
* @since 2022-05-27
*/
public class GenNotification {
private static final Logger LOG = Logger.getInstance(GenNotification.class);
private GenNotification() {
}
/**
* 消息通知
*
* @param project projectid
* @param content 提示内容
* @param title 提示栏内容
* @param type 提示类型 Error,Waring,info
*/
public static void notifyMessage(@javax.annotation.Nullable Project project,
String content,
String title,
NotificationType type) {
NotificationGroupManager manager = NotificationGroupManager.getInstance();
NotificationGroup notificationGroup = manager.getNotificationGroup("Generate.Result.Group");
Notification notification = notificationGroup.createNotification(content, type);
notification.setTitle(title);
notification.setContent(content);
if (NotificationType.ERROR.equals(type)) {
LOG.error(content);
} else if (NotificationType.WARNING.equals(type)) {
LOG.warn(content);
} else {
LOG.info(content);
}
Notifications.Bus.notify(notification, project);
}
}