diff --git a/.changelog/3143.internal.md b/.changelog/3143.internal.md new file mode 100644 index 00000000000..fd7599c48f7 --- /dev/null +++ b/.changelog/3143.internal.md @@ -0,0 +1 @@ +go/oasis-node: Fix the interactive prompt to be correct diff --git a/go/oasis-node/cmd/common/common.go b/go/oasis-node/cmd/common/common.go index 378f8fb2aa2..26a011f21aa 100644 --- a/go/oasis-node/cmd/common/common.go +++ b/go/oasis-node/cmd/common/common.go @@ -278,24 +278,34 @@ func ExportEntity(signerBackend, entityDir string) error { return err } -// GetUserConfirmation scans the input for user's confirmation. +// GetUserConfirmation displays the prompt, and scans the input for +// the user's confirmation, until the user either explicitly confirms +// or rejects the prompt. // -// If the user's response is not recognized, it prompts the user again. -func GetUserConfirmation() bool { - var response string - - _, err := fmt.Scanln(&response) - if err != nil && err.Error() != "unexpected newline" { - rootLog.Error("Error reading from line", "err", err) +// Note: If standard input is not a tty, this will omit displaying +// the prompt, and assume the user entered yes. +func GetUserConfirmation(prompt string) bool { + if !Isatty(os.Stdin.Fd()) { + return true } - switch strings.ToLower(response) { - case "y", "yes": - return true - case "n", "no": - return false - default: - fmt.Printf("Unrecognized response: '%s'. Please, type (y)es or (n)o: ", response) - return GetUserConfirmation() + fmt.Printf("%s", prompt) + + var response string + for { + _, err := fmt.Scanln(&response) + if err != nil && err.Error() != "unexpected newline" { + rootLog.Error("Error reading from line", "err", err) + continue + } + + switch strings.ToLower(response) { + case "y", "yes": + return true + case "n", "no": + return false + default: + fmt.Printf("Unrecognized response: '%s'. Please, type (y)es or (n)o: ", response) + } } } diff --git a/go/oasis-node/cmd/common/consensus/consensus.go b/go/oasis-node/cmd/common/consensus/consensus.go index 7608195836e..2201f146d67 100644 --- a/go/oasis-node/cmd/common/consensus/consensus.go +++ b/go/oasis-node/cmd/common/consensus/consensus.go @@ -124,8 +124,7 @@ func SignAndSaveTx(ctx context.Context, tx *transaction.Transaction) { tx.PrettyPrint(ctx, " ", os.Stdout) if !cmdFlags.AssumeYes() && cmdSigner.Backend() == signerFile.SignerName { - fmt.Printf("\nAre you sure you want to continue? (y)es/(n)o ") - if !cmdCommon.GetUserConfirmation() { + if !cmdCommon.GetUserConfirmation("\nAre you sure you want to continue? (y)es/(n)o: ") { os.Exit(1) } } diff --git a/go/oasis-node/cmd/common/isatty.go b/go/oasis-node/cmd/common/isatty.go new file mode 100644 index 00000000000..c043be72d4d --- /dev/null +++ b/go/oasis-node/cmd/common/isatty.go @@ -0,0 +1,31 @@ +package common + +import ( + "syscall" + "unsafe" +) + +// Isatty returns true iff the provided file descriptor is a terminal. +func Isatty(fd uintptr) bool { + var attrs syscall.Termios + + // This could examine the error more specifically to see if + // something really strange is going on since we expect it + // to return 0 or ENOTTY all the time, but, "the messed up + // thing the user passed in that makes it complain" also + // is not a tty. + // + // And yes, this is the standard way of doing this, see your + // libc implementation of choice. + _, _, errno := syscall.Syscall6( + syscall.SYS_IOCTL, + fd, + syscall.TCGETS, + uintptr(unsafe.Pointer(&attrs)), + 0, + 0, + 0, + ) + + return errno == 0 +} diff --git a/go/oasis-test-runner/oasis/cli/keymanager.go b/go/oasis-test-runner/oasis/cli/keymanager.go index 3fea8aec06c..419b58585a3 100644 --- a/go/oasis-test-runner/oasis/cli/keymanager.go +++ b/go/oasis-test-runner/oasis/cli/keymanager.go @@ -98,7 +98,6 @@ func (k *KeymanagerHelpers) GenUpdate(nonce uint64, polPath string, polSigPaths "--" + cmdConsensus.CfgTxFeeAmount, strconv.Itoa(0), // TODO: Make fee configurable. "--" + cmdConsensus.CfgTxFeeGas, strconv.Itoa(10000), // TODO: Make fee configurable. "--" + cmdKM.CfgPolicyFile, polPath, - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + cmdCommon.CfgDebugAllowTestKeys, "--" + flags.CfgDebugTestEntity, diff --git a/go/oasis-test-runner/oasis/cli/registry.go b/go/oasis-test-runner/oasis/cli/registry.go index 4840a1f2926..f347636fc58 100644 --- a/go/oasis-test-runner/oasis/cli/registry.go +++ b/go/oasis-test-runner/oasis/cli/registry.go @@ -129,7 +129,6 @@ func (r *RegistryHelpers) GenerateRegisterRuntimeTx( "--"+consensus.CfgTxFile, txPath, "--"+consensus.CfgTxFeeAmount, strconv.Itoa(0), // TODO: Make fee configurable. "--"+consensus.CfgTxFeeGas, strconv.Itoa(10000), // TODO: Make fee configurable. - "--"+flags.CfgAssumeYes, "--"+flags.CfgDebugDontBlameOasis, "--"+cmdCommon.CfgDebugAllowTestKeys, "--"+flags.CfgDebugTestEntity, diff --git a/go/oasis-test-runner/scenario/e2e/registry_cli.go b/go/oasis-test-runner/scenario/e2e/registry_cli.go index d91d90b613c..ebeb7223129 100644 --- a/go/oasis-test-runner/scenario/e2e/registry_cli.go +++ b/go/oasis-test-runner/scenario/e2e/registry_cli.go @@ -554,7 +554,6 @@ func (sc *registryCLIImpl) genRegisterEntityTx(childEnv *env.Env, nonce int, txP "--" + consensus.CfgTxFile, txPath, "--" + consensus.CfgTxFeeAmount, strconv.Itoa(0), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + cmdCommon.CfgDebugAllowTestKeys, "--" + cmdSigner.CfgSigner, fileSigner.SignerName, @@ -578,7 +577,6 @@ func (sc *registryCLIImpl) genDeregisterEntityTx(childEnv *env.Env, nonce int, t "--" + consensus.CfgTxFile, txPath, "--" + consensus.CfgTxFeeAmount, strconv.Itoa(0), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + cmdCommon.CfgDebugAllowTestKeys, "--" + cmdSigner.CfgSigner, fileSigner.SignerName, diff --git a/go/oasis-test-runner/scenario/e2e/stake_cli.go b/go/oasis-test-runner/scenario/e2e/stake_cli.go index 20b64c15da9..efbf6d5b3b5 100644 --- a/go/oasis-test-runner/scenario/e2e/stake_cli.go +++ b/go/oasis-test-runner/scenario/e2e/stake_cli.go @@ -760,7 +760,6 @@ func (sc *stakeCLIImpl) genTransferTx(childEnv *env.Env, amount int, nonce uint6 "--" + stake.CfgTransferDestination, dst.String(), "--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + flags.CfgDebugTestEntity, "--" + common.CfgDebugAllowTestKeys, @@ -782,7 +781,6 @@ func (sc *stakeCLIImpl) genBurnTx(childEnv *env.Env, amount int, nonce uint64, t "--" + consensus.CfgTxFile, txPath, "--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + flags.CfgDebugTestEntity, "--" + common.CfgDebugAllowTestKeys, @@ -805,7 +803,6 @@ func (sc *stakeCLIImpl) genEscrowTx(childEnv *env.Env, amount int, nonce uint64, "--" + stake.CfgEscrowAccount, escrow.String(), "--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + flags.CfgDebugTestEntity, "--" + common.CfgDebugAllowTestKeys, @@ -828,7 +825,6 @@ func (sc *stakeCLIImpl) genReclaimEscrowTx(childEnv *env.Env, shares int, nonce "--" + stake.CfgEscrowAccount, escrow.String(), "--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + flags.CfgDebugTestEntity, "--" + common.CfgDebugAllowTestKeys, @@ -849,7 +845,6 @@ func (sc *stakeCLIImpl) genAmendCommissionScheduleTx(childEnv *env.Env, nonce in "--" + consensus.CfgTxFile, txPath, "--" + consensus.CfgTxFeeAmount, strconv.Itoa(feeAmount), "--" + consensus.CfgTxFeeGas, strconv.Itoa(feeGas), - "--" + flags.CfgAssumeYes, "--" + flags.CfgDebugDontBlameOasis, "--" + flags.CfgDebugTestEntity, "--" + common.CfgDebugAllowTestKeys,