<commit_before>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/cli"
)

// StateMvCommand is a Command implementation that shows a single resource.
type StateMvCommand struct {
	Meta
	StateMeta
}

func (c *StateMvCommand) Run(args []string) int {
	args = c.Meta.process(args, true)

	// We create two metas to track the two states
	var meta1, meta2 Meta
	cmdFlags := c.Meta.flagSet("state show")
	cmdFlags.StringVar(&meta1.stateOutPath, "backup", "", "backup")
	cmdFlags.StringVar(&meta1.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&meta2.stateOutPath, "backup-out", "", "backup")
	cmdFlags.StringVar(&meta2.statePath, "state-out", "", "path")
	if err := cmdFlags.Parse(args); err != nil {
		return cli.RunResultHelp
	}
	args = cmdFlags.Args()
	if len(args) != 2 {
		c.Ui.Error("Exactly two arguments expected.\n")
		return cli.RunResultHelp
	}

	// Copy the `-state` flag for output if we weren't given a custom one
	if meta2.statePath == "" {
		meta2.statePath = meta1.statePath
	}

	// Read the from state
	stateFrom, err := c.StateMeta.State(&meta1)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
		return cli.RunResultHelp
	}

	stateFromReal := stateFrom.State()
	if stateFromReal == nil {
		c.Ui.Error(fmt.Sprintf(errStateNotFound))
		return 1
	}

	// Read the destination state
	stateTo := stateFrom
	stateToReal := stateFromReal
	if meta2.statePath != meta1.statePath {
		stateTo, err = c.StateMeta.State(&meta2)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
			return cli.RunResultHelp
		}

		stateToReal = stateTo.State()
		if stateToReal == nil {
			stateToReal = terraform.NewState()
		}
	}

	// Filter what we're moving
	filter := &terraform.StateFilter{State: stateFromReal}
	results, err := filter.Filter(args[0])
	if err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMv, err))
		return cli.RunResultHelp
	}
	if len(results) == 0 {
		c.Ui.Output(fmt.Sprintf("Item to move doesn't exist: %s", args[0]))
		return 1
	}

	// Do the actual move
	if err := stateFromReal.Remove(args[0]); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMv, err))
		return 1
	}

	if err := stateToReal.Add(args[0], args[1], results[0].Value); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMv, err))
		return 1
	}

	// Write the new state
	if err := stateTo.WriteState(stateToReal); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
		return 1
	}

	if err := stateTo.PersistState(); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
		return 1
	}

	// Write the old state if it is different
	if stateTo != stateFrom {
		if err := stateFrom.WriteState(stateFromReal); err != nil {
			c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
			return 1
		}

		if err := stateFrom.PersistState(); err != nil {
			c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
			return 1
		}
	}

	c.Ui.Output(fmt.Sprintf(
		"Moved %s to %s", args[0], args[1]))
	return 0
}

func (c *StateMvCommand) Help() string {
	helpText := `
Usage: terraform state mv [options] ADDRESS ADDRESS

  Move an item in the state to another location within the same state.

  This command is useful for module refactors (moving items into a module)
  or generally renaming of resources.

  This command creates a timestamped backup of the state on every invocation.
  This can't be disabled. Due to the destructive nature of this command,
  the backup is ensured by Terraform for safety reasons.

  This command can't currently move an item from one state file to a
  completely new state file, but this functionality will come in an update.

Options:

  -backup=PATH        Path where Terraform should write the backup for the original
                      state. This can't be disabled. If not set, Terraform
                      will write it to the same path as the statefile with
                      a backup extension.

  -backup-out=PATH    Path where Terraform should write the backup for the destination
                      state. This can't be disabled. If not set, Terraform
                      will write it to the same path as the destination state<commit_msg>command: update docs for state mv<commit_after>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/cli"
)

// StateMvCommand is a Command implementation that shows a single resource.
type StateMvCommand struct {
	Meta
	StateMeta
}

func (c *StateMvCommand) Run(args []string) int {
	args = c.Meta.process(args, true)

	// We create two metas to track the two states
	var meta1, meta2 Meta
	cmdFlags := c.Meta.flagSet("state show")
	cmdFlags.StringVar(&meta1.stateOutPath, "backup", "", "backup")
	cmdFlags.StringVar(&meta1.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&meta2.stateOutPath, "backup-out", "", "backup")
	cmdFlags.StringVar(&meta2.statePath, "state-out", "", "path")
	if err := cmdFlags.Parse(args); err != nil {
		return cli.RunResultHelp
	}
	args = cmdFlags.Args()
	if len(args) != 2 {
		c.Ui.Error("Exactly two arguments expected.\n")
		return cli.RunResultHelp
	}

	// Copy the `-state` flag for output if we weren't given a custom one
	if meta2.statePath == "" {
		meta2.statePath = meta1.statePath
	}

	// Read the from state
	stateFrom, err := c.StateMeta.State(&meta1)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
		return cli.RunResultHelp
	}

	stateFromReal := stateFrom.State()
	if stateFromReal == nil {
		c.Ui.Error(fmt.Sprintf(errStateNotFound))
		return 1
	}

	// Read the destination state
	stateTo := stateFrom
	stateToReal := stateFromReal
	if meta2.statePath != meta1.statePath {
		stateTo, err = c.StateMeta.State(&meta2)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
			return cli.RunResultHelp
		}

		stateToReal = stateTo.State()
		if stateToReal == nil {
			stateToReal = terraform.NewState()
		}
	}

	// Filter what we're moving
	filter := &terraform.StateFilter{State: stateFromReal}
	results, err := filter.Filter(args[0])
	if err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMv, err))
		return cli.RunResultHelp
	}
	if len(results) == 0 {
		c.Ui.Output(fmt.Sprintf("Item to move doesn't exist: %s", args[0]))
		return 1
	}

	// Do the actual move
	if err := stateFromReal.Remove(args[0]); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMv, err))
		return 1
	}

	if err := stateToReal.Add(args[0], args[1], results[0].Value); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMv, err))
		return 1
	}

	// Write the new state
	if err := stateTo.WriteState(stateToReal); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
		return 1
	}

	if err := stateTo.PersistState(); err != nil {
		c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
		return 1
	}

	// Write the old state if it is different
	if stateTo != stateFrom {
		if err := stateFrom.WriteState(stateFromReal); err != nil {
			c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
			return 1
		}

		if err := stateFrom.PersistState(); err != nil {
			c.Ui.Error(fmt.Sprintf(errStateMvPersist, err))
			return 1
		}
	}

	c.Ui.Output(fmt.Sprintf(
		"Moved %s to %s", args[0], args[1]))
	return 0
}

func (c *StateMvCommand) Help() string {
	helpText := `
Usage: terraform state mv [options] ADDRESS ADDRESS

  Move an item in the state to another location within the same state.

  This command is useful for module refactors (moving items into a module),
  configuration refactors (moving items to a completely different or new
  state file), or generally renaming of resources.

  This command creates a timestamped backup of the state on every invocation.
  This can't be disabled. Due to the destructive nature of this command,
  the backup is ensured by Terraform for safety reasons.

  If you're moving from one state file to a different state file, a backup
  will be created for each state file.

Options:

  -backup=PATH        Path where Terraform should write the backup for the original
                      state. This can't be disabled. If not set, Terraform
                      will write it to the same path as the statefile with
                      a backup extension.

  -backup-out=PATH    Path where Terraform should write the backup for the destination
                      state. This can't be disabled. If not set, Terraform
                      will write it to the same path as the destination state
{'fraction_non_alphanumeric': 0.11262434864992894, 'fraction_numerical': 0.007579346281383231, 'mean_word_length': 3.4261006289308176, 'pattern_counts': {'":': 0, '<': 3, '<?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': '7205635', 'n_tokens_mistral': 2922, 'n_tokens_neox': 2742, 'n_words': 862}