cli: use Writer from app instead of Stdout

It is useful in tests.
This commit is contained in:
Evgenii Stratonikov 2020-08-28 12:11:19 +03:00
parent bfe3b3d05d
commit 911be78cc7
7 changed files with 96 additions and 93 deletions

View file

@ -357,9 +357,9 @@ func startServer(ctx *cli.Context) error {
go serv.Start(errChan)
go rpcServer.Start(errChan)
fmt.Println(logo())
fmt.Println(serv.UserAgent)
fmt.Println()
fmt.Fprintln(ctx.App.Writer, logo())
fmt.Fprintln(ctx.App.Writer, serv.UserAgent)
fmt.Fprintln(ctx.App.Writer)
var shutdownErr error
Main:

View file

@ -366,7 +366,7 @@ func initSmartContract(ctx *cli.Context) error {
return cli.NewExitError(err, 1)
}
fmt.Printf("Successfully initialized smart contract [%s]\n", contractName)
fmt.Fprintf(ctx.App.Writer, "Successfully initialized smart contract [%s]\n", contractName)
return nil
}
@ -405,7 +405,7 @@ func contractCompile(ctx *cli.Context) error {
return cli.NewExitError(err, 1)
}
if ctx.Bool("verbose") {
fmt.Println(hex.EncodeToString(result))
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result))
}
return nil
@ -495,14 +495,14 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
}
fmt.Printf("Sent invocation transaction %s\n", txHash.StringLE())
fmt.Fprintf(ctx.App.Writer, "Sent invocation transaction %s\n", txHash.StringLE())
} else {
b, err := json.MarshalIndent(resp, "", " ")
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(string(b))
fmt.Fprintln(ctx.App.Writer, string(b))
}
return nil
@ -599,7 +599,7 @@ func testInvokeScript(ctx *cli.Context) error {
return cli.NewExitError(err, 1)
}
fmt.Println(string(b))
fmt.Fprintln(ctx.App.Writer, string(b))
return nil
}
@ -680,9 +680,9 @@ func getAccFromContext(ctx *cli.Context) (*wallet.Account, error) {
return nil, cli.NewExitError(fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr)), 1)
}
fmt.Printf("Enter account %s password > ", address.Uint160ToString(addr))
fmt.Fprintf(ctx.App.Writer, "Enter account %s password > ", address.Uint160ToString(addr))
rawPass, err := terminal.ReadPassword(syscall.Stdin)
fmt.Println()
fmt.Fprintln(ctx.App.Writer)
if err != nil {
return nil, cli.NewExitError(err, 1)
}
@ -751,7 +751,7 @@ func contractDeploy(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
}
fmt.Printf("Sent deployment transaction %s for contract %s\n", txHash.StringLE(), nefFile.Header.ScriptHash.StringLE())
fmt.Fprintf(ctx.App.Writer, "Sent deployment transaction %s for contract %s\n", txHash.StringLE(), nefFile.Header.ScriptHash.StringLE())
return nil
}

View file

@ -33,6 +33,6 @@ func handleParse(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Print(res)
fmt.Fprint(ctx.App.Writer, res)
return nil
}

View file

@ -3,6 +3,7 @@ package wallet
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"github.com/nspcc-dev/neo-go/cli/options"
@ -50,7 +51,7 @@ func signMultisig(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid address: %w", err), 1)
}
acc, err := getDecryptedAccount(wall, sh)
acc, err := getDecryptedAccount(ctx, wall, sh)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -59,7 +60,7 @@ func signMultisig(ctx *cli.Context) error {
if !ok {
return cli.NewExitError("verifiable item is not a transaction", 1)
}
printTxInfo(tx)
printTxInfo(ctx.App.Writer, tx)
priv := acc.PrivateKey()
sign := priv.Sign(tx.GetSignedPart())
@ -86,11 +87,11 @@ func signMultisig(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(res.StringLE())
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
}
fmt.Println(tx.Hash().StringLE())
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
return nil
}
@ -116,6 +117,6 @@ func writeParameterContext(c *context.ParameterContext, filename string) error {
return nil
}
func printTxInfo(t *transaction.Transaction) {
fmt.Printf("Hash: %s\n", t.Hash().StringLE())
func printTxInfo(w io.Writer, t *transaction.Transaction) {
fmt.Fprintf(w, "Hash: %s\n", t.Hash().StringLE())
}

View file

@ -162,9 +162,9 @@ func getNEP5Balance(ctx *cli.Context) error {
var token *wallet.Token
name := ctx.String("token")
if name != "" {
token, err = getMatchingToken(wall, name)
token, err = getMatchingToken(ctx, wall, name)
if err != nil {
token, err = getMatchingTokenRPC(c, addrHash, name)
token, err = getMatchingTokenRPC(ctx, c, addrHash, name)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -181,26 +181,26 @@ func getNEP5Balance(ctx *cli.Context) error {
if name != "" && !token.Hash.Equals(asset) {
continue
}
fmt.Printf("TokenHash: %s\n", asset.StringLE())
fmt.Printf("\tAmount : %s\n", balances.Balances[i].Amount)
fmt.Printf("\tUpdated: %d\n", balances.Balances[i].LastUpdated)
fmt.Fprintf(ctx.App.Writer, "TokenHash: %s\n", asset.StringLE())
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", balances.Balances[i].Amount)
fmt.Fprintf(ctx.App.Writer, "\tUpdated: %d\n", balances.Balances[i].LastUpdated)
}
return nil
}
func getMatchingToken(w *wallet.Wallet, name string) (*wallet.Token, error) {
func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string) (*wallet.Token, error) {
switch strings.ToLower(name) {
case "neo":
return neoToken, nil
case "gas":
return gasToken, nil
}
return getMatchingTokenAux(func(i int) *wallet.Token {
return getMatchingTokenAux(ctx, func(i int) *wallet.Token {
return w.Extra.Tokens[i]
}, len(w.Extra.Tokens), name)
}
func getMatchingTokenRPC(c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) {
func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) {
bs, err := c.GetNEP5Balances(addr)
if err != nil {
return nil, err
@ -209,18 +209,18 @@ func getMatchingTokenRPC(c *client.Client, addr util.Uint160, name string) (*wal
t, _ := c.NEP5TokenInfo(bs.Balances[i].Asset)
return t
}
return getMatchingTokenAux(get, len(bs.Balances), name)
return getMatchingTokenAux(ctx, get, len(bs.Balances), name)
}
func getMatchingTokenAux(get func(i int) *wallet.Token, n int, name string) (*wallet.Token, error) {
func getMatchingTokenAux(ctx *cli.Context, get func(i int) *wallet.Token, n int, name string) (*wallet.Token, error) {
var token *wallet.Token
var count int
for i := 0; i < n; i++ {
t := get(i)
if t != nil && (t.Name == name || t.Symbol == name || t.Address() == name || t.Hash.StringLE() == name) {
if count == 1 {
printTokenInfo(token)
printTokenInfo(t)
printTokenInfo(ctx, token)
printTokenInfo(ctx, t)
return nil, errors.New("multiple matching tokens found")
}
count++
@ -247,7 +247,7 @@ func importNEP5Token(ctx *cli.Context) error {
for _, t := range wall.Extra.Tokens {
if t.Hash.Equals(tokenHash) {
printTokenInfo(t)
printTokenInfo(ctx, t)
return cli.NewExitError("token already exists", 1)
}
}
@ -269,16 +269,17 @@ func importNEP5Token(ctx *cli.Context) error {
if err := wall.Save(); err != nil {
return cli.NewExitError(err, 1)
}
printTokenInfo(tok)
printTokenInfo(ctx, tok)
return nil
}
func printTokenInfo(tok *wallet.Token) {
fmt.Printf("Name:\t%s\n", tok.Name)
fmt.Printf("Symbol:\t%s\n", tok.Symbol)
fmt.Printf("Hash:\t%s\n", tok.Hash.StringLE())
fmt.Printf("Decimals: %d\n", tok.Decimals)
fmt.Printf("Address: %s\n", tok.Address())
func printTokenInfo(ctx *cli.Context, tok *wallet.Token) {
w := ctx.App.Writer
fmt.Fprintf(w, "Name:\t%s\n", tok.Name)
fmt.Fprintf(w, "Symbol:\t%s\n", tok.Symbol)
fmt.Fprintf(w, "Hash:\t%s\n", tok.Hash.StringLE())
fmt.Fprintf(w, "Decimals: %d\n", tok.Decimals)
fmt.Fprintf(w, "Address: %s\n", tok.Address())
}
func printNEP5Info(ctx *cli.Context) error {
@ -289,19 +290,19 @@ func printNEP5Info(ctx *cli.Context) error {
defer wall.Close()
if name := ctx.String("token"); name != "" {
token, err := getMatchingToken(wall, name)
token, err := getMatchingToken(ctx, wall, name)
if err != nil {
return cli.NewExitError(err, 1)
}
printTokenInfo(token)
printTokenInfo(ctx, token)
return nil
}
for i, t := range wall.Extra.Tokens {
if i > 0 {
fmt.Println()
fmt.Fprintln(ctx.App.Writer)
}
printTokenInfo(t)
printTokenInfo(ctx, t)
}
return nil
}
@ -317,12 +318,12 @@ func removeNEP5Token(ctx *cli.Context) error {
if name == "" {
return cli.NewExitError("token must be specified", 1)
}
token, err := getMatchingToken(wall, name)
token, err := getMatchingToken(ctx, wall, name)
if err != nil {
return cli.NewExitError(err, 1)
}
if !ctx.Bool("force") {
if ok := askForConsent(); !ok {
if ok := askForConsent(ctx.App.Writer); !ok {
return nil
}
}
@ -343,7 +344,7 @@ func multiTransferNEP5(ctx *cli.Context) error {
fromFlag := ctx.Generic("from").(*flags.Address)
from := fromFlag.Uint160()
acc, err := getDecryptedAccount(wall, from)
acc, err := getDecryptedAccount(ctx, wall, from)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -369,10 +370,10 @@ func multiTransferNEP5(ctx *cli.Context) error {
}
token, ok := cache[ss[0]]
if !ok {
token, err = getMatchingToken(wall, ss[0])
token, err = getMatchingToken(ctx, wall, ss[0])
if err != nil {
fmt.Println("Can't find matching token in the wallet. Querying RPC-node for balances.")
token, err = getMatchingTokenRPC(c, from, ctx.String("token"))
fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.")
token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"))
if err != nil {
return cli.NewExitError(err, 1)
}
@ -406,7 +407,7 @@ func transferNEP5(ctx *cli.Context) error {
fromFlag := ctx.Generic("from").(*flags.Address)
from := fromFlag.Uint160()
acc, err := getDecryptedAccount(wall, from)
acc, err := getDecryptedAccount(ctx, wall, from)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -421,10 +422,10 @@ func transferNEP5(ctx *cli.Context) error {
toFlag := ctx.Generic("to").(*flags.Address)
to := toFlag.Uint160()
token, err := getMatchingToken(wall, ctx.String("token"))
token, err := getMatchingToken(ctx, wall, ctx.String("token"))
if err != nil {
fmt.Println("Can't find matching token in the wallet. Querying RPC-node for balances.")
token, err = getMatchingTokenRPC(c, from, ctx.String("token"))
fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.")
token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"))
if err != nil {
return cli.NewExitError(err, 1)
}
@ -470,10 +471,10 @@ func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(res.StringLE())
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
}
fmt.Println(tx.Hash().StringLE())
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
return nil
}

View file

@ -83,7 +83,7 @@ func handleCandidate(ctx *cli.Context, method string) error {
addrFlag := ctx.Generic("address").(*flags.Address)
addr := addrFlag.Uint160()
acc, err := getDecryptedAccount(wall, addr)
acc, err := getDecryptedAccount(ctx, wall, addr)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -111,7 +111,7 @@ func handleCandidate(ctx *cli.Context, method string) error {
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(res.StringLE())
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
}
@ -123,7 +123,7 @@ func handleVote(ctx *cli.Context) error {
addrFlag := ctx.Generic("address").(*flags.Address)
addr := addrFlag.Uint160()
acc, err := getDecryptedAccount(wall, addr)
acc, err := getDecryptedAccount(ctx, wall, addr)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -168,17 +168,17 @@ func handleVote(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(res.StringLE())
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
}
func getDecryptedAccount(wall *wallet.Wallet, addr util.Uint160) (*wallet.Account, error) {
func getDecryptedAccount(ctx *cli.Context, wall *wallet.Wallet, addr util.Uint160) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr))
}
if pass, err := readPassword("Password > "); err != nil {
if pass, err := readPassword(ctx.App.Writer, "Password > "); err != nil {
return nil, err
} else if err := acc.Decrypt(pass); err != nil {
return nil, err

View file

@ -5,6 +5,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"strings"
"syscall"
@ -222,7 +223,7 @@ func claimGas(ctx *cli.Context) error {
return cli.NewExitError("address was not provided", 1)
}
scriptHash := addrFlag.Uint160()
acc, err := getDecryptedAccount(wall, scriptHash)
acc, err := getDecryptedAccount(ctx, wall, scriptHash)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -245,7 +246,7 @@ func claimGas(ctx *cli.Context) error {
return cli.NewExitError(err, 1)
}
fmt.Println(hash.StringLE())
fmt.Fprintln(ctx.App.Writer, hash.StringLE())
return nil
}
@ -265,7 +266,7 @@ func convertWallet(ctx *cli.Context) error {
for _, acc := range wall.Accounts {
address.Prefix = address.NEO2Prefix
pass, err := readPassword(fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label))
pass, err := readPassword(ctx.App.Writer, fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label))
if err != nil {
return cli.NewExitError(err, -1)
} else if err := acc.Decrypt(pass); err != nil {
@ -347,7 +348,7 @@ loop:
for _, wif := range wifs {
if decrypt {
pass, err := readPassword("Enter password > ")
pass, err := readPassword(ctx.App.Writer, "Enter password > ")
if err != nil {
return cli.NewExitError(err, 1)
}
@ -360,7 +361,7 @@ loop:
wif = pk.WIF()
}
fmt.Println(wif)
fmt.Fprintln(ctx.App.Writer, wif)
}
return nil
@ -389,7 +390,7 @@ func importMultisig(ctx *cli.Context) error {
}
}
acc, err := newAccountFromWIF(ctx.String("wif"))
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"))
if err != nil {
return cli.NewExitError(err, 1)
}
@ -419,7 +420,7 @@ func importDeployed(ctx *cli.Context) error {
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
}
acc, err := newAccountFromWIF(ctx.String("wif"))
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"))
if err != nil {
return cli.NewExitError(err, 1)
}
@ -463,7 +464,7 @@ func importWallet(ctx *cli.Context) error {
}
defer wall.Close()
acc, err := newAccountFromWIF(ctx.String("wif"))
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"))
if err != nil {
return cli.NewExitError(err, 1)
}
@ -502,8 +503,8 @@ func removeAccount(ctx *cli.Context) error {
}
if !ctx.Bool("force") {
fmt.Printf("Account %s will be removed. This action is irreversible.\n", addrArg)
if ok := askForConsent(); !ok {
fmt.Fprintf(ctx.App.Writer, "Account %s will be removed. This action is irreversible.\n", addrArg)
if ok := askForConsent(ctx.App.Writer); !ok {
return nil
}
}
@ -516,8 +517,8 @@ func removeAccount(ctx *cli.Context) error {
return nil
}
func askForConsent() bool {
fmt.Print("Are you sure? [y/N]: ")
func askForConsent(w io.Writer) bool {
fmt.Fprintln(w, "Are you sure? [y/N]: ")
reader := bufio.NewReader(os.Stdin)
response, err := reader.ReadString('\n')
if err == nil {
@ -526,7 +527,7 @@ func askForConsent() bool {
return true
}
}
fmt.Println("Cancelled.")
fmt.Fprintln(w, "Cancelled.")
return false
}
@ -536,7 +537,7 @@ func dumpWallet(ctx *cli.Context) error {
return cli.NewExitError(err, 1)
}
if ctx.Bool("decrypt") {
pass, err := readPassword("Enter wallet password > ")
pass, err := readPassword(ctx.App.Writer, "Enter wallet password > ")
if err != nil {
return cli.NewExitError(err, 1)
}
@ -548,7 +549,7 @@ func dumpWallet(ctx *cli.Context) error {
}
}
}
fmtPrintWallet(wall)
fmtPrintWallet(ctx.App.Writer, wall)
return nil
}
@ -571,20 +572,20 @@ func createWallet(ctx *cli.Context) error {
}
}
fmtPrintWallet(wall)
fmt.Printf("wallet successfully created, file location is %s\n", wall.Path())
fmtPrintWallet(ctx.App.Writer, wall)
fmt.Fprintf(ctx.App.Writer, "wallet successfully created, file location is %s\n", wall.Path())
return nil
}
func readAccountInfo() (string, string, error) {
func readAccountInfo(w io.Writer) (string, string, error) {
buf := bufio.NewReader(os.Stdin)
fmt.Print("Enter the name of the account > ")
fmt.Fprint(w, "Enter the name of the account > ")
rawName, _ := buf.ReadBytes('\n')
phrase, err := readPassword("Enter passphrase > ")
phrase, err := readPassword(w, "Enter passphrase > ")
if err != nil {
return "", "", err
}
phraseCheck, err := readPassword("Confirm passphrase > ")
phraseCheck, err := readPassword(w, "Confirm passphrase > ")
if err != nil {
return "", "", err
}
@ -598,7 +599,7 @@ func readAccountInfo() (string, string, error) {
}
func createAccount(ctx *cli.Context, wall *wallet.Wallet) error {
name, phrase, err := readAccountInfo()
name, phrase, err := readAccountInfo(ctx.App.Writer)
if err != nil {
return err
}
@ -612,11 +613,11 @@ func openWallet(path string) (*wallet.Wallet, error) {
return wallet.NewWalletFromFile(path)
}
func newAccountFromWIF(wif string) (*wallet.Account, error) {
func newAccountFromWIF(w io.Writer, wif string) (*wallet.Account, error) {
// note: NEP2 strings always have length of 58 even though
// base58 strings can have different lengths even if slice lengths are equal
if len(wif) == 58 {
pass, err := readPassword("Enter password > ")
pass, err := readPassword(w, "Enter password > ")
if err != nil {
return nil, err
}
@ -629,8 +630,8 @@ func newAccountFromWIF(wif string) (*wallet.Account, error) {
return nil, err
}
fmt.Println("Provided WIF was unencrypted. Wallet can contain only encrypted keys.")
name, pass, err := readAccountInfo()
fmt.Fprintln(w, "Provided WIF was unencrypted. Wallet can contain only encrypted keys.")
name, pass, err := readAccountInfo(w)
if err != nil {
return nil, err
}
@ -654,19 +655,19 @@ func addAccountAndSave(w *wallet.Wallet, acc *wallet.Account) error {
return w.Save()
}
func readPassword(prompt string) (string, error) {
fmt.Print(prompt)
func readPassword(w io.Writer, prompt string) (string, error) {
fmt.Fprint(w, prompt)
rawPass, err := terminal.ReadPassword(syscall.Stdin)
fmt.Println()
fmt.Fprintln(w)
if err != nil {
return "", err
}
return strings.TrimRight(string(rawPass), "\n"), nil
}
func fmtPrintWallet(wall *wallet.Wallet) {
func fmtPrintWallet(w io.Writer, wall *wallet.Wallet) {
b, _ := wall.JSON()
fmt.Println("")
fmt.Println(string(b))
fmt.Println("")
fmt.Fprintln(w, "")
fmt.Fprintln(w, string(b))
fmt.Fprintln(w, "")
}