<commit_before>package terraform

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"reflect"
	"sort"
	"strings"

	"github.com/hashicorp/terraform/config"
)

const (
	// StateVersion is the current version for our state file
	StateVersion = 1
)

// rootModulePath is the path of the root module
var rootModulePath = []string{"root"}

// State keeps track of a snapshot state-of-the-world that Terraform
// can use to keep track of what real world resources it is actually
// managing. This is the latest format as of Terraform 0.3
type State struct {
	// Version is the protocol version. Currently only "1".
	Version int `json:"version"`

	// Serial is incremented on any operation that modifies
	// the State file. It is used to detect potentially conflicting
	// updates.
	Serial int64 `json:"serial"`

	// Remote is used to track the metadata required to
	// pull and push state files from a remote storage endpoint.
	Remote *RemoteState `json:"remote,omitempty"`

	// Modules contains all the modules in a breadth-first order
	Modules []*ModuleState `json:"modules"`
}

// NewState is used to initialize a blank state
func NewState() *State {
	s := &State{}
	s.init()
	return s
}

// Children returns the ModuleStates that are direct children of
// the given path. If the path is "root", for example, then children
// returned might be "root.child", but not "root.child.grandchild".
func (s *State) Children(path []string) []*ModuleState {
	// TODO: test

	result := make([]*ModuleState, 0)
	for _, m := range s.Modules {
		if len(m.Path) != len(path)+1 {
			continue
		}
		if !reflect.DeepEqual(path, m.Path[:len(path)]) {
			continue
		}

		result = append(result, m)
	}

	return result
}

// AddModule adds the module with the given path to the state.
//
// This should be the preferred method to add module states since it
// allows us to optimize lookups later as well as control sorting.
func (s *State) AddModule(path []string) *ModuleState {
	m := &ModuleState{Path: path}
	m.init()
	s.Modules = append(s.Modules, m)
	s.sort()
	return m
}

// ModuleByPath is used to lookup the module state for the given path.
// This should be the prefered lookup mechanism as it allows for future
// lookup optimizations.
func (s *State) ModuleByPath(path []string) *ModuleState {
	if s == nil {
		return nil
	}
	for _, mod := range s.Modules {
		if mod.Path == nil {
			panic("missing module path")
		}
		if reflect.DeepEqual(mod.Path, path) {
			return mod
		}
	}
	return nil
}

// ModuleOrphans returns all the module orphans in this state by
// returning their full paths. These paths can be used with ModuleByPath
// to return the actual state.
func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string {
	// direct keeps track of what direct children we have both in our config
	// and in our state. childrenKeys keeps track of what isn't an orphan.
	direct := make(map[string]struct{})
	childrenKeys := make(map[string]struct{})
	if c != nil {
		for _, m := range c.Modules {
			childrenKeys[m.Name] = struct{}{}
			direct[m.Name] = struct{}{}
		}
	}

	// Go over the direct children and find any that aren't in our keys.
	var orphans [][]string
	for _, m := range s.Children(path) {
		key := m.Path[len(m.Path)-1]

		// Record that we found this key as a direct child. We use this
		// later to find orphan nested modules.
		direct[key] = struct{}{}

		// If we have a direct child still in our config, it is not an orphan
		if _, ok := childrenKeys[key]; ok {
			continue
		}

		orphans = append(orphans, m.Path)
	}

	// Find the orphans that are nested...
	for _, m := range s.Modules {
		// We only want modules that are at least grandchildren
		if len(m.Path) < len(path)+2 {
			continue
		}

		// If it isn't part of our tree, continue
		if !reflect.DeepEqual(path, m.Path[:len(path)]) {
			continue
		}

		// If we have the direct child, then just skip it.
		key := m.Path[len(m.Path)-2]
		if _, ok := direct[key]; ok {
			continue
		}

		// Add this orphan
		orphans = append(orphans, m.Path[:len(path)+1])
	}

	return orphans
}<commit_msg>terraform: state module orphans should only return direct<commit_after>package terraform

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"reflect"
	"sort"
	"strings"

	"github.com/hashicorp/terraform/config"
)

const (
	// StateVersion is the current version for our state file
	StateVersion = 1
)

// rootModulePath is the path of the root module
var rootModulePath = []string{"root"}

// State keeps track of a snapshot state-of-the-world that Terraform
// can use to keep track of what real world resources it is actually
// managing. This is the latest format as of Terraform 0.3
type State struct {
	// Version is the protocol version. Currently only "1".
	Version int `json:"version"`

	// Serial is incremented on any operation that modifies
	// the State file. It is used to detect potentially conflicting
	// updates.
	Serial int64 `json:"serial"`

	// Remote is used to track the metadata required to
	// pull and push state files from a remote storage endpoint.
	Remote *RemoteState `json:"remote,omitempty"`

	// Modules contains all the modules in a breadth-first order
	Modules []*ModuleState `json:"modules"`
}

// NewState is used to initialize a blank state
func NewState() *State {
	s := &State{}
	s.init()
	return s
}

// Children returns the ModuleStates that are direct children of
// the given path. If the path is "root", for example, then children
// returned might be "root.child", but not "root.child.grandchild".
func (s *State) Children(path []string) []*ModuleState {
	// TODO: test

	result := make([]*ModuleState, 0)
	for _, m := range s.Modules {
		if len(m.Path) != len(path)+1 {
			continue
		}
		if !reflect.DeepEqual(path, m.Path[:len(path)]) {
			continue
		}

		result = append(result, m)
	}

	return result
}

// AddModule adds the module with the given path to the state.
//
// This should be the preferred method to add module states since it
// allows us to optimize lookups later as well as control sorting.
func (s *State) AddModule(path []string) *ModuleState {
	m := &ModuleState{Path: path}
	m.init()
	s.Modules = append(s.Modules, m)
	s.sort()
	return m
}

// ModuleByPath is used to lookup the module state for the given path.
// This should be the prefered lookup mechanism as it allows for future
// lookup optimizations.
func (s *State) ModuleByPath(path []string) *ModuleState {
	if s == nil {
		return nil
	}
	for _, mod := range s.Modules {
		if mod.Path == nil {
			panic("missing module path")
		}
		if reflect.DeepEqual(mod.Path, path) {
			return mod
		}
	}
	return nil
}

// ModuleOrphans returns all the module orphans in this state by
// returning their full paths. These paths can be used with ModuleByPath
// to return the actual state.
func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string {
	// direct keeps track of what direct children we have both in our config
	// and in our state. childrenKeys keeps track of what isn't an orphan.
	direct := make(map[string]struct{})
	childrenKeys := make(map[string]struct{})
	if c != nil {
		for _, m := range c.Modules {
			childrenKeys[m.Name] = struct{}{}
			direct[m.Name] = struct{}{}
		}
	}

	// Go over the direct children and find any that aren't in our keys.
	var orphans [][]string
	for _, m := range s.Children(path) {
		key := m.Path[len(m.Path)-1]

		// Record that we found this key as a direct child. We use this
		// later to find orphan nested modules.
		direct[key] = struct{}{}

		// If we have a direct child still in our config, it is not an orphan
		if _, ok := childrenKeys[key]; ok {
			continue
		}

		orphans = append(orphans, m.Path)
	}

	// Find the orphans that are nested...
	for _, m := range s.Modules {
		// We only want modules that are at least grandchildren
		if len(m.Path) < len(path)+2 {
			continue
		}

		// If it isn't part of our tree, continue
		if !reflect.DeepEqual(path, m.Path[:len(path)]) {
			continue
		}

		// If we have the direct child, then just skip it.
		key := m.Path[len(path)]
		if _, ok := direct[key]; ok {
			continue
		}

		// Add this orphan
		orphans = append(orphans, m.Path[:len(path)+1])
	}

	return orphans
}
{'fraction_non_alphanumeric': 0.11610623781676413, 'fraction_numerical': 0.0028021442495126704, 'mean_word_length': 3.3159831756046265, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '873862', 'n_tokens_mistral': 2730, 'n_tokens_neox': 2579, 'n_words': 1035}