func packageCmd(cf *ChaincodeCmdFactory, cdsFact ccDepSpecFactory) *cobra.Command {
chaincodePackageCmd = &cobra.Command{
Use: "package",
Short: packageDesc,
Long: packageDesc,
ValidArgs: []string{"1"},
RunE: func(cmd *cobra.Command, args []string) error {
//package命令入口
//该命令必需且只有一个参数,指明输出文件
if len(args) != 1 {
return fmt.Errorf("output file not specified or invalid number of args (filename should be the only arg)")
}
//提供获取ChaincodeDeploymentSpec接口
if cdsFact == nil {
cdsFact = defaultCDSFactory
}
return chaincodePackage(cmd, args, cdsFact, cf)
},
}
//加入以下标记
flagList := []string{
"lang",
"ctor",
"path",
"name",
"version",
}
attachFlags(chaincodePackageCmd, flagList)
//额外绑定以下标记
chaincodePackageCmd.Flags().BoolVarP(&createSignedCCDepSpec, "cc-package", "s", false, "create CC deployment spec for owner endorsements instead of raw CC deployment spec")
chaincodePackageCmd.Flags().BoolVarP(&signCCDepSpec, "sign", "S", false, "if creating CC deployment spec package for owner endorsements, also sign it with local MSP")
chaincodePackageCmd.Flags().StringVarP(&instantiationPolicy, "instantiate-policy", "i", "", "instantiation policy for the chaincode")
return chaincodePackageCmd
}
func chaincodePackage(cmd *cobra.Command, args []string, cdsFact ccDepSpecFactory, cf *ChaincodeCmdFactory) error {
if cdsFact == nil {
return fmt.Errorf("Error chaincode deployment spec factory not specified")
}
var err error
//如果ChaincodeCmdFactory为空,者初始化
if cf == nil {
cf, err = InitCmdFactory(false, false)
if err != nil {
return err
}
}
//获取ChaincodeSpec
spec, err := getChaincodeSpec(cmd)
if err != nil {
return err
}
//cdsFact的定义
//type ccDepSpecFactory func(spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error)
//GO语言接口机制的不常见特性。它不仅是一个函数类型,还拥有自己的方法
//ccDepSpecFactory是一个让函数值满足接口的一个适配器
//获取ChaincodeDeploymentSpec
cds, err := cdsFact(spec)
if err != nil {
return fmt.Errorf("Error getting chaincode code %s: %s", chainFuncName, err)
}
var bytesToWrite []byte
//命令绑定为false
if createSignedCCDepSpec {
bytesToWrite, err = getChaincodeInstallPackage(cds, cf)
if err != nil {
return err
}
} else {
//获取到chaincode字节流
bytesToWrite = utils.MarshalOrPanic(cds)
}
logger.Debugf("Packaged chaincode into deployment spec of size <%d>, with args = %v", len(bytesToWrite), args)
//将chaincode字节流写入指定参数
fileToWrite := args[0]
err = ioutil.WriteFile(fileToWrite, bytesToWrite, 0700)
if err != nil {
logger.Errorf("Failed writing deployment spec to file [%s]: [%s]", fileToWrite, err)
return err
}
return err
}
func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) {
spec := &pb.ChaincodeSpec{}
if err := checkChaincodeCmdParams(cmd); err != nil {
return spec, err
}
//将传入的参数反序列化
input := &pb.ChaincodeInput{}
if err := json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil {
return spec, fmt.Errorf("Chaincode argument error: %s", err)
}
//语言判断,chaincode不可为java
chaincodeLang = strings.ToUpper(chaincodeLang)
if pb.ChaincodeSpec_Type_value[chaincodeLang] == int32(pb.ChaincodeSpec_JAVA) {
return nil, fmt.Errorf("Java chaincode is work-in-progress and disabled")
}
//返回ChaincodeSpec
spec = &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]),
ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion},
Input: input,
}
return spec, nil
}
func checkChaincodeCmdParams(cmd *cobra.Command) error {
//验证链码名称是否为空
if chaincodeName == common.UndefinedParamValue {
return fmt.Errorf("Must supply value for %s name parameter.", chainFuncName)
}
//验证链码版本
if cmd.Name() == instantiateCmdName || cmd.Name() == installCmdName ||
cmd.Name() == upgradeCmdName || cmd.Name() == packageCmdName {
if chaincodeVersion == common.UndefinedParamValue {
return fmt.Errorf("Chaincode version is not provided for %s", cmd.Name())
}
}
//验证是否使用escc
if escc != common.UndefinedParamValue {
logger.Infof("Using escc %s", escc)
} else {
logger.Info("Using default escc")
escc = "escc"
}
//验证是否使用vscc
if vscc != common.UndefinedParamValue {
logger.Infof("Using vscc %s", vscc)
} else {
logger.Info("Using default vscc")
vscc = "vscc"
}
//验证策略是否有效
if policy != common.UndefinedParamValue {
p, err := cauthdsl.FromString(policy)
if err != nil {
return fmt.Errorf("Invalid policy %s", policy)
}
policyMarhsalled = putils.MarshalOrPanic(p)
}
//根据传入的参数,进行序列化
if chaincodeCtorJSON != "{}" {
var f interface{}
err := json.Unmarshal([]byte(chaincodeCtorJSON), &f)
if err != nil {
return fmt.Errorf("Chaincode argument error: %s", err)
}
m := f.(map[string]interface{})
sm := make(map[string]interface{})
for k := range m {
sm[strings.ToLower(k)] = m[k]
}
//获取到参数,和执行的方法invoke或query
_, argsPresent := sm["args"]
_, funcPresent := sm["function"]
if !argsPresent || (len(m) == 2 && !funcPresent) || len(m) > 2 {
return errors.New("Non-empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'")
}
} else {
if cmd == nil || (cmd != chaincodeInstallCmd && cmd != chaincodePackageCmd) {
return errors.New("Empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'")
}
}
return nil
}