Go语言 在hclwrite中使用cty获取值的类型

0aydgbwb  于 2022-12-07  发布在  Go
关注(0)|答案(1)|浏览(152)

我正在寻找一种方法来找到变量的类型使用go-cty包在hclwrite
我的目标是生成一个如下所示的变量文件

variable "test_var" {
  val1 = bool
  val2 = string
  val3 = number
}

参考:https://developer.hashicorp.com/terraform/language/values/variables
我使用下面的代码来生成这个。

vars := hclwrite.NewEmptyFile()
    vars_root_body := vars.Body()
    vars_file, vars_create_err := os.Create("variables.tf")
    logErrors(vars_create_err)
    vars_block := vars_root_body.AppendNewBlock("variable",[]string{"test_var"})
    vars_block_body := vars_block.Body()

    vars_block_body.SetAttributeValue("val", cty.Value{})

    _, vars_write_err := vars_file.Write(vars.Bytes())
    logErrors(vars_write_err)
    defer vars_file.Close()

上面的代码生成了这个

variable "test_var" {
  val = null
}

我想获取该变量的类型,并根据该类型设置属性值,如上面的参考链接所示。我尝试了很多方法,但没有任何结果。有人能帮助我吗?
我尝试了上面的代码和许多其他方法,如

cty.SetValEmpty(cty.Bool)

但没有成功。

xuo3flqw

xuo3flqw1#

Terraform中variable块的预期语法包括一个名为type的参数,而不是名为val的参数。
Terraform使用的类型约束语法不是HCL的直接组成部分,因此没有任何内置的方法可以在一个步骤中生成该语法。然而,类型约束是从HCL的标识符和函数调用语法构建的,hclwrite确实有一些函数可以帮助生成这些单独的部分:

  • TokensForIdentifier
  • TokensForFunctionCall
f := hclwrite.NewEmptyFile()
    rootBody := f.Body()
    varBlock := rootBody.AppendNewBlock("variable", []string{"example"})
    varBody := varBlock.Body()
    varBody.SetAttributeRaw(
        "type",
        hclwrite.TokensForFunctionCall(
            "set",
            hclwrite.TokensForIdentifier("string"),
        ),
    )
    fmt.Printf("%s", f.Bytes())

以上操作将生成以下内容:

variable "example" {
  type = set(string)
}

如果你已经有了一个cty.Value值,那么你可以使用Type方法获得它的类型。但是,正如上面提到的,没有任何现成的函数可以将类型转换为类型表达式,所以如果你想为任何值生成一个类型约束,那么你需要自己编写一个函数。 Package TokensForFunctionCallTokensForIdentifier函数。例如:

package main

import (
    "fmt"
    "sort"

    "github.com/hashicorp/hcl/v2/hclwrite"
    "github.com/zclconf/go-cty/cty"
)

func main() {
    f := hclwrite.NewEmptyFile()
    rootBody := f.Body()
    varBlock := rootBody.AppendNewBlock("variable", []string{"example"})
    varBody := varBlock.Body()
    varBody.SetAttributeRaw(
        "type",
        typeExprTokens(cty.Set(cty.String)),
    )
    fmt.Printf("%s", f.Bytes())
}

func typeExprTokens(ty cty.Type) hclwrite.Tokens {
    switch ty {
    case cty.String:
        return hclwrite.TokensForIdentifier("string")
    case cty.Bool:
        return hclwrite.TokensForIdentifier("bool")
    case cty.Number:
        return hclwrite.TokensForIdentifier("number")
    case cty.DynamicPseudoType:
        return hclwrite.TokensForIdentifier("any")
    }

    if ty.IsCollectionType() {
        etyTokens := typeExprTokens(ty.ElementType())
        switch {
        case ty.IsListType():
            return hclwrite.TokensForFunctionCall("list", etyTokens)
        case ty.IsSetType():
            return hclwrite.TokensForFunctionCall("set", etyTokens)
        case ty.IsMapType():
            return hclwrite.TokensForFunctionCall("map", etyTokens)
        default:
            // Should never happen because the above is exhaustive
            panic("unsupported collection type")
        }
    }

    if ty.IsObjectType() {
        atys := ty.AttributeTypes()
        names := make([]string, 0, len(atys))
        for name := range atys {
            names = append(names, name)
        }
        sort.Strings(names)

        items := make([]hclwrite.ObjectAttrTokens, len(names))
        for i, name := range names {
            items[i] = hclwrite.ObjectAttrTokens{
                Name:  hclwrite.TokensForIdentifier(name),
                Value: typeExprTokens(atys[name]),
            }
        }

        return hclwrite.TokensForObject(items)
    }

    if ty.IsTupleType() {
        etys := ty.TupleElementTypes()
        items := make([]hclwrite.Tokens, len(etys))
        for i, ety := range etys {
            items[i] = typeExprTokens(ety)
        }
        return hclwrite.TokensForTuple(items)
    }

    panic(fmt.Errorf("unsupported type %#v", ty))
}

这个程序将生成与前面例子相同的输出。你可以改变func main,将不同的类型传递给typeExprTokens,看看它在处理一些不同类型时的行为。

相关问题