Skip to content

Commit 80140c9

Browse files
committed
Allow deploying Java chaincode from remote git repo
Currently only local deployment of Java chaincode is supported. Change-Id: Ib22ec81e7d1df137ee5ecd0f92353efdcad78d25 Signed-off-by: Satheesh Kathamuthu <[email protected]>
1 parent 2570f8f commit 80140c9

File tree

5 files changed

+222
-32
lines changed

5 files changed

+222
-32
lines changed

bddtests/java_shim.feature

+37
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,40 @@ Scenario: java RangeExample chaincode single peer
173173
|arg1|
174174
| 2 |
175175
Then I should get a JSON response with "result.message" = "No record found !"
176+
Scenario: Java chaincode example from remote git repository
177+
Given we compose "docker-compose-1.yml"
178+
When requesting "/chain" from "vp0"
179+
Then I should get a JSON response with "height" = "1"
180+
# TODO Needs to be replaced with an official test repo in the future.
181+
When I deploy lang chaincode "http://github.com/hyperledger/fabric-test-resources/javachaincode" of "JAVA" with ctor "init" to "vp0"
182+
| arg1 | arg2 | arg3 | arg4 |
183+
| a | 100 | b | 200 |
184+
Then I should have received a chaincode name
185+
Then I wait up to "300" seconds for transaction to be committed to all peers
186+
187+
When requesting "/chain" from "vp0"
188+
Then I should get a JSON response with "height" = "2"
189+
190+
When I query chaincode "SimpleSample" function name "query" on "vp0":
191+
|arg1|
192+
| a |
193+
Then I should get a JSON response with "result.message" = "{'Name':'a','Amount':'100'}"
194+
195+
When I invoke chaincode "SimpleSample" function name "transfer" on "vp0"
196+
|arg1|arg2|arg3|
197+
| a | b | 10 |
198+
Then I should have received a transactionID
199+
Then I wait up to "25" seconds for transaction to be committed to all peers
200+
201+
When requesting "/chain" from "vp0"
202+
Then I should get a JSON response with "height" = "3"
203+
204+
When I query chaincode "SimpleSample" function name "query" on "vp0":
205+
|arg1|
206+
| a |
207+
Then I should get a JSON response with "result.message" = "{'Name':'a','Amount':'90'}"
208+
209+
When I query chaincode "SimpleSample" function name "query" on "vp0":
210+
|arg1|
211+
| b |
212+
Then I should get a JSON response with "result.message" = "{'Name':'b','Amount':'210'}"

core/chaincode/platforms/java/hash.go

+21-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io/ioutil"
99
"os"
10+
"os/exec"
1011
"strings"
1112

1213
"github.com/golang/protobuf/proto"
@@ -71,8 +72,24 @@ func isCodeExist(tmppath string) error {
7172
}
7273

7374
func getCodeFromHTTP(path string) (codegopath string, err error) {
74-
//TODO
75-
return "", nil
75+
76+
var tmp string
77+
tmp, err = ioutil.TempDir("", "javachaincode")
78+
79+
if err != nil {
80+
return "", fmt.Errorf("Error creating temporary file: %s", err)
81+
}
82+
var out bytes.Buffer
83+
84+
cmd := exec.Command("git", "clone", path, tmp)
85+
cmd.Stderr = &out
86+
cmderr := cmd.Run()
87+
if cmderr != nil {
88+
return "", fmt.Errorf("Error cloning git repository %s", cmderr)
89+
}
90+
91+
return tmp, nil
92+
7693
}
7794

7895
//collectChaincodeFiles collects chaincode files and generates hashcode for the
@@ -106,13 +123,9 @@ func collectChaincodeFiles(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, erro
106123
}()
107124

108125
var err error
109-
if strings.HasPrefix(codepath, "http://") {
110-
ishttp = true
111-
codepath = codepath[7:]
112-
codepath, err = getCodeFromHTTP(codepath)
113-
} else if strings.HasPrefix(codepath, "https://") {
126+
if strings.HasPrefix(codepath, "http://") ||
127+
strings.HasPrefix(codepath, "https://") {
114128
ishttp = true
115-
codepath = codepath[8:]
116129
codepath, err = getCodeFromHTTP(codepath)
117130
} else if !strings.HasPrefix(codepath, "/") {
118131
wd := ""
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package java
18+
19+
import (
20+
"testing"
21+
22+
"encoding/hex"
23+
24+
"github.com/hyperledger/fabric/core/util"
25+
26+
"bytes"
27+
"os"
28+
)
29+
30+
func TestHashDiffRemoteRepo(t *testing.T) {
31+
b := []byte("firstcontent")
32+
hash := util.ComputeCryptoHash(b)
33+
34+
srcPath1, err := getCodeFromHTTP("https://github.com/hyperledger/fabric-test-resources/")
35+
if err != nil {
36+
t.Logf("Error getting code from remote repo %s", err)
37+
t.Fail()
38+
}
39+
srcPath2, err := getCodeFromHTTP("https://github.com/hyperledger/fabric-sdk-java")
40+
if err != nil {
41+
t.Logf("Error getting code from remote repo %s", err)
42+
t.Fail()
43+
}
44+
45+
defer func() {
46+
os.RemoveAll(srcPath1)
47+
}()
48+
defer func() {
49+
os.RemoveAll(srcPath2)
50+
}()
51+
hash1, err := hashFilesInDir(srcPath1, srcPath1, hash, nil)
52+
if err != nil {
53+
t.Logf("Error getting code %s", err)
54+
t.Fail()
55+
}
56+
hash2, err := hashFilesInDir(srcPath2, srcPath2, hash, nil)
57+
if err != nil {
58+
t.Logf("Error getting code %s", err)
59+
t.Fail()
60+
}
61+
if bytes.Compare(hash1, hash2) == 0 {
62+
t.Logf("Hash should be different for 2 different remote repos")
63+
t.Fail()
64+
}
65+
66+
}
67+
func TestHashSameRemoteRepo(t *testing.T) {
68+
b := []byte("firstcontent")
69+
hash := util.ComputeCryptoHash(b)
70+
71+
srcPath1, err := getCodeFromHTTP("https://github.com/hyperledger/fabric-test-resources")
72+
if err != nil {
73+
t.Logf("Error getting code from remote repo %s", err)
74+
t.Fail()
75+
}
76+
srcPath2, err := getCodeFromHTTP("https://github.com/hyperledger/fabric-test-resources")
77+
78+
if err != nil {
79+
t.Logf("Error getting code from remote repo %s", err)
80+
t.Fail()
81+
}
82+
83+
defer func() {
84+
os.RemoveAll(srcPath1)
85+
}()
86+
defer func() {
87+
os.RemoveAll(srcPath2)
88+
}()
89+
hash1, err := hashFilesInDir(srcPath1, srcPath1, hash, nil)
90+
if err != nil {
91+
t.Logf("Error getting code %s", err)
92+
t.Fail()
93+
}
94+
hash2, err := hashFilesInDir(srcPath2, srcPath2, hash, nil)
95+
if err != nil {
96+
t.Logf("Error getting code %s", err)
97+
t.Fail()
98+
}
99+
if bytes.Compare(hash1, hash2) != 0 {
100+
t.Logf("Hash should be same across multiple downloads")
101+
t.Fail()
102+
}
103+
}
104+
105+
func TestHashOverLocalDir(t *testing.T) {
106+
b := []byte("firstcontent")
107+
hash := util.ComputeCryptoHash(b)
108+
109+
hash, err := hashFilesInDir(".", "../golang/hashtestfiles", hash, nil)
110+
111+
if err != nil {
112+
t.Fail()
113+
t.Logf("error : %s", err)
114+
}
115+
116+
expectedHash := "7b3b2193bed2bd7c19300aa5d6d7f6bb4d61602e4978a78bc08028379cb5cf0ed877bd9db3e990230e8bf6c974edd765f3027f061fd8657d30fc858a676a6f4a"
117+
118+
computedHash := hex.EncodeToString(hash[:])
119+
120+
if expectedHash != computedHash {
121+
t.Fail()
122+
t.Logf("Hash expected to be unchanged")
123+
}
124+
}

core/chaincode/platforms/java/package.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"strings"
77
"time"
88

9+
"os"
10+
911
cutil "github.com/hyperledger/fabric/core/container/util"
1012
pb "github.com/hyperledger/fabric/protos/peer"
1113
"github.com/spf13/viper"
@@ -16,17 +18,20 @@ import (
1618
func writeChaincodePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error {
1719

1820
var urlLocation string
19-
if strings.HasPrefix(spec.ChaincodeID.Path, "http://") {
20-
urlLocation = spec.ChaincodeID.Path[7:]
21-
} else if strings.HasPrefix(spec.ChaincodeID.Path, "https://") {
22-
urlLocation = spec.ChaincodeID.Path[8:]
21+
var err error
22+
23+
if strings.HasPrefix(spec.ChaincodeID.Path, "http://") ||
24+
strings.HasPrefix(spec.ChaincodeID.Path, "https://") {
25+
26+
urlLocation, err = getCodeFromHTTP(spec.ChaincodeID.Path)
27+
defer func() {
28+
os.RemoveAll(urlLocation)
29+
}()
30+
if err != nil {
31+
return err
32+
}
2333
} else {
2434
urlLocation = spec.ChaincodeID.Path
25-
// if !strings.HasPrefix(urlLocation, "/") {
26-
// wd := ""
27-
// wd, _ = os.Getwd()
28-
// urlLocation = wd + "/" + urlLocation
29-
// }
3035
}
3136

3237
if urlLocation == "" {
@@ -36,7 +41,6 @@ func writeChaincodePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error {
3641
if strings.LastIndex(urlLocation, "/") == len(urlLocation)-1 {
3742
urlLocation = urlLocation[:len(urlLocation)-1]
3843
}
39-
urlLocation = urlLocation[strings.LastIndex(urlLocation, "/")+1:]
4044

4145
var dockerFileContents string
4246
var buf []string
@@ -58,7 +62,7 @@ func writeChaincodePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error {
5862
var zeroTime time.Time
5963
tw.WriteHeader(&tar.Header{Name: "Dockerfile", Size: dockerFileSize, ModTime: zeroTime, AccessTime: zeroTime, ChangeTime: zeroTime})
6064
tw.Write([]byte(dockerFileContents))
61-
err := cutil.WriteJavaProjectToPackage(tw, spec.ChaincodeID.Path)
65+
err = cutil.WriteJavaProjectToPackage(tw, urlLocation)
6266
if err != nil {
6367
return fmt.Errorf("Error writing Chaincode package contents: %s", err)
6468
}

core/container/util/writer.go

+25-13
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,21 @@ import (
3232

3333
var vmLogger = logging.MustGetLogger("container")
3434

35-
var fileTypes = map[string]bool{
35+
var includeFileTypes = map[string]bool{
3636
".c": true,
3737
".h": true,
3838
".go": true,
3939
".yaml": true,
4040
".json": true,
4141
}
42-
var javaFileTypes = map[string]bool{
43-
".java": true,
44-
".properties": true,
45-
".gradle": true,
42+
43+
// These filetypes are excluded while creating the tar package sent to Docker
44+
// Generated .class and other temporary files can be excluded
45+
var javaExcludeFileTypes = map[string]bool{
46+
".class": true,
4647
}
4748

48-
func WriteFolderToTarPackage(tw *tar.Writer, srcPath string, excludeDir string, includeFileTypeMap map[string]bool) error {
49+
func WriteFolderToTarPackage(tw *tar.Writer, srcPath string, excludeDir string, includeFileTypeMap map[string]bool, excludeFileTypeMap map[string]bool) error {
4950
rootDirectory := srcPath
5051
vmLogger.Infof("rootDirectory = %s", rootDirectory)
5152

@@ -75,11 +76,20 @@ func WriteFolderToTarPackage(tw *tar.Writer, srcPath string, excludeDir string,
7576
if len(path[rootDirLen:]) == 0 {
7677
return nil
7778
}
78-
79-
// we only want 'fileTypes' source files at this point
8079
ext := filepath.Ext(path)
81-
if _, ok := includeFileTypeMap[ext]; ok != true {
82-
return nil
80+
81+
if includeFileTypeMap != nil {
82+
// we only want 'fileTypes' source files at this point
83+
if _, ok := includeFileTypeMap[ext]; ok != true {
84+
return nil
85+
}
86+
}
87+
88+
//exclude the given file types
89+
if excludeFileTypeMap != nil {
90+
if exclude, ok := excludeFileTypeMap[ext]; ok && exclude {
91+
return nil
92+
}
8393
}
8494

8595
newPath := fmt.Sprintf("src%s", path[rootDirLen:])
@@ -89,7 +99,6 @@ func WriteFolderToTarPackage(tw *tar.Writer, srcPath string, excludeDir string,
8999
if err != nil {
90100
return fmt.Errorf("Error writing file to package: %s", err)
91101
}
92-
93102
return nil
94103
}
95104

@@ -109,7 +118,7 @@ func WriteGopathSrc(tw *tar.Writer, excludeDir string) error {
109118
rootDirectory := filepath.Join(gopath, "src")
110119
vmLogger.Infof("rootDirectory = %s", rootDirectory)
111120

112-
if err := WriteFolderToTarPackage(tw, rootDirectory, excludeDir, fileTypes); err != nil {
121+
if err := WriteFolderToTarPackage(tw, rootDirectory, excludeDir, includeFileTypes, nil); err != nil {
113122
vmLogger.Errorf("Error writing folder to tar package %s", err)
114123
return err
115124
}
@@ -130,9 +139,12 @@ func WriteGopathSrc(tw *tar.Writer, excludeDir string) error {
130139
return nil
131140
}
132141

142+
//Package Java project to tar file from the source path
133143
func WriteJavaProjectToPackage(tw *tar.Writer, srcPath string) error {
134144

135-
if err := WriteFolderToTarPackage(tw, srcPath, "", javaFileTypes); err != nil {
145+
vmLogger.Debugf("Packaging Java project from path %s", srcPath)
146+
147+
if err := WriteFolderToTarPackage(tw, srcPath, "", nil, javaExcludeFileTypes); err != nil {
136148

137149
vmLogger.Errorf("Error writing folder to tar package %s", err)
138150
return err

0 commit comments

Comments
 (0)