Skip to content

Commit

Permalink
Add packaging support for go module chaincode
Browse files Browse the repository at this point in the history
When a go.mod is present at the root of the chaincode path, package
directory as a module instead of an import path relative to GOPATH.

FABN-1375

Change-Id: Ifcf6436a856fa671b1fd1f00af40aa62925d4b7c
Signed-off-by: Matthew Sykes <[email protected]>
  • Loading branch information
sykesm committed Sep 5, 2019
1 parent 0a273c9 commit 1a4f191
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 20 deletions.
2 changes: 1 addition & 1 deletion fabric-client/lib/Packager.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ module.exports.package = async function (chaincodePath, chaincodeType, devmode,
handler = new Java();
break;
default:
handler = new Golang(['.go', '.c', '.h', '.s']);
handler = new Golang(['.go', '.c', '.h', '.s', '.mod', '.sum']);
}

return handler.package(chaincodePath, metadataPath, goPath);
Expand Down
41 changes: 27 additions & 14 deletions fabric-client/lib/packager/Golang.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
'use strict';

const fs = require('fs-extra');
const klaw = require('klaw');
const path = require('path');
const sbuf = require('stream-buffers');
Expand All @@ -26,7 +27,8 @@ class GolangPackager extends BasePackager {

/**
* Package chaincode source and metadata for deployment.
* @param {string} chaincodePath The Go package name. The package must be located under GOPATH/src.
* @param {string} chaincodePath The Go package name or path to Go module. If a package name, it must be
* located under GOPATH/src. If a path to a Go module, a go.mod must be present.
* @param {string} [metadataPath[] Optional. The path to the top-level directory containing metadata descriptors.
* @param {string} [goPath] Optional. The GOPATH setting used when building the chaincode. This will
* default to the environment setting "GOPATH".
Expand All @@ -39,49 +41,60 @@ class GolangPackager extends BasePackager {
_goPath = process.env.GOPATH;
}

// Compose the path to the go.mod candidate
const isModule = fs.existsSync(path.join(chaincodePath, 'go.mod'));

// Compose the path to the chaincode project directory
const projDir = path.join(_goPath, 'src', chaincodePath);
const projDir = isModule ? chaincodePath : path.join(_goPath, 'src', chaincodePath);
const basePath = isModule ? chaincodePath : _goPath;

logger.debug('packaging GOLANG chaincodePath from %s', chaincodePath);
logger.debug('packaging GOLANG isModule %s', isModule);
logger.debug('packaging GOLANG _goPath from %s', _goPath);
logger.debug('packaging GOLANG basePath from %s', basePath);
logger.debug('packaging GOLANG projDir from %s', projDir);

// We generate the tar in two phases: First grab a list of descriptors,
// and then pack them into an archive. While the two phases aren't
// strictly necessary yet, they pave the way for the future where we
// will need to assemble sources from multiple packages

const buffer = new sbuf.WritableStreamBuffer();

const srcDescriptors = await this.findSource(_goPath, projDir);

let descriptors = srcDescriptors;
const srcDescriptors = await this.findSource(basePath, projDir);
let descriptors = srcDescriptors.map(desc => {
if (isModule) {
desc.name = path.join('src', desc.name);
}
return desc;
});
if (metadataPath) {
const metaDescriptors = await super.findMetadataDescriptors(metadataPath);
descriptors = srcDescriptors.concat(metaDescriptors);
}

const buffer = new sbuf.WritableStreamBuffer();
await super.generateTarGz(descriptors, buffer);
return buffer.getContents();
}

/**
* Given an input 'filePath', recursively parse the filesystem for any files
* that fit the criteria for being valid golang source (ISREG + (*.(go|c|h)))
* As a convenience, we also formulate a tar-friendly "name" for each file
* based on relative position to 'goPath'.
* @param goPath
* Given an input 'filePath', recursively parse the filesystem for any
* files that fit the criteria for being valid golang source (ISREG +
* (*.(go|c|h|s|mod|sum))) As a convenience, we also formulate a
* tar-friendly "name" for each file based on relative position to
* 'basePath'.
* @param basePath
* @param filePath
* @returns {Promise}
*/
findSource(goPath, filePath) {
findSource(basePath, filePath) {
return new Promise((resolve, reject) => {
const descriptors = [];
klaw(filePath)
.on('data', (entry) => {

if (entry.stats.isFile() && super.isSource(entry.path)) {
const desc = {
name: path.relative(goPath, entry.path).split('\\').join('/'), // for windows style paths
name: path.relative(basePath, entry.path).split('\\').join('/'), // for windows style paths
fqp: entry.path
};

Expand Down
10 changes: 9 additions & 1 deletion fabric-client/test/Package.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ const chai = require('chai');
chai.should();
chai.use(require('chai-as-promised'));

const languages = ['golang', 'javascript', 'typescript', 'java'];
const languages = ['golang', 'gomodule', 'javascript', 'typescript', 'java'];

const languageToType = {
golang: 'golang',
gomodule: 'golang',
javascript: 'node',
typescript: 'node',
java: 'java'
Expand All @@ -29,6 +30,13 @@ const fileNames = {
'src/golang-contract/chaincode_test.go',
'src/golang-contract/main.go'
],
gomodule: [
'src/chaincode.go',
'src/chaincode_test.go',
'src/go.mod',
'src/go.sum',
'src/main.go'
],
javascript: [
'src/.editorconfig',
'src/.eslintignore',
Expand Down
Binary file not shown.
Binary file added fabric-client/test/data/gomodule-contract.cds
Binary file not shown.
32 changes: 32 additions & 0 deletions fabric-client/test/data/gomodule-contract/chaincode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright 2018 IBM All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/

package main

import (
"fmt"

"github.com/hyperledger/fabric-chaincode-go/shim"
sc "github.com/hyperledger/fabric-protos-go/peer"
)

// Chaincode is the definition of the chaincode structure.
type Chaincode struct {
}

// Init is called when the chaincode is instantiated by the blockchain network.
func (cc *Chaincode) Init(stub shim.ChaincodeStubInterface) sc.Response {
fcn, params := stub.GetFunctionAndParameters()
fmt.Println("Init()", fcn, params)
return shim.Success(nil)
}

// Invoke is called as a result of an application request to run the chaincode.
func (cc *Chaincode) Invoke(stub shim.ChaincodeStubInterface) sc.Response {
fcn, params := stub.GetFunctionAndParameters()
fmt.Println("Invoke()", fcn, params)
return shim.Success(nil)
}
36 changes: 36 additions & 0 deletions fabric-client/test/data/gomodule-contract/chaincode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2018 IBM All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/

package main

import (
"testing"

"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-chaincode-go/shimtest"
)

func TestInit(t *testing.T) {
cc := new(Chaincode)
stub := shimtest.NewMockStub("chaincode", cc)
res := stub.MockInit("1", [][]byte{[]byte("initFunc")})
if res.Status != shim.OK {
t.Error("Init failed", res.Status, res.Message)
}
}

func TestInvoke(t *testing.T) {
cc := new(Chaincode)
stub := shimtest.NewMockStub("chaincode", cc)
res := stub.MockInit("1", [][]byte{[]byte("initFunc")})
if res.Status != shim.OK {
t.Error("Init failed", res.Status, res.Message)
}
res = stub.MockInvoke("1", [][]byte{[]byte("invokeFunc")})
if res.Status != shim.OK {
t.Error("Invoke failed", res.Status, res.Message)
}
}
8 changes: 8 additions & 0 deletions fabric-client/test/data/gomodule-contract/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module module-chaincode

go 1.12

require (
github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85
github.com/hyperledger/fabric-protos-go v0.0.0-20190903152505-b42e76e96ddd
)
59 changes: 59 additions & 0 deletions fabric-client/test/data/gomodule-contract/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 h1:VEm3tPRTCzq3J/1XpVERh1PbOSnshUVwx2G5s3cLiTw=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85/go.mod h1:HZK6PKLWrvdD/t0oSLiyaRaUM6fZ7qjJuOlb0zrn0mo=
github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20190903152505-b42e76e96ddd h1:gRFH6vGCQNg98EKGNMBSg0evVQPLF2I4zFezFERQBJM=
github.com/hyperledger/fabric-protos-go v0.0.0-20190903152505-b42e76e96ddd/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ=
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
16 changes: 16 additions & 0 deletions fabric-client/test/data/gomodule-contract/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright 2018 IBM All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/

package main

import "github.com/hyperledger/fabric-chaincode-go/shim"

func main() {
err := shim.Start(new(Chaincode))
if err != nil {
panic(err)
}
}
11 changes: 7 additions & 4 deletions fabric-client/test/data/packager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
# SPDX-License-Identifier: Apache-2.0
#
set -ex
cd $(dirname $0)
export GOPATH=$PWD/go
peer chaincode package -l golang -n my-contract -v 1.2.3 -p golang-contract golang-contract.cds
cd "$(dirname "$0")"
GOPATH=$PWD/go peer chaincode package -l golang -n my-contract -v 1.2.3 -p golang-contract golang-contract.cds
cp -rf META-INF go/src/golang-contract/
peer chaincode package -l golang -n my-contract -v 1.2.3 -p golang-contract golang-contract-metadata.cds
GOPATH=$PWD/go peer chaincode package -l golang -n my-contract -v 1.2.3 -p golang-contract golang-contract-metadata.cds
rm -rf go/src/golang-contract/META-INF
peer chaincode package -l golang -n my-contract -v 1.2.3 -p gomodule-contract gomodule-contract.cds
cp -rf META-INF gomodule-contract/
peer chaincode package -l golang -n my-contract -v 1.2.3 -p gomodule-contract gomodule-contract-metadata.cds
rm -rf gomodule-contract/META-INF
peer chaincode package -l node -n my-contract -v 1.2.3 -p javascript-contract javascript-contract.cds
cp -rf META-INF javascript-contract/
peer chaincode package -l node -n my-contract -v 1.2.3 -p javascript-contract javascript-contract-metadata.cds
Expand Down
1 change: 1 addition & 0 deletions test/unit/packager.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ test('\n\n** Golang Packager tests **\n\n', (t) => {
}

const checkPath = path.join(destDir, 'src', 'github.com', 'example_cc', 'example_cc.go');
console.log('***** tmpFile :: ' + tmpFile);
console.log('***** checkPath :: ' + checkPath);
t.equal(fs.existsSync(checkPath), true, 'The tar.gz file produced by Packager.package() has the "chaincode/github.com/example_cc/example_cc.go" file');

Expand Down

0 comments on commit 1a4f191

Please sign in to comment.