Skip to content

Commit 7d670ea

Browse files
authored
Merge pull request #524 from 0xPolygon/thiago/env-vars
add a flag loader to allow flags to be set also via env vars
2 parents e999be0 + 9503b96 commit 7d670ea

File tree

13 files changed

+281
-16
lines changed

13 files changed

+281
-16
lines changed

cmd/cdk/cdk.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1213
"github.com/ethereum/go-ethereum/common"
1314
"github.com/ethereum/go-ethereum/ethclient"
1415
"github.com/go-errors/errors"
@@ -86,7 +87,10 @@ var CDKCmd = &cobra.Command{
8687
Use: "cdk",
8788
Short: "Utilities for interacting with CDK networks",
8889
Long: "Basic utility commands for interacting with the cdk contracts",
89-
Args: cobra.NoArgs,
90+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
91+
cdkInputArgs.rpcURL = flag_loader.GetRpcUrlFlagValue(cmd)
92+
},
93+
Args: cobra.NoArgs,
9094
}
9195

9296
type inputArgs struct {

cmd/dumpblocks/dumpblocks.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
_ "embed"
1414

15+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1516
"github.com/0xPolygon/polygon-cli/proto/gen/pb"
1617
"github.com/0xPolygon/polygon-cli/rpctypes"
1718
"github.com/0xPolygon/polygon-cli/util"
@@ -54,6 +55,10 @@ var DumpblocksCmd = &cobra.Command{
5455
Use: "dumpblocks start end",
5556
Short: "Export a range of blocks from a JSON-RPC endpoint.",
5657
Long: usage,
58+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
59+
rpcUrlFlagValue := flag_loader.GetRpcUrlFlagValue(cmd)
60+
inputDumpblocks.RpcUrl = *rpcUrlFlagValue
61+
},
5762
PreRunE: func(cmd *cobra.Command, args []string) error {
5863
return checkFlags()
5964
},

cmd/ecrecover/ecrecover.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"math/big"
88
"os"
99

10+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1011
"github.com/0xPolygon/polygon-cli/util"
1112
ethcommon "github.com/ethereum/go-ethereum/common"
1213
"github.com/ethereum/go-ethereum/core/types"
@@ -31,6 +32,10 @@ var EcRecoverCmd = &cobra.Command{
3132
Short: "Recovers and returns the public key of the signature",
3233
Long: usage,
3334
Args: cobra.NoArgs,
35+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
36+
rpcUrlFlagValue := flag_loader.GetRpcUrlFlagValue(cmd)
37+
rpcUrl = *rpcUrlFlagValue
38+
},
3439
PreRunE: func(cmd *cobra.Command, args []string) error {
3540
return checkFlags()
3641
},

cmd/fixnoncegap/fixnoncegap.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1213
"github.com/ethereum/go-ethereum"
1314
"github.com/ethereum/go-ethereum/accounts/abi/bind"
1415
"github.com/ethereum/go-ethereum/common"
@@ -20,10 +21,19 @@ import (
2021
)
2122

2223
var FixNonceGapCmd = &cobra.Command{
23-
Use: "fix-nonce-gap",
24-
Short: "Send txs to fix the nonce gap for a specific account",
25-
Long: fixNonceGapUsage,
26-
Args: cobra.NoArgs,
24+
Use: "fix-nonce-gap",
25+
Short: "Send txs to fix the nonce gap for a specific account",
26+
Long: fixNonceGapUsage,
27+
Args: cobra.NoArgs,
28+
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
29+
var err error
30+
inputFixNonceGapArgs.rpcURL = flag_loader.GetRpcUrlFlagValue(cmd)
31+
inputFixNonceGapArgs.privateKey, err = flag_loader.GetRequiredPrivateKeyFlagValue(cmd)
32+
if err != nil {
33+
return err
34+
}
35+
return nil
36+
},
2737
PreRunE: prepareRpcClient,
2838
RunE: fixNonceGap,
2939
SilenceUsage: true,
@@ -221,7 +231,6 @@ func init() {
221231
inputFixNonceGapArgs.privateKey = FixNonceGapCmd.PersistentFlags().String(ArgPrivateKey, "", "the private key to be used when sending the txs to fix the nonce gap")
222232
inputFixNonceGapArgs.replace = FixNonceGapCmd.PersistentFlags().Bool(ArgReplace, false, "replace the existing txs in the pool")
223233
inputFixNonceGapArgs.maxNonce = FixNonceGapCmd.PersistentFlags().Uint64(ArgMaxNonce, 0, "when set, the max nonce will be this value instead of trying to get it from the pool")
224-
fatalIfError(FixNonceGapCmd.MarkPersistentFlagRequired(ArgPrivateKey))
225234
}
226235

227236
// Wait for the transaction to be mined
@@ -255,13 +264,6 @@ func WaitMineTransaction(ctx context.Context, client *ethclient.Client, tx *type
255264
}
256265
}
257266

258-
func fatalIfError(err error) {
259-
if err == nil {
260-
return
261-
}
262-
log.Fatal().Err(err).Msg("Unexpected error occurred")
263-
}
264-
265267
func getMaxNonceFromTxPool(addr common.Address) (uint64, error) {
266268
var result PoolContent
267269
err := rpcClient.Client().Call(&result, "txpool_content")

cmd/flag_loader/flag_loader.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package flag_loader
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
const (
11+
rpcUrlFlagName, rpcUrlEnvVar = "rpc-url", "ETH_RPC_URL"
12+
privateKeyFlagName, privateKeyEnvVar = "private-key", "PRIVATE_KEY"
13+
)
14+
15+
func GetRpcUrlFlagValue(cmd *cobra.Command) *string {
16+
v, _ := getFlagValue(cmd, rpcUrlFlagName, rpcUrlEnvVar, false)
17+
return v
18+
}
19+
20+
func GetRequiredRpcUrlFlagValue(cmd *cobra.Command) (*string, error) {
21+
return getFlagValue(cmd, rpcUrlFlagName, rpcUrlEnvVar, true)
22+
}
23+
24+
func GetPrivateKeyFlagValue(cmd *cobra.Command) *string {
25+
v, _ := getFlagValue(cmd, privateKeyFlagName, privateKeyEnvVar, false)
26+
return v
27+
}
28+
29+
func GetRequiredPrivateKeyFlagValue(cmd *cobra.Command) (*string, error) {
30+
return getFlagValue(cmd, privateKeyFlagName, privateKeyEnvVar, true)
31+
}
32+
33+
func getFlagValue(cmd *cobra.Command, flagName, envVarName string, required bool) (*string, error) {
34+
flag := cmd.Flag(flagName)
35+
var flagValue string
36+
if flag.Changed {
37+
flagValue = flag.Value.String()
38+
}
39+
flagDefaultValue := flag.DefValue
40+
41+
envVarValue := os.Getenv(envVarName)
42+
43+
value := flagDefaultValue
44+
if envVarValue != "" {
45+
value = envVarValue
46+
}
47+
if flag.Changed {
48+
value = flagValue
49+
}
50+
51+
if required && (!flag.Changed && envVarValue == "") {
52+
return nil, fmt.Errorf("required flag(s) \"%s\" not set", flagName)
53+
}
54+
55+
return &value, nil
56+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package flag_loader
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strconv"
7+
"testing"
8+
9+
"github.com/spf13/cobra"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestValuePriority(t *testing.T) {
14+
type testCase struct {
15+
defaultValue *int
16+
envVarValue *int
17+
flagValue *int
18+
required bool
19+
20+
expectedValue *int
21+
expectedError error
22+
}
23+
24+
testCases := []testCase{
25+
{
26+
defaultValue: ptr(1),
27+
envVarValue: ptr(2),
28+
flagValue: ptr(3),
29+
expectedValue: ptr(3),
30+
required: true,
31+
expectedError: nil,
32+
},
33+
{
34+
defaultValue: ptr(1),
35+
envVarValue: ptr(2),
36+
flagValue: ptr(1),
37+
expectedValue: ptr(1),
38+
required: true,
39+
expectedError: nil,
40+
},
41+
{
42+
defaultValue: ptr(1),
43+
envVarValue: ptr(2),
44+
flagValue: nil,
45+
expectedValue: ptr(2),
46+
required: true,
47+
expectedError: nil,
48+
},
49+
{
50+
defaultValue: ptr(1),
51+
envVarValue: nil,
52+
flagValue: ptr(3),
53+
expectedValue: ptr(3),
54+
required: true,
55+
expectedError: nil,
56+
},
57+
{
58+
defaultValue: nil,
59+
envVarValue: ptr(2),
60+
flagValue: ptr(3),
61+
expectedValue: ptr(3),
62+
required: true,
63+
expectedError: nil,
64+
},
65+
{
66+
defaultValue: nil,
67+
envVarValue: nil,
68+
flagValue: ptr(3),
69+
expectedValue: ptr(3),
70+
required: true,
71+
expectedError: nil,
72+
},
73+
{
74+
defaultValue: ptr(1),
75+
envVarValue: nil,
76+
flagValue: nil,
77+
expectedValue: ptr(1),
78+
required: false,
79+
expectedError: nil,
80+
},
81+
{
82+
defaultValue: nil,
83+
envVarValue: ptr(2),
84+
flagValue: nil,
85+
expectedValue: ptr(2),
86+
required: true,
87+
expectedError: nil,
88+
},
89+
{
90+
defaultValue: nil,
91+
envVarValue: nil,
92+
flagValue: nil,
93+
expectedValue: ptr(0),
94+
required: false,
95+
expectedError: nil,
96+
},
97+
{
98+
defaultValue: nil,
99+
envVarValue: nil,
100+
flagValue: nil,
101+
expectedValue: nil,
102+
required: true,
103+
expectedError: fmt.Errorf("required flag(s) \"flag\" not set"),
104+
},
105+
}
106+
107+
for _, tc := range testCases {
108+
var value *int
109+
cmd := &cobra.Command{
110+
Use: "test",
111+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
112+
valueStr, err := getFlagValue(cmd, "flag", "FLAG", tc.required)
113+
if tc.expectedError != nil {
114+
assert.EqualError(t, err, tc.expectedError.Error())
115+
return
116+
}
117+
assert.NoError(t, err)
118+
valueInt, err := strconv.Atoi(*valueStr)
119+
assert.NoError(t, err)
120+
value = &valueInt
121+
},
122+
Run: func(cmd *cobra.Command, args []string) {
123+
if tc.expectedValue != nil {
124+
assert.Equal(t, *tc.expectedValue, *value)
125+
} else {
126+
assert.Nil(t, value)
127+
}
128+
},
129+
}
130+
if tc.defaultValue != nil {
131+
cmd.Flags().Int("flag", *tc.defaultValue, "flag")
132+
} else {
133+
cmd.Flags().Int("flag", 0, "flag")
134+
}
135+
136+
os.Unsetenv("FLAG")
137+
if tc.envVarValue != nil {
138+
v := strconv.Itoa(*tc.envVarValue)
139+
os.Setenv("FLAG", v)
140+
}
141+
142+
if tc.flagValue != nil {
143+
v := strconv.Itoa(*tc.flagValue)
144+
cmd.SetArgs([]string{"--flag", v})
145+
}
146+
147+
err := cmd.Execute()
148+
assert.Nil(t, err)
149+
}
150+
151+
}
152+
153+
func ptr[T any](v T) *T {
154+
return &v
155+
}

cmd/fund/cmd.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
_ "embed"
88

9+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
910
"github.com/0xPolygon/polygon-cli/util"
1011
"github.com/spf13/cobra"
1112
)
@@ -44,6 +45,10 @@ var FundCmd = &cobra.Command{
4445
Use: "fund",
4546
Short: "Bulk fund crypto wallets automatically.",
4647
Long: usage,
48+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
49+
params.RpcUrl = flag_loader.GetRpcUrlFlagValue(cmd)
50+
params.PrivateKey = flag_loader.GetPrivateKeyFlagValue(cmd)
51+
},
4752
PreRunE: func(cmd *cobra.Command, args []string) error {
4853
return checkFlags()
4954
},

cmd/loadtest/app.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"sync"
1010
"time"
1111

12+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1213
"github.com/0xPolygon/polygon-cli/rpctypes"
1314
"github.com/0xPolygon/polygon-cli/util"
1415
ethcommon "github.com/ethereum/go-ethereum/common"
@@ -166,6 +167,10 @@ var LoadtestCmd = &cobra.Command{
166167
Short: "Run a generic load test against an Eth/EVM style JSON-RPC endpoint.",
167168
Long: loadtestUsage,
168169
Args: cobra.NoArgs,
170+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
171+
inputLoadTestParams.RPCUrl = flag_loader.GetRpcUrlFlagValue(cmd)
172+
inputLoadTestParams.PrivateKey = flag_loader.GetPrivateKeyFlagValue(cmd)
173+
},
169174
PreRunE: func(cmd *cobra.Command, args []string) error {
170175
zerolog.DurationFieldUnit = time.Second
171176
zerolog.DurationFieldInteger = true

cmd/monitor/cmd.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1011
"github.com/0xPolygon/polygon-cli/util"
1112
"github.com/spf13/cobra"
1213
)
@@ -57,6 +58,8 @@ var MonitorCmd = &cobra.Command{
5758
Args: cobra.NoArgs,
5859
SilenceUsage: true,
5960
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
61+
rpcUrlFlagValue := flag_loader.GetRpcUrlFlagValue(cmd)
62+
rpcUrl = *rpcUrlFlagValue
6063
// By default, hide logs from `polycli monitor`.
6164
verbosityFlag := cmd.Flag("verbosity")
6265
if verbosityFlag != nil && !verbosityFlag.Changed {

cmd/nodekey/nodekey.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
_ "embed"
1717

18+
"github.com/0xPolygon/polygon-cli/cmd/flag_loader"
1819
gethcrypto "github.com/ethereum/go-ethereum/crypto"
1920
gethenode "github.com/ethereum/go-ethereum/p2p/enode"
2021
libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
@@ -65,6 +66,9 @@ var NodekeyCmd = &cobra.Command{
6566
Use: "nodekey",
6667
Short: "Generate node keys for different blockchain clients and protocols.",
6768
Long: usage,
69+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
70+
inputNodeKeyPrivateKey = flag_loader.GetRpcUrlFlagValue(cmd)
71+
},
6872
RunE: func(cmd *cobra.Command, args []string) error {
6973
var nko nodeKeyOut
7074
var withSeed bool

0 commit comments

Comments
 (0)