傳送門: 柏鏈項目學院git
以前咱們的介紹的是如何經過solc編譯智能合約,而且調用智能合約,本節咱們繼續實踐,將智能合約的代碼自動化編譯以及abi文件生成搞定。github
咱們須要掌握什麼技能呢?shell
go調用命令行,咱們使用exec包bash
TOML的全稱是Tom's Obvious, Minimal Language,由於它的做者是GitHub聯合創始人Tom Preston-Werner。TOML 的目標是成爲一個極簡的配置文件格式。TOML 被設計成能夠無歧義地被映射爲哈希表,從而被多種語言解析。ide
toml學習教程
在使用的時候,記得要安裝toml第三方包。函數
go get -u github.com/BurntSushi/toml
以後能夠根據咱們的須要,來編寫配置文件,配置文件的目的仍然是爲了讓程序運行更靈活,而不該該成爲咱們的負擔!工具
awk實際上是一個語言,unix平臺上處理文本的一種語言,其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。該語言的能力十分強大,能夠支持字符串處理,打印等操做,工程中對於文本處理要求比較高的環節多會使用awk進行操做。學習
awk功能舉例:ui
yekaideMacBook-Pro:awk yk$ cat factory.txt ProdA 70 ProdB 85 ProdC 74
示例以下:命令行
awk '{if ($2 < 75) printf("%s reorder\n",$0);if ($2 >= 75) print $0}' factory.txt
cat /etc/passwd |grep bash|awk -F ":" '{print $1}'
awk '/const.+ABI = .+/{print substr($4,2,length($4)-2) }' pdbank.go > pdbank.abi
main.go
package main import ( "fmt" "os" ) func Usage() { fmt.Printf("%s 1 -- compiler code\n", os.Args[0]) fmt.Printf("%s 2 -- build test code\n", os.Args[0]) } func main() { if len(os.Args) < 2 { Usage() os.Exit(0) } if os.Args[1] == "1" { CompilerRun() } else if os.Args[1] == "1" { //build test code } else { Usage() os.Exit(0) } }
接下來開始作填空題,也就是如何編譯,咱們先來實現。先編寫掃描目錄的代碼,獲取指定目錄的sol文件,而後自動化的造成編譯命令,送到命令行執行。
掃描指定目錄的sol文件
func CompilerRun() error { infos, err := ioutil.ReadDir("sol") if err != nil { fmt.Println("failed to readdir ", err) return err } for _, v := range infos { //後4位位.sol strNameRune := []rune(v.Name()) strfix := string(strNameRune[len(strNameRune)-4:]) if strfix == ".sol" && !v.IsDir() { fmt.Println(v.IsDir(), v.Name(), v.Size(), "ok") err = CompilerOnece("sol", v.Name(), "contracts") if err != nil { fmt.Println("call ompilerOnece err", err) break } } } return err }
編譯函數
//編譯一個智能合約 func CompilerOnece(solPath, solName, targetPath string) error { //xxx.sol - > xxx.go goName := strings.Replace(solName, ".sol", ".go", -1) cmd := exec.Command("abigen", "-sol", solPath+"/"+solName, "-pkg", targetPath, "-out", targetPath+"/"+goName) return cmd.Run() }
構建abi函數,咱們須要先用awk實現一個shell腳本,用來處理go文件的abi信息。
func BuildAbi(goCodeName string) error { abiName := strings.Replace(goCodeName, ".go", ".abi", -1) cmd := exec.Command("/bin/bash", "abi.sh", goCodeName, abiName) err := cmd.Run() fmt.Println("run BuildAbi ok!!", err) return nil }
abi.sh
filename=$1 targetfile=$2 awk '/const.+ABI = .+/{print substr($4,2,length($4)-2) }' $filename > $targetfile
統一調用處理
func ParseRun() { solfiles, err := ParseDir("sol") fmt.Println(solfiles, err) for _, solfile := range solfiles { fmt.Println(solfile) codeName, err := Compiler(solfile, "sol", "contracts") if err != nil { fmt.Println("failed to complie code", err) return } err = BuildAbi(codeName) if err != nil { fmt.Println("failed to build abi", err) return } } }
這樣咱們的基礎工做完成了,可是代碼不夠完美,咱們須要將部分寫死的變量用配置文件來設置,因此再加入toml處理配置文件的部分。
添加config.tomls
[version] auth = "yekai" company = "pdj" buildday = "2019-01-01" ver = "1.0.0" # 版本 [common] solidityPath = "sol" goPath = "contracts" abiSH = "./abi.sh"
添加config.go
package main import ( "log" "github.com/BurntSushi/toml" ) type ServerConfig struct { Version VersionInfo Common CommonInfo } type VersionInfo struct { Auth string Company string BuildDay string Ver string } type CommonInfo struct { SolidityPath string //智能合約原路徑 GoPath string //輸出go代碼路徑 AbiSH string //處理abi的shell腳本路徑 } var ServConf ServerConfig func init() { getConfig() } func getConfig() { var servConf ServerConfig _, err := toml.DecodeFile("config.toml", &servConf) if err != nil { log.Panic("faild to decodefile ", err) } ServConf = servConf //fmt.Println(servConf) }
接下來替換原來的代碼部分
package main import ( "fmt" "io/ioutil" "os/exec" "strings" ) //編譯一個智能合約 func CompilerOnece(solPath, solName, targetPath string) error { //xxx.sol - > xxx.go goName := strings.Replace(solName, ".sol", ".go", -1) cmd := exec.Command("abigen", "-sol", solPath+"/"+solName, "-pkg", targetPath, "-out", targetPath+"/"+goName) return cmd.Run() } //構造abi func BuildAbi(codePath string) error { //"contracts/pdbank.go" //xxx.sol - > xxx.abi abiName := strings.Replace(codePath, ".sol", ".abi", -1) goName := strings.Replace(codePath, ".sol", ".go", -1) cmd := exec.Command(ServConf.Common.AbiSH, goName, abiName) return cmd.Run() } //掃描目錄,得到所有的文件 func CompilerRun() error { infos, err := ioutil.ReadDir(ServConf.Common.SolidityPath) if err != nil { fmt.Println("failed to readdir ", err) return err } for _, v := range infos { //後4位位.sol strNameRune := []rune(v.Name()) strfix := string(strNameRune[len(strNameRune)-4:]) if strfix == ".sol" && !v.IsDir() { fmt.Println(v.IsDir(), v.Name(), v.Size(), "ok") err = CompilerOnece(ServConf.Common.SolidityPath, v.Name(), ServConf.Common.GoPath) if err != nil { fmt.Println("call ompilerOnece err", err) break } //建立abi err = BuildAbi(ServConf.Common.GoPath + "/" + v.Name()) if err != nil { fmt.Println("call BuildAbi err", err) break } } } return err }