如何从YAML文件生成GO应用程序?

问题描述 投票:-2回答:2

我有一个具有以下内容的YAML文件:

name: foo
port: 8080
routes:
route: /echo 
    method: GET
    body: Hello back!!!!
route: /greet 
    method: GET
    body: Hello, how are you!!!

从YAML文件中,我想生成具有以下内容的GO应用程序:

package main

import (
    "net/http"
    "github.com/labstack/echo"
)

func main() {
    e := echo.New()

    e.GET("/echo", func(c echo.Context) error {
        return c.String(http.StatusOK, "body: Hello back!!!!")
    })

    e.GET("/greet", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, how are you!!!")
    })

    e.Logger.Fatal(e.Start(":8080"))
}

最后,它应该编译一个随时可用的GO应用程序。我可以使用https://golang.org/pkg/text/template/来构建GO应用程序,还是有其他解决方案?

go go-templates
2个回答
0
投票

创建文件main.go

package main

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "log"
    "os"
    "text/template"
)

type Routes struct {
    Route  string `yaml:"route"`
    Method string `yaml:"method"`
    Body   string `yaml:"body"`
}

type Service struct {
    Name   string `yaml:"name"`
    Port   string `yaml:"port"`
    Routes []Routes
}

var serviceTpl = `
package main

import (
  "net/http"
  "github.com/labstack/echo"
)

func main() {
  e := echo.New()

{{range .Routes}}
  e.{{.Method}}("{{.Route}}", func(c echo.Context) error {
    return c.String(http.StatusOK, "{{.Body}}")
  })
{{end}}

  e.Logger.Fatal(e.Start(":{{.Port}}"))
}
`

func loadConfig(yamlPath string) (c Service) {
    if yamlPath == "" {
        log.Fatalf("missing YAML configuration")
    }

    f, err := ioutil.ReadFile(yamlPath)

    if err != nil {
        log.Fatalf("failed to read YAML file: %v", err)
    }

    if err := yaml.Unmarshal(f, &c); err != nil {
        log.Fatalf("failed to decode configuration: %v", err)
    }

    return
}

func generateService(c Service, outputPath string) {
    t, err := template.New("Service").Parse(serviceTpl)

    if err != nil {
        log.Fatalf("failed to parse template: %v", err)
    }

    f, err := os.Create(outputPath)

    if err != nil {
        log.Fatalf("failed to create file '%s':  %v", outputPath, err)
    }

    if err := t.Execute(f, c); err != nil {
        log.Fatalf("failed to generate service: ", err)
    }
}

func main() {
    c := loadConfig(os.Args[1])
    generateService(c, os.Args[2])
}

生成文件,并使用可执行文件

go build -o executable-name
./executable-name my_input.yml my_output_file.go

0
投票

基本上,有两种解决此类问题的方法:

  1. “普通”文本转换。

    您接受输入文本,然后进行[[翻译以遵循一组简单规则输出文本。

    是的,您可以为此使用任何合适的模板引擎。基本上,您将输入的YAML解析为一组(struct类型的Go值),然后对该集合运行模板以生成输出文本。

    此方法不“了解” Go的任何内容。

  2. 代码生成。

    这是第一种方法的一种变体,它不是盲目地操纵文本,而是实际上以抽象形式生成一个Go程序,然后将其[[formats转换为准确描述它的源代码文件。

    将输入的YAML解析为一组(struct类型的)Go值-与上面一样。

    1. 将集合转换为描述与输入数据匹配的Go程序的AST
    2. Produce Go source code形成AST。
  • 两种方法之间的差异大致如下:
  • 纯文本转换比较简单,但是一旦输入变得不平凡,它很容易就会出现麻烦。例如,模板将如何处理应在HTTP处理程序中输出的“怪异”字符?

    纯文本转换通常在生成格式正确的Go源代码时会遇到麻烦(因此,在其上运行gofmt -s -l会产生空输出)。

    通过AST生成代码在实现方面是一项更为复杂的任务-因为它需要您考虑“低级”内容,例如构成程序抽象形式的单个令牌,但总的来说,您要获得两点上面的代码是“免费”分类的-因为stdlib提供的Go源代码格式化程序无需任何额外的努力即可以规范的形式生成源代码,并且还处理了用字符串文字正确地掩盖怪异事物的所有麻烦。

  • © www.soinside.com 2019 - 2024. All rights reserved.