Skip to content

Commit fe28902

Browse files
committed
2.5 making the go chaincode build independent of the go fabric version
Signed-off-by: Fedor Partanskiy <fredprtnsk@gmail.com>
1 parent 2fbd79e commit fe28902

25 files changed

Lines changed: 4864 additions & 42 deletions

File tree

core/chaincode/platforms/golang/platform.go

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/hyperledger/fabric/internal/ccmetadata"
2727
"github.com/pkg/errors"
2828
"github.com/spf13/viper"
29+
"golang.org/x/mod/modfile"
30+
"golang.org/x/mod/semver"
2931
)
3032

3133
// Platform for chaincodes written in Go
@@ -207,6 +209,7 @@ func getLDFlagsOpts() string {
207209

208210
var buildScript = `
209211
set -e
212+
%[3]s
210213
if [ -f "/chaincode/input/src/go.mod" ] && [ -d "/chaincode/input/src/vendor" ]; then
211214
cd /chaincode/input/src
212215
GO111MODULE=on go build -v -mod=vendor %[1]s -o /chaincode/output/chaincode %[2]s
@@ -225,7 +228,21 @@ fi
225228
echo Done!
226229
`
227230

228-
func (p *Platform) DockerBuildOptions(path string) (util.DockerBuildOptions, error) {
231+
func (p *Platform) DockerBuildOptions(path string, goVer, osVer string, archVer string) (util.DockerBuildOptions, error) {
232+
// determine the presence of go.mod and the version of go in go.mod (go, toolchain)
233+
var insNewGo string
234+
if newGoVer, needGo := getNeedVersionGo(path, goVer); needGo {
235+
// preparing the insert for the go update
236+
insNewGoScript := `
237+
curl -sLO https://go.dev/dl/go%[1]s.%[2]s-%[3]s.tar.gz
238+
rm -rf /usr/local/go
239+
tar -C /usr/local -xzfv "go%[1]s.%[2]s-%[3]s.tar.gz"
240+
rm "go%[1]s.%[2]s-%[3]s.tar.gz"
241+
go version
242+
`
243+
insNewGo = fmt.Sprintf(insNewGoScript, newGoVer, osVer, archVer)
244+
}
245+
229246
env := []string{}
230247
for _, key := range []string{"GOPROXY", "GOSUMDB"} {
231248
if val, ok := os.LookupEnv(key); ok {
@@ -238,11 +255,54 @@ func (p *Platform) DockerBuildOptions(path string) (util.DockerBuildOptions, err
238255
}
239256
ldFlagOpts := getLDFlagsOpts()
240257
return util.DockerBuildOptions{
241-
Cmd: fmt.Sprintf(buildScript, ldFlagOpts, path),
258+
Cmd: fmt.Sprintf(buildScript, ldFlagOpts, path, insNewGo),
242259
Env: env,
243260
}, nil
244261
}
245262

263+
func getNeedVersionGo(path string, goVersion string) (string, bool) {
264+
name := filepath.Join(path, "go.mod")
265+
_, err := os.Stat(name)
266+
if err != nil {
267+
return "", false
268+
}
269+
data, err := os.ReadFile(name)
270+
if err != nil {
271+
return "", false
272+
}
273+
274+
// get your own version of go
275+
var need bool
276+
277+
// determine the presence of go.mod and the version of go in go.mod (go, toolchain)
278+
f, err := modfile.Parse("go.mod", data, nil)
279+
if err != nil {
280+
return "", false
281+
}
282+
283+
if f.Go != nil {
284+
fGoVer := "v" + f.Go.Version
285+
if semver.Compare(goVersion, fGoVer) == -1 {
286+
goVersion = fGoVer
287+
need = true
288+
}
289+
}
290+
291+
if f.Toolchain != nil {
292+
fToolchaiVer := "v" + strings.TrimPrefix(f.Toolchain.Name, "go")
293+
if semver.Compare(goVersion, fToolchaiVer) == -1 {
294+
goVersion = fToolchaiVer
295+
need = true
296+
}
297+
}
298+
299+
if need {
300+
return strings.TrimPrefix(goVersion, "v"), true
301+
}
302+
303+
return "", false
304+
}
305+
246306
// CodeDescriptor describes the code we're packaging.
247307
type CodeDescriptor struct {
248308
Source string // absolute path of the source to package

core/chaincode/platforms/golang/platform_test.go

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,13 @@ func TestDockerBuildOptions(t *testing.T) {
358358
platform := &Platform{}
359359

360360
t.Run("GOPROXY and GOSUMDB not set", func(t *testing.T) {
361-
opts, err := platform.DockerBuildOptions("the-path")
361+
opts, err := platform.DockerBuildOptions("the-path", "", "", "")
362362
require.NoError(t, err, "unexpected error from DockerBuildOptions")
363363

364364
expectedOpts := util.DockerBuildOptions{
365365
Cmd: `
366366
set -e
367+
367368
if [ -f "/chaincode/input/src/go.mod" ] && [ -d "/chaincode/input/src/vendor" ]; then
368369
cd /chaincode/input/src
369370
GO111MODULE=on go build -v -mod=vendor -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode the-path
@@ -387,24 +388,16 @@ echo Done!
387388
})
388389

389390
t.Run("GOPROXY and GOSUMDB set", func(t *testing.T) {
390-
oldGoproxy, set := os.LookupEnv("GOPROXY")
391-
if set {
392-
defer os.Setenv("GOPROXY", oldGoproxy)
393-
}
394-
os.Setenv("GOPROXY", "the-goproxy")
395-
396-
oldGosumdb, set := os.LookupEnv("GOSUMDB")
397-
if set {
398-
defer os.Setenv("GOSUMDB", oldGosumdb)
399-
}
400-
os.Setenv("GOSUMDB", "the-gosumdb")
391+
t.Setenv("GOPROXY", "the-goproxy")
392+
t.Setenv("GOSUMDB", "the-gosumdb")
401393

402-
opts, err := platform.DockerBuildOptions("the-path")
394+
opts, err := platform.DockerBuildOptions("the-path", "", "", "")
403395
require.NoError(t, err, "unexpected error from DockerBuildOptions")
404396

405397
expectedOpts := util.DockerBuildOptions{
406398
Cmd: `
407399
set -e
400+
408401
if [ -f "/chaincode/input/src/go.mod" ] && [ -d "/chaincode/input/src/vendor" ]; then
409402
cd /chaincode/input/src
410403
GO111MODULE=on go build -v -mod=vendor -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode the-path
@@ -426,6 +419,42 @@ echo Done!
426419
}
427420
require.Equal(t, expectedOpts, opts)
428421
})
422+
423+
t.Run("Upsate version go", func(t *testing.T) {
424+
opts, err := platform.DockerBuildOptions("testdata/src/chaincodes/toolchain", "v1.25.0", "linux", "arm64")
425+
require.NoError(t, err, "unexpected error from DockerBuildOptions")
426+
427+
expectedOpts := util.DockerBuildOptions{
428+
Cmd: `
429+
set -e
430+
431+
curl -sLO https://go.dev/dl/go1.26.3.linux-arm64.tar.gz
432+
rm -rf /usr/local/go
433+
tar -C /usr/local -xzfv "go1.26.3.linux-arm64.tar.gz"
434+
rm "go1.26.3.linux-arm64.tar.gz"
435+
go version
436+
437+
if [ -f "/chaincode/input/src/go.mod" ] && [ -d "/chaincode/input/src/vendor" ]; then
438+
cd /chaincode/input/src
439+
GO111MODULE=on go build -v -mod=vendor -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode testdata/src/chaincodes/toolchain
440+
elif [ -f "/chaincode/input/src/go.mod" ]; then
441+
cd /chaincode/input/src
442+
GO111MODULE=on go build -v -mod=readonly -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode testdata/src/chaincodes/toolchain
443+
elif [ -f "/chaincode/input/src/testdata/src/chaincodes/toolchain/go.mod" ] && [ -d "/chaincode/input/src/testdata/src/chaincodes/toolchain/vendor" ]; then
444+
cd /chaincode/input/src/testdata/src/chaincodes/toolchain
445+
GO111MODULE=on go build -v -mod=vendor -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode .
446+
elif [ -f "/chaincode/input/src/testdata/src/chaincodes/toolchain/go.mod" ]; then
447+
cd /chaincode/input/src/testdata/src/chaincodes/toolchain
448+
GO111MODULE=on go build -v -mod=readonly -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode .
449+
else
450+
GO111MODULE=off GOPATH=/chaincode/input:$GOPATH go build -v -ldflags "-linkmode external -extldflags '-static'" -o /chaincode/output/chaincode testdata/src/chaincodes/toolchain
451+
fi
452+
echo Done!
453+
`,
454+
Env: []string{"GOPROXY=https://proxy.golang.org"},
455+
}
456+
require.Equal(t, expectedOpts, opts)
457+
})
429458
}
430459

431460
func TestDescribeCode(t *testing.T) {
@@ -457,6 +486,20 @@ func TestDescribeCode(t *testing.T) {
457486
})
458487
}
459488

489+
func TestNeedVersionGo(t *testing.T) {
490+
newGoVer, need := getNeedVersionGo("testdata/src/chaincodes/noop", "v1.26.3")
491+
require.Equal(t, newGoVer, "")
492+
require.False(t, need)
493+
494+
newGoVer, need = getNeedVersionGo("testdata/src/chaincodes/noop", "v1.12.0")
495+
require.Equal(t, newGoVer, "1.13")
496+
require.True(t, need)
497+
498+
newGoVer, need = getNeedVersionGo("testdata/src/chaincodes/toolchain", "v1.25.0")
499+
require.Equal(t, newGoVer, "1.26.3")
500+
require.True(t, need)
501+
}
502+
460503
func TestRegularFileExists(t *testing.T) {
461504
t.Run("RegularFile", func(t *testing.T) {
462505
ok, err := regularFileExists("testdata/ccmodule/go.mod")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package main
8+
9+
func main() {
10+
// Empty shell with no dependencies
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module github.com/hyperledger/fabric/core/chaincode/platforms/golang/testdata/src/chaincodes/toolchain
2+
3+
go 1.25.10
4+
5+
toolchain go1.26.3
6+
7+
// This should not get included in packages that were created from a GOPATH

core/chaincode/platforms/golang/testdata/src/chaincodes/toolchain/go.sum

Whitespace-only changes.

core/chaincode/platforms/java/platform.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (p *Platform) GenerateDockerfile() (string, error) {
129129
return dockerFileContents, nil
130130
}
131131

132-
func (p *Platform) DockerBuildOptions(path string) (util.DockerBuildOptions, error) {
132+
func (p *Platform) DockerBuildOptions(string, string, string, string) (util.DockerBuildOptions, error) {
133133
return util.DockerBuildOptions{
134134
Image: util.GetDockerImageFromConfig("chaincode.java.runtime"),
135135
Cmd: "./build.sh",

core/chaincode/platforms/java/platform_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func TestGenerateDockerfile(t *testing.T) {
161161
func TestDockerBuildOptions(t *testing.T) {
162162
platform := java.Platform{}
163163

164-
opts, err := platform.DockerBuildOptions("path")
164+
opts, err := platform.DockerBuildOptions("path", "", "", "")
165165
require.NoError(t, err, "unexpected error from DockerBuildOptions")
166166

167167
expectedOpts := util.DockerBuildOptions{

core/chaincode/platforms/mock/platform.go

Lines changed: 25 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/chaincode/platforms/node/platform.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ else
182182
fi
183183
`
184184

185-
func (p *Platform) DockerBuildOptions(path string) (util.DockerBuildOptions, error) {
185+
func (p *Platform) DockerBuildOptions(string, string, string, string) (util.DockerBuildOptions, error) {
186186
return util.DockerBuildOptions{
187187
Image: util.GetDockerImageFromConfig("chaincode.node.runtime"),
188188
Cmd: buildScript,

core/chaincode/platforms/node/platform_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ fi
140140
`
141141

142142
func TestGenerateBuildOptions(t *testing.T) {
143-
opts, err := platform.DockerBuildOptions("pathname")
143+
opts, err := platform.DockerBuildOptions("pathname", "", "", "")
144144
require.NoError(t, err)
145145

146146
expectedOpts := util.DockerBuildOptions{

0 commit comments

Comments
 (0)