Skip to content

Commit 796d427

Browse files
refactor(nwo): remove fabric dependency from nwo fabric packager
This commit moves the utility functions imported from fabric into the local package, including tests. Signed-off-by: Marcus Brandenburger <bur@zurich.ibm.com>
1 parent aa23760 commit 796d427

File tree

8 files changed

+471
-60
lines changed

8 files changed

+471
-60
lines changed

integration/nwo/fabric/packager/golang/platform.go

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,11 @@ import (
2020
"runtime"
2121
"sort"
2222
"strings"
23-
"time"
2423

2524
"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/packager/ccmetadata"
2625
"github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/packager/replacer"
2726
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
28-
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils"
2927
pb "github.com/hyperledger/fabric-protos-go-apiv2/peer"
30-
"github.com/hyperledger/fabric/core/chaincode/platforms/util"
3128
)
3229

3330
// var logger = logging.MustGetLogger()
@@ -183,7 +180,7 @@ func (p *Platform) GetDeploymentPayload(codepath string, replacer replacer.Func)
183180
return nil, errors.Errorf("error writing %s to tar: %s", file.Name, err)
184181
}
185182
} else {
186-
err = util.WriteFileToPackage(file.Path, file.Name, tw)
183+
err = WriteFileToPackage(file.Path, file.Name, tw)
187184
if err != nil {
188185
return nil, errors.Errorf("error writing %s to tar: %s", file.Name, err)
189186
}
@@ -474,47 +471,3 @@ func distributions() []dist {
474471

475472
return list
476473
}
477-
478-
// WriteBytesToPackage writes a file to a tar stream.
479-
func WriteBytesToPackage(raw []byte, localpath string, packagepath string, tw *tar.Writer) error {
480-
fd, err := os.Open(localpath)
481-
if err != nil {
482-
return fmt.Errorf("%s: %s", localpath, err)
483-
}
484-
defer utils.IgnoreErrorFunc(fd.Close)
485-
486-
fi, err := fd.Stat()
487-
if err != nil {
488-
return fmt.Errorf("%s: %s", localpath, err)
489-
}
490-
491-
header, err := tar.FileInfoHeader(fi, localpath)
492-
if err != nil {
493-
return fmt.Errorf("failed calculating FileInfoHeader: %s", err)
494-
}
495-
496-
// Take the variance out of the tar by using zero time and fixed uid/gid.
497-
var zeroTime time.Time
498-
header.AccessTime = zeroTime
499-
header.ModTime = zeroTime
500-
header.ChangeTime = zeroTime
501-
header.Name = packagepath
502-
header.Mode = 0o100644
503-
header.Uid = 500
504-
header.Gid = 500
505-
header.Uname = ""
506-
header.Gname = ""
507-
header.Size = int64(len(raw))
508-
509-
err = tw.WriteHeader(header)
510-
if err != nil {
511-
return fmt.Errorf("failed to write header for %s: %s", localpath, err)
512-
}
513-
514-
_, err = io.Copy(tw, bytes.NewBuffer(raw))
515-
if err != nil {
516-
return fmt.Errorf("failed to write %s as %s: %s", localpath, packagepath, err)
517-
}
518-
519-
return nil
520-
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package golang
8+
9+
import (
10+
"archive/tar"
11+
"bufio"
12+
"bytes"
13+
"fmt"
14+
"io"
15+
"os"
16+
"time"
17+
18+
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils"
19+
)
20+
21+
// WriteBytesToPackage writes a file to a tar stream with the contents as provided via the raw parameter.
22+
func WriteBytesToPackage(raw []byte, localpath string, packagepath string, tw *tar.Writer) error {
23+
fd, err := os.Open(localpath)
24+
if err != nil {
25+
return fmt.Errorf("%s: %s", localpath, err)
26+
}
27+
defer utils.IgnoreErrorFunc(fd.Close)
28+
29+
fi, err := fd.Stat()
30+
if err != nil {
31+
return fmt.Errorf("%s: %s", localpath, err)
32+
}
33+
34+
header, err := tar.FileInfoHeader(fi, localpath)
35+
if err != nil {
36+
return fmt.Errorf("failed calculating FileInfoHeader: %s", err)
37+
}
38+
39+
// Take the variance out of the tar by using zero time and fixed uid/gid.
40+
var zeroTime time.Time
41+
header.AccessTime = zeroTime
42+
header.ModTime = zeroTime
43+
header.ChangeTime = zeroTime
44+
header.Name = packagepath
45+
header.Mode = 0o100644
46+
header.Uid = 500
47+
header.Gid = 500
48+
header.Uname = ""
49+
header.Gname = ""
50+
header.Size = int64(len(raw))
51+
52+
err = tw.WriteHeader(header)
53+
if err != nil {
54+
return fmt.Errorf("failed to write header for %s: %s", localpath, err)
55+
}
56+
57+
_, err = io.Copy(tw, bytes.NewBuffer(raw))
58+
if err != nil {
59+
return fmt.Errorf("failed to write %s as %s: %s", localpath, packagepath, err)
60+
}
61+
62+
return nil
63+
}
64+
65+
// WriteFileToPackage writes a file to a tar stream.
66+
func WriteFileToPackage(localpath string, packagepath string, tw *tar.Writer) error {
67+
fd, err := os.Open(localpath)
68+
if err != nil {
69+
return fmt.Errorf("%s: %s", localpath, err)
70+
}
71+
defer fd.Close()
72+
73+
fi, err := fd.Stat()
74+
if err != nil {
75+
return fmt.Errorf("%s: %s", localpath, err)
76+
}
77+
78+
header, err := tar.FileInfoHeader(fi, localpath)
79+
if err != nil {
80+
return fmt.Errorf("failed calculating FileInfoHeader: %s", err)
81+
}
82+
83+
// Take the variance out of the tar by using zero time and fixed uid/gid.
84+
var zeroTime time.Time
85+
header.AccessTime = zeroTime
86+
header.ModTime = zeroTime
87+
header.ChangeTime = zeroTime
88+
header.Name = packagepath
89+
header.Mode = 0o100644
90+
header.Uid = 500
91+
header.Gid = 500
92+
header.Uname = ""
93+
header.Gname = ""
94+
95+
err = tw.WriteHeader(header)
96+
if err != nil {
97+
return fmt.Errorf("failed to write header for %s: %s", localpath, err)
98+
}
99+
100+
is := bufio.NewReader(fd)
101+
_, err = io.Copy(tw, is)
102+
if err != nil {
103+
return fmt.Errorf("failed to write %s as %s: %s", localpath, packagepath, err)
104+
}
105+
106+
return nil
107+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package golang
8+
9+
import (
10+
"archive/tar"
11+
"bytes"
12+
"compress/gzip"
13+
"fmt"
14+
"io"
15+
"os"
16+
"path/filepath"
17+
"testing"
18+
"time"
19+
20+
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
21+
"github.com/stretchr/testify/require"
22+
)
23+
24+
func TestWriteBytesToPackage(t *testing.T) {
25+
tempDir := t.TempDir()
26+
27+
buf := bytes.NewBuffer(nil)
28+
gw := gzip.NewWriter(buf)
29+
tw := tar.NewWriter(gw)
30+
31+
// Create a file and write it to tar writer
32+
filename := "test.txt"
33+
filecontent := "hello"
34+
filePath := filepath.Join(tempDir, filename)
35+
err := os.WriteFile(filePath, bytes.NewBufferString(filecontent).Bytes(), 0o600)
36+
require.NoError(t, err, "Error creating file %s", filePath)
37+
38+
err = WriteBytesToPackage([]byte(filecontent), filePath, filename, tw)
39+
require.NoError(t, err, "Error returned by WriteFileToPackage while writing existing file")
40+
tw.Close()
41+
gw.Close()
42+
43+
// Read the file from the archive and check the name and file content
44+
r := bytes.NewReader(buf.Bytes())
45+
gr, err := gzip.NewReader(r)
46+
require.NoError(t, err, "Error creating a gzip reader")
47+
defer gr.Close()
48+
49+
tr := tar.NewReader(gr)
50+
header, err := tr.Next()
51+
require.NoError(t, err, "Error getting the file from the tar")
52+
require.Equal(t, filename, header.Name, "filename read from archive does not match what was added")
53+
require.Equal(t, time.Time{}, header.AccessTime, "expected zero access time")
54+
require.Equal(t, time.Unix(0, 0), header.ModTime, "expected zero modification time")
55+
require.Equal(t, time.Time{}, header.ChangeTime, "expected zero change time")
56+
require.Equal(t, int64(0o100644), header.Mode, "expected regular file mode")
57+
require.Equal(t, 500, header.Uid, "expected 500 uid")
58+
require.Equal(t, 500, header.Gid, "expected 500 gid")
59+
require.Equal(t, "", header.Uname, "expected empty user name")
60+
require.Equal(t, "", header.Gname, "expected empty group name")
61+
62+
b := make([]byte, 5)
63+
n, err := tr.Read(b)
64+
require.Equal(t, 5, n)
65+
require.True(t, err == nil || err == io.EOF, "Error reading file from the archive") // go1.10 returns io.EOF
66+
require.Equal(t, filecontent, string(b), "file content from archive does not equal original content")
67+
68+
t.Run("non existent file", func(t *testing.T) {
69+
tw := tar.NewWriter(&bytes.Buffer{})
70+
err := WriteBytesToPackage([]byte(filecontent), "missing-file", "", tw)
71+
require.Error(t, err, "expected error writing a non existent file")
72+
require.Contains(t, err.Error(), "missing-file")
73+
})
74+
75+
t.Run("closed tar writer", func(t *testing.T) {
76+
tw := tar.NewWriter(&bytes.Buffer{})
77+
tw.Close()
78+
err := WriteBytesToPackage([]byte(filecontent), filePath, "test.txt", tw)
79+
require.EqualError(t, err, fmt.Sprintf("failed to write header for %s: archive/tar: write after close", filePath))
80+
})
81+
82+
t.Run("stream write failure", func(t *testing.T) {
83+
failWriter := &failingWriter{failAt: 514}
84+
tw := tar.NewWriter(failWriter)
85+
err := WriteBytesToPackage([]byte(filecontent), filePath, "test.txt", tw)
86+
require.EqualError(t, err, fmt.Sprintf("failed to write %s as test.txt: failed-the-write", filePath))
87+
})
88+
}
89+
90+
func TestWriteFileToPackage(t *testing.T) {
91+
tempDir := t.TempDir()
92+
93+
buf := bytes.NewBuffer(nil)
94+
gw := gzip.NewWriter(buf)
95+
tw := tar.NewWriter(gw)
96+
97+
// Create a file and write it to tar writer
98+
filename := "test.txt"
99+
filecontent := "hello"
100+
filePath := filepath.Join(tempDir, filename)
101+
err := os.WriteFile(filePath, bytes.NewBufferString(filecontent).Bytes(), 0o600)
102+
require.NoError(t, err, "Error creating file %s", filePath)
103+
104+
err = WriteFileToPackage(filePath, filename, tw)
105+
require.NoError(t, err, "Error returned by WriteFileToPackage while writing existing file")
106+
tw.Close()
107+
gw.Close()
108+
109+
// Read the file from the archive and check the name and file content
110+
r := bytes.NewReader(buf.Bytes())
111+
gr, err := gzip.NewReader(r)
112+
require.NoError(t, err, "Error creating a gzip reader")
113+
defer gr.Close()
114+
115+
tr := tar.NewReader(gr)
116+
header, err := tr.Next()
117+
require.NoError(t, err, "Error getting the file from the tar")
118+
require.Equal(t, filename, header.Name, "filename read from archive does not match what was added")
119+
require.Equal(t, time.Time{}, header.AccessTime, "expected zero access time")
120+
require.Equal(t, time.Unix(0, 0), header.ModTime, "expected zero modification time")
121+
require.Equal(t, time.Time{}, header.ChangeTime, "expected zero change time")
122+
require.Equal(t, int64(0o100644), header.Mode, "expected regular file mode")
123+
require.Equal(t, 500, header.Uid, "expected 500 uid")
124+
require.Equal(t, 500, header.Gid, "expected 500 gid")
125+
require.Equal(t, "", header.Uname, "expected empty user name")
126+
require.Equal(t, "", header.Gname, "expected empty group name")
127+
128+
b := make([]byte, 5)
129+
n, err := tr.Read(b)
130+
require.Equal(t, 5, n)
131+
require.True(t, err == nil || err == io.EOF, "Error reading file from the archive") // go1.10 returns io.EOF
132+
require.Equal(t, filecontent, string(b), "file content from archive does not equal original content")
133+
134+
t.Run("non existent file", func(t *testing.T) {
135+
tw := tar.NewWriter(&bytes.Buffer{})
136+
err := WriteFileToPackage("missing-file", "", tw)
137+
require.Error(t, err, "expected error writing a non existent file")
138+
require.Contains(t, err.Error(), "missing-file")
139+
})
140+
141+
t.Run("closed tar writer", func(t *testing.T) {
142+
tw := tar.NewWriter(&bytes.Buffer{})
143+
tw.Close()
144+
err := WriteFileToPackage(filePath, "test.txt", tw)
145+
require.EqualError(t, err, fmt.Sprintf("failed to write header for %s: archive/tar: write after close", filePath))
146+
})
147+
148+
t.Run("stream write failure", func(t *testing.T) {
149+
failWriter := &failingWriter{failAt: 514}
150+
tw := tar.NewWriter(failWriter)
151+
err := WriteFileToPackage(filePath, "test.txt", tw)
152+
require.EqualError(t, err, fmt.Sprintf("failed to write %s as test.txt: failed-the-write", filePath))
153+
})
154+
}
155+
156+
type failingWriter struct {
157+
written int
158+
failAt int
159+
}
160+
161+
func (f *failingWriter) Write(b []byte) (int, error) {
162+
f.written += len(b)
163+
if f.written < f.failAt {
164+
return len(b), nil
165+
}
166+
return 0, errors.New("failed-the-write")
167+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package packager
8+
9+
import (
10+
"regexp"
11+
12+
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
13+
)
14+
15+
// LabelRegexp is the regular expression controlling the allowed characters
16+
// for the package label.
17+
var LabelRegexp = regexp.MustCompile(`^[[:alnum:]][[:alnum:]_.+-]*$`)
18+
19+
// ValidateLabel return an error if the provided label contains any invalid
20+
// characters, as determined by LabelRegexp.
21+
func ValidateLabel(label string) error {
22+
if !LabelRegexp.MatchString(label) {
23+
return errors.Errorf("invalid label '%s'. Label must be non-empty, can only consist of alphanumerics, symbols from '.+-_', and can only begin with alphanumerics", label)
24+
}
25+
26+
return nil
27+
}

0 commit comments

Comments
 (0)