Skip to content

Commit 7ed9533

Browse files
committed
Allow deploying Java chaincode from remote git repositories
Currently only local deployment of Java chaincode is supported. Change-Id: Id7651f6eeae232260f76f2280b935f7c9a15d169 Signed-off-by: Satheesh Kathamuthu <[email protected]>
1 parent 4b13232 commit 7ed9533

File tree

5 files changed

+217
-32
lines changed

5 files changed

+217
-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/xspeedcruiser/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
//generateHashcode gets hashcode of the code under path. If path is a HTTP(s) url
@@ -106,13 +123,9 @@ func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) {
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 := ""
+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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+
// TODO Change reference to an official test repo once established
34+
// Same repo being used in behave tests
35+
36+
srcPath1, err := getCodeFromHTTP("https://github.com/xspeedcruiser/javachaincodemvn")
37+
srcPath2, err := getCodeFromHTTP("https://github.com/xspeedcruiser/javachaincode")
38+
39+
if err != nil {
40+
t.Logf("Error getting code from remote repo %s", err)
41+
t.Fail()
42+
}
43+
44+
defer func() {
45+
os.RemoveAll(srcPath1)
46+
}()
47+
defer func() {
48+
os.RemoveAll(srcPath2)
49+
}()
50+
hash1, err := hashFilesInDir(srcPath1, srcPath1, hash, nil)
51+
if err != nil {
52+
t.Logf("Error getting code %s", err)
53+
t.Fail()
54+
}
55+
hash2, err := hashFilesInDir(srcPath2, srcPath2, hash, nil)
56+
if err != nil {
57+
t.Logf("Error getting code %s", err)
58+
t.Fail()
59+
}
60+
if bytes.Compare(hash1, hash2) == 0 {
61+
t.Logf("Hash should be different for 2 different remote repos")
62+
t.Fail()
63+
}
64+
65+
}
66+
func TestHashSameRemoteRepo(t *testing.T) {
67+
b := []byte("firstcontent")
68+
hash := util.ComputeCryptoHash(b)
69+
70+
srcPath1, err := getCodeFromHTTP("https://github.com/xspeedcruiser/javachaincodemvn")
71+
srcPath2, err := getCodeFromHTTP("https://github.com/xspeedcruiser/javachaincodemvn")
72+
73+
if err != nil {
74+
t.Logf("Error getting code from remote repo %s", err)
75+
t.Fail()
76+
}
77+
78+
defer func() {
79+
os.RemoveAll(srcPath1)
80+
}()
81+
defer func() {
82+
os.RemoveAll(srcPath2)
83+
}()
84+
hash1, err := hashFilesInDir(srcPath1, srcPath1, hash, nil)
85+
if err != nil {
86+
t.Logf("Error getting code %s", err)
87+
t.Fail()
88+
}
89+
hash2, err := hashFilesInDir(srcPath2, srcPath2, hash, nil)
90+
if err != nil {
91+
t.Logf("Error getting code %s", err)
92+
t.Fail()
93+
}
94+
if bytes.Compare(hash1, hash2) != 0 {
95+
t.Logf("Hash should be same across multiple downloads")
96+
t.Fail()
97+
}
98+
}
99+
100+
func TestHashOverLocalDir(t *testing.T) {
101+
b := []byte("firstcontent")
102+
hash := util.ComputeCryptoHash(b)
103+
104+
hash, err := hashFilesInDir(".", "../golang/hashtestfiles", hash, nil)
105+
106+
if err != nil {
107+
t.Fail()
108+
t.Logf("error : %s", err)
109+
}
110+
111+
expectedHash := "7b3b2193bed2bd7c19300aa5d6d7f6bb4d61602e4978a78bc08028379cb5cf0ed877bd9db3e990230e8bf6c974edd765f3027f061fd8657d30fc858a676a6f4a"
112+
113+
computedHash := hex.EncodeToString(hash[:])
114+
115+
if expectedHash != computedHash {
116+
t.Fail()
117+
t.Logf("Hash expected to be unchanged")
118+
}
119+
}

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"
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)