vendor: Add github.com/hashicorp/terraform-config-inspect
This commit is contained in:
parent
e27e0ddc9e
commit
047239e68c
3
go.mod
3
go.mod
|
@ -71,12 +71,13 @@ require (
|
||||||
github.com/hashicorp/go-uuid v1.0.0
|
github.com/hashicorp/go-uuid v1.0.0
|
||||||
github.com/hashicorp/go-version v1.0.0
|
github.com/hashicorp/go-version v1.0.0
|
||||||
github.com/hashicorp/golang-lru v0.5.0 // indirect
|
github.com/hashicorp/golang-lru v0.5.0 // indirect
|
||||||
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
|
github.com/hashicorp/hcl v1.0.0
|
||||||
github.com/hashicorp/hcl2 v0.0.0-20181220012050-6631d7cd0a68
|
github.com/hashicorp/hcl2 v0.0.0-20181220012050-6631d7cd0a68
|
||||||
github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250
|
github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250
|
||||||
github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3
|
github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3
|
||||||
github.com/hashicorp/memberlist v0.1.0 // indirect
|
github.com/hashicorp/memberlist v0.1.0 // indirect
|
||||||
github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb // indirect
|
github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb // indirect
|
||||||
|
github.com/hashicorp/terraform-config-inspect v0.0.0-20181213005350-314d8affa1db
|
||||||
github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4
|
github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4
|
||||||
github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a // indirect
|
github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a // indirect
|
||||||
github.com/jonboulle/clockwork v0.1.0 // indirect
|
github.com/jonboulle/clockwork v0.1.0 // indirect
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -9,6 +9,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 h1:dVyNL14dq1500J
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 h1:K9I21XUHNbYD3GNMmJBN0UKJCpdP+glftwNZ7Bo8kqY=
|
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 h1:K9I21XUHNbYD3GNMmJBN0UKJCpdP+glftwNZ7Bo8kqY=
|
||||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
|
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
|
||||||
|
github.com/DHowett/go-plist v0.0.0-20180609054337-500bd5b9081b/go.mod h1:5paT5ZDrOm8eAJPem2Bd+q3FTi3Gxm/U4tb2tH8YIUQ=
|
||||||
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI=
|
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI=
|
||||||
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no=
|
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no=
|
||||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
|
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
|
||||||
|
@ -159,6 +160,8 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
|
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
|
||||||
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200 h1:F/nGtDwtQsuw7ZHmiLpHsPWNljDC24kiSHSGUnou9sw=
|
github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200 h1:F/nGtDwtQsuw7ZHmiLpHsPWNljDC24kiSHSGUnou9sw=
|
||||||
github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200/go.mod h1:ShfpTh661oAaxo7VcNxg0zcZW6jvMa7Moy2oFx7e5dE=
|
github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200/go.mod h1:ShfpTh661oAaxo7VcNxg0zcZW6jvMa7Moy2oFx7e5dE=
|
||||||
github.com/hashicorp/hcl2 v0.0.0-20181214224644-4c4fdbdcc016 h1:rWpgzURetj/et0J6RoRw1+CBaiyrAQamwNCuYrHayU0=
|
github.com/hashicorp/hcl2 v0.0.0-20181214224644-4c4fdbdcc016 h1:rWpgzURetj/et0J6RoRw1+CBaiyrAQamwNCuYrHayU0=
|
||||||
|
@ -181,6 +184,8 @@ github.com/hashicorp/memberlist v0.1.0 h1:qSsCiC0WYD39lbSitKNt40e30uorm2Ss/d4JGU
|
||||||
github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE=
|
github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE=
|
||||||
github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb h1:ZbgmOQt8DOg796figP87/EFCVx2v2h9yRvwHF/zceX4=
|
github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb h1:ZbgmOQt8DOg796figP87/EFCVx2v2h9yRvwHF/zceX4=
|
||||||
github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE=
|
github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE=
|
||||||
|
github.com/hashicorp/terraform-config-inspect v0.0.0-20181213005350-314d8affa1db h1:AcZb6ClKGJoY9vDFvxw+t5s8EmtWP8fMerxP6j+veKc=
|
||||||
|
github.com/hashicorp/terraform-config-inspect v0.0.0-20181213005350-314d8affa1db/go.mod h1:2zR/i7/tO81bLaVoMEJlSLRJ36/TvPLapEmy682Zizo=
|
||||||
github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4 h1:SGDekHLK2IRoVS7Fb4olLyWvc2VmwKgyFC05j6X3NII=
|
github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4 h1:SGDekHLK2IRoVS7Fb4olLyWvc2VmwKgyFC05j6X3NII=
|
||||||
github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
|
github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||||
|
|
|
@ -3,7 +3,8 @@ sudo: false
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.8
|
- 1.x
|
||||||
|
- tip
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
|
|
@ -89,7 +89,7 @@ func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error
|
||||||
switch k.Kind() {
|
switch k.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return d.decodeBool(name, node, result)
|
return d.decodeBool(name, node, result)
|
||||||
case reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
return d.decodeFloat(name, node, result)
|
return d.decodeFloat(name, node, result)
|
||||||
case reflect.Int, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||||
return d.decodeInt(name, node, result)
|
return d.decodeInt(name, node, result)
|
||||||
|
@ -137,13 +137,13 @@ func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) e
|
||||||
func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
|
func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case *ast.LiteralType:
|
case *ast.LiteralType:
|
||||||
if n.Token.Type == token.FLOAT {
|
if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER {
|
||||||
v, err := strconv.ParseFloat(n.Token.Text, 64)
|
v, err := strconv.ParseFloat(n.Token.Text, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Set(reflect.ValueOf(v))
|
result.Set(reflect.ValueOf(v).Convert(result.Type()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,7 +573,11 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||||
|
|
||||||
// Compile the list of all the fields that we're going to be decoding
|
// Compile the list of all the fields that we're going to be decoding
|
||||||
// from all the structs.
|
// from all the structs.
|
||||||
fields := make(map[*reflect.StructField]reflect.Value)
|
type field struct {
|
||||||
|
field reflect.StructField
|
||||||
|
val reflect.Value
|
||||||
|
}
|
||||||
|
fields := []field{}
|
||||||
for len(structs) > 0 {
|
for len(structs) > 0 {
|
||||||
structVal := structs[0]
|
structVal := structs[0]
|
||||||
structs = structs[1:]
|
structs = structs[1:]
|
||||||
|
@ -616,7 +620,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal struct field, store it away
|
// Normal struct field, store it away
|
||||||
fields[&fieldType] = structVal.Field(i)
|
fields = append(fields, field{fieldType, structVal.Field(i)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,26 +628,27 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||||
decodedFields := make([]string, 0, len(fields))
|
decodedFields := make([]string, 0, len(fields))
|
||||||
decodedFieldsVal := make([]reflect.Value, 0)
|
decodedFieldsVal := make([]reflect.Value, 0)
|
||||||
unusedKeysVal := make([]reflect.Value, 0)
|
unusedKeysVal := make([]reflect.Value, 0)
|
||||||
for fieldType, field := range fields {
|
for _, f := range fields {
|
||||||
if !field.IsValid() {
|
field, fieldValue := f.field, f.val
|
||||||
|
if !fieldValue.IsValid() {
|
||||||
// This should never happen
|
// This should never happen
|
||||||
panic("field is not valid")
|
panic("field is not valid")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't set the field, then it is unexported or something,
|
// If we can't set the field, then it is unexported or something,
|
||||||
// and we just continue onwards.
|
// and we just continue onwards.
|
||||||
if !field.CanSet() {
|
if !fieldValue.CanSet() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldName := fieldType.Name
|
fieldName := field.Name
|
||||||
|
|
||||||
tagValue := fieldType.Tag.Get(tagName)
|
tagValue := field.Tag.Get(tagName)
|
||||||
tagParts := strings.SplitN(tagValue, ",", 2)
|
tagParts := strings.SplitN(tagValue, ",", 2)
|
||||||
if len(tagParts) >= 2 {
|
if len(tagParts) >= 2 {
|
||||||
switch tagParts[1] {
|
switch tagParts[1] {
|
||||||
case "decodedFields":
|
case "decodedFields":
|
||||||
decodedFieldsVal = append(decodedFieldsVal, field)
|
decodedFieldsVal = append(decodedFieldsVal, fieldValue)
|
||||||
continue
|
continue
|
||||||
case "key":
|
case "key":
|
||||||
if item == nil {
|
if item == nil {
|
||||||
|
@ -654,10 +659,10 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field.SetString(item.Keys[0].Token.Value().(string))
|
fieldValue.SetString(item.Keys[0].Token.Value().(string))
|
||||||
continue
|
continue
|
||||||
case "unusedKeys":
|
case "unusedKeys":
|
||||||
unusedKeysVal = append(unusedKeysVal, field)
|
unusedKeysVal = append(unusedKeysVal, fieldValue)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -684,7 +689,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||||
// because we actually want the value.
|
// because we actually want the value.
|
||||||
fieldName = fmt.Sprintf("%s.%s", name, fieldName)
|
fieldName = fmt.Sprintf("%s.%s", name, fieldName)
|
||||||
if len(prefixMatches.Items) > 0 {
|
if len(prefixMatches.Items) > 0 {
|
||||||
if err := d.decode(fieldName, prefixMatches, field); err != nil {
|
if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -694,12 +699,12 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||||
decodeNode = &ast.ObjectList{Items: ot.List.Items}
|
decodeNode = &ast.ObjectList{Items: ot.List.Items}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.decode(fieldName, decodeNode, field); err != nil {
|
if err := d.decode(fieldName, decodeNode, fieldValue); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedFields = append(decodedFields, fieldType.Name)
|
decodedFields = append(decodedFields, field.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(decodedFieldsVal) > 0 {
|
if len(decodedFieldsVal) > 0 {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/hashicorp/hcl
|
||||||
|
|
||||||
|
require github.com/davecgh/go-spew v1.1.1
|
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
@ -197,9 +197,18 @@ func (p *Parser) objectItem() (*ast.ObjectItem, error) {
|
||||||
keyStr = append(keyStr, k.Token.Text)
|
keyStr = append(keyStr, k.Token.Text)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf(
|
return nil, &PosError{
|
||||||
"key '%s' expected start of object ('{') or assignment ('=')",
|
Pos: p.tok.Pos,
|
||||||
strings.Join(keyStr, " "))
|
Err: fmt.Errorf(
|
||||||
|
"key '%s' expected start of object ('{') or assignment ('=')",
|
||||||
|
strings.Join(keyStr, " ")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// key=#comment
|
||||||
|
// val
|
||||||
|
if p.lineComment != nil {
|
||||||
|
o.LineComment, p.lineComment = p.lineComment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// do a look-ahead for line comment
|
// do a look-ahead for line comment
|
||||||
|
@ -319,7 +328,10 @@ func (p *Parser) objectType() (*ast.ObjectType, error) {
|
||||||
|
|
||||||
// No error, scan and expect the ending to be a brace
|
// No error, scan and expect the ending to be a brace
|
||||||
if tok := p.scan(); tok.Type != token.RBRACE {
|
if tok := p.scan(); tok.Type != token.RBRACE {
|
||||||
return nil, fmt.Errorf("object expected closing RBRACE got: %s", tok.Type)
|
return nil, &PosError{
|
||||||
|
Pos: tok.Pos,
|
||||||
|
Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.List = l
|
o.List = l
|
||||||
|
|
|
@ -252,6 +252,14 @@ func (p *printer) objectItem(o *ast.ObjectItem) []byte {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If key and val are on different lines, treat line comments like lead comments.
|
||||||
|
if o.LineComment != nil && o.Val.Pos().Line != o.Keys[0].Pos().Line {
|
||||||
|
for _, comment := range o.LineComment.List {
|
||||||
|
buf.WriteString(comment.Text)
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i, k := range o.Keys {
|
for i, k := range o.Keys {
|
||||||
buf.WriteString(k.Token.Text)
|
buf.WriteString(k.Token.Text)
|
||||||
buf.WriteByte(blank)
|
buf.WriteByte(blank)
|
||||||
|
@ -265,7 +273,7 @@ func (p *printer) objectItem(o *ast.ObjectItem) []byte {
|
||||||
|
|
||||||
buf.Write(p.output(o.Val))
|
buf.Write(p.output(o.Val))
|
||||||
|
|
||||||
if o.Val.Pos().Line == o.Keys[0].Pos().Line && o.LineComment != nil {
|
if o.LineComment != nil && o.Val.Pos().Line == o.Keys[0].Pos().Line {
|
||||||
buf.WriteByte(blank)
|
buf.WriteByte(blank)
|
||||||
for _, comment := range o.LineComment.List {
|
for _, comment := range o.LineComment.List {
|
||||||
buf.WriteString(comment.Text)
|
buf.WriteString(comment.Text)
|
||||||
|
@ -509,8 +517,13 @@ func (p *printer) alignedItems(items []*ast.ObjectItem) []byte {
|
||||||
|
|
||||||
// list returns the printable HCL form of an list type.
|
// list returns the printable HCL form of an list type.
|
||||||
func (p *printer) list(l *ast.ListType) []byte {
|
func (p *printer) list(l *ast.ListType) []byte {
|
||||||
|
if p.isSingleLineList(l) {
|
||||||
|
return p.singleLineList(l)
|
||||||
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString("[")
|
buf.WriteString("[")
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
|
||||||
var longestLine int
|
var longestLine int
|
||||||
for _, item := range l.List {
|
for _, item := range l.List {
|
||||||
|
@ -523,115 +536,112 @@ func (p *printer) list(l *ast.ListType) []byte {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
insertSpaceBeforeItem := false
|
haveEmptyLine := false
|
||||||
lastHadLeadComment := false
|
|
||||||
for i, item := range l.List {
|
for i, item := range l.List {
|
||||||
// Keep track of whether this item is a heredoc since that has
|
// If we have a lead comment, then we want to write that first
|
||||||
// unique behavior.
|
leadComment := false
|
||||||
heredoc := false
|
if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil {
|
||||||
|
leadComment = true
|
||||||
|
|
||||||
|
// Ensure an empty line before every element with a
|
||||||
|
// lead comment (except the first item in a list).
|
||||||
|
if !haveEmptyLine && i != 0 {
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, comment := range lit.LeadComment.List {
|
||||||
|
buf.Write(p.indent([]byte(comment.Text)))
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also indent each line
|
||||||
|
val := p.output(item)
|
||||||
|
curLen := len(val)
|
||||||
|
buf.Write(p.indent(val))
|
||||||
|
|
||||||
|
// if this item is a heredoc, then we output the comma on
|
||||||
|
// the next line. This is the only case this happens.
|
||||||
|
comma := []byte{','}
|
||||||
if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC {
|
if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC {
|
||||||
heredoc = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if item.Pos().Line != l.Lbrack.Line {
|
|
||||||
// multiline list, add newline before we add each item
|
|
||||||
buf.WriteByte(newline)
|
buf.WriteByte(newline)
|
||||||
insertSpaceBeforeItem = false
|
comma = p.indent(comma)
|
||||||
|
}
|
||||||
|
|
||||||
// If we have a lead comment, then we want to write that first
|
buf.Write(comma)
|
||||||
leadComment := false
|
|
||||||
if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil {
|
|
||||||
leadComment = true
|
|
||||||
|
|
||||||
// If this isn't the first item and the previous element
|
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
|
||||||
// didn't have a lead comment, then we need to add an extra
|
// if the next item doesn't have any comments, do not align
|
||||||
// newline to properly space things out. If it did have a
|
buf.WriteByte(blank) // align one space
|
||||||
// lead comment previously then this would be done
|
for i := 0; i < longestLine-curLen; i++ {
|
||||||
// automatically.
|
|
||||||
if i > 0 && !lastHadLeadComment {
|
|
||||||
buf.WriteByte(newline)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, comment := range lit.LeadComment.List {
|
|
||||||
buf.Write(p.indent([]byte(comment.Text)))
|
|
||||||
buf.WriteByte(newline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// also indent each line
|
|
||||||
val := p.output(item)
|
|
||||||
curLen := len(val)
|
|
||||||
buf.Write(p.indent(val))
|
|
||||||
|
|
||||||
// if this item is a heredoc, then we output the comma on
|
|
||||||
// the next line. This is the only case this happens.
|
|
||||||
comma := []byte{','}
|
|
||||||
if heredoc {
|
|
||||||
buf.WriteByte(newline)
|
|
||||||
comma = p.indent(comma)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.Write(comma)
|
|
||||||
|
|
||||||
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
|
|
||||||
// if the next item doesn't have any comments, do not align
|
|
||||||
buf.WriteByte(blank) // align one space
|
|
||||||
for i := 0; i < longestLine-curLen; i++ {
|
|
||||||
buf.WriteByte(blank)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, comment := range lit.LineComment.List {
|
|
||||||
buf.WriteString(comment.Text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastItem := i == len(l.List)-1
|
|
||||||
if lastItem {
|
|
||||||
buf.WriteByte(newline)
|
|
||||||
}
|
|
||||||
|
|
||||||
if leadComment && !lastItem {
|
|
||||||
buf.WriteByte(newline)
|
|
||||||
}
|
|
||||||
|
|
||||||
lastHadLeadComment = leadComment
|
|
||||||
} else {
|
|
||||||
if insertSpaceBeforeItem {
|
|
||||||
buf.WriteByte(blank)
|
buf.WriteByte(blank)
|
||||||
insertSpaceBeforeItem = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output the item itself
|
for _, comment := range lit.LineComment.List {
|
||||||
// also indent each line
|
buf.WriteString(comment.Text)
|
||||||
val := p.output(item)
|
|
||||||
curLen := len(val)
|
|
||||||
buf.Write(val)
|
|
||||||
|
|
||||||
// If this is a heredoc item we always have to output a newline
|
|
||||||
// so that it parses properly.
|
|
||||||
if heredoc {
|
|
||||||
buf.WriteByte(newline)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this isn't the last element, write a comma.
|
|
||||||
if i != len(l.List)-1 {
|
|
||||||
buf.WriteString(",")
|
|
||||||
insertSpaceBeforeItem = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
|
|
||||||
// if the next item doesn't have any comments, do not align
|
|
||||||
buf.WriteByte(blank) // align one space
|
|
||||||
for i := 0; i < longestLine-curLen; i++ {
|
|
||||||
buf.WriteByte(blank)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, comment := range lit.LineComment.List {
|
|
||||||
buf.WriteString(comment.Text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
|
||||||
|
// Ensure an empty line after every element with a
|
||||||
|
// lead comment (except the first item in a list).
|
||||||
|
haveEmptyLine = leadComment && i != len(l.List)-1
|
||||||
|
if haveEmptyLine {
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("]")
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// isSingleLineList returns true if:
|
||||||
|
// * they were previously formatted entirely on one line
|
||||||
|
// * they consist entirely of literals
|
||||||
|
// * there are either no heredoc strings or the list has exactly one element
|
||||||
|
// * there are no line comments
|
||||||
|
func (printer) isSingleLineList(l *ast.ListType) bool {
|
||||||
|
for _, item := range l.List {
|
||||||
|
if item.Pos().Line != l.Lbrack.Line {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
lit, ok := item.(*ast.LiteralType)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if lit.Token.Type == token.HEREDOC && len(l.List) != 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if lit.LineComment != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleLineList prints a simple single line list.
|
||||||
|
// For a definition of "simple", see isSingleLineList above.
|
||||||
|
func (p *printer) singleLineList(l *ast.ListType) []byte {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
buf.WriteString("[")
|
||||||
|
for i, item := range l.List {
|
||||||
|
if i != 0 {
|
||||||
|
buf.WriteString(", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the item itself
|
||||||
|
buf.Write(p.output(item))
|
||||||
|
|
||||||
|
// The heredoc marker needs to be at the end of line.
|
||||||
|
if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC {
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString("]")
|
buf.WriteString("]")
|
||||||
|
|
|
@ -74,14 +74,6 @@ func (s *Scanner) next() rune {
|
||||||
return eof
|
return eof
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch == utf8.RuneError && size == 1 {
|
|
||||||
s.srcPos.Column++
|
|
||||||
s.srcPos.Offset += size
|
|
||||||
s.lastCharLen = size
|
|
||||||
s.err("illegal UTF-8 encoding")
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
// remember last position
|
// remember last position
|
||||||
s.prevPos = s.srcPos
|
s.prevPos = s.srcPos
|
||||||
|
|
||||||
|
@ -89,18 +81,27 @@ func (s *Scanner) next() rune {
|
||||||
s.lastCharLen = size
|
s.lastCharLen = size
|
||||||
s.srcPos.Offset += size
|
s.srcPos.Offset += size
|
||||||
|
|
||||||
|
if ch == utf8.RuneError && size == 1 {
|
||||||
|
s.err("illegal UTF-8 encoding")
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
if ch == '\n' {
|
if ch == '\n' {
|
||||||
s.srcPos.Line++
|
s.srcPos.Line++
|
||||||
s.lastLineLen = s.srcPos.Column
|
s.lastLineLen = s.srcPos.Column
|
||||||
s.srcPos.Column = 0
|
s.srcPos.Column = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we see a null character with data left, then that is an error
|
if ch == '\x00' {
|
||||||
if ch == '\x00' && s.buf.Len() > 0 {
|
|
||||||
s.err("unexpected null character (0x00)")
|
s.err("unexpected null character (0x00)")
|
||||||
return eof
|
return eof
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ch == '\uE123' {
|
||||||
|
s.err("unicode code point U+E123 reserved for internal use")
|
||||||
|
return utf8.RuneError
|
||||||
|
}
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
// fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column)
|
// fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column)
|
||||||
return ch
|
return ch
|
||||||
|
@ -351,7 +352,7 @@ func (s *Scanner) scanNumber(ch rune) token.Type {
|
||||||
return token.NUMBER
|
return token.NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
// scanMantissa scans the mantissa beginning from the rune. It returns the next
|
||||||
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
||||||
func (s *Scanner) scanMantissa(ch rune) rune {
|
func (s *Scanner) scanMantissa(ch rune) rune {
|
||||||
scanned := false
|
scanned := false
|
||||||
|
@ -432,16 +433,16 @@ func (s *Scanner) scanHeredoc() {
|
||||||
|
|
||||||
// Read the identifier
|
// Read the identifier
|
||||||
identBytes := s.src[offs : s.srcPos.Offset-s.lastCharLen]
|
identBytes := s.src[offs : s.srcPos.Offset-s.lastCharLen]
|
||||||
if len(identBytes) == 0 {
|
if len(identBytes) == 0 || (len(identBytes) == 1 && identBytes[0] == '-') {
|
||||||
s.err("zero-length heredoc anchor")
|
s.err("zero-length heredoc anchor")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var identRegexp *regexp.Regexp
|
var identRegexp *regexp.Regexp
|
||||||
if identBytes[0] == '-' {
|
if identBytes[0] == '-' {
|
||||||
identRegexp = regexp.MustCompile(fmt.Sprintf(`[[:space:]]*%s\z`, identBytes[1:]))
|
identRegexp = regexp.MustCompile(fmt.Sprintf(`^[[:space:]]*%s\r*\z`, identBytes[1:]))
|
||||||
} else {
|
} else {
|
||||||
identRegexp = regexp.MustCompile(fmt.Sprintf(`[[:space:]]*%s\z`, identBytes))
|
identRegexp = regexp.MustCompile(fmt.Sprintf(`^[[:space:]]*%s\r*\z`, identBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the actual string value
|
// Read the actual string value
|
||||||
|
@ -551,7 +552,7 @@ func (s *Scanner) scanDigits(ch rune, base, n int) rune {
|
||||||
s.err("illegal char escape")
|
s.err("illegal char escape")
|
||||||
}
|
}
|
||||||
|
|
||||||
if n != start {
|
if n != start && ch != eof {
|
||||||
// we scanned all digits, put the last non digit char back,
|
// we scanned all digits, put the last non digit char back,
|
||||||
// only if we read anything at all
|
// only if we read anything at all
|
||||||
s.unread()
|
s.unread()
|
||||||
|
|
|
@ -246,7 +246,7 @@ func (s *Scanner) scanNumber(ch rune) token.Type {
|
||||||
return token.NUMBER
|
return token.NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
// scanMantissa scans the mantissa beginning from the rune. It returns the next
|
||||||
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
||||||
func (s *Scanner) scanMantissa(ch rune) rune {
|
func (s *Scanner) scanMantissa(ch rune) rune {
|
||||||
scanned := false
|
scanned := false
|
||||||
|
|
|
@ -0,0 +1,353 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. “Contributor”
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. “Contributor Version”
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor’s Contribution.
|
||||||
|
|
||||||
|
1.3. “Contribution”
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. “Covered Software”
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. “Incompatible With Secondary Licenses”
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of version
|
||||||
|
1.1 or earlier of the License, but not also under the terms of a
|
||||||
|
Secondary License.
|
||||||
|
|
||||||
|
1.6. “Executable Form”
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. “Larger Work”
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a separate
|
||||||
|
file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. “License”
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. “Licensable”
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether at the
|
||||||
|
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||||
|
this License.
|
||||||
|
|
||||||
|
1.10. “Modifications”
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to, deletion
|
||||||
|
from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. “Patent Claims” of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method, process,
|
||||||
|
and apparatus claims, in any patent Licensable by such Contributor that
|
||||||
|
would be infringed, but for the grant of the License, by the making,
|
||||||
|
using, selling, offering for sale, having made, import, or transfer of
|
||||||
|
either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. “Secondary License”
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. “Source Code Form”
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. “You” (or “Your”)
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, “You” includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, “control” means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or as
|
||||||
|
part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its Contributions
|
||||||
|
or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||||
|
effective for each Contribution on the date the Contributor first distributes
|
||||||
|
such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under this
|
||||||
|
License. No additional rights or licenses will be implied from the distribution
|
||||||
|
or licensing of Covered Software under this License. Notwithstanding Section
|
||||||
|
2.1(b) above, no patent license is granted by a Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party’s
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||||
|
Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks, or
|
||||||
|
logos of any Contributor (except as may be necessary to comply with the
|
||||||
|
notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this License
|
||||||
|
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||||
|
under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its Contributions
|
||||||
|
are its original creation(s) or it has sufficient rights to grant the
|
||||||
|
rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under applicable
|
||||||
|
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under the
|
||||||
|
terms of this License. You must inform recipients that the Source Code Form
|
||||||
|
of the Covered Software is governed by the terms of this License, and how
|
||||||
|
they can obtain a copy of this License. You may not attempt to alter or
|
||||||
|
restrict the recipients’ rights in the Source Code Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this License,
|
||||||
|
or sublicense it under different terms, provided that the license for
|
||||||
|
the Executable Form does not attempt to limit or alter the recipients’
|
||||||
|
rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for the
|
||||||
|
Covered Software. If the Larger Work is a combination of Covered Software
|
||||||
|
with a work governed by one or more Secondary Licenses, and the Covered
|
||||||
|
Software is not Incompatible With Secondary Licenses, this License permits
|
||||||
|
You to additionally distribute such Covered Software under the terms of
|
||||||
|
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||||
|
their option, further distribute the Covered Software under the terms of
|
||||||
|
either this License or such Secondary License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices (including
|
||||||
|
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||||
|
of liability) contained within the Source Code Form of the Covered
|
||||||
|
Software, except that You may alter any license notices to the extent
|
||||||
|
required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||||
|
of any Contributor. You must make it absolutely clear that any such
|
||||||
|
warranty, support, indemnity, or liability obligation is offered by You
|
||||||
|
alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute, judicial
|
||||||
|
order, or regulation then You must: (a) comply with the terms of this License
|
||||||
|
to the maximum extent possible; and (b) describe the limitations and the code
|
||||||
|
they affect. Such description must be placed in a text file included with all
|
||||||
|
distributions of the Covered Software under this License. Except to the
|
||||||
|
extent prohibited by statute or regulation, such description must be
|
||||||
|
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||||
|
understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||||
|
if such Contributor fails to notify You of the non-compliance by some
|
||||||
|
reasonable means prior to 60 days after You have come back into compliance.
|
||||||
|
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||||
|
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||||
|
some reasonable means, this is the first time You have received notice of
|
||||||
|
non-compliance with this License from such Contributor, and You become
|
||||||
|
compliant prior to 30 days after Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||||
|
and cross-claims) alleging that a Contributor Version directly or
|
||||||
|
indirectly infringes any patent, then the rights granted to You by any and
|
||||||
|
all Contributors for the Covered Software under Section 2.1 of this License
|
||||||
|
shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an “as is” basis, without
|
||||||
|
warranty of any kind, either expressed, implied, or statutory, including,
|
||||||
|
without limitation, warranties that the Covered Software is free of defects,
|
||||||
|
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||||
|
risk as to the quality and performance of the Covered Software is with You.
|
||||||
|
Should any Covered Software prove defective in any respect, You (not any
|
||||||
|
Contributor) assume the cost of any necessary servicing, repair, or
|
||||||
|
correction. This disclaimer of warranty constitutes an essential part of this
|
||||||
|
License. No use of any Covered Software is authorized under this License
|
||||||
|
except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from such
|
||||||
|
party’s negligence to the extent applicable law prohibits such limitation.
|
||||||
|
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||||
|
consequential damages, so this exclusion and limitation may not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts of
|
||||||
|
a jurisdiction where the defendant maintains its principal place of business
|
||||||
|
and such litigation shall be governed by laws of that jurisdiction, without
|
||||||
|
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||||
|
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject matter
|
||||||
|
hereof. If any provision of this License is held to be unenforceable, such
|
||||||
|
provision shall be reformed only to the extent necessary to make it
|
||||||
|
enforceable. Any law or regulation which provides that the language of a
|
||||||
|
contract shall be construed against the drafter shall not be used to construe
|
||||||
|
this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version of
|
||||||
|
the License under which You originally received the Covered Software, or
|
||||||
|
under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a modified
|
||||||
|
version of this License if you rename the license and remove any
|
||||||
|
references to the name of the license steward (except to note that such
|
||||||
|
modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file, then
|
||||||
|
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||||
|
directory) where a recipient would be likely to look for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||||
|
|
||||||
|
This Source Code Form is “Incompatible
|
||||||
|
With Secondary Licenses”, as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
138
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go
generated
vendored
Normal file
138
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go
generated
vendored
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
legacyhclparser "github.com/hashicorp/hcl/hcl/parser"
|
||||||
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Diagnostic describes a problem (error or warning) encountered during
|
||||||
|
// configuration loading.
|
||||||
|
type Diagnostic struct {
|
||||||
|
Severity DiagSeverity `json:"severity"`
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Detail string `json:"detail,omitempty"`
|
||||||
|
|
||||||
|
// Pos is not populated for all diagnostics, but when populated should
|
||||||
|
// indicate a particular line that the described problem relates to.
|
||||||
|
Pos *SourcePos `json:"pos,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnostics represents a sequence of diagnostics. This is the type that
|
||||||
|
// should be returned from a function that might generate diagnostics.
|
||||||
|
type Diagnostics []Diagnostic
|
||||||
|
|
||||||
|
// HasErrors returns true if there is at least one Diagnostic of severity
|
||||||
|
// DiagError in the receiever.
|
||||||
|
//
|
||||||
|
// If a function returns a Diagnostics without errors then the result can
|
||||||
|
// be assumed to be complete within the "best effort" constraints of this
|
||||||
|
// library. If errors are present then the caller may wish to employ more
|
||||||
|
// caution in relying on the result.
|
||||||
|
func (diags Diagnostics) HasErrors() bool {
|
||||||
|
for _, diag := range diags {
|
||||||
|
if diag.Severity == DiagError {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (diags Diagnostics) Error() string {
|
||||||
|
switch len(diags) {
|
||||||
|
case 0:
|
||||||
|
return "no problems"
|
||||||
|
case 1:
|
||||||
|
return fmt.Sprintf("%s: %s", diags[0].Summary, diags[0].Detail)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%s: %s (and %d other messages)", diags[0].Summary, diags[0].Detail, len(diags)-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns an error representing the receiver if the receiver HasErrors, or
|
||||||
|
// nil otherwise.
|
||||||
|
//
|
||||||
|
// The returned error can be type-asserted back to a Diagnostics if needed.
|
||||||
|
func (diags Diagnostics) Err() error {
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiagSeverity describes the severity of a Diagnostic.
|
||||||
|
type DiagSeverity rune
|
||||||
|
|
||||||
|
// DiagError indicates a problem that prevented proper processing of the
|
||||||
|
// configuration. In the precense of DiagError diagnostics the result is
|
||||||
|
// likely to be incomplete.
|
||||||
|
const DiagError DiagSeverity = 'E'
|
||||||
|
|
||||||
|
// DiagWarning indicates a problem that the user may wish to consider but
|
||||||
|
// that did not prevent proper processing of the configuration.
|
||||||
|
const DiagWarning DiagSeverity = 'W'
|
||||||
|
|
||||||
|
// MarshalJSON is an implementation of encoding/json.Marshaler
|
||||||
|
func (s DiagSeverity) MarshalJSON() ([]byte, error) {
|
||||||
|
switch s {
|
||||||
|
case DiagError:
|
||||||
|
return []byte(`"error"`), nil
|
||||||
|
case DiagWarning:
|
||||||
|
return []byte(`"warning"`), nil
|
||||||
|
default:
|
||||||
|
return []byte(`"invalid"`), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func diagnosticsHCL(diags hcl.Diagnostics) Diagnostics {
|
||||||
|
if len(diags) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := make(Diagnostics, len(diags))
|
||||||
|
for i, diag := range diags {
|
||||||
|
ret[i] = Diagnostic{
|
||||||
|
Summary: diag.Summary,
|
||||||
|
Detail: diag.Detail,
|
||||||
|
}
|
||||||
|
switch diag.Severity {
|
||||||
|
case hcl.DiagError:
|
||||||
|
ret[i].Severity = DiagError
|
||||||
|
case hcl.DiagWarning:
|
||||||
|
ret[i].Severity = DiagWarning
|
||||||
|
}
|
||||||
|
if diag.Subject != nil {
|
||||||
|
pos := sourcePosHCL(*diag.Subject)
|
||||||
|
ret[i].Pos = &pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func diagnosticsError(err error) Diagnostics {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if posErr, ok := err.(*legacyhclparser.PosError); ok {
|
||||||
|
pos := sourcePosLegacyHCL(posErr.Pos, "")
|
||||||
|
return Diagnostics{
|
||||||
|
Diagnostic{
|
||||||
|
Severity: DiagError,
|
||||||
|
Summary: posErr.Err.Error(),
|
||||||
|
Pos: &pos,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Diagnostics{
|
||||||
|
Diagnostic{
|
||||||
|
Severity: DiagError,
|
||||||
|
Summary: err.Error(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func diagnosticsErrorf(format string, args ...interface{}) Diagnostics {
|
||||||
|
return diagnosticsError(fmt.Errorf(format, args...))
|
||||||
|
}
|
21
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go
generated
vendored
Normal file
21
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Package tfconfig is a helper library that does careful, shallow parsing of
|
||||||
|
// Terraform modules to provide access to high-level metadata while
|
||||||
|
// remaining broadly compatible with configurations targeting various
|
||||||
|
// different Terraform versions.
|
||||||
|
//
|
||||||
|
// This packge focuses on describing top-level objects only, and in particular
|
||||||
|
// does not attempt any sort of processing that would require access to plugins.
|
||||||
|
// Currently it allows callers to extract high-level information about
|
||||||
|
// variables, outputs, resource blocks, provider dependencies, and Terraform
|
||||||
|
// Core dependencies.
|
||||||
|
//
|
||||||
|
// This package only works at the level of single modules. A full configuration
|
||||||
|
// is a tree of potentially several modules, some of which may be references
|
||||||
|
// to remote packages. There are some basic helpers for traversing calls to
|
||||||
|
// modules at relative local paths, however.
|
||||||
|
//
|
||||||
|
// This package employs a "best effort" parsing strategy, producing as complete
|
||||||
|
// a result as possible even though the input may not be entirely valid. The
|
||||||
|
// intended use-case is high-level analysis and indexing of externally-facing
|
||||||
|
// module characteristics, as opposed to validating or even applying the module.
|
||||||
|
package tfconfig
|
130
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go
generated
vendored
Normal file
130
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go
generated
vendored
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadModule reads the directory at the given path and attempts to interpret
|
||||||
|
// it as a Terraform module.
|
||||||
|
func LoadModule(dir string) (*Module, Diagnostics) {
|
||||||
|
|
||||||
|
// For broad compatibility here we actually have two separate loader
|
||||||
|
// codepaths. The main one uses the new HCL parser and API and is intended
|
||||||
|
// for configurations from Terraform 0.12 onwards (though will work for
|
||||||
|
// many older configurations too), but we'll also fall back on one that
|
||||||
|
// uses the _old_ HCL implementation so we can deal with some edge-cases
|
||||||
|
// that are not valid in new HCL.
|
||||||
|
|
||||||
|
module, diags := loadModule(dir)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
// Try using the legacy HCL parser and see if we fare better.
|
||||||
|
legacyModule, legacyDiags := loadModuleLegacyHCL(dir)
|
||||||
|
if !legacyDiags.HasErrors() {
|
||||||
|
legacyModule.init(legacyDiags)
|
||||||
|
return legacyModule, legacyDiags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.init(diags)
|
||||||
|
return module, diags
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsModuleDir checks if the given path contains terraform configuration files.
|
||||||
|
// This allows the caller to decide how to handle directories that do not have tf files.
|
||||||
|
func IsModuleDir(dir string) bool {
|
||||||
|
primaryPaths, _ := dirFiles(dir)
|
||||||
|
if len(primaryPaths) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Module) init(diags Diagnostics) {
|
||||||
|
// Fill in any additional provider requirements that are implied by
|
||||||
|
// resource configurations, to avoid the caller from needing to apply
|
||||||
|
// this logic itself. Implied requirements don't have version constraints,
|
||||||
|
// but we'll make sure the requirement value is still non-nil in this
|
||||||
|
// case so callers can easily recognize it.
|
||||||
|
for _, r := range m.ManagedResources {
|
||||||
|
if _, exists := m.RequiredProviders[r.Provider.Name]; !exists {
|
||||||
|
m.RequiredProviders[r.Provider.Name] = []string{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, r := range m.DataResources {
|
||||||
|
if _, exists := m.RequiredProviders[r.Provider.Name]; !exists {
|
||||||
|
m.RequiredProviders[r.Provider.Name] = []string{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We redundantly also reference the diagnostics from inside the module
|
||||||
|
// object, primarily so that we can easily included in JSON-serialized
|
||||||
|
// versions of the module object.
|
||||||
|
m.Diagnostics = diags
|
||||||
|
}
|
||||||
|
|
||||||
|
func dirFiles(dir string) (primary []string, diags hcl.Diagnostics) {
|
||||||
|
infos, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Failed to read module directory",
|
||||||
|
Detail: fmt.Sprintf("Module directory %s does not exist or cannot be read.", dir),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var override []string
|
||||||
|
for _, info := range infos {
|
||||||
|
if info.IsDir() {
|
||||||
|
// We only care about files
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := info.Name()
|
||||||
|
ext := fileExt(name)
|
||||||
|
if ext == "" || isIgnoredFile(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
baseName := name[:len(name)-len(ext)] // strip extension
|
||||||
|
isOverride := baseName == "override" || strings.HasSuffix(baseName, "_override")
|
||||||
|
|
||||||
|
fullPath := filepath.Join(dir, name)
|
||||||
|
if isOverride {
|
||||||
|
override = append(override, fullPath)
|
||||||
|
} else {
|
||||||
|
primary = append(primary, fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are assuming that any _override files will be logically named,
|
||||||
|
// and processing the files in alphabetical order. Primaries first, then overrides.
|
||||||
|
primary = append(primary, override...)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileExt returns the Terraform configuration extension of the given
|
||||||
|
// path, or a blank string if it is not a recognized extension.
|
||||||
|
func fileExt(path string) string {
|
||||||
|
if strings.HasSuffix(path, ".tf") {
|
||||||
|
return ".tf"
|
||||||
|
} else if strings.HasSuffix(path, ".tf.json") {
|
||||||
|
return ".tf.json"
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isIgnoredFile returns true if the given filename (which must not have a
|
||||||
|
// directory path ahead of it) should be ignored as e.g. an editor swap file.
|
||||||
|
func isIgnoredFile(name string) bool {
|
||||||
|
return strings.HasPrefix(name, ".") || // Unix-like hidden files
|
||||||
|
strings.HasSuffix(name, "~") || // vim
|
||||||
|
strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs
|
||||||
|
}
|
312
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go
generated
vendored
Normal file
312
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go
generated
vendored
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl2/gohcl"
|
||||||
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
"github.com/hashicorp/hcl2/hclparse"
|
||||||
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadModule(dir string) (*Module, Diagnostics) {
|
||||||
|
mod := newModule(dir)
|
||||||
|
primaryPaths, diags := dirFiles(dir)
|
||||||
|
|
||||||
|
parser := hclparse.NewParser()
|
||||||
|
|
||||||
|
for _, filename := range primaryPaths {
|
||||||
|
var file *hcl.File
|
||||||
|
var fileDiags hcl.Diagnostics
|
||||||
|
if strings.HasSuffix(filename, ".json") {
|
||||||
|
file, fileDiags = parser.ParseJSONFile(filename)
|
||||||
|
} else {
|
||||||
|
file, fileDiags = parser.ParseHCLFile(filename)
|
||||||
|
}
|
||||||
|
diags = append(diags, fileDiags...)
|
||||||
|
if file == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
content, _, contentDiags := file.Body.PartialContent(rootSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
for _, block := range content.Blocks {
|
||||||
|
switch block.Type {
|
||||||
|
|
||||||
|
case "terraform":
|
||||||
|
content, _, contentDiags := block.Body.PartialContent(terraformBlockSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["required_version"]; defined {
|
||||||
|
var version string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
if !valDiags.HasErrors() {
|
||||||
|
mod.RequiredCore = append(mod.RequiredCore, version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, block := range content.Blocks {
|
||||||
|
// Our schema only allows required_providers here, so we
|
||||||
|
// assume that we'll only get that block type.
|
||||||
|
attrs, attrDiags := block.Body.JustAttributes()
|
||||||
|
diags = append(diags, attrDiags...)
|
||||||
|
|
||||||
|
for name, attr := range attrs {
|
||||||
|
var version string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
if !valDiags.HasErrors() {
|
||||||
|
mod.RequiredProviders[name] = append(mod.RequiredProviders[name], version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "variable":
|
||||||
|
content, _, contentDiags := block.Body.PartialContent(variableSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
name := block.Labels[0]
|
||||||
|
v := &Variable{
|
||||||
|
Name: name,
|
||||||
|
Pos: sourcePosHCL(block.DefRange),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.Variables[name] = v
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["type"]; defined {
|
||||||
|
// We handle this particular attribute in a somewhat-tricky way:
|
||||||
|
// since Terraform may evolve its type expression syntax in
|
||||||
|
// future versions, we don't want to be overly-strict in how
|
||||||
|
// we handle it here, and so we'll instead just take the raw
|
||||||
|
// source provided by the user, using the source location
|
||||||
|
// information in the expression object.
|
||||||
|
//
|
||||||
|
// However, older versions of Terraform expected the type
|
||||||
|
// to be a string containing a keyword, so we'll need to
|
||||||
|
// handle that as a special case first for backward compatibility.
|
||||||
|
|
||||||
|
var typeExpr string
|
||||||
|
|
||||||
|
var typeExprAsStr string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &typeExprAsStr)
|
||||||
|
if !valDiags.HasErrors() {
|
||||||
|
typeExpr = typeExprAsStr
|
||||||
|
} else {
|
||||||
|
|
||||||
|
rng := attr.Expr.Range()
|
||||||
|
sourceFilename := rng.Filename
|
||||||
|
source, exists := parser.Sources()[sourceFilename]
|
||||||
|
if exists {
|
||||||
|
typeExpr = string(rng.SliceBytes(source))
|
||||||
|
} else {
|
||||||
|
// This should never happen, so we'll just warn about it and leave the type unspecified.
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Source code not available",
|
||||||
|
Detail: fmt.Sprintf("Source code is not available for the file %q, which declares the variable %q.", sourceFilename, name),
|
||||||
|
Subject: &block.DefRange,
|
||||||
|
})
|
||||||
|
typeExpr = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Type = typeExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["description"]; defined {
|
||||||
|
var description string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &description)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
v.Description = description
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["default"]; defined {
|
||||||
|
// To avoid the caller needing to deal with cty here, we'll
|
||||||
|
// use its JSON encoding to convert into an
|
||||||
|
// approximately-equivalent plain Go interface{} value
|
||||||
|
// to return.
|
||||||
|
val, valDiags := attr.Expr.Value(nil)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
if val.IsWhollyKnown() { // should only be false if there are errors in the input
|
||||||
|
valJSON, err := ctyjson.Marshal(val, val.Type())
|
||||||
|
if err != nil {
|
||||||
|
// Should never happen, since all possible known
|
||||||
|
// values have a JSON mapping.
|
||||||
|
panic(fmt.Errorf("failed to serialize default value as JSON: %s", err))
|
||||||
|
}
|
||||||
|
var def interface{}
|
||||||
|
err = json.Unmarshal(valJSON, &def)
|
||||||
|
if err != nil {
|
||||||
|
// Again should never happen, because valJSON is
|
||||||
|
// guaranteed valid by ctyjson.Marshal.
|
||||||
|
panic(fmt.Errorf("failed to re-parse default value from JSON: %s", err))
|
||||||
|
}
|
||||||
|
v.Default = def
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "output":
|
||||||
|
|
||||||
|
content, _, contentDiags := block.Body.PartialContent(outputSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
name := block.Labels[0]
|
||||||
|
o := &Output{
|
||||||
|
Name: name,
|
||||||
|
Pos: sourcePosHCL(block.DefRange),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.Outputs[name] = o
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["description"]; defined {
|
||||||
|
var description string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &description)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
o.Description = description
|
||||||
|
}
|
||||||
|
|
||||||
|
case "provider":
|
||||||
|
|
||||||
|
content, _, contentDiags := block.Body.PartialContent(providerConfigSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
name := block.Labels[0]
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["version"]; defined {
|
||||||
|
var version string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
if !valDiags.HasErrors() {
|
||||||
|
mod.RequiredProviders[name] = append(mod.RequiredProviders[name], version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even if there wasn't an explicit version required, we still
|
||||||
|
// need an entry in our map to signal the unversioned dependency.
|
||||||
|
if _, exists := mod.RequiredProviders[name]; !exists {
|
||||||
|
mod.RequiredProviders[name] = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "resource", "data":
|
||||||
|
|
||||||
|
content, _, contentDiags := block.Body.PartialContent(resourceSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
typeName := block.Labels[0]
|
||||||
|
name := block.Labels[1]
|
||||||
|
|
||||||
|
r := &Resource{
|
||||||
|
Type: typeName,
|
||||||
|
Name: name,
|
||||||
|
Pos: sourcePosHCL(block.DefRange),
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourcesMap map[string]*Resource
|
||||||
|
|
||||||
|
switch block.Type {
|
||||||
|
case "resource":
|
||||||
|
r.Mode = ManagedResourceMode
|
||||||
|
resourcesMap = mod.ManagedResources
|
||||||
|
case "data":
|
||||||
|
r.Mode = DataResourceMode
|
||||||
|
resourcesMap = mod.DataResources
|
||||||
|
}
|
||||||
|
|
||||||
|
key := r.MapKey()
|
||||||
|
|
||||||
|
resourcesMap[key] = r
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["provider"]; defined {
|
||||||
|
// New style here is to provide this as a naked traversal
|
||||||
|
// expression, but we also support quoted references for
|
||||||
|
// older configurations that predated this convention.
|
||||||
|
traversal, travDiags := hcl.AbsTraversalForExpr(attr.Expr)
|
||||||
|
if travDiags.HasErrors() {
|
||||||
|
traversal = nil // in case we got any partial results
|
||||||
|
|
||||||
|
// Fall back on trying to parse as a string
|
||||||
|
var travStr string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &travStr)
|
||||||
|
if !valDiags.HasErrors() {
|
||||||
|
var strDiags hcl.Diagnostics
|
||||||
|
traversal, strDiags = hclsyntax.ParseTraversalAbs([]byte(travStr), "", hcl.Pos{})
|
||||||
|
if strDiags.HasErrors() {
|
||||||
|
traversal = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get out here with a nil traversal then we didn't
|
||||||
|
// succeed in processing the input.
|
||||||
|
if len(traversal) > 0 {
|
||||||
|
providerName := traversal.RootName()
|
||||||
|
alias := ""
|
||||||
|
if len(traversal) > 1 {
|
||||||
|
if getAttr, ok := traversal[1].(hcl.TraverseAttr); ok {
|
||||||
|
alias = getAttr.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Provider = ProviderRef{
|
||||||
|
Name: providerName,
|
||||||
|
Alias: alias,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Invalid provider reference",
|
||||||
|
Detail: "Provider argument requires a provider name followed by an optional alias, like \"aws.foo\".",
|
||||||
|
Subject: attr.Expr.Range().Ptr(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If provider _isn't_ set then we'll infer it from the
|
||||||
|
// resource type.
|
||||||
|
r.Provider = ProviderRef{
|
||||||
|
Name: resourceTypeDefaultProviderName(r.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "module":
|
||||||
|
|
||||||
|
content, _, contentDiags := block.Body.PartialContent(moduleCallSchema)
|
||||||
|
diags = append(diags, contentDiags...)
|
||||||
|
|
||||||
|
name := block.Labels[0]
|
||||||
|
mc := &ModuleCall{
|
||||||
|
Name: block.Labels[0],
|
||||||
|
Pos: sourcePosHCL(block.DefRange),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.ModuleCalls[name] = mc
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["source"]; defined {
|
||||||
|
var source string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &source)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
mc.Source = source
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr, defined := content.Attributes["version"]; defined {
|
||||||
|
var version string
|
||||||
|
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version)
|
||||||
|
diags = append(diags, valDiags...)
|
||||||
|
mc.Version = version
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Should never happen because our cases above should be
|
||||||
|
// exhaustive for our schema.
|
||||||
|
panic(fmt.Errorf("unhandled block type %q", block.Type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod, diagnosticsHCL(diags)
|
||||||
|
}
|
322
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go
generated
vendored
Normal file
322
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go
generated
vendored
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
legacyhcl "github.com/hashicorp/hcl"
|
||||||
|
legacyast "github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadModuleLegacyHCL(dir string) (*Module, Diagnostics) {
|
||||||
|
// This implementation is intentionally more quick-and-dirty than the
|
||||||
|
// main loader. In particular, it doesn't bother to keep careful track
|
||||||
|
// of multiple error messages because we always fall back on returning
|
||||||
|
// the main parser's error message if our fallback parsing produces
|
||||||
|
// an error, and thus the errors here are not seen by the end-caller.
|
||||||
|
mod := newModule(dir)
|
||||||
|
|
||||||
|
primaryPaths, diags := dirFiles(dir)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return mod, diagnosticsHCL(diags)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filename := range primaryPaths {
|
||||||
|
src, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return mod, diagnosticsErrorf("Error reading %s: %s", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hclRoot, err := legacyhcl.Parse(string(src))
|
||||||
|
if err != nil {
|
||||||
|
return mod, diagnosticsErrorf("Error parsing %s: %s", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
list, ok := hclRoot.Node.(*legacyast.ObjectList)
|
||||||
|
if !ok {
|
||||||
|
return mod, diagnosticsErrorf("Error parsing %s: no root object", filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range list.Filter("terraform").Items {
|
||||||
|
if len(item.Keys) > 0 {
|
||||||
|
item = &legacyast.ObjectItem{
|
||||||
|
Val: &legacyast.ObjectType{
|
||||||
|
List: &legacyast.ObjectList{
|
||||||
|
Items: []*legacyast.ObjectItem{item},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TerraformBlock struct {
|
||||||
|
RequiredVersion string `hcl:"required_version"`
|
||||||
|
}
|
||||||
|
var block TerraformBlock
|
||||||
|
err = legacyhcl.DecodeObject(&block, item.Val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, diagnosticsErrorf("terraform block: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.RequiredVersion != "" {
|
||||||
|
mod.RequiredCore = append(mod.RequiredCore, block.RequiredVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if vars := list.Filter("variable"); len(vars.Items) > 0 {
|
||||||
|
vars = vars.Children()
|
||||||
|
type VariableBlock struct {
|
||||||
|
Type string `hcl:"type"`
|
||||||
|
Default interface{}
|
||||||
|
Description string
|
||||||
|
Fields []string `hcl:",decodedFields"`
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range vars.Items {
|
||||||
|
unwrapLegacyHCLObjectKeysFromJSON(item, 1)
|
||||||
|
|
||||||
|
if len(item.Keys) != 1 {
|
||||||
|
return nil, diagnosticsErrorf("variable block at %s has no label", item.Pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
name := item.Keys[0].Token.Value().(string)
|
||||||
|
|
||||||
|
var block VariableBlock
|
||||||
|
err := legacyhcl.DecodeObject(&block, item.Val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, diagnosticsErrorf("invalid variable block at %s: %s", item.Pos(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up legacy HCL decoding ambiguity by unwrapping list of maps
|
||||||
|
if ms, ok := block.Default.([]map[string]interface{}); ok {
|
||||||
|
def := make(map[string]interface{})
|
||||||
|
for _, m := range ms {
|
||||||
|
for k, v := range m {
|
||||||
|
def[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block.Default = def
|
||||||
|
}
|
||||||
|
|
||||||
|
v := &Variable{
|
||||||
|
Name: name,
|
||||||
|
Type: block.Type,
|
||||||
|
Description: block.Description,
|
||||||
|
Default: block.Default,
|
||||||
|
Pos: sourcePosLegacyHCL(item.Pos(), filename),
|
||||||
|
}
|
||||||
|
if _, exists := mod.Variables[name]; exists {
|
||||||
|
return nil, diagnosticsErrorf("duplicate variable block for %q", name)
|
||||||
|
}
|
||||||
|
mod.Variables[name] = v
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if outputs := list.Filter("output"); len(outputs.Items) > 0 {
|
||||||
|
outputs = outputs.Children()
|
||||||
|
type OutputBlock struct {
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range outputs.Items {
|
||||||
|
unwrapLegacyHCLObjectKeysFromJSON(item, 1)
|
||||||
|
|
||||||
|
if len(item.Keys) != 1 {
|
||||||
|
return nil, diagnosticsErrorf("output block at %s has no label", item.Pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
name := item.Keys[0].Token.Value().(string)
|
||||||
|
|
||||||
|
var block OutputBlock
|
||||||
|
err := legacyhcl.DecodeObject(&block, item.Val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, diagnosticsErrorf("invalid output block at %s: %s", item.Pos(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &Output{
|
||||||
|
Name: name,
|
||||||
|
Description: block.Description,
|
||||||
|
Pos: sourcePosLegacyHCL(item.Pos(), filename),
|
||||||
|
}
|
||||||
|
if _, exists := mod.Outputs[name]; exists {
|
||||||
|
return nil, diagnosticsErrorf("duplicate output block for %q", name)
|
||||||
|
}
|
||||||
|
mod.Outputs[name] = o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, blockType := range []string{"resource", "data"} {
|
||||||
|
if resources := list.Filter(blockType); len(resources.Items) > 0 {
|
||||||
|
resources = resources.Children()
|
||||||
|
type ResourceBlock struct {
|
||||||
|
Provider string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range resources.Items {
|
||||||
|
unwrapLegacyHCLObjectKeysFromJSON(item, 2)
|
||||||
|
|
||||||
|
if len(item.Keys) != 2 {
|
||||||
|
return nil, diagnosticsErrorf("resource block at %s has wrong label count", item.Pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
typeName := item.Keys[0].Token.Value().(string)
|
||||||
|
name := item.Keys[1].Token.Value().(string)
|
||||||
|
var mode ResourceMode
|
||||||
|
var rMap map[string]*Resource
|
||||||
|
switch blockType {
|
||||||
|
case "resource":
|
||||||
|
mode = ManagedResourceMode
|
||||||
|
rMap = mod.ManagedResources
|
||||||
|
case "data":
|
||||||
|
mode = DataResourceMode
|
||||||
|
rMap = mod.DataResources
|
||||||
|
}
|
||||||
|
|
||||||
|
var block ResourceBlock
|
||||||
|
err := legacyhcl.DecodeObject(&block, item.Val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, diagnosticsErrorf("invalid resource block at %s: %s", item.Pos(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerName, providerAlias string
|
||||||
|
if dotPos := strings.IndexByte(block.Provider, '.'); dotPos != -1 {
|
||||||
|
providerName = block.Provider[:dotPos]
|
||||||
|
providerAlias = block.Provider[dotPos+1:]
|
||||||
|
} else {
|
||||||
|
providerName = block.Provider
|
||||||
|
}
|
||||||
|
if providerName == "" {
|
||||||
|
providerName = resourceTypeDefaultProviderName(typeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &Resource{
|
||||||
|
Mode: mode,
|
||||||
|
Type: typeName,
|
||||||
|
Name: name,
|
||||||
|
Provider: ProviderRef{
|
||||||
|
Name: providerName,
|
||||||
|
Alias: providerAlias,
|
||||||
|
},
|
||||||
|
Pos: sourcePosLegacyHCL(item.Pos(), filename),
|
||||||
|
}
|
||||||
|
key := r.MapKey()
|
||||||
|
if _, exists := rMap[key]; exists {
|
||||||
|
return nil, diagnosticsErrorf("duplicate resource block for %q", key)
|
||||||
|
}
|
||||||
|
rMap[key] = r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if moduleCalls := list.Filter("module"); len(moduleCalls.Items) > 0 {
|
||||||
|
moduleCalls = moduleCalls.Children()
|
||||||
|
type ModuleBlock struct {
|
||||||
|
Source string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range moduleCalls.Items {
|
||||||
|
unwrapLegacyHCLObjectKeysFromJSON(item, 1)
|
||||||
|
|
||||||
|
if len(item.Keys) != 1 {
|
||||||
|
return nil, diagnosticsErrorf("module block at %s has no label", item.Pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
name := item.Keys[0].Token.Value().(string)
|
||||||
|
|
||||||
|
var block ModuleBlock
|
||||||
|
err := legacyhcl.DecodeObject(&block, item.Val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, diagnosticsErrorf("module block at %s: %s", item.Pos(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mc := &ModuleCall{
|
||||||
|
Name: name,
|
||||||
|
Source: block.Source,
|
||||||
|
Version: block.Version,
|
||||||
|
Pos: sourcePosLegacyHCL(item.Pos(), filename),
|
||||||
|
}
|
||||||
|
if _, exists := mod.ModuleCalls[name]; exists {
|
||||||
|
return nil, diagnosticsErrorf("duplicate module block for %q", name)
|
||||||
|
}
|
||||||
|
mod.ModuleCalls[name] = mc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if providerConfigs := list.Filter("provider"); len(providerConfigs.Items) > 0 {
|
||||||
|
providerConfigs = providerConfigs.Children()
|
||||||
|
type ProviderBlock struct {
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range providerConfigs.Items {
|
||||||
|
unwrapLegacyHCLObjectKeysFromJSON(item, 1)
|
||||||
|
|
||||||
|
if len(item.Keys) != 1 {
|
||||||
|
return nil, diagnosticsErrorf("provider block at %s has no label", item.Pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
name := item.Keys[0].Token.Value().(string)
|
||||||
|
|
||||||
|
var block ProviderBlock
|
||||||
|
err := legacyhcl.DecodeObject(&block, item.Val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, diagnosticsErrorf("invalid provider block at %s: %s", item.Pos(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.Version != "" {
|
||||||
|
mod.RequiredProviders[name] = append(mod.RequiredProviders[name], block.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even if there wasn't an explicit version required, we still
|
||||||
|
// need an entry in our map to signal the unversioned dependency.
|
||||||
|
if _, exists := mod.RequiredProviders[name]; !exists {
|
||||||
|
mod.RequiredProviders[name] = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// unwrapLegacyHCLObjectKeysFromJSON cleans up an edge case that can occur when
|
||||||
|
// parsing JSON as input: if we're parsing JSON then directly nested
|
||||||
|
// items will show up as additional "keys".
|
||||||
|
//
|
||||||
|
// For objects that expect a fixed number of keys, this breaks the
|
||||||
|
// decoding process. This function unwraps the object into what it would've
|
||||||
|
// looked like if it came directly from HCL by specifying the number of keys
|
||||||
|
// you expect.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// { "foo": { "baz": {} } }
|
||||||
|
//
|
||||||
|
// Will show up with Keys being: []string{"foo", "baz"}
|
||||||
|
// when we really just want the first two. This function will fix this.
|
||||||
|
func unwrapLegacyHCLObjectKeysFromJSON(item *legacyast.ObjectItem, depth int) {
|
||||||
|
if len(item.Keys) > depth && item.Keys[0].Token.JSON {
|
||||||
|
for len(item.Keys) > depth {
|
||||||
|
// Pop off the last key
|
||||||
|
n := len(item.Keys)
|
||||||
|
key := item.Keys[n-1]
|
||||||
|
item.Keys[n-1] = nil
|
||||||
|
item.Keys = item.Keys[:n-1]
|
||||||
|
|
||||||
|
// Wrap our value in a list
|
||||||
|
item.Val = &legacyast.ObjectType{
|
||||||
|
List: &legacyast.ObjectList{
|
||||||
|
Items: []*legacyast.ObjectItem{
|
||||||
|
&legacyast.ObjectItem{
|
||||||
|
Keys: []*legacyast.ObjectKey{key},
|
||||||
|
Val: item.Val,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go
generated
vendored
Normal file
35
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
// Module is the top-level type representing a parsed and processed Terraform
|
||||||
|
// module.
|
||||||
|
type Module struct {
|
||||||
|
// Path is the local filesystem directory where the module was loaded from.
|
||||||
|
Path string `json:"path"`
|
||||||
|
|
||||||
|
Variables map[string]*Variable `json:"variables"`
|
||||||
|
Outputs map[string]*Output `json:"outputs"`
|
||||||
|
|
||||||
|
RequiredCore []string `json:"required_core,omitempty"`
|
||||||
|
RequiredProviders map[string][]string `json:"required_providers"`
|
||||||
|
|
||||||
|
ManagedResources map[string]*Resource `json:"managed_resources"`
|
||||||
|
DataResources map[string]*Resource `json:"data_resources"`
|
||||||
|
ModuleCalls map[string]*ModuleCall `json:"module_calls"`
|
||||||
|
|
||||||
|
// Diagnostics records any errors and warnings that were detected during
|
||||||
|
// loading, primarily for inclusion in serialized forms of the module
|
||||||
|
// since this slice is also returned as a second argument from LoadModule.
|
||||||
|
Diagnostics Diagnostics `json:"diagnostics,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModule(path string) *Module {
|
||||||
|
return &Module{
|
||||||
|
Path: path,
|
||||||
|
Variables: make(map[string]*Variable),
|
||||||
|
Outputs: make(map[string]*Output),
|
||||||
|
RequiredProviders: make(map[string][]string),
|
||||||
|
ManagedResources: make(map[string]*Resource),
|
||||||
|
DataResources: make(map[string]*Resource),
|
||||||
|
ModuleCalls: make(map[string]*ModuleCall),
|
||||||
|
}
|
||||||
|
}
|
11
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
// ModuleCall represents a "module" block within a module. That is, a
|
||||||
|
// declaration of a child module from inside its parent.
|
||||||
|
type ModuleCall struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
|
||||||
|
Pos SourcePos `json:"pos"`
|
||||||
|
}
|
9
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go
generated
vendored
Normal file
9
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
// Output represents a single output from a Terraform module.
|
||||||
|
type Output struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
Pos SourcePos `json:"pos"`
|
||||||
|
}
|
9
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go
generated
vendored
Normal file
9
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
// ProviderRef is a reference to a provider configuration within a module.
|
||||||
|
// It represents the contents of a "provider" argument in a resource, or
|
||||||
|
// a value in the "providers" map for a module call.
|
||||||
|
type ProviderRef struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Alias string `json:"alias,omitempty"` // Empty if the default provider configuration is referenced
|
||||||
|
}
|
64
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go
generated
vendored
Normal file
64
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource represents a single "resource" or "data" block within a module.
|
||||||
|
type Resource struct {
|
||||||
|
Mode ResourceMode `json:"mode"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
Provider ProviderRef `json:"provider"`
|
||||||
|
|
||||||
|
Pos SourcePos `json:"pos"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapKey returns a string that can be used to uniquely identify the receiver
|
||||||
|
// in a map[string]*Resource.
|
||||||
|
func (r *Resource) MapKey() string {
|
||||||
|
switch r.Mode {
|
||||||
|
case ManagedResourceMode:
|
||||||
|
return fmt.Sprintf("%s.%s", r.Type, r.Name)
|
||||||
|
case DataResourceMode:
|
||||||
|
return fmt.Sprintf("data.%s.%s", r.Type, r.Name)
|
||||||
|
default:
|
||||||
|
// should never happen
|
||||||
|
return fmt.Sprintf("[invalid_mode!].%s.%s", r.Type, r.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceMode represents the "mode" of a resource, which is used to
|
||||||
|
// distinguish between managed resources ("resource" blocks in config) and
|
||||||
|
// data resources ("data" blocks in config).
|
||||||
|
type ResourceMode rune
|
||||||
|
|
||||||
|
const InvalidResourceMode ResourceMode = 0
|
||||||
|
const ManagedResourceMode ResourceMode = 'M'
|
||||||
|
const DataResourceMode ResourceMode = 'D'
|
||||||
|
|
||||||
|
func (m ResourceMode) String() string {
|
||||||
|
switch m {
|
||||||
|
case ManagedResourceMode:
|
||||||
|
return "managed"
|
||||||
|
case DataResourceMode:
|
||||||
|
return "data"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements encoding/json.Marshaler.
|
||||||
|
func (m ResourceMode) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(strconv.Quote(m.String())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceTypeDefaultProviderName(typeName string) string {
|
||||||
|
if underPos := strings.IndexByte(typeName, '_'); underPos != -1 {
|
||||||
|
return typeName[:underPos]
|
||||||
|
}
|
||||||
|
return typeName
|
||||||
|
}
|
106
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go
generated
vendored
Normal file
106
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rootSchema = &hcl.BodySchema{
|
||||||
|
Blocks: []hcl.BlockHeaderSchema{
|
||||||
|
{
|
||||||
|
Type: "terraform",
|
||||||
|
LabelNames: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "variable",
|
||||||
|
LabelNames: []string{"name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "output",
|
||||||
|
LabelNames: []string{"name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "provider",
|
||||||
|
LabelNames: []string{"name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "resource",
|
||||||
|
LabelNames: []string{"type", "name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "data",
|
||||||
|
LabelNames: []string{"type", "name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "module",
|
||||||
|
LabelNames: []string{"name"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var terraformBlockSchema = &hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{
|
||||||
|
Name: "required_version",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Blocks: []hcl.BlockHeaderSchema{
|
||||||
|
{
|
||||||
|
Type: "required_providers",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerConfigSchema = &hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{
|
||||||
|
Name: "version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "alias",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var variableSchema = &hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{
|
||||||
|
Name: "type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "description",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputSchema = &hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{
|
||||||
|
Name: "description",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleCallSchema = &hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{
|
||||||
|
Name: "source",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "providers",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourceSchema = &hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{
|
||||||
|
Name: "provider",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
50
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go
generated
vendored
Normal file
50
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
legacyhcltoken "github.com/hashicorp/hcl/hcl/token"
|
||||||
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SourcePos is a pointer to a particular location in a source file.
|
||||||
|
//
|
||||||
|
// This type is embedded into other structs to allow callers to locate the
|
||||||
|
// definition of each described module element. The SourcePos of an element
|
||||||
|
// is usually the first line of its definition, although the definition can
|
||||||
|
// be a little "fuzzy" with JSON-based config files.
|
||||||
|
type SourcePos struct {
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
Line int `json:"line"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func sourcePos(filename string, line int) SourcePos {
|
||||||
|
return SourcePos{
|
||||||
|
Filename: filename,
|
||||||
|
Line: line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sourcePosHCL(rng hcl.Range) SourcePos {
|
||||||
|
// We intentionally throw away the column information here because
|
||||||
|
// current and legacy HCL both disagree on the definition of a column
|
||||||
|
// and so a line-only reference is the best granularity we can do
|
||||||
|
// such that the result is consistent between both parsers.
|
||||||
|
return SourcePos{
|
||||||
|
Filename: rng.Filename,
|
||||||
|
Line: rng.Start.Line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sourcePosLegacyHCL(pos legacyhcltoken.Pos, filename string) SourcePos {
|
||||||
|
useFilename := pos.Filename
|
||||||
|
// We'll try to use the filename given in legacy HCL position, but
|
||||||
|
// in practice there's no way to actually get this populated via
|
||||||
|
// the HCL API so it's usually empty except in some specialized
|
||||||
|
// situations, such as positions in error objects.
|
||||||
|
if useFilename == "" {
|
||||||
|
useFilename = filename
|
||||||
|
}
|
||||||
|
return SourcePos{
|
||||||
|
Filename: useFilename,
|
||||||
|
Line: pos.Line,
|
||||||
|
}
|
||||||
|
}
|
16
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go
generated
vendored
Normal file
16
vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package tfconfig
|
||||||
|
|
||||||
|
// Variable represents a single variable from a Terraform module.
|
||||||
|
type Variable struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Default is an approximate representation of the default value in
|
||||||
|
// the native Go type system. The conversion from the value given in
|
||||||
|
// configuration may be slightly lossy. Only values that can be
|
||||||
|
// serialized by json.Marshal will be included here.
|
||||||
|
Default interface{} `json:"default,omitempty"`
|
||||||
|
|
||||||
|
Pos SourcePos `json:"pos"`
|
||||||
|
}
|
|
@ -340,7 +340,7 @@ github.com/hashicorp/go-tfe
|
||||||
github.com/hashicorp/go-uuid
|
github.com/hashicorp/go-uuid
|
||||||
# github.com/hashicorp/go-version v1.0.0
|
# github.com/hashicorp/go-version v1.0.0
|
||||||
github.com/hashicorp/go-version
|
github.com/hashicorp/go-version
|
||||||
# github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
|
# github.com/hashicorp/hcl v1.0.0
|
||||||
github.com/hashicorp/hcl
|
github.com/hashicorp/hcl
|
||||||
github.com/hashicorp/hcl/hcl/ast
|
github.com/hashicorp/hcl/hcl/ast
|
||||||
github.com/hashicorp/hcl/hcl/parser
|
github.com/hashicorp/hcl/hcl/parser
|
||||||
|
@ -372,6 +372,8 @@ github.com/hashicorp/hil/scanner
|
||||||
github.com/hashicorp/logutils
|
github.com/hashicorp/logutils
|
||||||
# github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb
|
# github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb
|
||||||
github.com/hashicorp/serf/coordinate
|
github.com/hashicorp/serf/coordinate
|
||||||
|
# github.com/hashicorp/terraform-config-inspect v0.0.0-20181213005350-314d8affa1db
|
||||||
|
github.com/hashicorp/terraform-config-inspect/tfconfig
|
||||||
# github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4
|
# github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4
|
||||||
github.com/hashicorp/vault/helper/pgpkeys
|
github.com/hashicorp/vault/helper/pgpkeys
|
||||||
github.com/hashicorp/vault/helper/jsonutil
|
github.com/hashicorp/vault/helper/jsonutil
|
||||||
|
|
Loading…
Reference in New Issue