diff --git a/fabric-client/lib/Packager.js b/fabric-client/lib/Packager.js index e5f78a2880..9c3677f6e3 100644 --- a/fabric-client/lib/Packager.js +++ b/fabric-client/lib/Packager.js @@ -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); diff --git a/fabric-client/lib/packager/Golang.js b/fabric-client/lib/packager/Golang.js index b89ef4b0d8..ff1ab77e3e 100644 --- a/fabric-client/lib/packager/Golang.js +++ b/fabric-client/lib/packager/Golang.js @@ -13,6 +13,7 @@ */ 'use strict'; +const fs = require('fs-extra'); const klaw = require('klaw'); const path = require('path'); const sbuf = require('stream-buffers'); @@ -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". @@ -39,11 +41,17 @@ 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, @@ -51,29 +59,34 @@ class GolangPackager extends BasePackager { // 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) @@ -81,7 +94,7 @@ class GolangPackager extends BasePackager { 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 }; diff --git a/fabric-client/test/Package.js b/fabric-client/test/Package.js index b954a81e85..5241a6ed8d 100644 --- a/fabric-client/test/Package.js +++ b/fabric-client/test/Package.js @@ -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' @@ -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', diff --git a/fabric-client/test/data/gomodule-contract-metadata.cds b/fabric-client/test/data/gomodule-contract-metadata.cds new file mode 100755 index 0000000000..5a42a9878d Binary files /dev/null and b/fabric-client/test/data/gomodule-contract-metadata.cds differ diff --git a/fabric-client/test/data/gomodule-contract.cds b/fabric-client/test/data/gomodule-contract.cds new file mode 100755 index 0000000000..381a4686e8 Binary files /dev/null and b/fabric-client/test/data/gomodule-contract.cds differ diff --git a/fabric-client/test/data/gomodule-contract/chaincode.go b/fabric-client/test/data/gomodule-contract/chaincode.go new file mode 100644 index 0000000000..93993d60b1 --- /dev/null +++ b/fabric-client/test/data/gomodule-contract/chaincode.go @@ -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) +} diff --git a/fabric-client/test/data/gomodule-contract/chaincode_test.go b/fabric-client/test/data/gomodule-contract/chaincode_test.go new file mode 100644 index 0000000000..07b0236c86 --- /dev/null +++ b/fabric-client/test/data/gomodule-contract/chaincode_test.go @@ -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) + } +} diff --git a/fabric-client/test/data/gomodule-contract/go.mod b/fabric-client/test/data/gomodule-contract/go.mod new file mode 100644 index 0000000000..76a4afa4fa --- /dev/null +++ b/fabric-client/test/data/gomodule-contract/go.mod @@ -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 +) diff --git a/fabric-client/test/data/gomodule-contract/go.sum b/fabric-client/test/data/gomodule-contract/go.sum new file mode 100644 index 0000000000..736cf08936 --- /dev/null +++ b/fabric-client/test/data/gomodule-contract/go.sum @@ -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= diff --git a/fabric-client/test/data/gomodule-contract/main.go b/fabric-client/test/data/gomodule-contract/main.go new file mode 100644 index 0000000000..4055ebd5e0 --- /dev/null +++ b/fabric-client/test/data/gomodule-contract/main.go @@ -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) + } +} diff --git a/fabric-client/test/data/packager.sh b/fabric-client/test/data/packager.sh index b535f66e0e..12d407605e 100755 --- a/fabric-client/test/data/packager.sh +++ b/fabric-client/test/data/packager.sh @@ -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 diff --git a/test/unit/packager.js b/test/unit/packager.js index aeb0c3a2b8..7c1e565332 100644 --- a/test/unit/packager.js +++ b/test/unit/packager.js @@ -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');