mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-18 18:29:44 -05:00
Apply some new go collection features (#36818)
This commit is contained in:
parent
7fadbe34de
commit
c0a7ff235b
26 changed files with 128 additions and 381 deletions
|
|
@ -13,6 +13,8 @@ import (
|
|||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"maps"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/backend/backendrun"
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/configs/configload"
|
||||
|
|
@ -400,9 +402,8 @@ func (b *Local) interactiveCollectVariables(ctx context.Context, existing map[st
|
|||
// variable's value.
|
||||
sort.Strings(needed) // prompt in lexical order
|
||||
ret := make(map[string]backendrun.UnparsedVariableValue, len(vcs))
|
||||
for k, v := range existing {
|
||||
ret[k] = v
|
||||
}
|
||||
maps.Copy(ret, existing) // don't use clone here, so we can have a non-nil map
|
||||
|
||||
for _, name := range needed {
|
||||
vc := vcs[name]
|
||||
query := fmt.Sprintf("var.%s", name)
|
||||
|
|
@ -467,9 +468,8 @@ func (b *Local) stubUnsetRequiredVariables(existing map[string]backendrun.Unpars
|
|||
|
||||
// If we get down here then there's at least one variable value to add.
|
||||
ret := make(map[string]backendrun.UnparsedVariableValue, len(vcs))
|
||||
for k, v := range existing {
|
||||
ret[k] = v
|
||||
}
|
||||
maps.Copy(ret, existing) // don't use clone here, so we can return a non-nil map
|
||||
|
||||
for name, vc := range vcs {
|
||||
if !vc.Required() {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"slices"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"maps"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/backend/backendrun"
|
||||
"github.com/hashicorp/terraform/internal/command/junit"
|
||||
"github.com/hashicorp/terraform/internal/command/views"
|
||||
|
|
@ -94,28 +96,18 @@ func (runner *TestSuiteRunner) Test() (moduletest.Status, tfdiags.Diagnostics) {
|
|||
|
||||
runner.View.Abstract(suite)
|
||||
|
||||
var files []string
|
||||
for name := range suite.Files {
|
||||
files = append(files, name)
|
||||
}
|
||||
sort.Strings(files) // execute the files in alphabetical order
|
||||
|
||||
// We have two sets of variables that are available to different test files.
|
||||
// Test files in the root directory have access to the GlobalVariables only,
|
||||
// while test files in the test directory have access to the union of
|
||||
// GlobalVariables and GlobalTestVariables.
|
||||
testDirectoryGlobalVariables := make(map[string]backendrun.UnparsedVariableValue)
|
||||
for name, value := range runner.GlobalVariables {
|
||||
testDirectoryGlobalVariables[name] = value
|
||||
}
|
||||
for name, value := range runner.GlobalTestVariables {
|
||||
// We're okay to overwrite the global variables in case of name
|
||||
// collisions, as the test directory variables should take precedence.
|
||||
testDirectoryGlobalVariables[name] = value
|
||||
}
|
||||
maps.Copy(testDirectoryGlobalVariables, runner.GlobalVariables)
|
||||
// We're okay to overwrite the global variables in case of name
|
||||
// collisions, as the test directory variables should take precedence.
|
||||
maps.Copy(testDirectoryGlobalVariables, runner.GlobalTestVariables)
|
||||
|
||||
suite.Status = moduletest.Pass
|
||||
for _, name := range files {
|
||||
for _, name := range slices.Sorted(maps.Keys(suite.Files)) {
|
||||
if runner.Cancelled {
|
||||
return suite.Status, diags
|
||||
}
|
||||
|
|
@ -144,9 +136,7 @@ func (runner *TestSuiteRunner) Test() (moduletest.Status, tfdiags.Diagnostics) {
|
|||
}
|
||||
|
||||
evalCtx.VariableCaches = hcltest.NewVariableCaches(func(vc *hcltest.VariableCaches) {
|
||||
for name, value := range currentGlobalVariables {
|
||||
vc.GlobalVariables[name] = value
|
||||
}
|
||||
maps.Copy(vc.GlobalVariables, currentGlobalVariables)
|
||||
vc.FileVariables = file.Config.Variables
|
||||
})
|
||||
fileRunner := &TestFileRunner{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import (
|
|||
"github.com/hashicorp/terraform/internal/states/remote"
|
||||
"github.com/hashicorp/terraform/internal/states/statemgr"
|
||||
|
||||
"maps"
|
||||
|
||||
coordinationv1 "k8s.io/api/coordination/v1"
|
||||
coordinationclientv1 "k8s.io/client-go/kubernetes/typed/coordination/v1"
|
||||
)
|
||||
|
|
@ -351,12 +353,7 @@ func (c *RemoteClient) getLabels() map[string]string {
|
|||
tfstateWorkspaceKey: c.workspace,
|
||||
managedByKey: "terraform",
|
||||
}
|
||||
|
||||
if len(c.labels) != 0 {
|
||||
for k, v := range c.labels {
|
||||
l[k] = v
|
||||
}
|
||||
}
|
||||
maps.Copy(l, c.labels)
|
||||
|
||||
return l
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -341,18 +342,14 @@ func (c *Config) Merge(c2 *Config) *Config {
|
|||
var result Config
|
||||
result.Providers = make(map[string]string)
|
||||
result.Provisioners = make(map[string]string)
|
||||
for k, v := range c.Providers {
|
||||
result.Providers[k] = v
|
||||
}
|
||||
maps.Copy(result.Providers, c.Providers)
|
||||
maps.Copy(result.Provisioners, c.Provisioners)
|
||||
for k, v := range c2.Providers {
|
||||
if v1, ok := c.Providers[k]; ok {
|
||||
log.Printf("[INFO] Local %s provider configuration '%s' overrides '%s'", k, v, v1)
|
||||
}
|
||||
result.Providers[k] = v
|
||||
}
|
||||
for k, v := range c.Provisioners {
|
||||
result.Provisioners[k] = v
|
||||
}
|
||||
for k, v := range c2.Provisioners {
|
||||
if v1, ok := c.Provisioners[k]; ok {
|
||||
log.Printf("[INFO] Local %s provisioner configuration '%s' overrides '%s'", k, v, v1)
|
||||
|
|
@ -375,35 +372,23 @@ func (c *Config) Merge(c2 *Config) *Config {
|
|||
|
||||
if (len(c.Hosts) + len(c2.Hosts)) > 0 {
|
||||
result.Hosts = make(map[string]*ConfigHost)
|
||||
for name, host := range c.Hosts {
|
||||
result.Hosts[name] = host
|
||||
}
|
||||
for name, host := range c2.Hosts {
|
||||
result.Hosts[name] = host
|
||||
}
|
||||
maps.Copy(result.Hosts, c.Hosts)
|
||||
maps.Copy(result.Hosts, c2.Hosts)
|
||||
}
|
||||
|
||||
if (len(c.Credentials) + len(c2.Credentials)) > 0 {
|
||||
result.Credentials = make(map[string]map[string]interface{})
|
||||
for host, creds := range c.Credentials {
|
||||
result.Credentials[host] = creds
|
||||
}
|
||||
for host, creds := range c2.Credentials {
|
||||
// We just clobber an entry from the other file right now. Will
|
||||
// improve on this later using the more-robust merging behavior
|
||||
// built in to HCL2.
|
||||
result.Credentials[host] = creds
|
||||
}
|
||||
maps.Copy(result.Credentials, c.Credentials)
|
||||
// We just clobber an entry from the other file right now. Will
|
||||
// improve on this later using the more-robust merging behavior
|
||||
// built in to HCL2.
|
||||
maps.Copy(result.Credentials, c2.Credentials)
|
||||
}
|
||||
|
||||
if (len(c.CredentialsHelpers) + len(c2.CredentialsHelpers)) > 0 {
|
||||
result.CredentialsHelpers = make(map[string]*ConfigCredentialsHelper)
|
||||
for name, helper := range c.CredentialsHelpers {
|
||||
result.CredentialsHelpers[name] = helper
|
||||
}
|
||||
for name, helper := range c2.CredentialsHelpers {
|
||||
result.CredentialsHelpers[name] = helper
|
||||
}
|
||||
maps.Copy(result.CredentialsHelpers, c.CredentialsHelpers)
|
||||
maps.Copy(result.CredentialsHelpers, c2.CredentialsHelpers)
|
||||
}
|
||||
|
||||
if (len(c.ProviderInstallation) + len(c2.ProviderInstallation)) > 0 {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"iter"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
|
@ -300,8 +301,7 @@ func (f *snippetFormatter) write() {
|
|||
// This is particularly useful for expressions that get evaluated
|
||||
// multiple times with different values, such as blocks using
|
||||
// "count" and "for_each", or within "for" expressions.
|
||||
values := make([]viewsjson.DiagnosticExpressionValue, len(snippet.Values))
|
||||
copy(values, snippet.Values)
|
||||
values := slices.Clone(snippet.Values)
|
||||
sort.Slice(values, func(i, j int) bool {
|
||||
return values[i].Traversal < values[j].Traversal
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
package jsonformat
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||
|
||||
|
|
@ -88,13 +89,7 @@ func (state State) renderHumanStateOutputs(renderer Renderer, opts computed.Rend
|
|||
if len(state.RootModuleOutputs) > 0 {
|
||||
renderer.Streams.Printf("\n\nOutputs:\n\n")
|
||||
|
||||
var keys []string
|
||||
for key := range state.RootModuleOutputs {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
for _, key := range slices.Sorted(maps.Keys(state.RootModuleOutputs)) {
|
||||
output := state.RootModuleOutputs[key]
|
||||
change := structured.FromJsonOutput(output)
|
||||
ctype, err := ctyjson.UnmarshalType(output.Type)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ package jsonstate
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
|
@ -477,13 +479,7 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module
|
|||
ret = append(ret, current)
|
||||
}
|
||||
|
||||
var sortedDeposedKeys []string
|
||||
for k := range ri.Deposed {
|
||||
sortedDeposedKeys = append(sortedDeposedKeys, string(k))
|
||||
}
|
||||
sort.Strings(sortedDeposedKeys)
|
||||
|
||||
for _, deposedKey := range sortedDeposedKeys {
|
||||
for _, deposedKey := range slices.Sorted(maps.Keys(ri.Deposed)) {
|
||||
rios := ri.Deposed[states.DeposedKey(deposedKey)]
|
||||
|
||||
// copy the base fields from the current instance
|
||||
|
|
@ -531,7 +527,7 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module
|
|||
if riObj.Status == states.ObjectTainted {
|
||||
deposed.Tainted = true
|
||||
}
|
||||
deposed.DeposedKey = deposedKey
|
||||
deposed.DeposedKey = string(deposedKey)
|
||||
ret = append(ret, deposed)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
|
@ -155,8 +156,9 @@ func junitXMLTestReport(suite *moduletest.Suite, suiteRunnerStopped bool, source
|
|||
|
||||
enc.EncodeToken(xml.StartElement{Name: suitesName})
|
||||
|
||||
sortedFiles := suiteFilesAsSortedList(suite.Files) // to ensure consistent ordering in XML
|
||||
for _, file := range sortedFiles {
|
||||
// Sort the file names to ensure consistent ordering in XML
|
||||
for _, name := range slices.Sorted(maps.Keys(suite.Files)) {
|
||||
file := suite.Files[name]
|
||||
// Each test file is modelled as a "test suite".
|
||||
|
||||
// First we'll count the number of tests and number of failures/errors
|
||||
|
|
@ -327,22 +329,6 @@ func skipDetails(runIndex int, file *moduletest.File, suiteStopped bool) *withMe
|
|||
return &withMessage{}
|
||||
}
|
||||
|
||||
func suiteFilesAsSortedList(files map[string]*moduletest.File) []*moduletest.File {
|
||||
fileNames := make([]string, len(files))
|
||||
i := 0
|
||||
for k := range files {
|
||||
fileNames[i] = k
|
||||
i++
|
||||
}
|
||||
slices.Sort(fileNames)
|
||||
|
||||
sortedFiles := make([]*moduletest.File, len(files))
|
||||
for i, name := range fileNames {
|
||||
sortedFiles[i] = files[name]
|
||||
}
|
||||
return sortedFiles
|
||||
}
|
||||
|
||||
func getDiagString(diags tfdiags.Diagnostics, sources map[string][]byte) string {
|
||||
var diagsStr strings.Builder
|
||||
for _, d := range diags {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/moduletest"
|
||||
)
|
||||
|
||||
func Test_TestJUnitXMLFile_save(t *testing.T) {
|
||||
|
|
@ -66,88 +64,3 @@ func Test_TestJUnitXMLFile_save(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_suiteFilesAsSortedList(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
Suite *moduletest.Suite
|
||||
ExpectedNames map[int]string
|
||||
}{
|
||||
"no test files": {
|
||||
Suite: &moduletest.Suite{},
|
||||
},
|
||||
"3 test files ordered in map": {
|
||||
Suite: &moduletest.Suite{
|
||||
Status: moduletest.Skip,
|
||||
Files: map[string]*moduletest.File{
|
||||
"test_file_1.tftest.hcl": {
|
||||
Name: "test_file_1.tftest.hcl",
|
||||
Status: moduletest.Skip,
|
||||
Runs: []*moduletest.Run{},
|
||||
},
|
||||
"test_file_2.tftest.hcl": {
|
||||
Name: "test_file_2.tftest.hcl",
|
||||
Status: moduletest.Skip,
|
||||
Runs: []*moduletest.Run{},
|
||||
},
|
||||
"test_file_3.tftest.hcl": {
|
||||
Name: "test_file_3.tftest.hcl",
|
||||
Status: moduletest.Skip,
|
||||
Runs: []*moduletest.Run{},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedNames: map[int]string{
|
||||
0: "test_file_1.tftest.hcl",
|
||||
1: "test_file_2.tftest.hcl",
|
||||
2: "test_file_3.tftest.hcl",
|
||||
},
|
||||
},
|
||||
"3 test files unordered in map": {
|
||||
Suite: &moduletest.Suite{
|
||||
Status: moduletest.Skip,
|
||||
Files: map[string]*moduletest.File{
|
||||
"test_file_3.tftest.hcl": {
|
||||
Name: "test_file_3.tftest.hcl",
|
||||
Status: moduletest.Skip,
|
||||
Runs: []*moduletest.Run{},
|
||||
},
|
||||
"test_file_1.tftest.hcl": {
|
||||
Name: "test_file_1.tftest.hcl",
|
||||
Status: moduletest.Skip,
|
||||
Runs: []*moduletest.Run{},
|
||||
},
|
||||
"test_file_2.tftest.hcl": {
|
||||
Name: "test_file_2.tftest.hcl",
|
||||
Status: moduletest.Skip,
|
||||
Runs: []*moduletest.Run{},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedNames: map[int]string{
|
||||
0: "test_file_1.tftest.hcl",
|
||||
1: "test_file_2.tftest.hcl",
|
||||
2: "test_file_3.tftest.hcl",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range cases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
list := suiteFilesAsSortedList(tc.Suite.Files)
|
||||
|
||||
if len(tc.ExpectedNames) != len(tc.Suite.Files) {
|
||||
t.Fatalf("expected there to be %d items, got %d", len(tc.ExpectedNames), len(tc.Suite.Files))
|
||||
}
|
||||
|
||||
if len(tc.ExpectedNames) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range tc.ExpectedNames {
|
||||
if list[k].Name != v {
|
||||
t.Fatalf("expected element %d in sorted list to be named %s, got %s", k, v, list[k].Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
|
@ -293,9 +294,7 @@ func (m *Meta) StateOutPath() string {
|
|||
// Colorize returns the colorization structure for a command.
|
||||
func (m *Meta) Colorize() *colorstring.Colorize {
|
||||
colors := make(map[string]string)
|
||||
for k, v := range colorstring.DefaultColors {
|
||||
colors[k] = v
|
||||
}
|
||||
maps.Copy(colors, colorstring.DefaultColors)
|
||||
colors["purple"] = "38;5;57"
|
||||
|
||||
return &colorstring.Colorize{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ package configs
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
|
@ -135,13 +138,8 @@ func (c *Config) Depth() int {
|
|||
func (c *Config) DeepEach(cb func(c *Config)) {
|
||||
cb(c)
|
||||
|
||||
names := make([]string, 0, len(c.Children))
|
||||
for name := range c.Children {
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
c.Children[name].DeepEach(cb)
|
||||
for _, ch := range c.Children {
|
||||
ch.DeepEach(cb)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -826,12 +824,8 @@ func (c *Config) ProviderTypes() []addrs.Provider {
|
|||
// Ignore diagnostics here because they relate to version constraints
|
||||
reqs, _ := c.ProviderRequirements()
|
||||
|
||||
ret := make([]addrs.Provider, 0, len(reqs))
|
||||
for k := range reqs {
|
||||
ret = append(ret, k)
|
||||
}
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
return ret[i].String() < ret[j].String()
|
||||
ret := slices.SortedFunc(maps.Keys(reqs), func(i, j addrs.Provider) int {
|
||||
return strings.Compare(i.String(), j.String())
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ package configs
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"path"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
|
@ -150,17 +151,10 @@ func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config,
|
|||
|
||||
// We'll sort the calls by their local names so that they'll appear in a
|
||||
// predictable order in any logging that's produced during the walk.
|
||||
callNames := make([]string, 0, len(calls))
|
||||
for k := range calls {
|
||||
callNames = append(callNames, k)
|
||||
}
|
||||
sort.Strings(callNames)
|
||||
|
||||
for _, callName := range callNames {
|
||||
for _, callName := range slices.Sorted(maps.Keys(calls)) {
|
||||
call := calls[callName]
|
||||
path := make([]string, len(parent.Path)+1)
|
||||
copy(path, parent.Path)
|
||||
path[len(path)-1] = call.Name
|
||||
path := slices.Clone(parent.Path)
|
||||
path = append(path, call.Name)
|
||||
|
||||
req := ModuleRequest{
|
||||
Name: call.Name,
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ package configload
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
|
@ -257,11 +258,7 @@ func (fs snapshotFS) Open(name string) (afero.File, error) {
|
|||
modDir := filepath.Clean(candidate.Dir)
|
||||
if modDir == directDir {
|
||||
// We've matched the module directory itself
|
||||
filenames := make([]string, 0, len(candidate.Files))
|
||||
for n := range candidate.Files {
|
||||
filenames = append(filenames, n)
|
||||
}
|
||||
sort.Strings(filenames)
|
||||
filenames := slices.Sorted(maps.Keys(candidate.Files))
|
||||
return &snapshotDir{
|
||||
filenames: filenames,
|
||||
}, nil
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ package dag
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
|
@ -97,13 +99,8 @@ func (v *marshalVertex) dot(g *marshalGraph, opts *DotOpts) []byte {
|
|||
return []byte{}
|
||||
}
|
||||
|
||||
newAttrs := make(map[string]string)
|
||||
for k, v := range attrs {
|
||||
newAttrs[k] = v
|
||||
}
|
||||
for k, v := range node.Attrs {
|
||||
newAttrs[k] = v
|
||||
}
|
||||
newAttrs := maps.Clone(attrs)
|
||||
maps.Copy(newAttrs, node.Attrs)
|
||||
|
||||
name = node.Name
|
||||
attrs = newAttrs
|
||||
|
|
@ -218,13 +215,7 @@ func (g *marshalGraph) writeBody(opts *DotOpts, w *indentWriter) {
|
|||
}
|
||||
|
||||
// sort these again to match the old output
|
||||
dotEdgesList := make([]string, 0, len(dotEdges))
|
||||
for _, v := range dotEdges {
|
||||
dotEdgesList = append(dotEdgesList, v)
|
||||
}
|
||||
sort.Strings(dotEdgesList)
|
||||
|
||||
for _, e := range dotEdgesList {
|
||||
for _, e := range slices.Sorted(maps.Values(dotEdges)) {
|
||||
w.WriteString(e + "\n")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
package dag
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Set is a set data structure.
|
||||
type Set map[interface{}]interface{}
|
||||
|
||||
|
|
@ -92,25 +97,18 @@ func (s Set) Len() int {
|
|||
return len(s)
|
||||
}
|
||||
|
||||
// List returns the list of set elements.
|
||||
func (s Set) List() []interface{} {
|
||||
if s == nil {
|
||||
return nil
|
||||
// List returns the sequence of set elements.
|
||||
func (s Set) List() iter.Seq[any] {
|
||||
return func(yield func(any) bool) {
|
||||
for _, v := range s {
|
||||
if !yield(v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r := make([]interface{}, 0, len(s))
|
||||
for _, v := range s {
|
||||
r = append(r, v)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Copy returns a shallow copy of the set.
|
||||
func (s Set) Copy() Set {
|
||||
c := make(Set, len(s))
|
||||
for k, v := range s {
|
||||
c[k] = v
|
||||
}
|
||||
return c
|
||||
return maps.Clone(s)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@ package depsfile
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"maps"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/getproviders/providerreqs"
|
||||
)
|
||||
|
|
@ -69,11 +72,7 @@ func (l *Locks) Provider(addr addrs.Provider) *ProviderLock {
|
|||
func (l *Locks) AllProviders() map[addrs.Provider]*ProviderLock {
|
||||
// We return a copy of our internal map so that future calls to
|
||||
// SetProvider won't modify the map we're returning, or vice-versa.
|
||||
ret := make(map[addrs.Provider]*ProviderLock, len(l.providers))
|
||||
for k, v := range l.providers {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret
|
||||
return maps.Clone(l.providers)
|
||||
}
|
||||
|
||||
// SetProvider creates a new lock or replaces the existing lock for the given
|
||||
|
|
@ -315,11 +314,7 @@ func (l *Locks) Empty() bool {
|
|||
func (l *Locks) DeepCopy() *Locks {
|
||||
ret := NewLocks()
|
||||
for addr, lock := range l.providers {
|
||||
var hashes []providerreqs.Hash
|
||||
if len(lock.hashes) > 0 {
|
||||
hashes = make([]providerreqs.Hash, len(lock.hashes))
|
||||
copy(hashes, lock.hashes)
|
||||
}
|
||||
hashes := slices.Clone(lock.hashes)
|
||||
ret.SetProvider(addr, lock.version, lock.versionConstraints, hashes)
|
||||
}
|
||||
return ret
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ package depsfile
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
|
@ -138,10 +140,7 @@ func SaveLocksToBytes(locks *Locks) ([]byte, tfdiags.Diagnostics) {
|
|||
},
|
||||
})
|
||||
|
||||
providers := make([]addrs.Provider, 0, len(locks.providers))
|
||||
for provider := range locks.providers {
|
||||
providers = append(providers, provider)
|
||||
}
|
||||
providers := slices.Collect(maps.Keys(locks.providers))
|
||||
sort.Slice(providers, func(i, j int) bool {
|
||||
return providers[i].LessThan(providers[j])
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ package genconfig
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
|
@ -72,14 +73,7 @@ func writeConfigAttributes(addr addrs.AbsResourceInstance, buf *strings.Builder,
|
|||
}
|
||||
|
||||
// Get a list of sorted attribute names so the output will be consistent between runs.
|
||||
keys := make([]string, 0, len(attrs))
|
||||
for k := range attrs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i := range keys {
|
||||
name := keys[i]
|
||||
for _, name := range slices.Sorted(maps.Keys(attrs)) {
|
||||
attrS := attrs[name]
|
||||
if attrS.NestedType != nil {
|
||||
diags = diags.Append(writeConfigNestedTypeAttribute(addr, buf, name, attrS, indent))
|
||||
|
|
@ -124,15 +118,8 @@ func writeConfigAttributesFromExisting(addr addrs.AbsResourceInstance, buf *stri
|
|||
return diags
|
||||
}
|
||||
|
||||
// Get a list of sorted attribute names so the output will be consistent between runs.
|
||||
keys := make([]string, 0, len(attrs))
|
||||
for k := range attrs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i := range keys {
|
||||
name := keys[i]
|
||||
// Sort attribute names so the output will be consistent between runs.
|
||||
for _, name := range slices.Sorted(maps.Keys(attrs)) {
|
||||
attrS := attrs[name]
|
||||
if attrS.NestedType != nil {
|
||||
writeConfigNestedTypeAttributeFromExisting(addr, buf, name, attrS, stateVal, indent)
|
||||
|
|
@ -233,14 +220,7 @@ func writeConfigBlocks(addr addrs.AbsResourceInstance, buf *strings.Builder, blo
|
|||
}
|
||||
|
||||
// Get a list of sorted block names so the output will be consistent between runs.
|
||||
names := make([]string, 0, len(blocks))
|
||||
for k := range blocks {
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
for i := range names {
|
||||
name := names[i]
|
||||
for _, name := range slices.Sorted(maps.Keys(blocks)) {
|
||||
blockS := blocks[name]
|
||||
diags = diags.Append(writeConfigNestedBlock(addr, buf, name, blockS, indent))
|
||||
}
|
||||
|
|
@ -329,14 +309,8 @@ func writeConfigBlocksFromExisting(addr addrs.AbsResourceInstance, buf *strings.
|
|||
return diags
|
||||
}
|
||||
|
||||
// Get a list of sorted block names so the output will be consistent between runs.
|
||||
names := make([]string, 0, len(blocks))
|
||||
for k := range blocks {
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
for _, name := range names {
|
||||
// Sort block names so the output will be consistent between runs.
|
||||
for _, name := range slices.Sorted(maps.Keys(blocks)) {
|
||||
blockS := blocks[name]
|
||||
// This shouldn't happen in real usage; state always has all values (set
|
||||
// to null as needed), but it protects against panics in tests (and any
|
||||
|
|
@ -436,15 +410,10 @@ func writeConfigNestedTypeAttributeFromExisting(addr addrs.AbsResourceInstance,
|
|||
}
|
||||
|
||||
vals := attr.AsValueMap()
|
||||
keys := make([]string, 0, len(vals))
|
||||
for key := range vals {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s = {\n", name))
|
||||
for _, key := range keys {
|
||||
for _, key := range slices.Sorted(maps.Keys(vals)) {
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(fmt.Sprintf("%s = {", hclEscapeString(key)))
|
||||
|
||||
|
|
@ -513,12 +482,7 @@ func writeConfigNestedBlockFromExisting(addr addrs.AbsResourceInstance, buf *str
|
|||
}
|
||||
|
||||
vals := stateVal.AsValueMap()
|
||||
keys := make([]string, 0, len(vals))
|
||||
for key := range vals {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
for _, key := range slices.Sorted(maps.Keys(vals)) {
|
||||
buf.WriteString(strings.Repeat(" ", indent))
|
||||
buf.WriteString(fmt.Sprintf("%s %q {", name, key))
|
||||
// This entire map element is marked
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import (
|
|||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
|
||||
"maps"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/instances"
|
||||
|
|
@ -442,10 +444,10 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
// traversal, but we also expose them under "resource" as an escaping
|
||||
// technique if we add a reserved name in a future language edition which
|
||||
// conflicts with someone's existing provider.
|
||||
for k, v := range buildResourceObjects(managedResources) {
|
||||
vals[k] = v
|
||||
}
|
||||
vals["resource"] = cty.ObjectVal(buildResourceObjects(managedResources))
|
||||
builtManagedResources := buildResourceObjects(managedResources)
|
||||
maps.Copy(vals, builtManagedResources)
|
||||
|
||||
vals["resource"] = cty.ObjectVal(builtManagedResources)
|
||||
vals["ephemeral"] = cty.ObjectVal(buildResourceObjects(ephemeralResources))
|
||||
vals["data"] = cty.ObjectVal(buildResourceObjects(dataResources))
|
||||
vals["module"] = cty.ObjectVal(wholeModules)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package moduleref
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
|
|
@ -23,10 +24,7 @@ type Resolver struct {
|
|||
func NewResolver(internalManifest modsdir.Manifest) *Resolver {
|
||||
// Since maps are pointers, create a copy of the internal manifest to
|
||||
// prevent introducing side effects to the original
|
||||
internalManifestCopy := make(modsdir.Manifest, len(internalManifest))
|
||||
for k, v := range internalManifest {
|
||||
internalManifestCopy[k] = v
|
||||
}
|
||||
internalManifestCopy := maps.Clone(internalManifest)
|
||||
|
||||
// Remove the root module entry from the internal manifest as it is
|
||||
// never directly referenced.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import (
|
|||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
|
||||
"maps"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/command/views"
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
|
|
@ -313,9 +315,7 @@ func (ec *EvalContext) GetOutputs() map[addrs.Run]cty.Value {
|
|||
ec.outputsLock.Lock()
|
||||
defer ec.outputsLock.Unlock()
|
||||
outputCopy := make(map[addrs.Run]cty.Value, len(ec.runOutputs))
|
||||
for k, v := range ec.runOutputs {
|
||||
outputCopy[k] = v
|
||||
}
|
||||
maps.Copy(outputCopy, ec.runOutputs) // don't use clone here, so we can return a non-nil map
|
||||
return outputCopy
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"path"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -158,15 +159,10 @@ func writeConfigSnapshot(snap *configload.Snapshot, z *zip.Writer) error {
|
|||
// need to be user-actionable.
|
||||
|
||||
var manifest configSnapshotModuleManifest
|
||||
keys := make([]string, 0, len(snap.Modules))
|
||||
for k := range snap.Modules {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// We'll re-use this fileheader for each Create we do below.
|
||||
|
||||
for _, k := range keys {
|
||||
for _, k := range slices.Sorted(maps.Keys(snap.Modules)) {
|
||||
snapMod := snap.Modules[k]
|
||||
record := configSnapshotModuleRecord{
|
||||
Dir: snapMod.Dir,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package planfile
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
|
@ -598,10 +599,7 @@ func writeTfplan(plan *plans.Plan, w io.Writer) error {
|
|||
rawPlan.Variables[name] = valueToTfplan(val)
|
||||
}
|
||||
if plan.ApplyTimeVariables.Len() != 0 {
|
||||
rawPlan.ApplyTimeVariables = make([]string, 0, plan.ApplyTimeVariables.Len())
|
||||
for name := range plan.ApplyTimeVariables.All() {
|
||||
rawPlan.ApplyTimeVariables = append(rawPlan.ApplyTimeVariables, name)
|
||||
}
|
||||
rawPlan.ApplyTimeVariables = slices.Collect(plan.ApplyTimeVariables.All())
|
||||
}
|
||||
|
||||
for _, hash := range plan.ProviderFunctionResults {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
package states
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Taking deep copies of states is an important operation because state is
|
||||
|
|
@ -128,45 +130,15 @@ func (os *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc {
|
|||
return nil
|
||||
}
|
||||
|
||||
var attrsFlat map[string]string
|
||||
if os.AttrsFlat != nil {
|
||||
attrsFlat = make(map[string]string, len(os.AttrsFlat))
|
||||
for k, v := range os.AttrsFlat {
|
||||
attrsFlat[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
var attrsJSON []byte
|
||||
if os.AttrsJSON != nil {
|
||||
attrsJSON = make([]byte, len(os.AttrsJSON))
|
||||
copy(attrsJSON, os.AttrsJSON)
|
||||
}
|
||||
|
||||
var identityJSON []byte
|
||||
if os.IdentityJSON != nil {
|
||||
identityJSON = make([]byte, len(os.IdentityJSON))
|
||||
copy(identityJSON, os.IdentityJSON)
|
||||
}
|
||||
|
||||
var sensitiveAttrPaths []cty.Path
|
||||
if os.AttrSensitivePaths != nil {
|
||||
sensitiveAttrPaths = make([]cty.Path, len(os.AttrSensitivePaths))
|
||||
copy(sensitiveAttrPaths, os.AttrSensitivePaths)
|
||||
}
|
||||
|
||||
var private []byte
|
||||
if os.Private != nil {
|
||||
private = make([]byte, len(os.Private))
|
||||
copy(private, os.Private)
|
||||
}
|
||||
attrsFlat := maps.Clone(os.AttrsFlat)
|
||||
attrsJSON := slices.Clone(os.AttrsJSON)
|
||||
identityJSON := slices.Clone(os.IdentityJSON)
|
||||
sensitiveAttrPaths := slices.Clone(os.AttrSensitivePaths)
|
||||
private := slices.Clone(os.Private)
|
||||
|
||||
// Some addrs.Referencable implementations are technically mutable, but
|
||||
// we treat them as immutable by convention and so we don't deep-copy here.
|
||||
var dependencies []addrs.ConfigResource
|
||||
if os.Dependencies != nil {
|
||||
dependencies = make([]addrs.ConfigResource, len(os.Dependencies))
|
||||
copy(dependencies, os.Dependencies)
|
||||
}
|
||||
dependencies := slices.Clone(os.Dependencies)
|
||||
|
||||
return &ResourceInstanceObjectSrc{
|
||||
Status: os.Status,
|
||||
|
|
@ -197,19 +169,11 @@ func (o *ResourceInstanceObject) DeepCopy() *ResourceInstanceObject {
|
|||
return nil
|
||||
}
|
||||
|
||||
var private []byte
|
||||
if o.Private != nil {
|
||||
private = make([]byte, len(o.Private))
|
||||
copy(private, o.Private)
|
||||
}
|
||||
private := slices.Clone(o.Private)
|
||||
|
||||
// Some addrs.Referenceable implementations are technically mutable, but
|
||||
// we treat them as immutable by convention and so we don't deep-copy here.
|
||||
var dependencies []addrs.ConfigResource
|
||||
if o.Dependencies != nil {
|
||||
dependencies = make([]addrs.ConfigResource, len(o.Dependencies))
|
||||
copy(dependencies, o.Dependencies)
|
||||
}
|
||||
dependencies := slices.Clone(o.Dependencies)
|
||||
|
||||
return &ResourceInstanceObject{
|
||||
Value: o.Value,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import (
|
|||
"github.com/zclconf/go-cty/cty"
|
||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||
|
||||
"maps"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
|
|
@ -315,13 +317,7 @@ func upgradeInstanceObjectV3ToV4(rsOld *resourceStateV2, isOld *instanceStateV2,
|
|||
}
|
||||
}
|
||||
|
||||
var attributes map[string]string
|
||||
if isOld.Attributes != nil {
|
||||
attributes = make(map[string]string, len(isOld.Attributes))
|
||||
for k, v := range isOld.Attributes {
|
||||
attributes[k] = v
|
||||
}
|
||||
}
|
||||
attributes := maps.Clone(isOld.Attributes)
|
||||
if isOld.ID != "" {
|
||||
// As a special case, if we don't already have an "id" attribute and
|
||||
// yet there's a non-empty first-class ID on the old object then we'll
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func (t *ephemeralResourceCloseTransformer) Transform(g *Graph) error {
|
|||
return len(up) == 0
|
||||
})
|
||||
|
||||
for _, last := range lastReferences.List() {
|
||||
for last := range lastReferences.List() {
|
||||
g.Connect(dag.BasicEdge(closeNode, last))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue