github.com/turingchain2020/turingchain@v1.1.21/cmd/tools/strategy/importpackage.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package strategy
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"strings"
    16  
    17  	"github.com/turingchain2020/turingchain/cmd/tools/util"
    18  	"github.com/BurntSushi/toml"
    19  )
    20  
    21  const (
    22  	dappFolderName      = "dapp"
    23  	consensusFolderName = "consensus"
    24  	storeFolderName     = "store"
    25  	cryptoFolderName    = "crypto"
    26  	mempoolFolderName   = "mempool"
    27  )
    28  
    29  type pluginConfigItem struct {
    30  	Type    string
    31  	Gitrepo string
    32  	Version string
    33  }
    34  
    35  type pluginItem struct {
    36  	name    string
    37  	gitRepo string
    38  	version string
    39  }
    40  
    41  type importPackageStrategy struct {
    42  	strategyBasic
    43  	cfgFileName    string
    44  	cfgItems       map[string]*pluginConfigItem
    45  	projRootPath   string
    46  	projPluginPath string
    47  	items          map[string][]*pluginItem
    48  }
    49  
    50  func (im *importPackageStrategy) Run() error {
    51  	mlog.Info("Begin run turingchain import packages.")
    52  	defer mlog.Info("Run turingchain import packages finish.")
    53  	return im.runImpl()
    54  }
    55  
    56  func (im *importPackageStrategy) runImpl() error {
    57  	type STEP func() error
    58  	steps := []STEP{
    59  		im.readConfig,
    60  		im.initData,
    61  		im.generateImportFile,
    62  		im.fetchPluginPackage,
    63  	}
    64  
    65  	for s, step := range steps {
    66  		err := step()
    67  		if err != nil {
    68  			fmt.Println("call", s+1, "step error", err)
    69  			return err
    70  		}
    71  	}
    72  	return nil
    73  }
    74  
    75  func (im *importPackageStrategy) readConfig() error {
    76  	mlog.Info("读取配置文件")
    77  	conf, _ := im.getParam("conf")
    78  	if conf == "" {
    79  		return nil
    80  	}
    81  	if conf != "" {
    82  		im.cfgFileName = conf
    83  	}
    84  	_, err := toml.DecodeFile(im.cfgFileName, &im.cfgItems)
    85  	return err
    86  }
    87  
    88  func (im *importPackageStrategy) initData() error {
    89  	mlog.Info("初始化数据")
    90  	im.items = make(map[string][]*pluginItem)
    91  	dappItems := make([]*pluginItem, 0)
    92  	consensusItems := make([]*pluginItem, 0)
    93  	storeItems := make([]*pluginItem, 0)
    94  	cryptoItems := make([]*pluginItem, 0)
    95  	mempoolItems := make([]*pluginItem, 0)
    96  
    97  	//read current plugin dir
    98  	//(分成两级,并且去掉了 init 目录)
    99  	path, _ := im.getParam("path")
   100  	dirlist, err := im.readPluginDir(path)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	if im.cfgItems == nil {
   105  		im.cfgItems = make(map[string]*pluginConfigItem)
   106  	}
   107  	for name, value := range dirlist {
   108  		im.cfgItems[name] = value
   109  	}
   110  	out, _ := im.getParam("out")
   111  	//输出新的配置文件
   112  	if out != "" {
   113  		buf := new(bytes.Buffer)
   114  		err = toml.NewEncoder(buf).Encode(im.cfgItems)
   115  		if err != nil {
   116  			return err
   117  		}
   118  		err = ioutil.WriteFile(out, buf.Bytes(), 0666)
   119  		if err != nil {
   120  			return err
   121  		}
   122  	}
   123  	if len(im.cfgItems) == 0 {
   124  		return errors.New("empty config")
   125  	}
   126  	for name, cfgItem := range im.cfgItems {
   127  		splitdata := strings.Split(name, "-")
   128  		if len(splitdata) == 2 {
   129  			cfgItem.Type = splitdata[0]
   130  			name = splitdata[1]
   131  		}
   132  		item := &pluginItem{
   133  			name:    name,
   134  			gitRepo: cfgItem.Gitrepo,
   135  			version: cfgItem.Version,
   136  		}
   137  		switch cfgItem.Type {
   138  		case dappFolderName:
   139  			dappItems = append(dappItems, item)
   140  		case consensusFolderName:
   141  			consensusItems = append(consensusItems, item)
   142  		case storeFolderName:
   143  			storeItems = append(storeItems, item)
   144  		case cryptoFolderName:
   145  			cryptoItems = append(cryptoItems, item)
   146  		case mempoolFolderName:
   147  			mempoolItems = append(mempoolItems, item)
   148  		default:
   149  			fmt.Printf("type %s is not supported.\n", cfgItem.Type)
   150  			return errors.New("config error")
   151  		}
   152  	}
   153  	im.items[dappFolderName] = dappItems
   154  	im.items[consensusFolderName] = consensusItems
   155  	im.items[storeFolderName] = storeItems
   156  	im.items[cryptoFolderName] = cryptoItems
   157  	im.items[mempoolFolderName] = mempoolItems
   158  	im.projRootPath = ""
   159  	im.projPluginPath, _ = im.getParam("path")
   160  	return nil
   161  }
   162  
   163  func getDirList(path string) ([]string, error) {
   164  	dirlist, err := ioutil.ReadDir(path)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	dirs := make([]string, 0)
   169  	for _, f := range dirlist {
   170  		if f.IsDir() {
   171  			if f.Name() == "." || f.Name() == ".." || f.Name() == "init" || f.Name() == ".git" {
   172  				continue
   173  			}
   174  			dirs = append(dirs, f.Name())
   175  		}
   176  	}
   177  	return dirs, nil
   178  }
   179  
   180  func (im *importPackageStrategy) readPluginDir(path string) (map[string]*pluginConfigItem, error) {
   181  	dirlist, err := getDirList(path)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	packname, _ := im.getParam("packname")
   186  	conf := make(map[string]*pluginConfigItem)
   187  	for _, ty := range dirlist {
   188  		names, err := getDirList(path + "/" + ty)
   189  		if err != nil {
   190  			return nil, err
   191  		}
   192  		for _, name := range names {
   193  			key := ty + "-" + name
   194  			item := &pluginConfigItem{
   195  				Type:    ty,
   196  				Gitrepo: packname + "/" + ty + "/" + name,
   197  			}
   198  			conf[key] = item
   199  		}
   200  	}
   201  	return conf, nil
   202  }
   203  
   204  func (im *importPackageStrategy) generateImportFile() error {
   205  	mlog.Info("生成引用文件")
   206  	importStrs := map[string]string{}
   207  	for name, plugins := range im.items {
   208  		for _, item := range plugins {
   209  			importStrs[name] += fmt.Sprintf("\n_ \"%s\" //auto gen", item.gitRepo)
   210  		}
   211  	}
   212  	for key, value := range importStrs {
   213  		content := fmt.Sprintf("package init\n\nimport(%s\n)", value)
   214  		initFile := fmt.Sprintf("%s/%s/init/init.go", im.projPluginPath, key)
   215  		util.MakeDir(initFile)
   216  
   217  		{ // 写入到文件中
   218  			util.DeleteFile(initFile)
   219  			file, err := util.OpenFile(initFile)
   220  			if err != nil {
   221  				return err
   222  			}
   223  			defer file.Close()
   224  			_, err = io.WriteString(file, content)
   225  			if err != nil {
   226  				return err
   227  			}
   228  		}
   229  		// 格式化生成的文件
   230  		cmd := exec.Command("gofmt", "-l", "-s", "-w", initFile)
   231  		err := cmd.Run()
   232  		if err != nil {
   233  			return err
   234  		}
   235  	}
   236  	return nil
   237  }
   238  
   239  func (im *importPackageStrategy) fetchPlugin(gitrepo, version string) error {
   240  	var param string
   241  	if len(version) > 0 {
   242  		param = fmt.Sprintf("%s@%s", gitrepo, version)
   243  	} else {
   244  		param = gitrepo
   245  	}
   246  	cmd := exec.Command("govendor", "fetch", param)
   247  	cmd.Stdout = os.Stdout
   248  	cmd.Stderr = os.Stderr
   249  	return cmd.Run()
   250  }
   251  
   252  // fetchPluginPackage 使用govendor来下载依赖包
   253  func (im *importPackageStrategy) fetchPluginPackage() error {
   254  	mlog.Info("下载插件源码包")
   255  	pwd := util.Pwd()
   256  
   257  	defer os.Chdir(pwd)
   258  	for _, plugins := range im.items {
   259  		for _, plugin := range plugins {
   260  			mlog.Info("同步插件", "repo", plugin.gitRepo, "version", plugin.version)
   261  			if plugin.version == "" {
   262  				//留给后面的 fetch +m
   263  				continue
   264  			}
   265  			err := im.fetchPlugin(plugin.gitRepo, plugin.version)
   266  			if err != nil {
   267  				mlog.Info("同步插件包出错", "repo", plugin.gitRepo, "error", err.Error())
   268  				return err
   269  			}
   270  		}
   271  	}
   272  	return nil
   273  }