2016-02-02 19:29:08 +01:00
|
|
|
// Go support for Protocol Buffers - Google's data interchange format
|
|
|
|
//
|
|
|
|
// Copyright 2010 The Go Authors. All rights reserved.
|
|
|
|
// https://github.com/golang/protobuf
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above
|
|
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
|
|
// in the documentation and/or other materials provided with the
|
|
|
|
// distribution.
|
|
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived from
|
|
|
|
// this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
package proto
|
|
|
|
|
|
|
|
// Functions for writing the text protocol buffer format.
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"encoding"
|
2017-01-20 02:10:17 +01:00
|
|
|
"errors"
|
2016-02-02 19:29:08 +01:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"math"
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
newline = []byte("\n")
|
|
|
|
spaces = []byte(" ")
|
|
|
|
endBraceNewline = []byte("}\n")
|
|
|
|
backslashN = []byte{'\\', 'n'}
|
|
|
|
backslashR = []byte{'\\', 'r'}
|
|
|
|
backslashT = []byte{'\\', 't'}
|
|
|
|
backslashDQ = []byte{'\\', '"'}
|
|
|
|
backslashBS = []byte{'\\', '\\'}
|
|
|
|
posInf = []byte("inf")
|
|
|
|
negInf = []byte("-inf")
|
|
|
|
nan = []byte("nan")
|
|
|
|
)
|
|
|
|
|
|
|
|
type writer interface {
|
|
|
|
io.Writer
|
|
|
|
WriteByte(byte) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// textWriter is an io.Writer that tracks its indentation level.
|
|
|
|
type textWriter struct {
|
|
|
|
ind int
|
|
|
|
complete bool // if the current position is a complete line
|
|
|
|
compact bool // whether to write out as a one-liner
|
|
|
|
w writer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *textWriter) WriteString(s string) (n int, err error) {
|
|
|
|
if !strings.Contains(s, "\n") {
|
|
|
|
if !w.compact && w.complete {
|
|
|
|
w.writeIndent()
|
|
|
|
}
|
|
|
|
w.complete = false
|
|
|
|
return io.WriteString(w.w, s)
|
|
|
|
}
|
|
|
|
// WriteString is typically called without newlines, so this
|
|
|
|
// codepath and its copy are rare. We copy to avoid
|
|
|
|
// duplicating all of Write's logic here.
|
|
|
|
return w.Write([]byte(s))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *textWriter) Write(p []byte) (n int, err error) {
|
|
|
|
newlines := bytes.Count(p, newline)
|
|
|
|
if newlines == 0 {
|
|
|
|
if !w.compact && w.complete {
|
|
|
|
w.writeIndent()
|
|
|
|
}
|
|
|
|
n, err = w.w.Write(p)
|
|
|
|
w.complete = false
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
frags := bytes.SplitN(p, newline, newlines+1)
|
|
|
|
if w.compact {
|
|
|
|
for i, frag := range frags {
|
|
|
|
if i > 0 {
|
|
|
|
if err := w.w.WriteByte(' '); err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
nn, err := w.w.Write(frag)
|
|
|
|
n += nn
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, frag := range frags {
|
|
|
|
if w.complete {
|
|
|
|
w.writeIndent()
|
|
|
|
}
|
|
|
|
nn, err := w.w.Write(frag)
|
|
|
|
n += nn
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
if i+1 < len(frags) {
|
|
|
|
if err := w.w.WriteByte('\n'); err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w.complete = len(frags[len(frags)-1]) == 0
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *textWriter) WriteByte(c byte) error {
|
|
|
|
if w.compact && c == '\n' {
|
|
|
|
c = ' '
|
|
|
|
}
|
|
|
|
if !w.compact && w.complete {
|
|
|
|
w.writeIndent()
|
|
|
|
}
|
|
|
|
err := w.w.WriteByte(c)
|
|
|
|
w.complete = c == '\n'
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *textWriter) indent() { w.ind++ }
|
|
|
|
|
|
|
|
func (w *textWriter) unindent() {
|
|
|
|
if w.ind == 0 {
|
2017-01-20 02:10:17 +01:00
|
|
|
log.Print("proto: textWriter unindented too far")
|
2016-02-02 19:29:08 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
w.ind--
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeName(w *textWriter, props *Properties) error {
|
|
|
|
if _, err := w.WriteString(props.OrigName); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if props.Wire != "group" {
|
|
|
|
return w.WriteByte(':')
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-01-20 02:10:17 +01:00
|
|
|
func requiresQuotes(u string) bool {
|
|
|
|
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
|
|
|
for _, ch := range u {
|
|
|
|
switch {
|
|
|
|
case ch == '.' || ch == '/' || ch == '_':
|
|
|
|
continue
|
|
|
|
case '0' <= ch && ch <= '9':
|
|
|
|
continue
|
|
|
|
case 'A' <= ch && ch <= 'Z':
|
|
|
|
continue
|
|
|
|
case 'a' <= ch && ch <= 'z':
|
|
|
|
continue
|
|
|
|
default:
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// isAny reports whether sv is a google.protobuf.Any message
|
|
|
|
func isAny(sv reflect.Value) bool {
|
|
|
|
type wkt interface {
|
|
|
|
XXX_WellKnownType() string
|
|
|
|
}
|
|
|
|
t, ok := sv.Addr().Interface().(wkt)
|
|
|
|
return ok && t.XXX_WellKnownType() == "Any"
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeProto3Any writes an expanded google.protobuf.Any message.
|
|
|
|
//
|
|
|
|
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
|
|
|
// required messages are not linked in).
|
|
|
|
//
|
|
|
|
// It returns (true, error) when sv was written in expanded format or an error
|
|
|
|
// was encountered.
|
|
|
|
func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {
|
|
|
|
turl := sv.FieldByName("TypeUrl")
|
|
|
|
val := sv.FieldByName("Value")
|
|
|
|
if !turl.IsValid() || !val.IsValid() {
|
|
|
|
return true, errors.New("proto: invalid google.protobuf.Any message")
|
|
|
|
}
|
|
|
|
|
|
|
|
b, ok := val.Interface().([]byte)
|
|
|
|
if !ok {
|
|
|
|
return true, errors.New("proto: invalid google.protobuf.Any message")
|
2016-02-02 19:29:08 +01:00
|
|
|
}
|
|
|
|
|
2017-01-20 02:10:17 +01:00
|
|
|
parts := strings.Split(turl.String(), "/")
|
|
|
|
mt := MessageType(parts[len(parts)-1])
|
|
|
|
if mt == nil {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
m := reflect.New(mt.Elem())
|
|
|
|
if err := Unmarshal(b, m.Interface().(Message)); err != nil {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
w.Write([]byte("["))
|
|
|
|
u := turl.String()
|
|
|
|
if requiresQuotes(u) {
|
|
|
|
writeString(w, u)
|
|
|
|
} else {
|
|
|
|
w.Write([]byte(u))
|
|
|
|
}
|
|
|
|
if w.compact {
|
|
|
|
w.Write([]byte("]:<"))
|
|
|
|
} else {
|
|
|
|
w.Write([]byte("]: <\n"))
|
|
|
|
w.ind++
|
|
|
|
}
|
|
|
|
if err := tm.writeStruct(w, m.Elem()); err != nil {
|
|
|
|
return true, err
|
|
|
|
}
|
|
|
|
if w.compact {
|
|
|
|
w.Write([]byte("> "))
|
|
|
|
} else {
|
|
|
|
w.ind--
|
|
|
|
w.Write([]byte(">\n"))
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|
|
|
if tm.ExpandAny && isAny(sv) {
|
|
|
|
if canExpand, err := tm.writeProto3Any(w, sv); canExpand {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2016-02-02 19:29:08 +01:00
|
|
|
st := sv.Type()
|
|
|
|
sprops := GetProperties(st)
|
|
|
|
for i := 0; i < sv.NumField(); i++ {
|
|
|
|
fv := sv.Field(i)
|
|
|
|
props := sprops.Prop[i]
|
|
|
|
name := st.Field(i).Name
|
|
|
|
|
2018-06-12 18:44:16 +02:00
|
|
|
if name == "XXX_NoUnkeyedLiteral" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-02-02 19:29:08 +01:00
|
|
|
if strings.HasPrefix(name, "XXX_") {
|
|
|
|
// There are two XXX_ fields:
|
|
|
|
// XXX_unrecognized []byte
|
|
|
|
// XXX_extensions map[int32]proto.Extension
|
|
|
|
// The first is handled here;
|
|
|
|
// the second is handled at the bottom of this function.
|
|
|
|
if name == "XXX_unrecognized" && !fv.IsNil() {
|
|
|
|
if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
|
|
|
// Field not filled in. This could be an optional field or
|
|
|
|
// a required field that wasn't filled in. Either way, there
|
|
|
|
// isn't anything we can show for it.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if fv.Kind() == reflect.Slice && fv.IsNil() {
|
|
|
|
// Repeated field that is empty, or a bytes field that is unused.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if props.Repeated && fv.Kind() == reflect.Slice {
|
|
|
|
// Repeated field.
|
|
|
|
for j := 0; j < fv.Len(); j++ {
|
|
|
|
if err := writeName(w, props); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v := fv.Index(j)
|
|
|
|
if v.Kind() == reflect.Ptr && v.IsNil() {
|
|
|
|
// A nil message in a repeated field is not valid,
|
|
|
|
// but we can handle that more gracefully than panicking.
|
|
|
|
if _, err := w.Write([]byte("<nil>\n")); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeAny(w, v, props); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if fv.Kind() == reflect.Map {
|
|
|
|
// Map fields are rendered as a repeated struct with key/value fields.
|
2017-01-20 02:10:17 +01:00
|
|
|
keys := fv.MapKeys()
|
2016-02-02 19:29:08 +01:00
|
|
|
sort.Sort(mapKeys(keys))
|
|
|
|
for _, key := range keys {
|
|
|
|
val := fv.MapIndex(key)
|
|
|
|
if err := writeName(w, props); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// open struct
|
|
|
|
if err := w.WriteByte('<'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w.indent()
|
|
|
|
// key
|
|
|
|
if _, err := w.WriteString("key:"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-08-27 20:26:52 +02:00
|
|
|
if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// nil values aren't legal, but we can avoid panicking because of them.
|
|
|
|
if val.Kind() != reflect.Ptr || !val.IsNil() {
|
|
|
|
// value
|
|
|
|
if _, err := w.WriteString("value:"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-08-27 20:26:52 +02:00
|
|
|
if err := tm.writeAny(w, val, props.MapValProp); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// close struct
|
|
|
|
w.unindent()
|
|
|
|
if err := w.WriteByte('>'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 {
|
|
|
|
// empty bytes field
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice {
|
|
|
|
// proto3 non-repeated scalar field; skip if zero value
|
2017-01-20 02:10:17 +01:00
|
|
|
if isProto3Zero(fv) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if fv.Kind() == reflect.Interface {
|
|
|
|
// Check if it is a oneof.
|
|
|
|
if st.Field(i).Tag.Get("protobuf_oneof") != "" {
|
|
|
|
// fv is nil, or holds a pointer to generated struct.
|
|
|
|
// That generated struct has exactly one field,
|
|
|
|
// which has a protobuf struct tag.
|
|
|
|
if fv.IsNil() {
|
2016-02-02 19:29:08 +01:00
|
|
|
continue
|
|
|
|
}
|
2017-01-20 02:10:17 +01:00
|
|
|
inner := fv.Elem().Elem() // interface -> *T -> T
|
|
|
|
tag := inner.Type().Field(0).Tag.Get("protobuf")
|
|
|
|
props = new(Properties) // Overwrite the outer props var, but not its pointee.
|
|
|
|
props.Parse(tag)
|
|
|
|
// Write the value in the oneof, not the oneof itself.
|
|
|
|
fv = inner.Field(0)
|
|
|
|
|
|
|
|
// Special case to cope with malformed messages gracefully:
|
|
|
|
// If the value in the oneof is a nil pointer, don't panic
|
|
|
|
// in writeAny.
|
|
|
|
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
|
|
|
// Use errors.New so writeAny won't render quotes.
|
|
|
|
msg := errors.New("/* nil */")
|
|
|
|
fv = reflect.ValueOf(&msg).Elem()
|
2016-02-02 19:29:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := writeName(w, props); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enums have a String method, so writeAny will work fine.
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeAny(w, fv, props); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extensions (the XXX_extensions field).
|
|
|
|
pv := sv.Addr()
|
2018-06-12 18:44:16 +02:00
|
|
|
if _, err := extendable(pv.Interface()); err == nil {
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeExtensions(w, pv); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
|
|
|
|
2016-02-02 19:29:08 +01:00
|
|
|
// writeAny writes an arbitrary field.
|
2017-01-20 02:10:17 +01:00
|
|
|
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
2016-02-02 19:29:08 +01:00
|
|
|
v = reflect.Indirect(v)
|
|
|
|
|
|
|
|
// Floats have special cases.
|
|
|
|
if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
|
|
|
|
x := v.Float()
|
|
|
|
var b []byte
|
|
|
|
switch {
|
|
|
|
case math.IsInf(x, 1):
|
|
|
|
b = posInf
|
|
|
|
case math.IsInf(x, -1):
|
|
|
|
b = negInf
|
|
|
|
case math.IsNaN(x):
|
|
|
|
b = nan
|
|
|
|
}
|
|
|
|
if b != nil {
|
|
|
|
_, err := w.Write(b)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Other values are handled below.
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't attempt to serialise every possible value type; only those
|
|
|
|
// that can occur in protocol buffers.
|
|
|
|
switch v.Kind() {
|
|
|
|
case reflect.Slice:
|
|
|
|
// Should only be a []byte; repeated fields are handled in writeStruct.
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := writeString(w, string(v.Bytes())); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
case reflect.String:
|
|
|
|
if err := writeString(w, v.String()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case reflect.Struct:
|
|
|
|
// Required/optional group/message.
|
|
|
|
var bra, ket byte = '<', '>'
|
|
|
|
if props != nil && props.Wire == "group" {
|
|
|
|
bra, ket = '{', '}'
|
|
|
|
}
|
|
|
|
if err := w.WriteByte(bra); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w.indent()
|
2018-06-12 18:44:16 +02:00
|
|
|
if v.CanAddr() {
|
|
|
|
// Calling v.Interface on a struct causes the reflect package to
|
|
|
|
// copy the entire struct. This is racy with the new Marshaler
|
|
|
|
// since we atomically update the XXX_sizecache.
|
|
|
|
//
|
|
|
|
// Thus, we retrieve a pointer to the struct if possible to avoid
|
|
|
|
// a race since v.Interface on the pointer doesn't copy the struct.
|
|
|
|
//
|
|
|
|
// If v is not addressable, then we are not worried about a race
|
|
|
|
// since it implies that the binary Marshaler cannot possibly be
|
|
|
|
// mutating this value.
|
|
|
|
v = v.Addr()
|
|
|
|
}
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if v.Type().Implements(textMarshalerType) {
|
|
|
|
text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
|
2016-02-02 19:29:08 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err = w.Write(text); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-06-12 18:44:16 +02:00
|
|
|
} else {
|
|
|
|
if v.Kind() == reflect.Ptr {
|
|
|
|
v = v.Elem()
|
|
|
|
}
|
|
|
|
if err := tm.writeStruct(w, v); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-02-02 19:29:08 +01:00
|
|
|
}
|
|
|
|
w.unindent()
|
|
|
|
if err := w.WriteByte(ket); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
_, err := fmt.Fprint(w, v.Interface())
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// equivalent to C's isprint.
|
|
|
|
func isprint(c byte) bool {
|
|
|
|
return c >= 0x20 && c < 0x7f
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeString writes a string in the protocol buffer text format.
|
|
|
|
// It is similar to strconv.Quote except we don't use Go escape sequences,
|
|
|
|
// we treat the string as a byte sequence, and we use octal escapes.
|
|
|
|
// These differences are to maintain interoperability with the other
|
|
|
|
// languages' implementations of the text format.
|
|
|
|
func writeString(w *textWriter, s string) error {
|
|
|
|
// use WriteByte here to get any needed indent
|
|
|
|
if err := w.WriteByte('"'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Loop over the bytes, not the runes.
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
var err error
|
|
|
|
// Divergence from C++: we don't escape apostrophes.
|
|
|
|
// There's no need to escape them, and the C++ parser
|
|
|
|
// copes with a naked apostrophe.
|
|
|
|
switch c := s[i]; c {
|
|
|
|
case '\n':
|
|
|
|
_, err = w.w.Write(backslashN)
|
|
|
|
case '\r':
|
|
|
|
_, err = w.w.Write(backslashR)
|
|
|
|
case '\t':
|
|
|
|
_, err = w.w.Write(backslashT)
|
|
|
|
case '"':
|
|
|
|
_, err = w.w.Write(backslashDQ)
|
|
|
|
case '\\':
|
|
|
|
_, err = w.w.Write(backslashBS)
|
|
|
|
default:
|
|
|
|
if isprint(c) {
|
|
|
|
err = w.w.WriteByte(c)
|
|
|
|
} else {
|
|
|
|
_, err = fmt.Fprintf(w.w, "\\%03o", c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return w.WriteByte('"')
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
|
|
|
if !w.compact {
|
|
|
|
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b := NewBuffer(data)
|
|
|
|
for b.index < len(b.buf) {
|
|
|
|
x, err := b.DecodeVarint()
|
|
|
|
if err != nil {
|
|
|
|
_, err := fmt.Fprintf(w, "/* %v */\n", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
wire, tag := x&7, x>>3
|
|
|
|
if wire == WireEndGroup {
|
|
|
|
w.unindent()
|
|
|
|
if _, err := w.Write(endBraceNewline); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if _, err := fmt.Fprint(w, tag); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if wire != WireStartGroup {
|
|
|
|
if err := w.WriteByte(':'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !w.compact || wire == WireStartGroup {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch wire {
|
|
|
|
case WireBytes:
|
|
|
|
buf, e := b.DecodeRawBytes(false)
|
|
|
|
if e == nil {
|
|
|
|
_, err = fmt.Fprintf(w, "%q", buf)
|
|
|
|
} else {
|
|
|
|
_, err = fmt.Fprintf(w, "/* %v */", e)
|
|
|
|
}
|
|
|
|
case WireFixed32:
|
|
|
|
x, err = b.DecodeFixed32()
|
|
|
|
err = writeUnknownInt(w, x, err)
|
|
|
|
case WireFixed64:
|
|
|
|
x, err = b.DecodeFixed64()
|
|
|
|
err = writeUnknownInt(w, x, err)
|
|
|
|
case WireStartGroup:
|
|
|
|
err = w.WriteByte('{')
|
|
|
|
w.indent()
|
|
|
|
case WireVarint:
|
|
|
|
x, err = b.DecodeVarint()
|
|
|
|
err = writeUnknownInt(w, x, err)
|
|
|
|
default:
|
|
|
|
_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err = w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeUnknownInt(w *textWriter, x uint64, err error) error {
|
|
|
|
if err == nil {
|
|
|
|
_, err = fmt.Fprint(w, x)
|
|
|
|
} else {
|
|
|
|
_, err = fmt.Fprintf(w, "/* %v */", err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
type int32Slice []int32
|
|
|
|
|
|
|
|
func (s int32Slice) Len() int { return len(s) }
|
|
|
|
func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
|
|
|
|
func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
|
|
|
|
// writeExtensions writes all the extensions in pv.
|
|
|
|
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
2017-01-20 02:10:17 +01:00
|
|
|
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
|
2016-02-02 19:29:08 +01:00
|
|
|
emap := extensionMaps[pv.Type().Elem()]
|
2017-01-20 02:10:17 +01:00
|
|
|
ep, _ := extendable(pv.Interface())
|
2016-02-02 19:29:08 +01:00
|
|
|
|
|
|
|
// Order the extensions by ID.
|
|
|
|
// This isn't strictly necessary, but it will give us
|
|
|
|
// canonical output, which will also make testing easier.
|
2017-01-20 02:10:17 +01:00
|
|
|
m, mu := ep.extensionsRead()
|
|
|
|
if m == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
mu.Lock()
|
2016-02-02 19:29:08 +01:00
|
|
|
ids := make([]int32, 0, len(m))
|
|
|
|
for id := range m {
|
|
|
|
ids = append(ids, id)
|
|
|
|
}
|
|
|
|
sort.Sort(int32Slice(ids))
|
2017-01-20 02:10:17 +01:00
|
|
|
mu.Unlock()
|
2016-02-02 19:29:08 +01:00
|
|
|
|
|
|
|
for _, extNum := range ids {
|
|
|
|
ext := m[extNum]
|
|
|
|
var desc *ExtensionDesc
|
|
|
|
if emap != nil {
|
|
|
|
desc = emap[extNum]
|
|
|
|
}
|
|
|
|
if desc == nil {
|
|
|
|
// Unknown extension.
|
|
|
|
if err := writeUnknownStruct(w, ext.enc); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
pb, err := GetExtension(ep, desc)
|
|
|
|
if err != nil {
|
2017-01-20 02:10:17 +01:00
|
|
|
return fmt.Errorf("failed getting extension: %v", err)
|
2016-02-02 19:29:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Repeated extensions will appear as a slice.
|
|
|
|
if !desc.repeated() {
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeExtension(w, desc.Name, pb); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
v := reflect.ValueOf(pb)
|
|
|
|
for i := 0; i < v.Len(); i++ {
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-01-20 02:10:17 +01:00
|
|
|
func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {
|
2016-02-02 19:29:08 +01:00
|
|
|
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !w.compact {
|
|
|
|
if err := w.WriteByte(' '); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := w.WriteByte('\n'); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *textWriter) writeIndent() {
|
|
|
|
if !w.complete {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
remain := w.ind * 2
|
|
|
|
for remain > 0 {
|
|
|
|
n := remain
|
|
|
|
if n > len(spaces) {
|
|
|
|
n = len(spaces)
|
|
|
|
}
|
|
|
|
w.w.Write(spaces[:n])
|
|
|
|
remain -= n
|
|
|
|
}
|
|
|
|
w.complete = false
|
|
|
|
}
|
|
|
|
|
2017-01-20 02:10:17 +01:00
|
|
|
// TextMarshaler is a configurable text format marshaler.
|
|
|
|
type TextMarshaler struct {
|
|
|
|
Compact bool // use compact text format (one line).
|
|
|
|
ExpandAny bool // expand google.protobuf.Any messages of known types
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marshal writes a given protocol buffer in text format.
|
|
|
|
// The only errors returned are from w.
|
|
|
|
func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
|
2016-02-02 19:29:08 +01:00
|
|
|
val := reflect.ValueOf(pb)
|
|
|
|
if pb == nil || val.IsNil() {
|
|
|
|
w.Write([]byte("<nil>"))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var bw *bufio.Writer
|
|
|
|
ww, ok := w.(writer)
|
|
|
|
if !ok {
|
|
|
|
bw = bufio.NewWriter(w)
|
|
|
|
ww = bw
|
|
|
|
}
|
|
|
|
aw := &textWriter{
|
|
|
|
w: ww,
|
|
|
|
complete: true,
|
2017-01-20 02:10:17 +01:00
|
|
|
compact: tm.Compact,
|
2016-02-02 19:29:08 +01:00
|
|
|
}
|
|
|
|
|
2017-01-20 02:10:17 +01:00
|
|
|
if etm, ok := pb.(encoding.TextMarshaler); ok {
|
|
|
|
text, err := etm.MarshalText()
|
2016-02-02 19:29:08 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err = aw.Write(text); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if bw != nil {
|
|
|
|
return bw.Flush()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// Dereference the received pointer so we don't have outer < and >.
|
|
|
|
v := reflect.Indirect(val)
|
2017-01-20 02:10:17 +01:00
|
|
|
if err := tm.writeStruct(aw, v); err != nil {
|
2016-02-02 19:29:08 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if bw != nil {
|
|
|
|
return bw.Flush()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-01-20 02:10:17 +01:00
|
|
|
// Text is the same as Marshal, but returns the string directly.
|
|
|
|
func (tm *TextMarshaler) Text(pb Message) string {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
tm.Marshal(&buf, pb)
|
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
defaultTextMarshaler = TextMarshaler{}
|
|
|
|
compactTextMarshaler = TextMarshaler{Compact: true}
|
|
|
|
)
|
|
|
|
|
|
|
|
// TODO: consider removing some of the Marshal functions below.
|
|
|
|
|
2016-02-02 19:29:08 +01:00
|
|
|
// MarshalText writes a given protocol buffer in text format.
|
|
|
|
// The only errors returned are from w.
|
2017-01-20 02:10:17 +01:00
|
|
|
func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
|
2016-02-02 19:29:08 +01:00
|
|
|
|
|
|
|
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
2017-01-20 02:10:17 +01:00
|
|
|
func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
|
2016-02-02 19:29:08 +01:00
|
|
|
|
|
|
|
// CompactText writes a given protocol buffer in compact text format (one line).
|
2017-01-20 02:10:17 +01:00
|
|
|
func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
|
2016-02-02 19:29:08 +01:00
|
|
|
|
|
|
|
// CompactTextString is the same as CompactText, but returns the string directly.
|
2017-01-20 02:10:17 +01:00
|
|
|
func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
|