mirror of https://github.com/coder/coder.git
106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
package clibase
|
|
|
|
import (
|
|
"github.com/iancoleman/strcase"
|
|
"github.com/mitchellh/go-wordwrap"
|
|
"golang.org/x/xerrors"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// deepMapNode returns the mapping node at the given path,
|
|
// creating it if it doesn't exist.
|
|
func deepMapNode(n *yaml.Node, path []string, headComment string) *yaml.Node {
|
|
if len(path) == 0 {
|
|
return n
|
|
}
|
|
|
|
// Name is every two nodes.
|
|
for i := 0; i < len(n.Content)-1; i += 2 {
|
|
if n.Content[i].Value == path[0] {
|
|
// Found matching name, recurse.
|
|
return deepMapNode(n.Content[i+1], path[1:], headComment)
|
|
}
|
|
}
|
|
|
|
// Not found, create it.
|
|
nameNode := yaml.Node{
|
|
Kind: yaml.ScalarNode,
|
|
Value: path[0],
|
|
HeadComment: headComment,
|
|
}
|
|
valueNode := yaml.Node{
|
|
Kind: yaml.MappingNode,
|
|
}
|
|
n.Content = append(n.Content, &nameNode)
|
|
n.Content = append(n.Content, &valueNode)
|
|
return deepMapNode(&valueNode, path[1:], headComment)
|
|
}
|
|
|
|
// ToYAML converts the option set to a YAML node, that can be
|
|
// converted into bytes via yaml.Marshal.
|
|
//
|
|
// The node is returned to enable post-processing higher up in
|
|
// the stack.
|
|
func (s OptionSet) ToYAML() (*yaml.Node, error) {
|
|
root := yaml.Node{
|
|
Kind: yaml.MappingNode,
|
|
}
|
|
|
|
for _, opt := range s {
|
|
if opt.YAML == "" {
|
|
continue
|
|
}
|
|
nameNode := yaml.Node{
|
|
Kind: yaml.ScalarNode,
|
|
Value: opt.YAML,
|
|
HeadComment: wordwrap.WrapString(opt.Description, 80),
|
|
}
|
|
var valueNode yaml.Node
|
|
if m, ok := opt.Value.(yaml.Marshaler); ok {
|
|
v, err := m.MarshalYAML()
|
|
if err != nil {
|
|
return nil, xerrors.Errorf(
|
|
"marshal %q: %w", opt.Name, err,
|
|
)
|
|
}
|
|
valueNode, ok = v.(yaml.Node)
|
|
if !ok {
|
|
return nil, xerrors.Errorf(
|
|
"marshal %q: unexpected underlying type %T",
|
|
opt.Name, v,
|
|
)
|
|
}
|
|
} else {
|
|
valueNode = yaml.Node{
|
|
Kind: yaml.ScalarNode,
|
|
Value: opt.Value.String(),
|
|
}
|
|
}
|
|
var group []string
|
|
for _, g := range opt.Group.Ancestry() {
|
|
if g.Name == "" {
|
|
return nil, xerrors.Errorf(
|
|
"group name is empty for %q, groups: %+v",
|
|
opt.Name,
|
|
opt.Group,
|
|
)
|
|
}
|
|
group = append(group, strcase.ToLowerCamel(g.Name))
|
|
}
|
|
var groupDesc string
|
|
if opt.Group != nil {
|
|
groupDesc = wordwrap.WrapString(opt.Group.Description, 80)
|
|
}
|
|
parentValueNode := deepMapNode(
|
|
&root, group,
|
|
groupDesc,
|
|
)
|
|
parentValueNode.Content = append(
|
|
parentValueNode.Content,
|
|
&nameNode,
|
|
&valueNode,
|
|
)
|
|
}
|
|
return &root, nil
|
|
}
|