blob: 56ae1c6736df376536131df5ee4673c954e6427c [file]
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1
package arguments
import (
"fmt"
"os"
"path/filepath"
"github.com/hashicorp/terraform/internal/depsfile"
"github.com/hashicorp/terraform/internal/tfdiags"
)
const lockFileName = depsfile.LockFilePath // .terraform.lock.hcl
// StateMigrate represents the command-line arguments for the state migrate command.
type StateMigrate struct {
SourceLockFilePath string
DestinationLockFilePath string
Upgrade bool
ForceCopy bool
InputEnabled bool
ViewType ViewType
}
// ParseStateMigrate processes CLI arguments, returning a StateMigrate value and
// diagnostics. If errors are encountered, a StateMigrate value is still returned
// representing the best effort interpretation of the arguments.
func ParseStateMigrate(args []string) (*StateMigrate, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
migrate := &StateMigrate{}
var srcLockFilePath, dstLockFilePath string
var upgrade, inputEnabled, forceCopy, json bool
cmdFlags := defaultFlagSet("state migrate")
cmdFlags.StringVar(&srcLockFilePath, "source-provider-lock-file", "", "Path to a provider lock file for the source provider.")
cmdFlags.StringVar(&dstLockFilePath, "destination-provider-lock-file", "", "Path to a provider lock file for the destination provider.")
cmdFlags.BoolVar(&upgrade, "upgrade", false, "Trigger upgrade of the provider.")
cmdFlags.BoolVar(&inputEnabled, "input", true, "Enable input for interactive prompts.")
cmdFlags.BoolVar(&forceCopy, "force-copy", false, "Suppress and auto-approve prompts about copying state data. Enables state migrations when interactive prompts are disabled via -input=false.")
cmdFlags.BoolVar(&json, "json", false, "Enable JSON output.")
if err := cmdFlags.Parse(args); err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Failed to parse command-line flags",
err.Error(),
))
return migrate, diags
}
migrate.Upgrade = upgrade
migrate.InputEnabled = inputEnabled
migrate.ForceCopy = forceCopy
if inputEnabled {
// lock file paths are only to be used in automation
if srcLockFilePath != "" {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Conflicting command-line flags provided",
"-source-provider-lock-file cannot be used outside of automation (with -input=true)",
))
}
if dstLockFilePath != "" {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Conflicting command-line flags provided",
"-destination-provider-lock-file cannot be used outside of automation (with -input=true)",
))
}
// JSON output is only to be used in automation, as input cannot be received
if json {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Conflicting command-line flags provided",
"-json cannot be used outside of automation (with -input=true)",
))
}
}
if srcLockFilePath != "" {
// If a file is supplied via flag, it must exist.
if _, err := os.Stat(srcLockFilePath); err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Unreadable source provider lock file",
fmt.Sprintf("%q: %s", srcLockFilePath, err.Error()),
))
}
srcFilename := filepath.Base(srcLockFilePath)
if srcFilename != lockFileName {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid source-provider-lock-file",
fmt.Sprintf("Expected lock file name to be %s, got: %s", lockFileName, srcFilename),
))
}
migrate.SourceLockFilePath = srcLockFilePath
}
if dstLockFilePath != "" {
// If a file is supplied via flag, it must exist.
if _, err := os.Stat(dstLockFilePath); err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Unreadable destination provider lock file",
fmt.Sprintf("%q: %s", dstLockFilePath, err.Error()),
))
}
dstFilename := filepath.Base(dstLockFilePath)
if dstFilename != lockFileName {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid destination-provider-lock-file",
fmt.Sprintf("Expected lock file name to be %s, got: %s", lockFileName, dstFilename),
))
}
migrate.DestinationLockFilePath = dstLockFilePath
}
if json {
migrate.ViewType = ViewJSON
} else {
migrate.ViewType = ViewHuman
}
return migrate, diags
}