func (d *InstanceDiff) SetTainted(b bool) {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.DestroyTainted = b
}
These methods are properly locked, for use outside other InstanceDiff
methods but everywhere else within in the terraform package.
TODO refactor the locking scheme
package terraform
import (
	"bufio"
	"bytes"
	"fmt"
	"reflect"
	"regexp"
	"sort"
	"strings"
	"sync"
	"github.com/mitchellh/copystructure"
)
type DiffChangeType byte
const (
	DiffInvalid DiffChangeType = iota
	DiffNone
	DiffCreate
	DiffUpdate
	DiffDestroy
	DiffDestroyCreate
)
type Diff struct {
	Modules []*ModuleDiff
}
func (d *Diff) Prune() {
	if d == nil {
		return
	}
	newModules := make([]*ModuleDiff, 0, len(d.Modules))
	for _, m := range d.Modules {
		if !m.Empty() {
			newModules = append(newModules, m)
		}
	}
	if len(newModules) == 0 {
		newModules = nil
	}
	d.Modules = newModules
}
func (d *Diff) AddModule(path []string) *ModuleDiff {
	m := &ModuleDiff{Path: path}
	m.init()
	d.Modules = append(d.Modules, m)
	return m
}
func (d *Diff) ModuleByPath(path []string) *ModuleDiff {
	if d == nil {
		return nil
	}
	for _, mod := range d.Modules {
		if mod.Path == nil {
			panic("missing module path")
		}
		if reflect.DeepEqual(mod.Path, path) {
			return mod
		}
	}
	return nil
}
func (d *Diff) RootModule() *ModuleDiff {
	root := d.ModuleByPath(rootModulePath)
	if root == nil {
		panic("missing root module")
	}
	return root
}
func (d *Diff) Empty() bool {
	if d == nil {
		return true
	}
	for _, m := range d.Modules {
		if !m.Empty() {
			return false
		}
	}
	return true
}
func (d *Diff) Equal(d2 *Diff) bool {
	if d == nil || d2 == nil {
		return d == d2
	}
	sort.Sort(moduleDiffSort(d.Modules))
	sort.Sort(moduleDiffSort(d2.Modules))
	dCopy := d.DeepCopy()
	d2Copy := d2.DeepCopy()
	for _, m := range dCopy.Modules {
		m.Destroy = false
	}
	for _, m := range d2Copy.Modules {
		m.Destroy = false
	}
	return reflect.DeepEqual(dCopy, d2Copy)
}
func (d *Diff) DeepCopy() *Diff {
	copy, err := copystructure.Config{Lock: true}.Copy(d)
	if err != nil {
		panic(err)
	}
	return copy.(*Diff)
}
func (d *Diff) String() string {
	var buf bytes.Buffer
	keys := make([]string, 0, len(d.Modules))
	lookup := make(map[string]*ModuleDiff)
	for _, m := range d.Modules {
		key := fmt.Sprintf("module.%s", strings.Join(m.Path[1:], "."))
		keys = append(keys, key)
		lookup[key] = m
	}
	sort.Strings(keys)
	for _, key := range keys {
		m := lookup[key]
		mStr := m.String()
		if reflect.DeepEqual(m.Path, rootModulePath) {
			buf.WriteString(mStr + "\n")
			continue
		}
		buf.WriteString(fmt.Sprintf("%s:\n", key))
		s := bufio.NewScanner(strings.NewReader(mStr))
		for s.Scan() {
			buf.WriteString(fmt.Sprintf("  %s\n", s.Text()))
		}
	}
	return strings.TrimSpace(buf.String())
}
func (d *Diff) init() {
	if d.Modules == nil {
		rootDiff := &ModuleDiff{Path: rootModulePath}
		d.Modules = []*ModuleDiff{rootDiff}
	}
	for _, m := range d.Modules {
		m.init()
	}
}
type ModuleDiff struct {
	Path      []string
	Resources map[string]*InstanceDiff
	Destroy   bool  
}
func (d *ModuleDiff) init() {
	if d.Resources == nil {
		d.Resources = make(map[string]*InstanceDiff)
	}
	for _, r := range d.Resources {
		r.init()
	}
}
func (d *ModuleDiff) ChangeType() DiffChangeType {
	result := DiffNone
	for _, r := range d.Resources {
		change := r.ChangeType()
		switch change {
		case DiffCreate, DiffDestroy:
			if result == DiffNone {
				result = change
			}
		case DiffDestroyCreate, DiffUpdate:
			result = DiffUpdate
		}
	}
	return result
}
func (d *ModuleDiff) Empty() bool {
	if d.Destroy {
		return false
	}
	if len(d.Resources) == 0 {
		return true
	}
	for _, rd := range d.Resources {
		if !rd.Empty() {
			return false
		}
	}
	return true
}
func (d *ModuleDiff) Instances(id string) []*InstanceDiff {
	var result []*InstanceDiff
	for k, diff := range d.Resources {
		if k == id || strings.HasPrefix(k, id+".") {
			if !diff.Empty() {
				result = append(result, diff)
			}
		}
	}
	return result
}
func (d *ModuleDiff) IsRoot() bool {
	return reflect.DeepEqual(d.Path, rootModulePath)
}
func (d *ModuleDiff) String() string {
	var buf bytes.Buffer
	names := make([]string, 0, len(d.Resources))
	for name, _ := range d.Resources {
		names = append(names, name)
	}
	sort.Strings(names)
	for _, name := range names {
		rdiff := d.Resources[name]
		crud := "UPDATE"
		switch {
		case rdiff.RequiresNew() && (rdiff.GetDestroy() || rdiff.GetDestroyTainted()):
			crud = "DESTROY/CREATE"
		case rdiff.GetDestroy() || rdiff.GetDestroyDeposed():
			crud = "DESTROY"
		case rdiff.RequiresNew():
			crud = "CREATE"
		}
		extra := ""
		if !rdiff.GetDestroy() && rdiff.GetDestroyDeposed() {
			extra = " (deposed only)"
		}
		buf.WriteString(fmt.Sprintf(
			"%s: %s%s\n",
			crud,
			name,
			extra))
		keyLen := 0
		rdiffAttrs := rdiff.CopyAttributes()
		keys := make([]string, 0, len(rdiffAttrs))
		for key, _ := range rdiffAttrs {
			if key == "id" {
				continue
			}
			keys = append(keys, key)
			if len(key) > keyLen {
				keyLen = len(key)
			}
		}
		sort.Strings(keys)
		for _, attrK := range keys {
			attrDiff, _ := rdiff.GetAttribute(attrK)
			v := attrDiff.New
			u := attrDiff.Old
			if attrDiff.NewComputed {
				v = "<computed>"
			}
			if attrDiff.Sensitive {
				u = "<sensitive>"
				v = "<sensitive>"
			}
			updateMsg := ""
			if attrDiff.RequiresNew {
				updateMsg = " (forces new resource)"
			} else if attrDiff.Sensitive {
				updateMsg = " (attribute changed)"
			}
			buf.WriteString(fmt.Sprintf(
				"  %s:%s %#v => %#v%s\n",
				attrK,
				strings.Repeat(" ", keyLen-len(attrK)),
				u,
				v,
				updateMsg))
		}
	}
	return buf.String()
}
type InstanceDiff struct {
	mu             sync.Mutex
	Attributes     map[string]*ResourceAttrDiff
	Destroy        bool
	DestroyDeposed bool
	DestroyTainted bool
	Meta map[string]interface{}
}
func (d *InstanceDiff) Lock()   { d.mu.Lock() }
func (d *InstanceDiff) Unlock() { d.mu.Unlock() }
type ResourceAttrDiff struct {
	Old         string       
	New         string       
	NewComputed bool         
	NewRemoved  bool         
	NewExtra    interface{}  
	RequiresNew bool         
	Sensitive   bool         
	Type        DiffAttrType
}
func (d *ResourceAttrDiff) Empty() bool {
	return d.Old == d.New && !d.NewComputed && !d.NewRemoved
}
func (d *ResourceAttrDiff) GoString() string {
	return fmt.Sprintf("*%#v", *d)
}
type DiffAttrType byte
const (
	DiffAttrUnknown DiffAttrType = iota
	DiffAttrInput
	DiffAttrOutput
)
func (d *InstanceDiff) init() {
	if d.Attributes == nil {
		d.Attributes = make(map[string]*ResourceAttrDiff)
	}
}
func NewInstanceDiff() *InstanceDiff {
	return &InstanceDiff{Attributes: make(map[string]*ResourceAttrDiff)}
}
func (d *InstanceDiff) Copy() (*InstanceDiff, error) {
	if d == nil {
		return nil, nil
	}
	dCopy, err := copystructure.Config{Lock: true}.Copy(d)
	if err != nil {
		return nil, err
	}
	return dCopy.(*InstanceDiff), nil
}
func (d *InstanceDiff) ChangeType() DiffChangeType {
	if d.Empty() {
		return DiffNone
	}
	if d.RequiresNew() && (d.GetDestroy() || d.GetDestroyTainted()) {
		return DiffDestroyCreate
	}
	if d.GetDestroy() || d.GetDestroyDeposed() {
		return DiffDestroy
	}
	if d.RequiresNew() {
		return DiffCreate
	}
	return DiffUpdate
}
func (d *InstanceDiff) Empty() bool {
	if d == nil {
		return true
	}
	d.mu.Lock()
	defer d.mu.Unlock()
	return !d.Destroy &&
		!d.DestroyTainted &&
		!d.DestroyDeposed &&
		len(d.Attributes) == 0
}
func (d *InstanceDiff) Equal(d2 *InstanceDiff) bool {
	if d == nil || d2 == nil {
		return d == d2
	}
	return reflect.DeepEqual(d, d2)
}
func (d *InstanceDiff) DeepCopy() *InstanceDiff {
	copy, err := copystructure.Config{Lock: true}.Copy(d)
	if err != nil {
		panic(err)
	}
	return copy.(*InstanceDiff)
}
func (d *InstanceDiff) GoString() string {
	return fmt.Sprintf("*%#v", InstanceDiff{
		Attributes:     d.Attributes,
		Destroy:        d.Destroy,
		DestroyTainted: d.DestroyTainted,
		DestroyDeposed: d.DestroyDeposed,
	})
}
func (d *InstanceDiff) RequiresNew() bool {
	if d == nil {
		return false
	}
	d.mu.Lock()
	defer d.mu.Unlock()
	return d.requiresNew()
}
func (d *InstanceDiff) requiresNew() bool {
	if d == nil {
		return false
	}
	if d.DestroyTainted {
		return true
	}
	for _, rd := range d.Attributes {
		if rd != nil && rd.RequiresNew {
			return true
		}
	}
	return false
}
func (d *InstanceDiff) GetDestroyDeposed() bool {
	d.mu.Lock()
	defer d.mu.Unlock()
	return d.DestroyDeposed
}
func (d *InstanceDiff) SetDestroyDeposed(b bool) {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.DestroyDeposed = b
}