github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/newcmd/contract/contractcompile.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package contract
     7  
     8  import (
     9  	"encoding/json"
    10  	"os"
    11  	"strings"
    12  
    13  	"github.com/pkg/errors"
    14  	"github.com/spf13/cobra"
    15  
    16  	"github.com/iotexproject/iotex-core/ioctl"
    17  	"github.com/iotexproject/iotex-core/ioctl/config"
    18  )
    19  
    20  // Multi-language support
    21  var (
    22  	_contractCompileCmdUses = map[config.Language]string{
    23  		config.English: "compile CONTRACT_NAME [CODE_FILES...] [--abi-out ABI_PATH] [--bin-out BIN_PATH]",
    24  		config.Chinese: "compile 合约名 [代码文件...] [--abi-out ABI路径] [--bin-out BIN路径]",
    25  	}
    26  	_contractCompileCmdShorts = map[config.Language]string{
    27  		config.English: "Compile smart contract of IoTeX blockchain from source code file(s).",
    28  		config.Chinese: "编译IoTeX区块链的智能合约代码,支持多文件编译",
    29  	}
    30  	_flagAbiOutUsage = map[config.Language]string{
    31  		config.English: "set abi file output path",
    32  		config.Chinese: "设置abi文件输出路径",
    33  	}
    34  	_flagBinOutUsage = map[config.Language]string{
    35  		config.English: "set bin file output path",
    36  		config.Chinese: "设置bin文件输出路径",
    37  	}
    38  )
    39  
    40  // NewContractCompileCmd represents the contract compile command
    41  func NewContractCompileCmd(client ioctl.Client) *cobra.Command {
    42  	var (
    43  		_abiOut string
    44  		_binOut string
    45  	)
    46  
    47  	use, _ := client.SelectTranslation(_contractCompileCmdUses)
    48  	short, _ := client.SelectTranslation(_contractCompileCmdShorts)
    49  	flagAbi, _ := client.SelectTranslation(_flagAbiOutUsage)
    50  	flagBin, _ := client.SelectTranslation(_flagBinOutUsage)
    51  
    52  	cmd := &cobra.Command{
    53  		Use:   use,
    54  		Short: short,
    55  		Args:  cobra.MinimumNArgs(1),
    56  		RunE: func(cmd *cobra.Command, args []string) error {
    57  			cmd.SilenceUsage = true
    58  			contractName := args[0]
    59  
    60  			files := args[1:]
    61  			if len(files) == 0 {
    62  				dirInfo, err := os.ReadDir("./")
    63  				if err != nil {
    64  					return errors.Wrap(err, "failed to get current directory")
    65  				}
    66  
    67  				for _, fileInfo := range dirInfo {
    68  					if !fileInfo.IsDir() && strings.HasSuffix(fileInfo.Name(), ".sol") {
    69  						files = append(files, fileInfo.Name())
    70  					}
    71  				}
    72  
    73  				if len(files) == 0 {
    74  					return errors.New("failed to get source file(s)")
    75  				}
    76  			}
    77  
    78  			contracts, err := Compile(files...)
    79  			if err != nil {
    80  				return errors.WithMessage(err, "failed to compile")
    81  			}
    82  
    83  			for name := range contracts {
    84  				if name == contractName {
    85  					break
    86  				}
    87  				nameSplit := strings.Split(name, ":")
    88  				if nameSplit[len(nameSplit)-1] == contractName {
    89  					contractName = name
    90  					break
    91  				}
    92  			}
    93  
    94  			contract, ok := contracts[contractName]
    95  			if !ok {
    96  				return errors.Errorf("failed to find out contract %s", contractName)
    97  			}
    98  
    99  			abiByte, err := json.Marshal(contract.Info.AbiDefinition)
   100  			if err != nil {
   101  				return errors.Wrap(err, "failed to marshal abi")
   102  			}
   103  			cmd.Printf("======= %s =======\nBinary:\n%s\nContract JSON ABI\n%s", contractName, contract.Code, string(abiByte))
   104  
   105  			if _binOut != "" {
   106  				// bin file starts with "0x" prefix
   107  				if err := os.WriteFile(_binOut, []byte(contract.Code), 0600); err != nil {
   108  					return errors.Wrap(err, "failed to write bin file")
   109  				}
   110  			}
   111  
   112  			if _abiOut != "" {
   113  				if err := os.WriteFile(_abiOut, abiByte, 0600); err != nil {
   114  					return errors.Wrap(err, "failed to write abi file")
   115  				}
   116  			}
   117  
   118  			return nil
   119  		},
   120  	}
   121  	cmd.Flags().StringVar(&_abiOut, "abi-out", "", flagAbi)
   122  	cmd.Flags().StringVar(&_binOut, "bin-out", "", flagBin)
   123  	return cmd
   124  }