英文:
How to write to yml files in Go
问题
我正在尝试为Go中的Snowfakery编写一个yml文件,但我对Go非常陌生,对它们的结构体不熟悉。我已经能够使用Python编写自己的脚本来实现这一点,但在Go中遇到了一些困难。我已经查看了一些关于如何在Go中编写yml文件的答案,它们对于入门帮助很大,但由于我特定yml中的不同类型,我感到困惑。
我需要yml文件看起来像这样:
- snowfakery_version: 3
- object: Logistics
count: 1
fields:
Product_ID:
random_choice:
- M14860
- L47181
- L47182
Type:
random_choice:
- A10
- C17
- F16
Air_Temperature:
random_number:
min: 298
max: 300
Tool Wear Fail:
if:
- choice:
when: ${{Tool_Wear>2}}
pick:
random_choice:
- 1
- 0
- choice:
when: ${{Tool_Wear<2}}
pick: 2
所以我尝试创建类似这样的结构体:
package main
import (
"fmt"
"io/ioutil"
"log"
"gopkg.in/yaml.v3"
)
// TotalSchema represents the YAML schema
type TotalSchema struct {
Snowfakery_version []string `yaml:"snowfakery_version"`
Object []DataItem `yaml:"objects"`
}
// DataItem represents an object type in the schema
type DataItem struct {
Object string `yaml:"object"`
Count int `yaml:"count"`
Fields LogisticsFields `yaml:"fields"`
}
// Fields represents the fields of an object type
type LogisticsFields struct {
ProductID RandomChoice `yaml:"Product_ID"`
Type RandomChoice `yaml:"Type"`
AirTemperature RandomNumber `yaml:"Air_Temperature"`
ToolWearFail []ChoiceCondition `yaml:"Tool Wear Fail"`
}
type RandomNumber struct {
Min int `yaml:"min"`
Max int `yaml:"max"`
}
type RandomChoice struct {
RandomChoice []string `yaml:"random_choice"`
}
type ChoiceCondition struct {
When string `yaml:"when"`
Pick int `yaml:"pick"`
}
但是,每当我尝试创建结构体并使用它来写入yml文件时,我得到一个完全空的yml文件。我希望能得到任何帮助。提前谢谢。
编辑
通过使用接口结构和映射,我已经能够完成大部分工作,例如:
package main
import (
"fmt"
"io/ioutil"
"gopkg.in/yaml.v3"
)
// TotalSchema represents the YAML schema
type TotalSchema struct {
Snowfakery_version int `yaml:"snowfakery_version"`
}
// DataItem represents an object type in the schema
type DataItem struct {
Object string `yaml:"object"`
Count int `yaml:"count"`
Fields interface{} `yaml:"fields"`
}
// Fields represents the fields of an object type
type Fields struct {
RandomChoices []string `yaml:"random_choices,omitempty"`
RandomNumber RandomNumber `yaml:"random_number,omitempty"`
Choice []ChoiceArray `yaml:"if,omitempty"`
Random_Choice []ChoiceProbArray `yaml:"random_choice,omitempty"`
}
type RandomNumber struct {
Min int `yaml:"min"`
Max int `yaml:"max"`
}
type RandomChoice struct {
RandomChoice []string `yaml:"random_choice"`
}
type ChoiceArray struct {
Choice ChoiceCondition `yaml:"choice"`
}
type ChoiceProbArray struct {
ChoiceProb ChoiceProbability `yaml:"choice"`
}
type ChoiceCondition struct {
When string `yaml:"when"`
Pick int `yaml:"pick"`
}
type ChoiceProbability struct {
Probability string `yaml:"probability"`
Pick int `yaml:"pick"`
}
var logisticsDict []interface{}
var totalStructDict TotalSchema
var objArray []DataItem
var object DataItem
func logisticsHandler(number int, objectName string) {
object.Count = number
object.Object = objectName
logisticsDict = []interface{}{
TotalSchema{Snowfakery_version: 3},
DataItem{
Object: "logistics",
Count: 4,
Fields: map[string]interface{}{
"Product ID": Fields{
RandomChoices: []string{"M14860",
"L47181",
"L47182",
},
},
"Air_Temperature": Fields{
RandomNumber: RandomNumber{
Min: 298,
Max: 300,
},
},
"Process_Temperature": Fields{
RandomNumber: RandomNumber{
Min: 298,
Max: 300,
},
},
"Heat Dissipation Fail": Fields{
Choice: []ChoiceArray{
{ChoiceCondition{
When: "${{(Process_Temperature - Air_Temperature)<8.6 and Rotational_Speed<1380}}",
Pick: 1,
}},
{ChoiceCondition{
When: "${{(Process_Temperature - Air_Temperature)>8.6 or Rotational_Speed>1380}}",
Pick: 0,
}},
},
},
},
},
}
}
func main() {
//other funciton I use to populate the rest of the struct
logisticsHandler(4, "logistics")
fmt.Println(logisticsDict)
data, err := yaml.Marshal(logisticsDict)
if err != nil {
panic(err)
}
err = ioutil.WriteFile("logistics.yml", data, 0)
if err != nil {
panic(err)
}
fmt.Println("YAML data has been written to 'logistics.yml' file.")
}
但是,每当我运行yaml.Marshal
代码时,它会自动对我的代码进行排序。我现在想知道如何使其保持与我创建的顺序完全一致,因为Snowfakery依赖于按顺序定义变量。
英文:
I am trying to write a yml file for snowfakery in go and I am very new to go so I am unfamiliar with their structs. I have been able to write my own script to do this in python but am struggling a bit more with go. I have looked at some of the other answers for how to write to a yml file in go and they helped a lot with starting but because of the different types in my specific yml I got confused
I need the yml file to look something like this
- snowfakery_version: 3
- object: Logistics
count: 1
fields:
Product_ID:
random_choice:
- M14860
- L47181
- L47182
Type:
random_choice:
- A10
- C17
- F16
Air_Temperature:
random_number:
min: 298
max: 300
Tool Wear Fail:
if:
- choice:
when: ${{Tool_Wear>2}}
pick:
random_choice:
- 1
- 0
- choice:
when: ${{Tool_Wear<2}}
pick: 2
so i have tried making structs like
package main
import (
"fmt"
"io/ioutil"
"log"
"gopkg.in/yaml.v3"
// "os"
// "strings"
)
// TotalSchema represents the YAML schema
type TotalSchema struct {
snowfakery_version []string `yaml:"snowfakery_version"`
object []DataItem `yaml:"objects"`
}
// DataItem represents an object type in the schema
type DataItem struct {
Object string `yaml:"object"`
Count int `yaml:"count"`
Fields LogisticsFields `yaml:"fields"`
}
// Fields represents the fields of an object type
type LogisticsFields struct {
ProductID RandomChoice `yaml:"Product_ID"`
Type RandomChoice `yaml:"Type"`
ToolWear RandomNumber `yaml:"Tool_Wear"`
ToolWearFail []ChoiceCondition `yaml:"Tool Wear Fail"`
}
type RandomNumber struct {
Min int `yaml:"min"`
Max int `yaml:"max"`
}
type RandomChoice struct {
RandomChoice []string `yaml:"random_choice"`
}
type ChoiceCondition struct {
When string `yaml:"when"`
Pick int `yaml:"pick"`
}
but whenever I try to create the struct and use it to write to a yml file
func main() {
totalStructDict.snowfakery_version = []string{"3"}
//other funciton I use to populate the rest of the struct
logisticsHandler(4, "logistics")
fmt.Println(totalStructDict)
data, err := yaml.Marshal(totalStructDict)
if err != nil {
panic(err)
}
fmt.Println( data)
err = ioutil.WriteFile("logistics.yml", data, 0)
if err != nil {
panic(err)
}
fmt.Println("YAML data has been written to 'logistics.yml' file.")
I get a completely empty yml file. I would love any help. Thanks in advance
EDIT
I have been able to get most of the way with by using the interface structure and maps ie.
package main
import (
"fmt"
"io/ioutil"
"gopkg.in/yaml.v3"
// "os"
// "strings"
)
// TotalSchema represents the YAML schema
type TotalSchema struct {
Snowfakery_version int `yaml:"snowfakery_version"`
}
// DataItem represents an object type in the schema
type DataItem struct {
Object string `yaml:"object"`
Count int `yaml:"count"`
Fields interface{} `yaml:"fields"`
}
// Fields represents the fields of an object type
type Fields struct {
RandomChoices []string `yaml:"random_choices,omitempty"`
RandomNumber RandomNumber `yaml:"random_number,omitempty"`
Choice []ChoiceArray `yaml:"if,omitempty"`
Random_Choice []ChoiceProbArray `yaml:"random_choice,omitempty"`
}
type RandomNumber struct {
Min int `yaml:"min"`
Max int `yaml:"max"`
}
type RandomChoice struct {
RandomChoice []string `yaml:"random_choice"`
}
type ChoiceArray struct {
Choice ChoiceCondition `yaml:"choice"`
}
type ChoiceProbArray struct {
ChoiceProb ChoiceProbability `yaml:"choice"`
}
type ChoiceCondition struct {
When string `yaml:"when"`
Pick int `yaml:"pick"`
}
type ChoiceProbability struct {
Probability string `yaml:"probability"`
Pick int `yaml:"pick"`
}
var logisticsDict []interface{}
var totalStructDict TotalSchema
var objArray []DataItem
var object DataItem
func logisticsHandler(number int, objectName string) {
object.Count = number
object.Object = objectName
logisticsDict = []interface{}{
TotalSchema{Snowfakery_version: 3},
DataItem{
Object: "logistics",
Count: 4,
Fields: map[string]interface{}{
"Product ID": Fields{
RandomChoices: []string{"M14860",
"L47181",
"L47182",
},
},
"Air_Temperature": Fields{
RandomNumber: RandomNumber{
Min: 298,
Max: 300,
},
},
"Process_Temperature": Fields{
RandomNumber: RandomNumber{
Min: 298,
Max: 300,
},
},
"Heat Dissipation Fail": Fields{
Choice: []ChoiceArray{
{ChoiceCondition{
When: "${{(Process_Temperature - Air_Temperature)<8.6 and Rotational_Speed<1380}}",
Pick: 1,
}},
{ChoiceCondition{
When: "${{(Process_Temperature - Air_Temperature)>8.6 or Rotational_Speed>1380}}",
Pick: 0,
}},
},
},
},
},
}
}
func main() {
//other funciton I use to populate the rest of the struct
logisticsHandler(4, "logistics")
fmt.Println(logisticsDict)
data, err := yaml.Marshal(logisticsDict)
if err != nil {
panic(err)
}
// fmt.Println(data)
err = ioutil.WriteFile("logistics.yml", data, 0)
if err != nil {
panic(err)
}
fmt.Println("YAML data has been written to 'logistics.yml' file.")
}
But now whenever I run the yaml.Marshel code it is auto sorting my code. I am now wondering how to get it to stay exactly in the order that I created it in because snowfakery relies on variables to be defined in order
答案1
得分: 1
在你的示例中,snowfakery_version
是一个字典中唯一的键,其值是标量整数值3
。这个字典是列表中的第一项:
- snowfakery_version: 3
上述内容的JSON等效形式是:
[
{"snowfakery_version": 3}
]
这与你的数据结构不匹配,你的数据结构看起来是这样的:
type TotalSchema struct {
snowfakery_version []string `yaml:"snowfakery_version"`
object []DataItem `yaml:"objects"`
}
这对应于一个类似以下的YAML文件:
snowfakery_version: [3]
或者作为JSON:
{
"snowfakery_version": [3]
}
考虑到你正在解析一个已建立的格式,我认为将其解析为Go结构可能会有些麻烦:
-
似乎没有正式的模式文档
-
看起来一些字段实际上是“联合”类型。也就是说:
- 字段定义可以是结构,也可以是其他对象的列表。
pick
可以是标量值(整数、字符串)或结构体
等等。
在Go中,解析联合类型通常意味着使用interface{}
,然后通过在运行时检查数据来动态确定要执行的操作。
从顶部开始,你的文件格式是一个“事物”的列表,其中每个事物可以是snowfakery_version
或对象定义。因此,我们从以下内容开始:
type SnowfakeryConfig []interface{}
然后,我们为预期的各种类型创建struct
定义,例如:
SnowfakeryVersion struct {
SnowfakeryVersion int `yaml:"snowfakery_version"`
}
ObjectSpec struct {
Object string `yaml:"object,omitempty"`
Count int `yaml:"count,omitempty"`
Fields map[string]interface{} `yaml:"fields,omitempty"`
}
.
.
.
这些可以附加到SnowfakeryConfig
列表中。以下是一个通过程序生成你问题中示例配置的示例:
package main
import (
"os"
"gopkg.in/yaml.v3"
)
type (
SnowfakeryConfig []interface{}
SnowfakeryVersion struct {
SnowfakeryVersion int `yaml:"snowfakery_version"`
}
ObjectSpec struct {
Object string `yaml:"object,omitempty"`
Count int `yaml:"count,omitempty"`
Fields map[string]interface{} `yaml:"fields,omitempty"`
}
FieldSpec struct {
Fake string `yaml:"fake,omitempty"`
RandomChoice RandomChoice `yaml:"random_choice,omitempty"`
RandomNumber *RandomNumber `yaml:"random_number,omitempty"`
IfExpression IfExpression `yaml:"if,omitempty"`
Object string `yaml:"object,omitempty"`
}
RandomChoice []interface{}
RandomNumber struct {
Min int
Max int
}
IfExpression []Choice
Choice struct {
Choice ChoiceSpec
}
ChoiceSpec struct {
When string
Pick interface{}
}
)
func main() {
config := SnowfakeryConfig{}
config = append(config, SnowfakeryVersion{SnowfakeryVersion: 3})
config = append(config, ObjectSpec{
Object: "Logistics",
Count: 1,
Fields: map[string]interface{}{
"Product_ID": FieldSpec{
RandomChoice: RandomChoice{
"M14860",
"L47181",
"L47182",
},
},
"Type": FieldSpec{
RandomChoice: RandomChoice{
"A10",
"C17",
"F16",
},
},
"Air_Temperature": FieldSpec{
RandomNumber: &RandomNumber{
Min: 298,
Max: 300,
},
},
"Tool Wear Fail": FieldSpec{
IfExpression: IfExpression{
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear>2}}",
Pick: FieldSpec{
RandomChoice: RandomChoice{
1,
0,
},
},
},
},
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear<2}}",
Pick: 2,
},
},
},
},
},
})
content, err := yaml.Marshal(config)
if err != nil {
panic(err)
}
if err := os.WriteFile("output.yaml", content, 0666); err != nil {
panic(err)
}
}
运行上述代码会在output.yaml
中生成以下内容:
- snowfakery_version: 3
- object: Logistics
count: 1
fields:
Air_Temperature:
random_number:
min: 298
max: 300
Product_ID:
random_choice:
- M14860
- L47181
- L47182
Tool Wear Fail:
if:
- choice:
when: ${{Tool_Wear>2}}
pick:
random_choice:
- 1
- 0
- choice:
when: ${{Tool_Wear<2}}
pick: 2
Type:
random_choice:
- A10
- C17
- F16
解析YAML需要我们在运行时动态检测对象类型。我们可以通过查找从文件中读取的每个项中的特定键来实现这一点:
fd, err := os.ReadFile("sample.yaml")
if err != nil {
panic(err)
}
if err := yaml.Unmarshal(fd, &config); err != nil {
panic(err)
}
for _, item := range config {
if _, ok := item.(map[string]interface{})["snowfakery_version"]; ok {
fmt.Println("found version")
if err := mapstructure.Decode(item, &version); err != nil {
panic(err)
}
fmt.Printf("version: %d\n", version.SnowfakeryVersion)
continue
}
if _, ok := item.(map[string]interface{})["object"]; ok {
fmt.Println("found object")
if err := mapstructure.Decode(item, &objspec); err != nil {
panic(err)
}
fmt.Printf("object name: %s\n", objspec.Object)
for k := range objspec.Fields {
fmt.Printf(" field: %s\n", k)
}
continue
}
}
在这个示例中,我使用mapstructure
模块将我们的map[string]interface{}
转换为我们在确定对象类型后所需的结构。
这里包含了我使用的完整测试代码;你可以调用./example generate
来创建output.yaml
,或者调用./example parse somefile.yaml
来解析somefile.yaml
中的YAML。
package main
import (
"fmt"
"os"
"github.com/mitchellh/mapstructure"
"gopkg.in/yaml.v3"
)
type (
SnowfakeryConfig []interface{}
SnowfakeryVersion struct {
SnowfakeryVersion int `mapstructure:"snowfakery_version"`
}
ObjectSpec struct {
Object string `mapstructure:"object,omitempty"`
Count int `mapstructure:"count,omitempty"`
Fields map[string]interface{} `mapstructure:"fields,omitempty"`
}
FieldSpec struct {
Fake string `mapstructure:"fake,omitempty"`
RandomChoice RandomChoice `mapstructure:"random_choice,omitempty"`
RandomNumber *RandomNumber `mapstructure:"random_number,omitempty"`
IfExpression IfExpression `mapstructure:"if,omitempty"`
Object string `mapstructure:"object,omitempty"`
}
RandomChoice []interface{}
RandomNumber struct {
Min int
Max int
}
IfExpression []Choice
Choice struct {
Choice ChoiceSpec
}
ChoiceSpec struct {
When string
Pick interface{}
}
)
func main() {
config := SnowfakeryConfig{}
if os.Args[1] == "parse" {
version := SnowfakeryVersion{}
objspec := ObjectSpec{}
fd, err := os.ReadFile(os.Args[2])
if err != nil {
panic(err)
}
if err := yaml.Unmarshal(fd, &config); err != nil {
panic(err)
}
for _, item := range config {
if _, ok := item.(map[string]interface{})["snowfakery_version"]; ok {
fmt.Println("found version")
if err := mapstructure.Decode(item, &version); err != nil {
panic(err)
}
fmt.Printf("version: %d\n", version.SnowfakeryVersion)
continue
}
if _, ok := item.(map[string]interface{})["object"]; ok {
fmt.Println("found object")
if err := mapstructure.Decode(item, &objspec); err != nil {
panic(err)
}
fmt.Printf("object name: %s\n", objspec.Object)
for k := range objspec.Fields {
fmt.Printf(" field: %s\n", k)
}
continue
}
}
} else if os.Args[1] == "generate" {
config = append(config, SnowfakeryVersion{SnowfakeryVersion: 3})
config = append(config, ObjectSpec{
Object: "Logistics",
Count: 1,
Fields: map[string]interface{}{
"Product_ID": FieldSpec{
RandomChoice: RandomChoice{
"M14860",
"L47181",
"L47182",
},
},
"Type": FieldSpec{
RandomChoice: RandomChoice{
"A10",
"C17",
"F16",
},
},
"Air_Temperature": FieldSpec{
RandomNumber: &RandomNumber{
Min: 298,
Max: 300,
},
},
"Tool Wear Fail": FieldSpec{
IfExpression: IfExpression{
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear>2}}",
Pick: FieldSpec{
RandomChoice: RandomChoice{
1,
0,
},
},
},
},
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear<2}}",
Pick: 2,
},
},
},
},
},
})
content, err := yaml.Marshal(config)
if err != nil {
panic(err)
}
if err := os.WriteFile("output.yaml", content, 0666); err != nil {
panic(err)
}
}
}
英文:
In your example, snowfakery_version
is the only key in a dictionary whose value is the scalar integer value 3
. This dictionary is the first item in a list:
- snowfakery_version: 3
The JSON equivalent to the above is:
[
{"snowfakery_version": 3}
]
That doesn't match your data structure, which looks like:
type TotalSchema struct {
snowfakery_version []string `yaml:"snowfakery_version"`
object []DataItem `yaml:"objects"`
}
This would correspond to a YAML file that looks like:
snowfakery_version: [3]
Or as JSON:
{
"snowfakery_version": [3]
}
With the understanding that you're parsing an established format, I think it's going to be a bit of pain to parse this into Go structs:
-
There does not appear to be a formal schema document
-
It looks like some of the fields are effectively "union" types. That is:
- A field definition can either be a structure, or it can be a list of additional objects.
pick
can be a scalar value (integer, string) or structure
etc.
In go, parsing a union type usually means using an interface{}
and then figuring out what to do dynamically by inspecting the data at runtime.
Starting at the top, your file format is a list of "things", where each thing can be either a snowfakery_version
or an object definition. So that means we start with:
type SnowfakeryConfig []interface{}
Then we create the struct
definitions for various types that we expect, e.g.:
SnowfakeryVersion struct {
SnowfakeryVersion int `yaml:"snowfakery_version"`
}
ObjectSpec struct {
Object string `yaml:"object,omitempty"`
Count int `yaml:"count,omitempty"`
Fields map[string]interface{} `yaml:"fields,omitempty"`
}
.
.
.
These can be appended to a SnowfakeryConfig
list. Here's an example that programatically produces the sample config from your question:
package main
import (
"os"
"gopkg.in/yaml.v3"
)
type (
SnowfakeryConfig []interface{}
SnowfakeryVersion struct {
SnowfakeryVersion int `yaml:"snowfakery_version"`
}
ObjectSpec struct {
Object string `yaml:"object,omitempty"`
Count int `yaml:"count,omitempty"`
Fields map[string]interface{} `yaml:"fields,omitempty"`
}
FieldSpec struct {
Fake string `yaml:"fake,omitempty"`
RandomChoice RandomChoice `yaml:"random_choice,omitempty"`
RandomNumber *RandomNumber `yaml:"random_number,omitempty"`
IfExpression IfExpression `yaml:"if,omitempty"`
Object string `yaml:"object,omitempty"`
}
RandomChoice []interface{}
RandomNumber struct {
Min int
Max int
}
IfExpression []Choice
Choice struct {
Choice ChoiceSpec
}
ChoiceSpec struct {
When string
Pick interface{}
}
)
func main() {
config := SnowfakeryConfig{}
config = append(config, SnowfakeryVersion{SnowfakeryVersion: 3})
config = append(config, ObjectSpec{
Object: "Logistics",
Count: 1,
Fields: map[string]interface{}{
"Product_ID": FieldSpec{
RandomChoice: RandomChoice{
"M14860",
"L47181",
"L47182",
},
},
"Type": FieldSpec{
RandomChoice: RandomChoice{
"A10",
"C17",
"F16",
},
},
"Air_Temperature": FieldSpec{
RandomNumber: &RandomNumber{
Min: 298,
Max: 300,
},
},
"Tool Wear Fail": FieldSpec{
IfExpression: IfExpression{
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear>2}}",
Pick: FieldSpec{
RandomChoice: RandomChoice{
1,
0,
},
},
},
},
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear<2}}",
Pick: 2,
},
},
},
},
},
})
content, err := yaml.Marshal(config)
if err != nil {
panic(err)
}
if err := os.WriteFile("output.yaml", content, 0666); err != nil {
panic(err)
}
}
Running the above code produces, in output.yaml
:
- snowfakery_version: 3
- object: Logistics
count: 1
fields:
Air_Temperature:
random_number:
min: 298
max: 300
Product_ID:
random_choice:
- M14860
- L47181
- L47182
Tool Wear Fail:
if:
- choice:
when: ${{Tool_Wear>2}}
pick:
random_choice:
- 1
- 0
- choice:
when: ${{Tool_Wear<2}}
pick: 2
Type:
random_choice:
- A10
- C17
- F16
Parsing the YAML requires us to dynamically detect object types at runtime. We can do this by looking for specific keys in each item read from the file:
fd, err := os.ReadFile("sample.yaml")
if err != nil {
panic(err)
}
if err := yaml.Unmarshal(fd, &config); err != nil {
panic(err)
}
for _, item := range config {
if _, ok := item.(map[string]interface{})["snowfakery_version"]; ok {
fmt.Println("found version")
if err := mapstructure.Decode(item, &version); err != nil {
panic(err)
}
fmt.Printf("version: %d\n", version.SnowfakeryVersion)
continue
}
if _, ok := item.(map[string]interface{})["object"]; ok {
fmt.Println("found object")
if err := mapstructure.Decode(item, &objspec); err != nil {
panic(err)
}
fmt.Printf("object name: %s\n", objspec.Object)
for k := range objspec.Fields {
fmt.Printf(" field: %s\n", k)
}
continue
}
}
In this example I'm using the mapstructure
module to convert our map[string]interface{}
into the desired structure after we've figured out what object type we have.
The complete test code I used here is included below; you can call ./example generate
to create output.yaml
, or ./example parse somefile.yaml
to parse the YAML in somefile.yaml
.
package main
import (
"fmt"
"os"
"github.com/mitchellh/mapstructure"
"gopkg.in/yaml.v3"
)
type (
SnowfakeryConfig []interface{}
SnowfakeryVersion struct {
SnowfakeryVersion int `mapstructure:"snowfakery_version"`
}
ObjectSpec struct {
Object string `mapstructure:"object,omitempty"`
Count int `mapstructure:"count,omitempty"`
Fields map[string]interface{} `mapstructure:"fields,omitempty"`
}
FieldSpec struct {
Fake string `mapstructure:"fake,omitempty"`
RandomChoice RandomChoice `mapstructure:"random_choice,omitempty"`
RandomNumber *RandomNumber `mapstructure:"random_number,omitempty"`
IfExpression IfExpression `mapstructure:"if,omitempty"`
Object string `mapstructure:"object,omitempty"`
}
RandomChoice []interface{}
RandomNumber struct {
Min int
Max int
}
IfExpression []Choice
Choice struct {
Choice ChoiceSpec
}
ChoiceSpec struct {
When string
Pick interface{}
}
)
func main() {
config := SnowfakeryConfig{}
if os.Args[1] == "parse" {
version := SnowfakeryVersion{}
objspec := ObjectSpec{}
fd, err := os.ReadFile(os.Args[2])
if err != nil {
panic(err)
}
if err := yaml.Unmarshal(fd, &config); err != nil {
panic(err)
}
for _, item := range config {
if _, ok := item.(map[string]interface{})["snowfakery_version"]; ok {
fmt.Println("found version")
if err := mapstructure.Decode(item, &version); err != nil {
panic(err)
}
fmt.Printf("version: %d\n", version.SnowfakeryVersion)
continue
}
if _, ok := item.(map[string]interface{})["object"]; ok {
fmt.Println("found object")
if err := mapstructure.Decode(item, &objspec); err != nil {
panic(err)
}
fmt.Printf("object name: %s\n", objspec.Object)
for k := range objspec.Fields {
fmt.Printf(" field: %s\n", k)
}
continue
}
}
} else if os.Args[1] == "generate" {
config = append(config, SnowfakeryVersion{SnowfakeryVersion: 3})
config = append(config, ObjectSpec{
Object: "Logistics",
Count: 1,
Fields: map[string]interface{}{
"Product_ID": FieldSpec{
RandomChoice: RandomChoice{
"M14860",
"L47181",
"L47182",
},
},
"Type": FieldSpec{
RandomChoice: RandomChoice{
"A10",
"C17",
"F16",
},
},
"Air_Temperature": FieldSpec{
RandomNumber: &RandomNumber{
Min: 298,
Max: 300,
},
},
"Tool Wear Fail": FieldSpec{
IfExpression: IfExpression{
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear>2}}",
Pick: FieldSpec{
RandomChoice: RandomChoice{
1,
0,
},
},
},
},
Choice{
Choice: ChoiceSpec{
When: "${{Tool_Wear<2}}",
Pick: 2,
},
},
},
},
},
})
content, err := yaml.Marshal(config)
if err != nil {
panic(err)
}
if err := os.WriteFile("output.yaml", content, 0666); err != nil {
panic(err)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论