Skip to content

Commit

Permalink
[ioctl] create main for ioctl/newcmd (#3296)
Browse files Browse the repository at this point in the history
* create main for ioctl/newcmd
  • Loading branch information
huof6829 authored Jun 23, 2022
1 parent 9c24171 commit 1f10a0f
Show file tree
Hide file tree
Showing 11 changed files with 414 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ BUILD_TARGET_SERVER=server
BUILD_TARGET_ACTINJV2=actioninjectorv2
BUILD_TARGET_ADDRGEN=addrgen
BUILD_TARGET_IOCTL=ioctl
BUILD_TARGET_NEWIOCTL=newioctl
BUILD_TARGET_XCTL=xctl
BUILD_TARGET_NEWXCTL=newxctl
BUILD_TARGET_MINICLUSTER=minicluster
BUILD_TARGET_RECOVER=recover
BUILD_TARGET_IOMIGRATER=iomigrater
Expand Down Expand Up @@ -218,6 +220,10 @@ recover:
.PHONY: ioctl
ioctl:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_IOCTL) -v ./tools/ioctl

.PHONY: newioctl
newioctl:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_NEWIOCTL) -v ./tools/newioctl

.PHONY: ioctl-cross
ioctl-cross:
Expand All @@ -229,10 +235,24 @@ ioctl-cross:
cd $(GOPATH)/src && $(GOPATH)/bin/xgo --targets=$(BUILD_TARGET_OS)/$(BUILD_TARGET_ARCH) .
mkdir -p ./bin/$(BUILD_TARGET_IOCTL) && sudo mv $(GOPATH)/src/main-$(BUILD_TARGET_OS)-$(BUILD_TARGET_ARCH) ./bin/$(BUILD_TARGET_IOCTL)/ioctl-$(BUILD_TARGET_OS)-$(BUILD_TARGET_ARCH)

.PHONY: newioctl-cross
newioctl-cross:
$(DOCKERCMD) pull techknowlogick/xgo:latest
$(GOCMD) get src.techknowlogick.com/xgo
mkdir -p $(GOPATH)/src
sudo cp ./tools/newioctl/ioctl.go $(GOPATH)/src
cd $(GOPATH)/src && sudo rm -f go.mod && $(GOCMD) mod init main && $(GOCMD) mod tidy
cd $(GOPATH)/src && $(GOPATH)/bin/xgo --targets=$(BUILD_TARGET_OS)/$(BUILD_TARGET_ARCH) .
mkdir -p ./bin/$(BUILD_TARGET_NEWIOCTL) && sudo mv $(GOPATH)/src/main-$(BUILD_TARGET_OS)-$(BUILD_TARGET_ARCH) ./bin/$(BUILD_TARGET_NEWIOCTL)/ioctl-$(BUILD_TARGET_OS)-$(BUILD_TARGET_ARCH)

.PHONY: xctl
xctl:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_XCTL) -v ./tools/xctl

.PHONY: newxctl
newxctl:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_NEWXCTL) -v ./tools/newxctl

.PHONY: iomigrater
iomigrater:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_IOMIGRATER) -v ./tools/iomigrater
2 changes: 2 additions & 0 deletions ioctl/newcmd/account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func NewAccountCmd(client ioctl.Client) *cobra.Command {
Short: accountShorts,
}
ac.AddCommand(NewAccountCreate(client))
ac.AddCommand(NewAccountCreateAdd(client))
ac.AddCommand(NewAccountDelete(client))
ac.AddCommand(NewAccountNonce(client))
ac.AddCommand(NewAccountList(client))
Expand All @@ -73,6 +74,7 @@ func NewAccountCmd(client ioctl.Client) *cobra.Command {
ac.AddCommand(NewAccountExportPublic(client))
ac.AddCommand(NewAccountExport(client))
ac.AddCommand(NewAccountImportCmd(client))
ac.AddCommand(NewAccountBalance(client))

client.SetEndpointWithFlag(ac.PersistentFlags().StringVar)
client.SetInsecureWithFlag(ac.PersistentFlags().BoolVar)
Expand Down
165 changes: 165 additions & 0 deletions ioctl/newcmd/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package config

import (
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/pkg/errors"
"gopkg.in/yaml.v2"

serverCfg "github.com/iotexproject/iotex-core/config"
"github.com/iotexproject/iotex-core/ioctl/config"
)

// Regexp patterns
const (
_ipPattern = `((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)`
_domainPattern = `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}`
_urlPattern = `[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`
_localPattern = "localhost"
_endpointPattern = "(" + _ipPattern + "|(" + _domainPattern + ")" + "|(" + _localPattern + "))" + `(:\d{1,5})?`
_defaultAnalyserEndpoint = "https://iotex-analyser-api-mainnet.chainanalytics.org"
_defaultConfigFileName = "config.default"
)

var (
_supportedLanguage = []string{"English", "中文"}
_validArgs = []string{"endpoint", "wallet", "explorer", "defaultacc", "language", "nsv2height"}
_validGetArgs = []string{"endpoint", "wallet", "explorer", "defaultacc", "language", "nsv2height", "analyserEndpoint", "all"}
_validExpl = []string{"iotexscan", "iotxplorer"}
_endpointCompile = regexp.MustCompile("^" + _endpointPattern + "$")
_configDir = os.Getenv("HOME") + "/.config/ioctl/default"
)

// info contains the information of config file
type info struct {
readConfig config.Config
defaultConfigFile string // Path to config file
}

// InitConfig load config data from default config file
func InitConfig() (config.Config, string, error) {
info := &info{
readConfig: config.Config{
Aliases: make(map[string]string),
},
}

// Create path to config directory
err := os.MkdirAll(_configDir, 0700)
if err != nil {
return info.readConfig, info.defaultConfigFile, err
}
info.defaultConfigFile = filepath.Join(_configDir, _defaultConfigFileName)

// Load or reset config file
err = info.loadConfig()
if os.IsNotExist(err) {
err = info.reset() // Config file doesn't exist
} else if err != nil {
return info.readConfig, info.defaultConfigFile, err
}

// Check completeness of config file
completeness := true
if info.readConfig.Wallet == "" {
info.readConfig.Wallet = _configDir
completeness = false
}
if info.readConfig.Language == "" {
info.readConfig.Language = _supportedLanguage[0]
completeness = false
}
if info.readConfig.Nsv2height == 0 {
info.readConfig.Nsv2height = serverCfg.Default.Genesis.FairbankBlockHeight
}
if info.readConfig.AnalyserEndpoint == "" {
info.readConfig.AnalyserEndpoint = _defaultAnalyserEndpoint
completeness = false
}
if !completeness {
if err = info.writeConfig(); err != nil {
return info.readConfig, info.defaultConfigFile, err
}
}
// Set language for ioctl
if info.isSupportedLanguage(info.readConfig.Language) == -1 {
fmt.Printf("Warn: Language %s is not supported, English instead.\n", info.readConfig.Language)
}
return info.readConfig, info.defaultConfigFile, nil
}

// newInfo create config info
func newInfo(readConfig config.Config, defaultConfigFile string) *info {
return &info{
readConfig: readConfig,
defaultConfigFile: defaultConfigFile,
}
}

// reset resets all values of config
func (c *info) reset() error {
c.readConfig.Wallet = path.Dir(c.defaultConfigFile)
c.readConfig.Endpoint = ""
c.readConfig.SecureConnect = true
c.readConfig.DefaultAccount = *new(config.Context)
c.readConfig.Explorer = _validExpl[0]
c.readConfig.Language = _supportedLanguage[0]
c.readConfig.AnalyserEndpoint = _defaultAnalyserEndpoint

err := c.writeConfig()
if err != nil {
return err
}

fmt.Println("Config set to default values")
return nil
}

// isSupportedLanguage checks if the language is a supported option and returns index when supported
func (c *info) isSupportedLanguage(arg string) config.Language {
if index, err := strconv.Atoi(arg); err == nil && index >= 0 && index < len(_supportedLanguage) {
return config.Language(index)
}
for i, lang := range _supportedLanguage {
if strings.EqualFold(arg, lang) {
return config.Language(i)
}
}
return config.Language(-1)
}

// writeConfig writes to config file
func (c *info) writeConfig() error {
out, err := yaml.Marshal(&c.readConfig)
if err != nil {
return errors.Wrap(err, "failed to marshal config")
}
if err := os.WriteFile(c.defaultConfigFile, out, 0600); err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to write to config file %s", c.defaultConfigFile))
}
return nil
}

// loadConfig loads config file in yaml format
func (c *info) loadConfig() error {
in, err := os.ReadFile(c.defaultConfigFile)
if err != nil {
return err
}
if err = yaml.Unmarshal(in, &c.readConfig); err != nil {
return errors.Wrap(err, "failed to unmarshal config")
}
return nil
}
7 changes: 7 additions & 0 deletions ioctl/newcmd/config/config_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package config
7 changes: 7 additions & 0 deletions ioctl/newcmd/config/config_reset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package config
7 changes: 7 additions & 0 deletions ioctl/newcmd/config/config_set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package config
33 changes: 33 additions & 0 deletions ioctl/newcmd/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package config

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-core/testutil"
)

func TestInitConfig(t *testing.T) {
require := require.New(t)
testPath, err := os.MkdirTemp(os.TempDir(), "testCfg")
require.NoError(err)
defer func() {
testutil.CleanupPath(testPath)
}()
_configDir = testPath
cfg, cfgFilePath, err := InitConfig()
require.NoError(err)
require.Equal(testPath, cfg.Wallet)
require.Equal(_validExpl[0], cfg.Explorer)
require.Equal(_supportedLanguage[0], cfg.Language)
require.Equal(filepath.Join(testPath, _defaultConfigFileName), cfgFilePath)
}
79 changes: 79 additions & 0 deletions ioctl/newcmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package newcmd

import (
"github.com/spf13/cobra"

"github.com/iotexproject/iotex-core/ioctl"
"github.com/iotexproject/iotex-core/ioctl/config"
"github.com/iotexproject/iotex-core/ioctl/newcmd/account"
)

// Multi-language support
var (
_ioctlRootCmdShorts = map[config.Language]string{
config.English: "Command-line interface for IoTeX blockchain",
config.Chinese: "IoTeX区块链命令行工具",
}
_ioctlRootCmdLongs = map[config.Language]string{
config.English: `ioctl is a command-line interface for interacting with IoTeX blockchain.`,
config.Chinese: `ioctl 是用于与IoTeX区块链进行交互的命令行工具`,
}
_ioctlRootCmdUses = map[config.Language]string{
config.English: "ioctl",
config.Chinese: "ioctl",
}
_xctlRootCmdShorts = map[config.Language]string{
config.English: "Command-line interface for consortium blockchain",
config.Chinese: "联盟链命令行工具",
}
_xctlRootCmdLongs = map[config.Language]string{
config.English: `xctl is a command-line interface for interacting with consortium blockchain.`,
config.Chinese: `xctl 是用于与联盟链进行交互的命令行工具`,
}
_xctlRootCmdUses = map[config.Language]string{
config.English: "xctl",
config.Chinese: "xctl",
}
)

// NewIoctl returns ioctl root cmd
func NewIoctl(client ioctl.Client) *cobra.Command {
rootUses, _ := client.SelectTranslation(_ioctlRootCmdUses)
rootShorts, _ := client.SelectTranslation(_ioctlRootCmdShorts)
rootLongs, _ := client.SelectTranslation(_ioctlRootCmdLongs)

rootCmd := &cobra.Command{
Use: rootUses,
Short: rootShorts,
Long: rootLongs,
}

rootCmd.AddCommand(config.ConfigCmd)
rootCmd.AddCommand(account.NewAccountCmd(client))

return rootCmd
}

// NewXctl returns xctl root cmd
func NewXctl(client ioctl.Client) *cobra.Command {
rootUses, _ := client.SelectTranslation(_xctlRootCmdUses)
rootShorts, _ := client.SelectTranslation(_xctlRootCmdShorts)
rootLongs, _ := client.SelectTranslation(_xctlRootCmdLongs)

var rootCmd = &cobra.Command{
Use: rootUses,
Short: rootShorts,
Long: rootLongs,
}

rootCmd.AddCommand(config.ConfigCmd)
rootCmd.AddCommand(account.NewAccountCmd(client))

return rootCmd
}
Loading

0 comments on commit 1f10a0f

Please sign in to comment.