ronantakizawa/codereview-bench huggingface dataset:
Repository: opentofu/opentofu
File: internal/dag/dot.go (Go)

Code before:
}

func (w *indentWriter) indent() {
	newline := []byte("\n")
	if !bytes.HasSuffix(w.Bytes(), newline) {
		return
	}
	for i := 0; i < w.level; i++ {
		w.Buffer.WriteString("\t")
	}
}

// Indent increases indentation by 1
func (w *indentWriter) Indent() { w.level++ }

// Unindent decreases indentation by 1
func (w *indentWriter) Unindent() { w.level-- }

// the following methods intercept the byte.Buffer writes and insert the
// indentation when starting a new line.
func (w *indentWriter) Write(b []byte) {
	w.indent()
	w.Buffer.Write(b) //nolint:errcheck // err is always nil
}

func (w *indentWriter) WriteString(s string) {
	w.indent()
	w.Buffer.WriteString(s) //nolint:errcheck // err is always nil
}
func (w *indentWriter) WriteByte(b byte) error {
	w.indent()
	return w.Buffer.WriteByte(b)
}
func (w *indentWriter) WriteRune(r rune) (int, error) {
	w.indent()
	return w.Buffer.WriteRune(r)
}


Review comment (suggestion):
By changing the signature of these 2 methods, `*identWriter` does not implicitly implement some interfaces. This can create unwanted and unexpected behaviour.
I do not advise on doing this.

Code after:
	level int
}

func (w *indentWriter) indent() {
	newline := []byte("\n")
	if !bytes.HasSuffix(w.Bytes(), newline) {
		return
	}
	for i := 0; i < w.level; i++ {
		w.Buffer.WriteString("\t")
	}
}

// Indent increases indentation by 1
func (w *indentWriter) Indent() { w.level++ }

// Unindent decreases indentation by 1
func (w *indentWriter) Unindent() { w.level-- }

// the following methods intercept the byte.Buffer writes and insert the
// indentation when starting a new line.
func (w *indentWriter) Write(b []byte) (int, error) {
	w.indent()
	return w.Buffer.Write(b)
}

// writeString is a helper function to write a string to the indentWriter without the need for handling errors.
// the errors are ignored here because writing to a bytes.Buffer should never fail
func (w *indentWriter) writeString(s string) {
	_, _ = w.WriteString(s)
}

func (w *indentWriter) WriteString(s string) (int, error) {
	w.indent()
	return w.Buffer.WriteString(s)
}
func (w *indentWriter) WriteByte(b byte) error {
	w.indent()
	return w.Buffer.WriteByte(b)
}
func (w *indentWriter) WriteRune(r rune) (int, error) {
	w.indent()
	return w.Buffer.WriteRune(r)
}
Repository: opentofu/opentofu
File: internal/backend/remote-state/http/client_test.go (Go)

Code before:
	brokenHandler := new(testBrokenHTTPHandler)
	brokenHandler.handler = new(testHTTPHandler)
	ts = httptest.NewServer(http.HandlerFunc(brokenHandler.Handle))
	defer ts.Close()

	url, err = url.Parse(ts.URL)
	if err != nil {
		t.Fatalf("Parse: %s", err)
	}
	client = &httpClient{URL: url, Client: retryablehttp.NewClient()}
	remote.TestClient(t, client)
}

type testHTTPHandler struct {
	Data   []byte
	Locked bool
}

func (h *testHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		if _, err := w.Write(h.Data); err != nil {
			w.WriteHeader(500)
		}
		w.WriteHeader(200)
	case "PUT":
		buf := new(bytes.Buffer)
		if _, err := io.Copy(buf, r.Body); err != nil {
			w.WriteHeader(500)
		}
		w.WriteHeader(201)
		h.Data = buf.Bytes()
	case "POST":
		buf := new(bytes.Buffer)
		if _, err := io.Copy(buf, r.Body); err != nil {
			w.WriteHeader(500)
		}
		h.Data = buf.Bytes()
	case "LOCK":
		if h.Locked {
			w.WriteHeader(423)
		} else {
			h.Locked = true
		}
	case "UNLOCK":
		h.Locked = false
	case "DELETE":
		h.Data = nil
		w.WriteHeader(200)
	default:
		w.WriteHeader(500)

Review comment (suggestion):
```suggestion
		} else {
			w.WriteHeader(200)
		}
```
I know this is a test file, but in case of an error, we will be calling the `WriteHeader` twice, so we might as well put it in an else condition.

Code after:
	brokenHandler := new(testBrokenHTTPHandler)
	brokenHandler.handler = new(testHTTPHandler)
	ts = httptest.NewServer(http.HandlerFunc(brokenHandler.Handle))
	defer ts.Close()

	url, err = url.Parse(ts.URL)
	if err != nil {
		t.Fatalf("Parse: %s", err)
	}
	client = &httpClient{URL: url, Client: retryablehttp.NewClient()}
	remote.TestClient(t, client)
}

type testHTTPHandler struct {
	Data   []byte
	Locked bool
}

func (h *testHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		if _, err := w.Write(h.Data); err != nil {
			w.WriteHeader(500)
			return
		}
		w.WriteHeader(200)
	case "PUT":
		buf := new(bytes.Buffer)
		if _, err := io.Copy(buf, r.Body); err != nil {
			w.WriteHeader(500)
			return
		}
		w.WriteHeader(201)
		h.Data = buf.Bytes()
	case "POST":
		buf := new(bytes.Buffer)
		if _, err := io.Copy(buf, r.Body); err != nil {
			w.WriteHeader(500)
			return
		}
		h.Data = buf.Bytes()
	case "LOCK":
		if h.Locked {
			w.WriteHeader(423)
		} else {
			h.Locked = true
		}
	case "UNLOCK":
		h.Locked = false
	case "DELETE":
		h.Data = nil
Repository: opentofu/opentofu
File: internal/backend/remote/backend_plan.go (Go)

Code before:
				return
			case <-time.After(lockTimeout):
				// Retrieve the run to get its current status.
				r, err := b.client.Runs.Read(cancelCtx, r.ID)
				if err != nil {
					log.Printf("[ERROR] error reading run: %v", err)
					return
				}

				if r.Status == tfe.RunPending && r.Actions.IsCancelable {
					if b.CLI != nil {
						b.CLI.Output(b.Colorize().Color(strings.TrimSpace(lockTimeoutErr)))
					}

					// We abuse the auto approve flag to indicate that we do not
					// want to ask if the remote operation should be canceled.
					op.AutoApprove = true

					p, err := os.FindProcess(os.Getpid())
					if err != nil {
						log.Printf("[ERROR] error searching process ID: %v", err)
						return
					}
					if err := p.Signal(syscall.SIGINT); err != nil {
						log.Printf("[ERROR] error sending interrupt signal: %v", err)
						return
					}
				}
			}
		}()
	}

	if b.CLI != nil {
		b.CLI.Output(b.Colorize().Color(strings.TrimSpace(fmt.Sprintf(
			runHeader, b.hostname, b.organization, op.Workspace, r.ID)) + "\n"))
	}

	r, err = b.waitForRun(stopCtx, cancelCtx, op, "plan", r, w)
	if err != nil {
		return r, err
	}

	logs, err := b.client.Plans.Logs(stopCtx, r.Plan.ID)
	if err != nil {
		return r, generalError("Failed to retrieve logs", err)
	}
	reader := bufio.NewReaderSize(logs, 64*1024)

	if b.CLI != nil {
		for next := true; next; {
			var l, line []byte

Review comment (suggestion):
```suggestion

```
Does this return serve any purpose? It is at the end of the function, and likely redundant.

Code after:
				return
			case <-time.After(lockTimeout):
				// Retrieve the run to get its current status.
				r, err := b.client.Runs.Read(cancelCtx, r.ID)
				if err != nil {
					log.Printf("[ERROR] error reading run: %v", err)
					return
				}

				if r.Status == tfe.RunPending && r.Actions.IsCancelable {
					if b.CLI != nil {
						b.CLI.Output(b.Colorize().Color(strings.TrimSpace(lockTimeoutErr)))
					}

					// We abuse the auto approve flag to indicate that we do not
					// want to ask if the remote operation should be canceled.
					op.AutoApprove = true

					p, err := os.FindProcess(os.Getpid())
					if err != nil {
						log.Printf("[ERROR] error searching process ID: %v", err)
						return
					}
					if err := p.Signal(syscall.SIGINT); err != nil {
						log.Printf("[ERROR] error sending interrupt signal: %v", err)
					}
				}
			}
		}()
	}

	if b.CLI != nil {
		b.CLI.Output(b.Colorize().Color(strings.TrimSpace(fmt.Sprintf(
			runHeader, b.hostname, b.organization, op.Workspace, r.ID)) + "\n"))
	}

	r, err = b.waitForRun(stopCtx, cancelCtx, op, "plan", r, w)
	if err != nil {
		return r, err
	}

	logs, err := b.client.Plans.Logs(stopCtx, r.Plan.ID)
	if err != nil {
		return r, generalError("Failed to retrieve logs", err)
	}
	reader := bufio.NewReaderSize(logs, 64*1024)

	if b.CLI != nil {
		for next := true; next; {
			var l, line []byte
Repository: opentofu/opentofu
File: internal/backend/testing.go (Go)

Code before:
	infoB := statemgr.NewLockInfo()
	infoB.Operation = "test"
	infoB.Who = "clientB"

	lockIDA, err := lockerA.Lock(infoA)
	if err != nil {
		t.Fatal("unable to get initial lock:", err)
	}

	// Make sure we can still get the statemgr.Full from another instance even
	// when locked.  This should only happen when a state is loaded via the
	// backend, and as a remote state.
	_, err = b2.StateMgr(t.Context(), DefaultStateName)
	if err != nil {
		t.Errorf("failed to read locked state from another backend instance: %s", err)
	}

	// If the lock ID is blank, assume locking is disabled
	if lockIDA == "" {
		t.Logf("TestBackend: %T: empty string returned for lock, assuming disabled", b1)
		return
	}

	_, err = lockerB.Lock(infoB)
	if err == nil {
		lockerA.Unlock(lockIDA) //nolint:errcheck // test already failed, no need to check err further
		t.Fatal("client B obtained lock while held by client A")
	}

	if err := lockerA.Unlock(lockIDA); err != nil {
		t.Fatal("error unlocking client A", err)
	}

	lockIDB, err := lockerB.Lock(infoB)
	if err != nil {
		t.Fatal("unable to obtain lock from client B")
	}

	if lockIDB == lockIDA {
		t.Errorf("duplicate lock IDs: %q", lockIDB)
	}

	if err = lockerB.Unlock(lockIDB); err != nil {
		t.Fatal("error unlocking client B:", err)
	}

	// test the equivalent of -force-unlock, by using the id from the error
	// output.
	if !testForceUnlock {
		return
	}

Review comment (suggestion):
```suggestion
		_ = lockerA.Unlock(lockIDA)
```
I've had the same comment at another place: we can use Go's syntax here to ignore errors.

Code after:
	infoB := statemgr.NewLockInfo()
	infoB.Operation = "test"
	infoB.Who = "clientB"

	lockIDA, err := lockerA.Lock(infoA)
	if err != nil {
		t.Fatal("unable to get initial lock:", err)
	}

	// Make sure we can still get the statemgr.Full from another instance even
	// when locked.  This should only happen when a state is loaded via the
	// backend, and as a remote state.
	_, err = b2.StateMgr(t.Context(), DefaultStateName)
	if err != nil {
		t.Errorf("failed to read locked state from another backend instance: %s", err)
	}

	// If the lock ID is blank, assume locking is disabled
	if lockIDA == "" {
		t.Logf("TestBackend: %T: empty string returned for lock, assuming disabled", b1)
		return
	}

	_, err = lockerB.Lock(infoB)
	if err == nil {
		_ = lockerA.Unlock(lockIDA) // test already failed, no need to check err further
		t.Fatal("client B obtained lock while held by client A")
	}

	if err := lockerA.Unlock(lockIDA); err != nil {
		t.Fatal("error unlocking client A", err)
	}

	lockIDB, err := lockerB.Lock(infoB)
	if err != nil {
		t.Fatal("unable to obtain lock from client B")
	}

	if lockIDB == lockIDA {
		t.Errorf("duplicate lock IDs: %q", lockIDB)
	}

	if err = lockerB.Unlock(lockIDB); err != nil {
		t.Fatal("error unlocking client B:", err)
	}

	// test the equivalent of -force-unlock, by using the id from the error
	// output.
	if !testForceUnlock {
		return
	}
Repository: opentofu/opentofu
File: internal/tofu/update_state_hook.go (Go)

Code before:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"github.com/opentofu/opentofu/internal/states"
)

// updateState calls the PostStateUpdate hook with the state modification function and applies the change to the "live" state object
func updateState(ctx EvalContext, fn func(*states.SyncState)) error {
	// Modify the state
	fn(ctx.State())

	// Call the hook
	return ctx.Hook(func(h Hook) (HookAction, error) {
		return h.PostStateUpdate(fn)
	})
}


Review comment (suggestion):
```suggestion
	// Since the EvalContext.State() is not in sync with the StateMgr hold one, we want to update both in the same call.
```
If you find it redundant or useless, just ignore the suggestion.

Code after:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/states"
)

// updateState calls the PostStateUpdate hook with the state modification function
func updateStateHook(evalCtx EvalContext, addr addrs.AbsResourceInstance) error {
	// Call the hook
	return evalCtx.Hook(func(h Hook) (HookAction, error) {
		return h.PostStateUpdate(func(s *states.SyncState) {
			provider := evalCtx.State().ResourceProvider(addr.ContainingResource())
			if provider == nil {
				// If there is no provider currently defined for the resource, it has been removed
				// See the documentation of ResourceProvider for more details
				s.RemoveResource(addr.ContainingResource())
			} else {
				s.SetResourceInstance(addr, evalCtx.State().ResourceInstance(addr), *provider)
			}
		})
	})
}
Repository: opentofu/opentofu
File: internal/tofu/update_state_hook.go (Go)

Code before:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"github.com/opentofu/opentofu/internal/states"
)

// updateState calls the PostStateUpdate hook with the state modification function and applies the change to the "live" state object
func updateState(ctx EvalContext, fn func(*states.SyncState)) error {
	// Since the EvalContext.State() is not in sync with the StateMgr hold one, we want to update both in the same call.
	fn(ctx.State())

	// Call the hook
	return ctx.Hook(func(h Hook) (HookAction, error) {
		return h.PostStateUpdate(fn)
	})
}


Review comment (suggestion):
```suggestion
func updateState(evalCtx EvalContext, fn func(*states.SyncState)) error {
```

(and then update the references to it below, of course!)


Code after:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/states"
)

// updateState calls the PostStateUpdate hook with the state modification function
func updateStateHook(evalCtx EvalContext, addr addrs.AbsResourceInstance) error {
	// Call the hook
	return evalCtx.Hook(func(h Hook) (HookAction, error) {
		return h.PostStateUpdate(func(s *states.SyncState) {
			provider := evalCtx.State().ResourceProvider(addr.ContainingResource())
			if provider == nil {
				// If there is no provider currently defined for the resource, it has been removed
				// See the documentation of ResourceProvider for more details
				s.RemoveResource(addr.ContainingResource())
			} else {
				s.SetResourceInstance(addr, evalCtx.State().ResourceInstance(addr), *provider)
			}
		})
	})
}
Repository: opentofu/opentofu
File: cmd/tofu/provider_source_test.go (Go)

Code before:
package main

import (
	"context"
	"os"
	"path/filepath"
	"testing"

	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/command/cliconfig"
	"github.com/opentofu/opentofu/internal/command/cliconfig/ociauthconfig"
	"github.com/opentofu/svchost/disco"
)

func TestImplicitProviderSource(t *testing.T) {
	tests := []struct {
		name               string
		originalWorkingDir string
		usingChdir         bool
		setupFunc          func(t *testing.T, originalDir string) string
		expectedLocalDirs  []string
	}{
		{
			name:               "without chdir - should use relative terraform.d/plugins",
			originalWorkingDir: "/original/dir",
			usingChdir:         false,
			setupFunc: func(t *testing.T, originalDir string) string {
				// Create terraform.d/plugins in current directory
				currentDir, err := os.Getwd()
				if err != nil {
					t.Fatalf("Failed to get current directory: %v", err)
				}
				pluginsDir := filepath.Join(currentDir, "terraform.d", "plugins")
				err = os.MkdirAll(pluginsDir, 0755)
				if err != nil {
					t.Fatalf("Failed to create plugins directory: %v", err)
				}
				return currentDir
			},
			expectedLocalDirs: []string{"terraform.d/plugins"},
		},
		{
			name:               "with chdir - should use absolute path to original directory",
			originalWorkingDir: "",

Review comment (suggestion):
`usingChdir` doesn't alter the behaviour of `implicitProviderSource`; therefore, it is not needed here.

Code after:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package main

import (
	"context"
	"os"
	"path/filepath"
	"testing"

	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/command/cliconfig"
	"github.com/opentofu/opentofu/internal/command/cliconfig/ociauthconfig"
	"github.com/opentofu/svchost/disco"
)

func TestProviderSource(t *testing.T) {
	tests := []struct {
		name             string
		setupFunc        func(t *testing.T) (string, string) // returns (originalDir, overrideDir)
		expectedProvider string
	}{
		{
			name: "without overrideWd - should use terraform.d/plugins in original working directory",
			setupFunc: func(t *testing.T) (string, string) {
				// Create a temporary directory to conduct the test in
				tempDir := t.TempDir()

				// Create terraform.d/plugins in the testing directory
				pluginsDir := filepath.Join(tempDir, "terraform.d", "plugins")
				err := os.MkdirAll(pluginsDir, 0755)
				if err != nil {
					t.Fatalf("Failed to create plugins directory: %v", err)
				}

				// Create a mock provider in the plugins directory
				providerDir := filepath.Join(pluginsDir, "registry.opentofu.org", "hashicorp", "test-provider", "1.0.0", "linux_amd64")
				err = os.MkdirAll(providerDir, 0755)
				if err != nil {
					t.Fatalf("Failed to create provider directory: %v", err)
				}
Repository: opentofu/opentofu
File: cmd/tofu/provider_source_test.go (Go)

Code before:
			ociCredsPolicy := func(ctx context.Context) (ociauthconfig.CredentialsConfigs, error) {
				return ociauthconfig.CredentialsConfigs{}, nil
			}

			// Call the function under test
			source, diags := providerSource(context.Background(), []*cliconfig.ProviderInstallation{}, services, ociCredsPolicy, originalWorkingDir)

			// Verify no diagnostics were returned
			if len(diags) > 0 {
				t.Fatalf("Expected no diagnostics, got: %v", diags)
			}

			// Verify the source is not nil
			if source == nil {
				t.Fatal("Expected source to be non-nil")
			}

			// Try to get available versions for a test provider
			// This will help verify that the local directories are properly configured
			provider := addrs.MustParseProviderSourceString(tt.expectedProvider)
			versions, _, err := source.AvailableVersions(context.Background(), provider)
			if err != nil {
				// It's okay if this fails since we're not setting up actual providers
				// We're mainly testing that the source is created correctly
				t.Logf("AvailableVersions failed (expected for test): %v", err)
			}

			t.Logf("Source created successfully for test case: %s", tt.name)
			t.Logf("Provider: %v", provider)
			if versions != nil {
				t.Logf("Available versions: %v", versions)
			}
		})
	}
}


Review comment (bug):
We should make this check fatal. 
You can take a look at how the `AvailableVersions` function works in `filesystem_mirror_source.go`. If the `AvailableVersions` returns an error and hence can't find the provider version, the behaviour is not correct, and we need to make this check fatal.
`AvailableVersions` scans the directory structure and determines the provider versions based on that. It doesn't validate the binary, and there is no reason for this to fail in our test cases.
 You can verify that by running this test without your fix in this PR. If you don't fail at this point, the version before your fix passes just fine.

Code after:

			// Call the function under test
			source, diags := providerSource(context.Background(), []*cliconfig.ProviderInstallation{}, services, ociCredsPolicy, originalWorkingDir)

			// Verify no diagnostics were returned
			if len(diags) > 0 {
				t.Fatalf("Expected no diagnostics, got: %v", diags)
			}

			// Verify the source is not nil
			if source == nil {
				t.Fatal("Expected source to be non-nil")
			}

			// Try to get available versions for a test provider
			// This will help verify that the local directories are properly configured
			provider := addrs.MustParseProviderSourceString(tt.expectedProvider)
			versions, _, err := source.AvailableVersions(context.Background(), provider)
			if err != nil {
				// If available provider versions could not be determined, something went wrong with mock provider setup
				t.Fatalf("AvailableVersions failed (expected for test): %v", err)
			}

			t.Logf("Source created successfully for test case: %s", tt.name)
			t.Logf("Provider: %v", provider)
			if versions != nil {
				t.Logf("Available versions: %v", versions)
			}
		})
	}
}
Repository: opentofu/opentofu
File: internal/tofu/node_provider_eval.go (Go)

Code before:
package tofu

import (
	"context"

	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/providers"
	"github.com/opentofu/opentofu/internal/tfdiags"
)

// NodeEvalableProvider represents a provider during an "eval" walk.
// This special provider node type just initializes a provider and
// fetches its schema, without configuring it or otherwise interacting
// with it.
type NodeEvalableProvider struct {
	*NodeAbstractProvider
}

var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)

// GraphNodeExecutable
func (n *NodeEvalableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
	provider, err := evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)

	diags = diags.Append(err)
	return diags.Append(n.InitEvalableProvider(ctx, evalCtx, provider))
}

// InitEvalableProvider fetches its schema, builds it, and adds it
// to the context.
func (n *NodeEvalableProvider) InitEvalableProvider(ctx context.Context, evalCtx EvalContext, provider providers.Interface) tfdiags.Diagnostics {
	providerKey := addrs.NoKey
	config := n.ProviderConfig()
	configBody := buildProviderConfig(ctx, evalCtx, n.Addr, config)

	schemaResp := provider.GetProviderSchema(ctx)
	return schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey))
}


Review comment (suggestion):
This is a tiny thing. But bothers me enough to mention.
I think calling `InitEvalableProvider` is better done on a separate line, and then appending the diagnostics.
Now, you might skim over it and not pay attention to it being passed as an argument to the `Append` function.
```suggestion
	provider, err := evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)
	diags = diags.Append(err)
	initDiags := n.InitEvalableProvider(ctx, evalCtx, provider)
	return diags.Append(initDiags)
```

Code after:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"context"

	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/tfdiags"
)

// NodeEvalableProvider represents a provider during an "eval" walk.
// This special provider node type just initializes a provider and
// fetches its schema, without configuring it or otherwise interacting
// with it.
type NodeEvalableProvider struct {
	*NodeAbstractProvider
}

var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil)

// GraphNodeExecutable
func (n *NodeEvalableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
	_, err := evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)
	return diags.Append(err)
}