用Darabonba一键生成7种语言的代码

图片

0x1 介绍

最近在看阿里的SDK的时候,突然看到了一个好玩的东西,这玩意叫 Darabonba。是一种 OpenAPI 应用的领域特定语言。可以利用它为任意风格的接口生成多语言的 SDK、代码示例、测试用例、接口编排等。现在阿里云的多语言 SDK 就是用这个生成的。下面是官方的介绍流程图。

image-20210604161124444

0x2 安装

我们按照官方的步骤来安装它,因为是用 Nodejs 写的,所以可以用 npm 来安装它

sudo npm install -g @darabonba/cli

安装完成后可以在终端输入 dara ,如果输出版本号就是说明安装成功了

➜ dara

The CLI for Darabonba 1.1.8

0x3 使用

安装完成后就可以使用了,首先创建一个文件夹来存放这个项目

mkdir demo && cd demo

然后用 dara 命令来进行初始化模块,然后依次输入包名等信息。

➜ dara init
package scope: demo
package name: demo
package version: 1.0.0
main entry: ./demo.dara

初始化完成后,我们就可以在 demo.dara 文件里进行 Darabonba DSL 表达式的编写里

比如我们编写一个经典的输出 hello world!

编写 Darabonba DSL 表达式

demo.dara 文件里写入如下代码

import Console;

init(){
}

function hello(): void {
        Console.log("hello world!");
}

安装自定义模块

因为上面我们用到了 Console 模块,所以我们在当前文件路径下执行如下命令,进行模块的安装

dara install

# 执行后将显示下面这些信息
fetching from remote repository

1 libraries installed. (0 local, 1 remote)

执行完命令后,当前文件夹下就会出现一个 libraries 文件夹

配置 Darafile

DarafileDarabonba 的模块管理文件,类似 Java 中的 pom.xml 或者 Node.js 中的 package.json,这里我们要生成 GoJava 的代码,所以只要做如下配置就可以了。具体的可以查看官方的详细介绍

{
  "scope": "demo",
  "name": "demo",
  "version": "1.0.0",
  "main": "./demo.dara",
  "libraries": {
      "Console": "darabonba:Console:*"
    },
  "java": {
      "package": "top.mjava.demo",
      "className":"TestDemo"
    }
}

libraries 里配置我们刚才所使用的 Console 依赖模块,在 java 对象字段里配置了包名和类文件名。

生成代码

官方暂时只支持 TypeScript、C#、Java、 Go、PHP、Python3、Python2、CPP 的代码生成,后续的话还会支持 Swift、Dart、Ruby、Lua、Kotlin。

我们这边只生成一下 Java 和 Go 代码,所以执行下面的命令就可以了

# 生成 Java 代码
dara codegen java ./java-demo
# 生成 Go 代码
dara codegen go ./go-demo

执行完命令后,当前文件夹就会出现 java-demogo-demo 两个文件夹了。然后就可以进入文件夹看到相应生成的代码了

Java

// This file is auto-generated, don't edit it. Thanks.
package top.mjava.demo;

import com.aliyun.tea.*;
import com.aliyun.teaconsole.*;

public class TestDemo {

    public TestDemo() throws Exception {
    }


    public void hello() throws Exception {
        com.aliyun.teaconsole.Client.log("hello world!");
    }
}

Go:

// This file is auto-generated, don't edit it. Thanks.
package client

import (
  console  "github.com/alibabacloud-go/tea-console/client"
  "github.com/alibabacloud-go/tea/tea"
)

type Client struct {
}

func NewClient()(*Client, error) {
  client := new(Client)
  err := client.Init()
  return client, err
}

func (client *Client)Init()(_err error) {
  return nil
}

0x3 自定义模块

上面所用到的 Console 就是通过自定义模块打包上传到了 Darabonba 的模块仓库,然后我们可以直接通过 libraries 来使用它。

所以我们可以自定义自己的模块上传到 Darabonba 模块仓库,接下来我们自定义一个获取 UUID 的模块,让它支持 Java 和 Go 语言来生成使用。

未命名文件

从上面的流程图可以知道,模块是由各个语言自己编写代码,然后通过 Darabonba 聚合后上传到模块仓库,然后使用者从仓库安装模块,并且下载对应语言的依赖包。

我们这边要编写 Java 和 Go 语言获取 UUID 的代码,然后通过 Darabonba 打包上传到模块仓库。

配置模版

编写模块我们也是用 Darabonba 先生成各个语言的模版代码,然后再编写相应的具体实现。

初始化

➜ dara init
package scope: greycode
package name: UUID
package version: 1.0.0
main entry: ./main.dara

我们先配置好 Darafile:

{
  "scope": "greycode",
  "name": "UUID",
  "version": "1.0.0",
  "main": "./main.dara",
  "java": {
		"package": "top.mjava.uuid",
		"packageInfo": {
			"description": "UUID generated for Darabonba moudle",
			"url": "https://github.com/greycodee/tea-uuid",
			"developerId": "greycode",
			"developerName": "greycode",
			"developerEmail": "zhengminghui99@gmail.com"
		}
  }
}

然后在 main.dara 里编写一个静态方法:

/**
* @return uuid
*/
static function uuid(): string;

编写 Java 模块

按上面的步骤配置好后就可以生成 Java 代码了,在当前目录下执行下面的命令

dara codegen java ./java

然后进入 java 文件夹,找到 Client.java,在 uuid() 方法里添加 UUID 生成的代码

// This file is auto-generated, don't edit it. Thanks.
package top.mjava.uuid;

import com.aliyun.tea.*;

public class Client {

    public static String uuid() throws Exception {
      	// 添加这行代码
        return UUID.randomUUID().toString();
    }
}

编写好代码后,还需要配置 pom.xml 文件,然后把 Java 代码打包发布到 maven 仓库上。

配置好 pom.xml 文件到下面这几个配置

<groupId>top.mjava</groupId>
<artifactId>tea-uuid</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>tea-uuid</name>

还有把 pom.xml 里的仓库配置换成我们自己的,我这边也是用阿里云的 maven 参考。你们可以自己去阿里云 maven 注册自己的账号。

-  <distributionManagement>
-    <snapshotRepository>
-      <id>sonatype-nexus-snapshots</id>
-      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-    </snapshotRepository>
-    <repository>
-      <id>sonatype-nexus-staging</id>
-      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
-    </repository>
-  </distributionManagement>

+ <distributionManagement>
+    <repository>
+        <id>rdc-releases_my</id>
+        <url>https://repo.rdc.aliyun.com/repository/102997-release-dTwmzu/</url>
+    </repository>
+    <snapshotRepository>
+        <id>rdc-snapshots_my</id>
+        <url>https://repo.rdc.aliyun.com/repository/102997-snapshot-d0gx8B/</url>
+    </snapshotRepository>
+ </distributionManagement>

配置好后就可以执行下面的命令将代码打包推送到远程 maven 仓库了

mvn clean source:jar javadoc:jar package deploy -Dmaven.test.skip=true -Dgpg.skip

看到下面的信息就说明部署成功了

[INFO] 阿里云Maven中央仓库为阿里云云效提供的公共代理仓库,云效也提供了免费、可靠的Maven私有仓库Packages,欢迎您体验使用。https://www.aliyun.com/product/yunxiao/packages?channel=pd_maven_download
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  5.538 s
[INFO] Finished at: 2021-06-05T16:00:28+08:00
[INFO] ------------------------------------------------------------------------

Maven 命令执行出现问题解决办法

  • 如果执行 maven 命令进行部署时,出现下面的错误

    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-gpg-plugin:1.6:sign (sign-artifacts) on project tea-uuid: Unable to execute gpg command: Error while executing process. Cannot run program "gpg": error=2, No such file or directory -> [Help 1]
    

    可以通过添加 -Dgpg.skip 解决

    mvn clean source:jar javadoc:jar package deploy -Dmaven.test.skip=true -Dgpg.skip
    
  • 如果出现下面的的错误

    [ERROR] Failed to execute goal org.sonatype.plugins:nexus-staging-maven-plugin:1.6.3:deploy (injected-nexus-deploy) on project tea-uuid: Execution injected-nexus-deploy of goal org.sonatype.plugins:nexus-staging-maven-plugin:1.6.3:deploy failed: Server credentials with ID "sonatype-nexus-staging" not found! -
    

    可以删除 pom.xml 文件里的 sonatype-nexus-staging 配置

    - <plugin>
    -   <groupId>org.sonatype.plugins</groupId>
    -   <artifactId>nexus-staging-maven-plugin</artifactId>
    -   <version>1.6.3</version>
    -   <extensions>true</extensions>
    -   <configuration>
    -     <serverId>sonatype-nexus-staging</serverId>
    -     <nexusUrl>https://oss.sonatype.org/</nexusUrl>
    -     <autoReleaseAfterClose>true</autoReleaseAfterClose>
    -   </configuration>
    - </plugin>
    

编写 Go 模块

老规矩,首先先生成 Go 的代码

dara codegen go ./go

然后编辑 client.go 文件,改为如下代码

// This file is auto-generated, don't edit it. Thanks.
/**
* @return uuid
*/
package client

import (
  "github.com/google/uuid"
)


func Uuid () (_result string) {
  // V4 基于随机数
  u4 := uuid.New()
  return u4.String()
}

然后 go.mod 文件里的 module 改为我们的上传 Go 代码的仓库地址

module github.com/greycodee/tea-uuid-go

然后推送到 GitHub 并打上一个 Tag 作为这个 Go 库的版本号,这边我设置版本号为 v1.0.0

git tag v1.0.0
git push origin v1.0.0

上传 Darabonba 仓库

编写好相应模块的代码并打包上传到对应的原创仓库后,就可以配置 Darafile 文件了

在 Darafile 添加 releases 信息

{
  "scope": "greycode",
  "name": "UUID",
  "version": "1.0.0",
  "main": "./main.dara",
  "releases": {
		"go": "github.com/greycodee/tea-uuid-go/client:v1.0.0",
		"java": "top.mjava:tea-uuid:1.0",
  },
  "java": {
		"package": "top.mjava.uuid",
		"packageInfo": {
			"description": "UUID generated for Darabonba moudle",
			"url": "https://github.com/greycodee/tea-uuid",
			"developerId": "greycode",
			"developerName": "greycode",
			"developerEmail": "zhengminghui99@gmail.com"
		}
  }
}

然后去 Darabonba 模块仓库里注册一个账号,然后点击个人中心->Scope->添加scope,添加一个 scope ,保持和 Darafile 文件里的 scope 一致。

注册完成后在项目目录下执行 dara login 命令,输入刚才注册的账号密码,进行登陆。

执行 dara pack 进行打包

再执行 dara publish 进行发布

发布完成后就可在 Darabonba 模块仓库里看到刚才发布的包了

image-20210605170948596

Darabonba UUID 模块代码地址:https://github.com/greycodee/tea-uuid

Go 模块代码地址: https://github.com/greycodee/tea-uuid-go

使用自定义的模块

上传 Darabonba 模块仓库后,我们就可以向刚开始使用 Console 模块那样来使用 UUID 模块了

Darafile 添加 libraries

"libraries": {
  "UUID": "greycode:UUID:*",
}

dara 代码里使用:

import Console;
import UUID;
init(){
}

function hello(): void {
	Console.log(UUID.uuid());
}