diff --git a/cmd/run.go b/cmd/run.go index 0b9be00..a33f49f 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "os" - "github.com/hashicorp/hcl2/hclwrite" + "github.com/hashicorp/hcl/v2/hclwrite" "github.com/jessevdk/go-flags" "go.starlark.net/starlark" ) diff --git a/go.mod b/go.mod index 1f38c9f..776ad66 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,12 @@ require ( github.com/containers/image/v5 v5.2.1 github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/go-metrics v0.0.1 // indirect - github.com/go-git/go-git/v5 v5.0.0 github.com/gobs/args v0.0.0-20180315064131-86002b4df18c github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect github.com/hashicorp/go-hclog v0.11.0 github.com/hashicorp/go-plugin v1.0.1-0.20190610192547-a1bc61569a26 - github.com/hashicorp/hcl2 v0.0.0-20190618163856-0b64543c968c + github.com/hashicorp/hcl/v2 v2.3.0 + github.com/hashicorp/hcl2 v0.0.0-00010101000000-000000000000 github.com/hashicorp/terraform v0.12.23 github.com/jessevdk/go-flags v1.4.0 github.com/kr/text v0.2.0 // indirect @@ -20,7 +20,6 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/oklog/ulid/v2 v2.0.2 github.com/qri-io/starlib v0.4.2-0.20200326221746-d3997998591b - github.com/rogpeppe/go-internal v1.5.2 github.com/sergi/go-diff v1.1.0 // indirect github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect diff --git a/go.sum b/go.sum index d495530..4eee5ee 100644 --- a/go.sum +++ b/go.sum @@ -60,7 +60,6 @@ github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190329064014-6e358769c32a h1:APorzFpCcv6wtD5vmRWYqNm4N55kbepL7c7kTq9XI6A= @@ -70,7 +69,6 @@ github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70/go.mod h1 github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible h1:ABQ7FF+IxSFHDMOTtjCfmMDMHiCq6EsAoCV/9sFinaM= github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible/go.mod h1:LDQHRZylxvcg8H7wBIDfvO5g/cy4/sz1iucBlc2l3Jw= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e h1:ptBAamGVd6CfRsUtyHD+goy2JGhv1QC32v3gqM8mYAM= github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0 h1:JaCC8jz0zdMLk2m+qCCVLLLM/PL93p84w4pK3aJWj60= @@ -90,7 +88,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -183,27 +180,14 @@ github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURU github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1 h1:r1oACdS2XYiAWcfF8BJXkoU8l1J71KehGR+d99yWEDA= github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1/go.mod h1:lcy9/2gH1jn/VCLouHA6tOEwLoNVd4GW6zhuKLmHC2Y= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/ghodss/yaml v0.0.0-20161207003320-04f313413ffd/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git v1.0.0 h1:YcN9iDGDoXuIw0vHls6rINwV416HYa0EB2X+RBsyYp4= -github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrOvKnuittYVdA= -github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg= -github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -329,6 +313,7 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+ github.com/hashicorp/golang-lru v0.5.1/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/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= @@ -349,8 +334,6 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -371,8 +354,6 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -538,8 +519,6 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/qri-io/starlib v0.4.2-0.20200326221746-d3997998591b h1:n460ZPlc7+1evliXpUzGhIVr080j5c+2zsXuThfEGGM= github.com/qri-io/starlib v0.4.2-0.20200326221746-d3997998591b/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w= -github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -780,15 +759,12 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/starlark/types/attribute.go b/starlark/types/attribute.go index 4956a4b..847fbf7 100644 --- a/starlark/types/attribute.go +++ b/starlark/types/attribute.go @@ -125,6 +125,10 @@ func (c *Attribute) Attr(name string) (starlark.Value, error) { return NewAttributeWithPath(c.r, c.t.AttributeType(name), name, path), nil } +func (c *Attribute) String() string { + return c.sString.GoString() +} + // AttrNames honors the starlark.HasAttrs interface. func (c *Attribute) AttrNames() []string { return []string{"__resource__", "__type__"} diff --git a/starlark/types/hcl.go b/starlark/types/hcl.go index 7086062..526989b 100644 --- a/starlark/types/hcl.go +++ b/starlark/types/hcl.go @@ -2,11 +2,15 @@ package types import ( "fmt" + "math/big" + "regexp" "sort" + "unicode" + "unicode/utf8" - "github.com/hashicorp/hcl2/hcl" - "github.com/hashicorp/hcl2/hcl/hclsyntax" - "github.com/hashicorp/hcl2/hclwrite" + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" + "github.com/hashicorp/hcl/v2/hclwrite" "github.com/zclconf/go-cty/cty" "go.starlark.net/starlark" ) @@ -151,15 +155,8 @@ func (r *Resource) doToHCLAttributes(body *hclwrite.Body) { return nil } - if c, ok := v.v.(*Attribute); ok { - body.SetAttributeTraversal(v.Name, hcl.Traversal{ - hcl.TraverseRoot{Name: c.String()}, - }) - - return nil - } - - body.SetAttributeValue(v.Name, v.Cty()) + tokens := appendTokensForValue(v.v, nil) + body.SetAttributeRaw(v.Name, tokens) return nil }) @@ -230,3 +227,178 @@ func (r *Resource) doToHCLProvisioner(body *hclwrite.Body) { p.ToHCL(body) } } + +var containsInterpolation = regexp.MustCompile(`(?mU)\$\{.*\}`) + +func appendTokensForValue(val starlark.Value, toks hclwrite.Tokens) hclwrite.Tokens { + switch v := val.(type) { + case starlark.NoneType: + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenIdent, + Bytes: []byte(`null`), + }) + case starlark.Bool: + var src []byte + if v { + src = []byte(`true`) + } else { + src = []byte(`false`) + } + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenIdent, + Bytes: src, + }) + case starlark.Float: + bf := big.NewFloat(float64(v)) + srcStr := bf.Text('f', -1) + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenNumberLit, + Bytes: []byte(srcStr), + }) + case starlark.Int: + bf := v.BigInt() + srcStr := bf.Text('2') + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenNumberLit, + Bytes: []byte(srcStr), + }) + case starlark.String: + src := []byte(v.GoString()) + if !containsInterpolation.Match(src) { + src = escapeQuotedStringLit(v.GoString()) + } + + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenOQuote, + Bytes: []byte{'"'}, + }) + if len(src) > 0 { + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenQuotedLit, + Bytes: []byte(src), + }) + } + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenCQuote, + Bytes: []byte{'"'}, + }) + case *starlark.List: + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenOBrack, + Bytes: []byte{'['}, + }) + + for i := 0; i < v.Len(); i++ { + if i > 0 { + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenComma, + Bytes: []byte{','}, + }) + } + + toks = appendTokensForValue(v.Index(i), toks) + } + + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenCBrack, + Bytes: []byte{']'}, + }) + + case *starlark.Dict: + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenOBrace, + Bytes: []byte{'{'}, + }) + + i := 0 + for _, eKey := range v.Keys() { + if i > 0 { + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenComma, + Bytes: []byte{','}, + }) + } + + eVal, _, _ := v.Get(eKey) + if hclsyntax.ValidIdentifier(eKey.(starlark.String).GoString()) { + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenIdent, + Bytes: []byte(eKey.(starlark.String).GoString()), + }) + } else { + toks = appendTokensForValue(eKey, toks) + } + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenEqual, + Bytes: []byte{'='}, + }) + toks = appendTokensForValue(eVal, toks) + i++ + } + + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenCBrace, + Bytes: []byte{'}'}, + }) + case *Attribute: + toks = append(toks, &hclwrite.Token{ + Type: hclsyntax.TokenIdent, + Bytes: []byte(v.sString.String()), + }) + default: + panic(fmt.Sprintf("cannot produce tokens for %#v", val)) + } + + return toks +} + +func escapeQuotedStringLit(s string) []byte { + if len(s) == 0 { + return nil + } + buf := make([]byte, 0, len(s)) + for i, r := range s { + switch r { + case '\n': + buf = append(buf, '\\', 'n') + case '\r': + buf = append(buf, '\\', 'r') + case '\t': + buf = append(buf, '\\', 't') + case '"': + buf = append(buf, '\\', '"') + case '\\': + buf = append(buf, '\\', '\\') + case '$', '%': + buf = appendRune(buf, r) + remain := s[i+1:] + if len(remain) > 0 && remain[0] == '{' { + // Double up our template introducer symbol to escape it. + buf = appendRune(buf, r) + } + default: + if !unicode.IsPrint(r) { + var fmted string + if r < 65536 { + fmted = fmt.Sprintf("\\u%04x", r) + } else { + fmted = fmt.Sprintf("\\U%08x", r) + } + buf = append(buf, fmted...) + } else { + buf = appendRune(buf, r) + } + } + } + return buf +} + +func appendRune(b []byte, r rune) []byte { + l := utf8.RuneLen(r) + for i := 0; i < l; i++ { + b = append(b, 0) // make room at the end of our buffer + } + ch := b[len(b)-l:] + utf8.EncodeRune(ch, r) + return b +} diff --git a/starlark/types/testdata/attribute.star b/starlark/types/testdata/attribute.star index 4541036..bc19ad6 100644 --- a/starlark/types/testdata/attribute.star +++ b/starlark/types/testdata/attribute.star @@ -8,7 +8,7 @@ ami = aws.data.ami() web = aws.resource.instance() web.ami = ami.id assert.eq(type(web.ami), "Attribute") -assert.eq(str(web.ami), '"${data.aws_ami.id_2.id}"') +assert.eq(str(web.ami), "${data.aws_ami.id_2.id}") assert.eq(web.ami.__resource__, ami) assert.eq(web.ami.__type__, "string") @@ -18,35 +18,35 @@ assert.eq("__type__" in dir(web.ami), True) # attribute of set table = aws.data.dynamodb_table() -assert.eq(str(table.ttl), '"${data.aws_dynamodb_table.id_4.ttl}"') -assert.eq(str(table.ttl[0]), '"${data.aws_dynamodb_table.id_4.ttl.0}"') -assert.eq(str(table.ttl[0].attribute_name), '"${data.aws_dynamodb_table.id_4.ttl.0.attribute_name}"') +assert.eq(str(table.ttl), "${data.aws_dynamodb_table.id_4.ttl}") +assert.eq(str(table.ttl[0]), "${data.aws_dynamodb_table.id_4.ttl.0}") +assert.eq(str(table.ttl[0].attribute_name), "${data.aws_dynamodb_table.id_4.ttl.0.attribute_name}") # attribute of list instance = aws.data.instance() -assert.eq(str(instance.credit_specification), '"${data.aws_instance.id_5.credit_specification}"') -assert.eq(str(instance.credit_specification[0]), '"${data.aws_instance.id_5.credit_specification.0}"') -assert.eq(str(instance.credit_specification[0].cpu_credits), '"${data.aws_instance.id_5.credit_specification.0.cpu_credits}"') +assert.eq(str(instance.credit_specification), "${data.aws_instance.id_5.credit_specification}") +assert.eq(str(instance.credit_specification[0]), "${data.aws_instance.id_5.credit_specification.0}") +assert.eq(str(instance.credit_specification[0].cpu_credits), "${data.aws_instance.id_5.credit_specification.0.cpu_credits}") # attribute of block attribute = str(aws.resource.instance().root_block_device.volume_size) -assert.eq(attribute, '"${aws_instance.id_6.root_block_device.0.volume_size}"') +assert.eq(attribute, "${aws_instance.id_6.root_block_device.0.volume_size}") # attribute on data source -assert.eq(str(aws.resource.instance().id), '"${aws_instance.id_7.id}"') +assert.eq(str(aws.resource.instance().id), "${aws_instance.id_7.id}") # attribute on resource -assert.eq(str(aws.data.ami().id), '"${data.aws_ami.id_8.id}"') +assert.eq(str(aws.data.ami().id), "${data.aws_ami.id_8.id}") gcp = tf.provider("google", "3.13.0") # attribute on list with MaxItem:1 cluster = gcp.resource.container_cluster("foo") -assert.eq(str(cluster.master_auth.client_certificate), '"${google_container_cluster.foo.master_auth.0.client_certificate}"') +assert.eq(str(cluster.master_auth.client_certificate), "${google_container_cluster.foo.master_auth.0.client_certificate}") # attr non-object assert.fails(lambda: web.ami.foo, "Attribute it's not a object") # fn wrapping -assert.eq(str(fn("base64encode", web.ami)), '"${base64encode(data.aws_ami.id_2.id)}"') +assert.eq(str(fn("base64encode", web.ami)), "${base64encode(data.aws_ami.id_2.id)}") diff --git a/starlark/types/testdata/examples/attribute.star b/starlark/types/testdata/examples/attribute.star index 9ba3ca9..9a43ba3 100644 --- a/starlark/types/testdata/examples/attribute.star +++ b/starlark/types/testdata/examples/attribute.star @@ -11,4 +11,4 @@ instance.ami = ami.id print(instance.ami) # Output: -# "${aws_ami.ubuntu.id}" \ No newline at end of file +# ${aws_ami.ubuntu.id} \ No newline at end of file diff --git a/starlark/types/testdata/hcl.star b/starlark/types/testdata/hcl.star index a63d617..0500173 100644 --- a/starlark/types/testdata/hcl.star +++ b/starlark/types/testdata/hcl.star @@ -11,4 +11,32 @@ assert.eq(hcl(helm), "" + ' kubernetes {\n' + \ ' token = "foo"\n' + \ ' }\n' + \ +'}\n\n') + +google = tf.provider("google", "3.16.0", "default") +sa = google.resource.service_account("sa") +sa.account_id = "service-account" + +m = google.resource.storage_bucket_iam_member(sa.account_id+"-admin") +m.bucket = "main-storage" +m.role = "roles/storage.objectAdmin" +m.member = "serviceAccount:%s" % sa.email + +# hcl with interpoaltion +assert.eq(hcl(google), "" + +'provider "google" {\n' + \ +' alias = "default"\n' + \ +' version = "3.16.0"\n' + \ +'}\n' + \ +'\n' + \ +'resource "google_service_account" "sa" {\n' + \ +' provider = google.default\n' + \ +' account_id = "service-account"\n' + \ +'}\n' + \ +'\n' + \ +'resource "google_storage_bucket_iam_member" "service-account-admin" {\n' + \ +' provider = google.default\n' + \ +' bucket = "main-storage"\n' + \ +' member = "serviceAccount:${google_service_account.sa.email}"\n' + \ +' role = "roles/storage.objectAdmin"\n' + \ '}\n\n') \ No newline at end of file diff --git a/starlark/types/testdata/resource.star b/starlark/types/testdata/resource.star index e45919b..7b8d6d0 100644 --- a/starlark/types/testdata/resource.star +++ b/starlark/types/testdata/resource.star @@ -32,7 +32,7 @@ assert.fails(lambda: qux.foo, "Resource has no .foo field or method") # attr id assert.eq(type(qux.id), "Attribute") -assert.eq(str(qux.id), '"${data.ignition_user.id_2.id}"') +assert.eq(str(qux.id), "${data.ignition_user.id_2.id}") aws = tf.provider("aws", "2.13.0") # attr output assignation @@ -58,7 +58,7 @@ assert.eq("__kind__" in dir(web), True) assert.eq("__dict__" in dir(web), True) # attr optional computed -assert.eq(str(group.name), '"${aws_autoscaling_group.id_6.name}"') +assert.eq(str(group.name), "${aws_autoscaling_group.id_6.name}") group.name = "foo" assert.eq(group.name, "foo") @@ -124,7 +124,7 @@ assert.eq(ignition.data.user(groups=["foo"]), ignition.data.user(groups=["foo"]) # constructor with name quux = ignition.data.user("quux") -assert.eq(str(quux.id), '"${data.ignition_user.quux.id}"') +assert.eq(str(quux.id), "${data.ignition_user.quux.id}") # constructor from kwargs bar = ignition.data.user(uid=42, system=True) @@ -135,7 +135,7 @@ assert.eq(bar.system, True) fred = ignition.data.user("fred", uid=42, system=True) assert.eq(fred.uid, 42) assert.eq(fred.system, True) -assert.eq(str(fred.id), '"${data.ignition_user.fred.id}"') +assert.eq(str(fred.id), "${data.ignition_user.fred.id}") # constructor from dict foo = ignition.data.user({"uid": 42, "system": True}) @@ -146,13 +146,13 @@ assert.eq(foo.system, True) baz = ignition.data.user("baz", {"uid": 42, "system": True}) assert.eq(baz.uid, 42) assert.eq(baz.system, True) -assert.eq(str(baz.id), '"${data.ignition_user.baz.id}"') +assert.eq(str(baz.id), "${data.ignition_user.baz.id}") # constructor from dict with name and kwargs baz = ignition.data.user("baz", {"uid": 42, "system": True}, uid=84) assert.eq(baz.uid, 84) assert.eq(baz.system, True) -assert.eq(str(baz.id), '"${data.ignition_user.baz.id}"') +assert.eq(str(baz.id), "${data.ignition_user.baz.id}") assert.eq(bar, foo) diff --git a/starlark/types/type.go b/starlark/types/type.go index 62d1b1d..b2fbdd9 100644 --- a/starlark/types/type.go +++ b/starlark/types/type.go @@ -27,14 +27,14 @@ func MustTypeFromStarlark(typ string) *Type { // NewTypeFromStarlark returns a Type from a given starlark type string. func NewTypeFromStarlark(typ string) (*Type, error) { - t := &Type{} - t.typ = typ - complex := strings.SplitN(typ, "<", 2) if len(complex) == 2 { typ = complex[0] } + t := &Type{} + t.typ = typ + switch typ { case "bool": t.cty = cty.Bool diff --git a/starlark/types/value.go b/starlark/types/value.go index b88eb41..0d6ebc2 100644 --- a/starlark/types/value.go +++ b/starlark/types/value.go @@ -81,7 +81,7 @@ func (v *Value) Cty() cty.Value { case "Attribute": return cty.StringVal(v.v.(*Attribute).GoString()) default: - return cty.StringVal(fmt.Sprintf("unhandled: %s", v.t.typ)) + panic(fmt.Sprintf("unhandled: %s", v.t.Starlark())) } }