From 71aed35094e2e10fecb044b30e9064735264b779 Mon Sep 17 00:00:00 2001 From: Cole Wippern Date: Fri, 17 Jan 2020 13:36:23 -0800 Subject: [PATCH 1/6] GetFSFromLayers * add util.GetFSFromLayers * GetFSFromImage delegates to GetFSFromLayers * add FSOpts and FSConfig for GetFSFromLayers * add tests for GetFSFromLayers * add gomock for test support * add mock_v1 for layers --- go.mod | 3 +- go.sum | 6 + .../Dockerfile_test_deleted_file_cached | 5 + .../go-containerregistry/mock_v1/mocks.go | 126 ++++++++ pkg/util/fs_util.go | 67 ++++- pkg/util/fs_util_test.go | 282 ++++++++++++++++++ 6 files changed, 476 insertions(+), 13 deletions(-) create mode 100644 integration/dockerfiles/Dockerfile_test_deleted_file_cached create mode 100644 pkg/mocks/go-containerregistry/mock_v1/mocks.go diff --git a/go.mod b/go.mod index 47c583a23..6eaca49cb 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/gliderlabs/ssh v0.2.2 // indirect github.com/gogo/protobuf v1.1.1 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/golang/mock v1.3.1 github.com/golang/protobuf v1.1.0 // indirect github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a // indirect github.com/google/go-cmp v0.2.0 @@ -94,7 +95,7 @@ require ( go.opencensus.io v0.14.0 // indirect golang.org/x/net v0.0.0-20190311183353-d8887717615a golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc - golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f + golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect google.golang.org/api v0.0.0-20180730000901-31ca0e01cd79 // indirect google.golang.org/appengine v1.1.0 // indirect diff --git a/go.sum b/go.sum index 32b35ffad..de01172fb 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -239,6 +241,8 @@ golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc h1:3ElrZeO6IBP+M8kgu5YFwR golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564 h1:o6ENHFwwr1TZ9CUPQcfo1HGvLP1OPsPOTB7xCIOPNmU= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -252,6 +256,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/api v0.0.0-20180730000901-31ca0e01cd79 h1:wCy2/9bhO1JeP2zZUALrj7ZdZuZoR4mRV57kTxjqRpo= google.golang.org/api v0.0.0-20180730000901-31ca0e01cd79/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= diff --git a/integration/dockerfiles/Dockerfile_test_deleted_file_cached b/integration/dockerfiles/Dockerfile_test_deleted_file_cached new file mode 100644 index 000000000..17864adaf --- /dev/null +++ b/integration/dockerfiles/Dockerfile_test_deleted_file_cached @@ -0,0 +1,5 @@ +FROM alpine + +RUN mkdir -p /some/dir/ && echo 'first' > /some/dir/first.txt + +RUN rm /some/dir/first.txt diff --git a/pkg/mocks/go-containerregistry/mock_v1/mocks.go b/pkg/mocks/go-containerregistry/mock_v1/mocks.go new file mode 100644 index 000000000..0415fe721 --- /dev/null +++ b/pkg/mocks/go-containerregistry/mock_v1/mocks.go @@ -0,0 +1,126 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/google/go-containerregistry/pkg/v1 (interfaces: Layer) + +// Package mock_v1 is a generated GoMock package. +package mock_v1 + +import ( + gomock "github.com/golang/mock/gomock" + v1 "github.com/google/go-containerregistry/pkg/v1" + types "github.com/google/go-containerregistry/pkg/v1/types" + io "io" + reflect "reflect" +) + +// MockLayer is a mock of Layer interface +type MockLayer struct { + ctrl *gomock.Controller + recorder *MockLayerMockRecorder +} + +// MockLayerMockRecorder is the mock recorder for MockLayer +type MockLayerMockRecorder struct { + mock *MockLayer +} + +// NewMockLayer creates a new mock instance +func NewMockLayer(ctrl *gomock.Controller) *MockLayer { + mock := &MockLayer{ctrl: ctrl} + mock.recorder = &MockLayerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockLayer) EXPECT() *MockLayerMockRecorder { + return m.recorder +} + +// Compressed mocks base method +func (m *MockLayer) Compressed() (io.ReadCloser, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Compressed") + ret0, _ := ret[0].(io.ReadCloser) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Compressed indicates an expected call of Compressed +func (mr *MockLayerMockRecorder) Compressed() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compressed", reflect.TypeOf((*MockLayer)(nil).Compressed)) +} + +// DiffID mocks base method +func (m *MockLayer) DiffID() (v1.Hash, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DiffID") + ret0, _ := ret[0].(v1.Hash) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DiffID indicates an expected call of DiffID +func (mr *MockLayerMockRecorder) DiffID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DiffID", reflect.TypeOf((*MockLayer)(nil).DiffID)) +} + +// Digest mocks base method +func (m *MockLayer) Digest() (v1.Hash, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Digest") + ret0, _ := ret[0].(v1.Hash) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Digest indicates an expected call of Digest +func (mr *MockLayerMockRecorder) Digest() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Digest", reflect.TypeOf((*MockLayer)(nil).Digest)) +} + +// MediaType mocks base method +func (m *MockLayer) MediaType() (types.MediaType, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MediaType") + ret0, _ := ret[0].(types.MediaType) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MediaType indicates an expected call of MediaType +func (mr *MockLayerMockRecorder) MediaType() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MediaType", reflect.TypeOf((*MockLayer)(nil).MediaType)) +} + +// Size mocks base method +func (m *MockLayer) Size() (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Size") + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Size indicates an expected call of Size +func (mr *MockLayerMockRecorder) Size() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Size", reflect.TypeOf((*MockLayer)(nil).Size)) +} + +// Uncompressed mocks base method +func (m *MockLayer) Uncompressed() (io.ReadCloser, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Uncompressed") + ret0, _ := ret[0].(io.ReadCloser) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Uncompressed indicates an expected call of Uncompressed +func (mr *MockLayerMockRecorder) Uncompressed() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Uncompressed", reflect.TypeOf((*MockLayer)(nil).Uncompressed)) +} diff --git a/pkg/util/fs_util.go b/pkg/util/fs_util.go index 0792e1d66..53a7ce6ff 100644 --- a/pkg/util/fs_util.go +++ b/pkg/util/fs_util.go @@ -71,25 +71,58 @@ var excluded []string type ExtractFunction func(string, *tar.Header, io.Reader) error +type FSConfig struct { + includeWhiteout bool + extractFunc ExtractFunction +} + +type FSOpt func(*FSConfig) + +func IncludeWhiteout() FSOpt { + return func(opts *FSConfig) { + opts.includeWhiteout = true + } +} + +func ExtractFunc(extractFunc ExtractFunction) FSOpt { + return func(opts *FSConfig) { + opts.extractFunc = extractFunc + } +} + // GetFSFromImage extracts the layers of img to root // It returns a list of all files extracted func GetFSFromImage(root string, img v1.Image, extract ExtractFunction) ([]string, error) { - if extract == nil { - return nil, errors.New("must supply an extract function") - } if img == nil { return nil, errors.New("image cannot be nil") } - if err := DetectFilesystemWhitelist(constants.WhitelistPath); err != nil { - return nil, err - } - logrus.Debugf("Mounted directories: %v", whitelist) + layers, err := img.Layers() if err != nil { return nil, err } - extractedFiles := []string{} + return GetFSFromLayers(root, layers, ExtractFunc(extract)) +} + +func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, error) { + cfg := new(FSConfig) + + for _, opt := range opts { + opt(cfg) + } + + if cfg.extractFunc == nil { + return nil, errors.New("must supply an extract function") + } + + if err := DetectFilesystemWhitelist(constants.WhitelistPath); err != nil { + return nil, err + } + + logrus.Debugf("Mounted directories: %v", whitelist) + + extractedFiles := []string{} for i, l := range layers { if mediaType, err := l.MediaType(); err == nil { logrus.Tracef("Extracting layer %d of media type %s", i, mediaType) @@ -102,29 +135,39 @@ func GetFSFromImage(root string, img v1.Image, extract ExtractFunction) ([]strin return nil, err } defer r.Close() + tr := tar.NewReader(r) for { hdr, err := tr.Next() if err == io.EOF { break } + if err != nil { return nil, errors.Wrap(err, fmt.Sprintf("error reading tar %d", i)) } + path := filepath.Join(root, filepath.Clean(hdr.Name)) base := filepath.Base(path) dir := filepath.Dir(path) + if strings.HasPrefix(base, ".wh.") { logrus.Debugf("Whiting out %s", path) + name := strings.TrimPrefix(base, ".wh.") if err := os.RemoveAll(filepath.Join(dir, name)); err != nil { return nil, errors.Wrapf(err, "removing whiteout %s", hdr.Name) } - continue - } - if err := extract(root, hdr, tr); err != nil { - return nil, err + + if !cfg.includeWhiteout { + continue + } + } else { + if err := cfg.extractFunc(root, hdr, tr); err != nil { + return nil, err + } } + extractedFiles = append(extractedFiles, filepath.Join(root, filepath.Clean(hdr.Name))) } } diff --git a/pkg/util/fs_util_test.go b/pkg/util/fs_util_test.go index 1ea074f58..65eb461a6 100644 --- a/pkg/util/fs_util_test.go +++ b/pkg/util/fs_util_test.go @@ -20,6 +20,7 @@ import ( "archive/tar" "bytes" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -28,7 +29,11 @@ import ( "strings" "testing" + "github.com/GoogleContainerTools/kaniko/pkg/mocks/go-containerregistry/mock_v1" "github.com/GoogleContainerTools/kaniko/testutil" + "github.com/golang/mock/gomock" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/types" ) func Test_DetectFilesystemWhitelist(t *testing.T) { @@ -863,3 +868,280 @@ func Test_CopyFile_skips_self(t *testing.T) { t.Fatalf("expected file contents to be %q, but got %q", expected, actual) } } + +func fakeExtract(dest string, hdr *tar.Header, tr io.Reader) error { + return nil +} + +func Test_GetFSFromLayers_with_whiteouts_include_whiteout_enabled(t *testing.T) { + ctrl := gomock.NewController(t) + + root, err := ioutil.TempDir("", "layers-test") + if err != nil { + t.Fatal(err) + } + defer os.Remove(root) + + opts := []FSOpt{ + // I'd rather use the real func (util.ExtractFile) + // but you have to be root to chown + ExtractFunc(fakeExtract), + IncludeWhiteout(), + } + + expectErr := false + + f := func(expectedFiles []string, tw *tar.Writer) { + body := "Hello World\n" + for _, f := range expectedFiles { + f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/") + + hdr := &tar.Header{ + Name: f, + Mode: 0644, + Size: int64(len(body)), + } + + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + + if _, err := tw.Write([]byte(body)); err != nil { + t.Fatal(err) + } + } + + if err := tw.Close(); err != nil { + t.Fatal(err) + } + } + + expectedFiles := []string{ + filepath.Join(root, "foobar"), + } + + buf := new(bytes.Buffer) + tw := tar.NewWriter(buf) + + f(expectedFiles, tw) + + mockLayer := mock_v1.NewMockLayer(ctrl) + mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil) + + rc := ioutil.NopCloser(buf) + mockLayer.EXPECT().Uncompressed().Return(rc, nil) + + secondLayerFiles := []string{ + filepath.Join(root, ".wh.foobar"), + } + + buf = new(bytes.Buffer) + tw = tar.NewWriter(buf) + + f(secondLayerFiles, tw) + + mockLayer2 := mock_v1.NewMockLayer(ctrl) + mockLayer2.EXPECT().MediaType().Return(types.OCILayer, nil) + + rc = ioutil.NopCloser(buf) + mockLayer2.EXPECT().Uncompressed().Return(rc, nil) + + layers := []v1.Layer{ + mockLayer, + mockLayer2, + } + + expectedFiles = append(expectedFiles, secondLayerFiles...) + + actualFiles, err := GetFSFromLayers(root, layers, opts...) + + assertGetFSFromLayers( + t, + actualFiles, + expectedFiles, + err, + expectErr, + ) +} + +func Test_GetFSFromLayers_with_whiteouts_include_whiteout_disabled(t *testing.T) { + ctrl := gomock.NewController(t) + + root, err := ioutil.TempDir("", "layers-test") + if err != nil { + t.Fatal(err) + } + defer os.Remove(root) + + opts := []FSOpt{ + // I'd rather use the real func (util.ExtractFile) + // but you have to be root to chown + ExtractFunc(fakeExtract), + } + + expectErr := false + + f := func(expectedFiles []string, tw *tar.Writer) { + body := "Hello World\n" + for _, f := range expectedFiles { + f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/") + + hdr := &tar.Header{ + Name: f, + Mode: 0644, + Size: int64(len(body)), + } + + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + + if _, err := tw.Write([]byte(body)); err != nil { + t.Fatal(err) + } + } + + if err := tw.Close(); err != nil { + t.Fatal(err) + } + } + + expectedFiles := []string{ + filepath.Join(root, "foobar"), + } + + buf := new(bytes.Buffer) + tw := tar.NewWriter(buf) + + f(expectedFiles, tw) + + mockLayer := mock_v1.NewMockLayer(ctrl) + mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil) + + rc := ioutil.NopCloser(buf) + mockLayer.EXPECT().Uncompressed().Return(rc, nil) + + secondLayerFiles := []string{ + filepath.Join(root, ".wh.foobar"), + } + + buf = new(bytes.Buffer) + tw = tar.NewWriter(buf) + + f(secondLayerFiles, tw) + + mockLayer2 := mock_v1.NewMockLayer(ctrl) + mockLayer2.EXPECT().MediaType().Return(types.OCILayer, nil) + + rc = ioutil.NopCloser(buf) + mockLayer2.EXPECT().Uncompressed().Return(rc, nil) + + layers := []v1.Layer{ + mockLayer, + mockLayer2, + } + + actualFiles, err := GetFSFromLayers(root, layers, opts...) + + assertGetFSFromLayers( + t, + actualFiles, + expectedFiles, + err, + expectErr, + ) +} + +func Test_GetFSFromLayers(t *testing.T) { + ctrl := gomock.NewController(t) + + root, err := ioutil.TempDir("", "layers-test") + if err != nil { + t.Fatal(err) + } + defer os.Remove(root) + + opts := []FSOpt{ + // I'd rather use the real func (util.ExtractFile) + // but you have to be root to chown + ExtractFunc(fakeExtract), + } + + expectErr := false + expectedFiles := []string{ + filepath.Join(root, "foobar"), + } + + buf := new(bytes.Buffer) + tw := tar.NewWriter(buf) + + body := "Hello World\n" + for _, f := range expectedFiles { + f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/") + + hdr := &tar.Header{ + Name: f, + Mode: 0644, + Size: int64(len(body)), + } + + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + + if _, err := tw.Write([]byte(body)); err != nil { + t.Fatal(err) + } + } + + if err := tw.Close(); err != nil { + t.Fatal(err) + } + + mockLayer := mock_v1.NewMockLayer(ctrl) + mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil) + + rc := ioutil.NopCloser(buf) + mockLayer.EXPECT().Uncompressed().Return(rc, nil) + + layers := []v1.Layer{ + mockLayer, + } + + actualFiles, err := GetFSFromLayers(root, layers, opts...) + + assertGetFSFromLayers( + t, + actualFiles, + expectedFiles, + err, + expectErr, + ) +} + +func assertGetFSFromLayers( + t *testing.T, + actualFiles []string, + expectedFiles []string, + err error, + expectErr bool, +) { + if !expectErr && err != nil { + t.Error(err) + t.FailNow() + } else if expectErr && err == nil { + t.Error("expected err to not be nil") + t.FailNow() + } + + if len(actualFiles) != len(expectedFiles) { + t.Errorf("expected %s to equal %s", actualFiles, expectedFiles) + t.FailNow() + } + + for i := range expectedFiles { + if actualFiles[i] != expectedFiles[i] { + t.Errorf("expected %s to equal %s", actualFiles[i], expectedFiles[i]) + } + } +} From 876f24b0c985b25bc98815f26e2c33fdd7f91425 Mon Sep 17 00:00:00 2001 From: Cole Wippern Date: Fri, 17 Jan 2020 14:16:42 -0800 Subject: [PATCH 2/6] update caching run and copy extracted files Update caching run and copy commands to use the new GetFSFromLayers method and include the whiteout option so that whiteout files are extracted and included in extractedFiles --- pkg/commands/copy.go | 13 +++++++++++-- pkg/commands/run.go | 18 ++++++++++++++++-- pkg/util/fs_util.go | 10 ++++++---- pkg/util/fs_util_test.go | 15 ++++++--------- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/pkg/commands/copy.go b/pkg/commands/copy.go index fd4b18a04..bdbc65c4d 100644 --- a/pkg/commands/copy.go +++ b/pkg/commands/copy.go @@ -167,7 +167,13 @@ func (cr *CachingCopyCommand) ExecuteCommand(config *v1.Config, buildArgs *docke if cr.img == nil { return errors.New(fmt.Sprintf("cached command image is nil %v", cr.String())) } - cr.extractedFiles, err = util.GetFSFromImage(RootDir, cr.img, cr.extractFn) + + layers, err := cr.img.Layers() + if err != nil { + return errors.Wrapf(err, "retrieve image layers") + } + + cr.extractedFiles, err = util.GetFSFromLayers(RootDir, layers, util.ExtractFunc(cr.extractFn), util.IncludeWhiteout()) logrus.Infof("extractedFiles: %s", cr.extractedFiles) if err != nil { @@ -182,7 +188,10 @@ func (cr *CachingCopyCommand) FilesUsedFromContext(config *v1.Config, buildArgs } func (cr *CachingCopyCommand) FilesToSnapshot() []string { - return cr.extractedFiles + f := cr.extractedFiles + logrus.Debugf("files extracted by caching copy command %s", f) + + return f } func (cr *CachingCopyCommand) String() string { diff --git a/pkg/commands/run.go b/pkg/commands/run.go index 0dcd4ed52..1687000c4 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -197,7 +197,18 @@ func (cr *CachingRunCommand) ExecuteCommand(config *v1.Config, buildArgs *docker if cr.img == nil { return errors.New(fmt.Sprintf("command image is nil %v", cr.String())) } - cr.extractedFiles, err = util.GetFSFromImage(constants.RootDir, cr.img, cr.extractFn) + + layers, err := cr.img.Layers() + if err != nil { + return errors.Wrap(err, "retrieving image layers") + } + + cr.extractedFiles, err = util.GetFSFromLayers( + constants.RootDir, + layers, + util.ExtractFunc(cr.extractFn), + util.IncludeWhiteout(), + ) if err != nil { return errors.Wrap(err, "extracting fs from image") } @@ -206,7 +217,10 @@ func (cr *CachingRunCommand) ExecuteCommand(config *v1.Config, buildArgs *docker } func (cr *CachingRunCommand) FilesToSnapshot() []string { - return cr.extractedFiles + f := cr.extractedFiles + logrus.Debugf("files extracted from caching run command %s", f) + + return f } func (cr *CachingRunCommand) String() string { diff --git a/pkg/util/fs_util.go b/pkg/util/fs_util.go index 53a7ce6ff..5b704f33f 100644 --- a/pkg/util/fs_util.go +++ b/pkg/util/fs_util.go @@ -160,12 +160,14 @@ func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, e } if !cfg.includeWhiteout { + logrus.Debug("not including whiteout files") continue } - } else { - if err := cfg.extractFunc(root, hdr, tr); err != nil { - return nil, err - } + + } + + if err := cfg.extractFunc(root, hdr, tr); err != nil { + return nil, err } extractedFiles = append(extractedFiles, filepath.Join(root, filepath.Clean(hdr.Name))) diff --git a/pkg/util/fs_util_test.go b/pkg/util/fs_util_test.go index 65eb461a6..d2adaebaa 100644 --- a/pkg/util/fs_util_test.go +++ b/pkg/util/fs_util_test.go @@ -892,21 +892,20 @@ func Test_GetFSFromLayers_with_whiteouts_include_whiteout_enabled(t *testing.T) expectErr := false f := func(expectedFiles []string, tw *tar.Writer) { - body := "Hello World\n" for _, f := range expectedFiles { f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/") hdr := &tar.Header{ Name: f, Mode: 0644, - Size: int64(len(body)), + Size: int64(len("Hello World\n")), } if err := tw.WriteHeader(hdr); err != nil { t.Fatal(err) } - if _, err := tw.Write([]byte(body)); err != nil { + if _, err := tw.Write([]byte("Hello World\n")); err != nil { t.Fatal(err) } } @@ -982,21 +981,20 @@ func Test_GetFSFromLayers_with_whiteouts_include_whiteout_disabled(t *testing.T) expectErr := false f := func(expectedFiles []string, tw *tar.Writer) { - body := "Hello World\n" for _, f := range expectedFiles { f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/") hdr := &tar.Header{ Name: f, Mode: 0644, - Size: int64(len(body)), + Size: int64(len("Hello world\n")), } if err := tw.WriteHeader(hdr); err != nil { t.Fatal(err) } - if _, err := tw.Write([]byte(body)); err != nil { + if _, err := tw.Write([]byte("Hello world\n")); err != nil { t.Fatal(err) } } @@ -1075,21 +1073,20 @@ func Test_GetFSFromLayers(t *testing.T) { buf := new(bytes.Buffer) tw := tar.NewWriter(buf) - body := "Hello World\n" for _, f := range expectedFiles { f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/") hdr := &tar.Header{ Name: f, Mode: 0644, - Size: int64(len(body)), + Size: int64(len("Hello world\n")), } if err := tw.WriteHeader(hdr); err != nil { t.Fatal(err) } - if _, err := tw.Write([]byte(body)); err != nil { + if _, err := tw.Write([]byte("Hello world\n")); err != nil { t.Fatal(err) } } From 274f21857c1d6ffad8e2a9cd282fdb347091acad Mon Sep 17 00:00:00 2001 From: Cole Wippern Date: Fri, 17 Jan 2020 14:28:17 -0800 Subject: [PATCH 3/6] update vendor --- vendor/github.com/golang/mock/AUTHORS | 12 + vendor/github.com/golang/mock/CONTRIBUTORS | 37 ++ vendor/github.com/golang/mock/LICENSE | 202 +++++++++ vendor/github.com/golang/mock/gomock/call.go | 420 ++++++++++++++++++ .../github.com/golang/mock/gomock/callset.go | 108 +++++ .../golang/mock/gomock/controller.go | 264 +++++++++++ .../github.com/golang/mock/gomock/matchers.go | 141 ++++++ vendor/golang.org/x/sync/errgroup/errgroup.go | 3 +- .../x/sync/singleflight/singleflight.go | 11 +- vendor/modules.txt | 4 +- 10 files changed, 1198 insertions(+), 4 deletions(-) create mode 100644 vendor/github.com/golang/mock/AUTHORS create mode 100644 vendor/github.com/golang/mock/CONTRIBUTORS create mode 100644 vendor/github.com/golang/mock/LICENSE create mode 100644 vendor/github.com/golang/mock/gomock/call.go create mode 100644 vendor/github.com/golang/mock/gomock/callset.go create mode 100644 vendor/github.com/golang/mock/gomock/controller.go create mode 100644 vendor/github.com/golang/mock/gomock/matchers.go diff --git a/vendor/github.com/golang/mock/AUTHORS b/vendor/github.com/golang/mock/AUTHORS new file mode 100644 index 000000000..660b8ccc8 --- /dev/null +++ b/vendor/github.com/golang/mock/AUTHORS @@ -0,0 +1,12 @@ +# This is the official list of GoMock authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Alex Reece +Google Inc. diff --git a/vendor/github.com/golang/mock/CONTRIBUTORS b/vendor/github.com/golang/mock/CONTRIBUTORS new file mode 100644 index 000000000..def849cab --- /dev/null +++ b/vendor/github.com/golang/mock/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This is the official list of people who can contribute (and typically +# have contributed) code to the gomock repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# The submission process automatically checks to make sure +# that people submitting code are listed in this file (by email address). +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# http://code.google.com/legal/individual-cla-v1.0.html +# http://code.google.com/legal/corporate-cla-v1.0.html +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. + +# Names should be added to this file like so: +# Name +# +# An entry with two email addresses specifies that the +# first address should be used in the submit logs and +# that the second address should be recognized as the +# same person when interacting with Rietveld. + +# Please keep the list sorted. + +Aaron Jacobs +Alex Reece +David Symonds +Ryan Barrett diff --git a/vendor/github.com/golang/mock/LICENSE b/vendor/github.com/golang/mock/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/golang/mock/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/mock/gomock/call.go b/vendor/github.com/golang/mock/gomock/call.go new file mode 100644 index 000000000..3d54d9f5d --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/call.go @@ -0,0 +1,420 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "fmt" + "reflect" + "strconv" + "strings" +) + +// Call represents an expected call to a mock. +type Call struct { + t TestHelper // for triggering test failures on invalid call setup + + receiver interface{} // the receiver of the method call + method string // the name of the method + methodType reflect.Type // the type of the method + args []Matcher // the args + origin string // file and line number of call setup + + preReqs []*Call // prerequisite calls + + // Expectations + minCalls, maxCalls int + + numCalls int // actual number made + + // actions are called when this Call is called. Each action gets the args and + // can set the return values by returning a non-nil slice. Actions run in the + // order they are created. + actions []func([]interface{}) []interface{} +} + +// newCall creates a *Call. It requires the method type in order to support +// unexported methods. +func newCall(t TestHelper, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + t.Helper() + + // TODO: check arity, types. + margs := make([]Matcher, len(args)) + for i, arg := range args { + if m, ok := arg.(Matcher); ok { + margs[i] = m + } else if arg == nil { + // Handle nil specially so that passing a nil interface value + // will match the typed nils of concrete args. + margs[i] = Nil() + } else { + margs[i] = Eq(arg) + } + } + + origin := callerInfo(3) + actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} { + // Synthesize the zero value for each of the return args' types. + rets := make([]interface{}, methodType.NumOut()) + for i := 0; i < methodType.NumOut(); i++ { + rets[i] = reflect.Zero(methodType.Out(i)).Interface() + } + return rets + }} + return &Call{t: t, receiver: receiver, method: method, methodType: methodType, + args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions} +} + +// AnyTimes allows the expectation to be called 0 or more times +func (c *Call) AnyTimes() *Call { + c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity + return c +} + +// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called, MinTimes also +// sets the maximum number of calls to infinity. +func (c *Call) MinTimes(n int) *Call { + c.minCalls = n + if c.maxCalls == 1 { + c.maxCalls = 1e8 + } + return c +} + +// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called, MaxTimes also +// sets the minimum number of calls to 0. +func (c *Call) MaxTimes(n int) *Call { + c.maxCalls = n + if c.minCalls == 1 { + c.minCalls = 0 + } + return c +} + +// DoAndReturn declares the action to run when the call is matched. +// The return values from this function are returned by the mocked function. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) DoAndReturn(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + vrets := v.Call(vargs) + rets := make([]interface{}, len(vrets)) + for i, ret := range vrets { + rets[i] = ret.Interface() + } + return rets + }) + return c +} + +// Do declares the action to run when the call is matched. The function's +// return values are ignored to retain backward compatibility. To use the +// return values call DoAndReturn. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) Do(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + v.Call(vargs) + return nil + }) + return c +} + +// Return declares the values to be returned by the mocked function call. +func (c *Call) Return(rets ...interface{}) *Call { + c.t.Helper() + + mt := c.methodType + if len(rets) != mt.NumOut() { + c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]", + c.receiver, c.method, len(rets), mt.NumOut(), c.origin) + } + for i, ret := range rets { + if got, want := reflect.TypeOf(ret), mt.Out(i); got == want { + // Identical types; nothing to do. + } else if got == nil { + // Nil needs special handling. + switch want.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + // ok + default: + c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]", + i, c.receiver, c.method, want, c.origin) + } + } else if got.AssignableTo(want) { + // Assignable type relation. Make the assignment now so that the generated code + // can return the values with a type assertion. + v := reflect.New(want).Elem() + v.Set(reflect.ValueOf(ret)) + rets[i] = v.Interface() + } else { + c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]", + i, c.receiver, c.method, got, want, c.origin) + } + } + + c.addAction(func([]interface{}) []interface{} { + return rets + }) + + return c +} + +// Times declares the exact number of times a function call is expected to be executed. +func (c *Call) Times(n int) *Call { + c.minCalls, c.maxCalls = n, n + return c +} + +// SetArg declares an action that will set the nth argument's value, +// indirected through a pointer. Or, in the case of a slice, SetArg +// will copy value's elements into the nth argument. +func (c *Call) SetArg(n int, value interface{}) *Call { + c.t.Helper() + + mt := c.methodType + // TODO: This will break on variadic methods. + // We will need to check those at invocation time. + if n < 0 || n >= mt.NumIn() { + c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]", + n, mt.NumIn(), c.origin) + } + // Permit setting argument through an interface. + // In the interface case, we don't (nay, can't) check the type here. + at := mt.In(n) + switch at.Kind() { + case reflect.Ptr: + dt := at.Elem() + if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) { + c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]", + n, vt, dt, c.origin) + } + case reflect.Interface: + // nothing to do + case reflect.Slice: + // nothing to do + default: + c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]", + n, at, c.origin) + } + + c.addAction(func(args []interface{}) []interface{} { + v := reflect.ValueOf(value) + switch reflect.TypeOf(args[n]).Kind() { + case reflect.Slice: + setSlice(args[n], v) + default: + reflect.ValueOf(args[n]).Elem().Set(v) + } + return nil + }) + return c +} + +// isPreReq returns true if other is a direct or indirect prerequisite to c. +func (c *Call) isPreReq(other *Call) bool { + for _, preReq := range c.preReqs { + if other == preReq || preReq.isPreReq(other) { + return true + } + } + return false +} + +// After declares that the call may only match after preReq has been exhausted. +func (c *Call) After(preReq *Call) *Call { + c.t.Helper() + + if c == preReq { + c.t.Fatalf("A call isn't allowed to be its own prerequisite") + } + if preReq.isPreReq(c) { + c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq) + } + + c.preReqs = append(c.preReqs, preReq) + return c +} + +// Returns true if the minimum number of calls have been made. +func (c *Call) satisfied() bool { + return c.numCalls >= c.minCalls +} + +// Returns true iff the maximum number of calls have been made. +func (c *Call) exhausted() bool { + return c.numCalls >= c.maxCalls +} + +func (c *Call) String() string { + args := make([]string, len(c.args)) + for i, arg := range c.args { + args[i] = arg.String() + } + arguments := strings.Join(args, ", ") + return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin) +} + +// Tests if the given call matches the expected call. +// If yes, returns nil. If no, returns error with message explaining why it does not match. +func (c *Call) matches(args []interface{}) error { + if !c.methodType.IsVariadic() { + if len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + + for i, m := range c.args { + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + } + } else { + if len(c.args) < c.methodType.NumIn()-1 { + return fmt.Errorf("Expected call at %s has the wrong number of matchers. Got: %d, want: %d", + c.origin, len(c.args), c.methodType.NumIn()-1) + } + if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + if len(args) < len(c.args)-1 { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d", + c.origin, len(args), len(c.args)-1) + } + + for i, m := range c.args { + if i < c.methodType.NumIn()-1 { + // Non-variadic args + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + continue + } + // The last arg has a possibility of a variadic argument, so let it branch + + // sample: Foo(a int, b int, c ...int) + if i < len(c.args) && i < len(args) { + if m.Matches(args[i]) { + // Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC) + // Got Foo(a, b) want Foo(matcherA, matcherB) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD) + continue + } + } + + // The number of actual args don't match the number of matchers, + // or the last matcher is a slice and the last arg is not. + // If this function still matches it is because the last matcher + // matches all the remaining arguments or the lack of any. + // Convert the remaining arguments, if any, into a slice of the + // expected type. + vargsType := c.methodType.In(c.methodType.NumIn() - 1) + vargs := reflect.MakeSlice(vargsType, 0, len(args)-i) + for _, arg := range args[i:] { + vargs = reflect.Append(vargs, reflect.ValueOf(arg)) + } + if m.Matches(vargs.Interface()) { + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher) + break + } + // Wrong number of matchers or not match. Fail. + // Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB) + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i:], c.args[i]) + + } + } + + // Check that all prerequisite calls have been satisfied. + for _, preReqCall := range c.preReqs { + if !preReqCall.satisfied() { + return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v", + c.origin, preReqCall, c) + } + } + + // Check that the call is not exhausted. + if c.exhausted() { + return fmt.Errorf("Expected call at %s has already been called the max number of times.", c.origin) + } + + return nil +} + +// dropPrereqs tells the expected Call to not re-check prerequisite calls any +// longer, and to return its current set. +func (c *Call) dropPrereqs() (preReqs []*Call) { + preReqs = c.preReqs + c.preReqs = nil + return +} + +func (c *Call) call(args []interface{}) []func([]interface{}) []interface{} { + c.numCalls++ + return c.actions +} + +// InOrder declares that the given calls should occur in order. +func InOrder(calls ...*Call) { + for i := 1; i < len(calls); i++ { + calls[i].After(calls[i-1]) + } +} + +func setSlice(arg interface{}, v reflect.Value) { + va := reflect.ValueOf(arg) + for i := 0; i < v.Len(); i++ { + va.Index(i).Set(v.Index(i)) + } +} + +func (c *Call) addAction(action func([]interface{}) []interface{}) { + c.actions = append(c.actions, action) +} diff --git a/vendor/github.com/golang/mock/gomock/callset.go b/vendor/github.com/golang/mock/gomock/callset.go new file mode 100644 index 000000000..c44a8a585 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/callset.go @@ -0,0 +1,108 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "bytes" + "fmt" +) + +// callSet represents a set of expected calls, indexed by receiver and method +// name. +type callSet struct { + // Calls that are still expected. + expected map[callSetKey][]*Call + // Calls that have been exhausted. + exhausted map[callSetKey][]*Call +} + +// callSetKey is the key in the maps in callSet +type callSetKey struct { + receiver interface{} + fname string +} + +func newCallSet() *callSet { + return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)} +} + +// Add adds a new expected call. +func (cs callSet) Add(call *Call) { + key := callSetKey{call.receiver, call.method} + m := cs.expected + if call.exhausted() { + m = cs.exhausted + } + m[key] = append(m[key], call) +} + +// Remove removes an expected call. +func (cs callSet) Remove(call *Call) { + key := callSetKey{call.receiver, call.method} + calls := cs.expected[key] + for i, c := range calls { + if c == call { + // maintain order for remaining calls + cs.expected[key] = append(calls[:i], calls[i+1:]...) + cs.exhausted[key] = append(cs.exhausted[key], call) + break + } + } +} + +// FindMatch searches for a matching call. Returns error with explanation message if no call matched. +func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) { + key := callSetKey{receiver, method} + + // Search through the expected calls. + expected := cs.expected[key] + var callsErrors bytes.Buffer + for _, call := range expected { + err := call.matches(args) + if err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } else { + return call, nil + } + } + + // If we haven't found a match then search through the exhausted calls so we + // get useful error messages. + exhausted := cs.exhausted[key] + for _, call := range exhausted { + if err := call.matches(args); err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } + } + + if len(expected)+len(exhausted) == 0 { + fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method) + } + + return nil, fmt.Errorf(callsErrors.String()) +} + +// Failures returns the calls that are not satisfied. +func (cs callSet) Failures() []*Call { + failures := make([]*Call, 0, len(cs.expected)) + for _, calls := range cs.expected { + for _, call := range calls { + if !call.satisfied() { + failures = append(failures, call) + } + } + } + return failures +} diff --git a/vendor/github.com/golang/mock/gomock/controller.go b/vendor/github.com/golang/mock/gomock/controller.go new file mode 100644 index 000000000..0651c91e4 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/controller.go @@ -0,0 +1,264 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package gomock is a mock framework for Go. +// +// Standard usage: +// (1) Define an interface that you wish to mock. +// type MyInterface interface { +// SomeMethod(x int64, y string) +// } +// (2) Use mockgen to generate a mock from the interface. +// (3) Use the mock in a test: +// func TestMyThing(t *testing.T) { +// mockCtrl := gomock.NewController(t) +// defer mockCtrl.Finish() +// +// mockObj := something.NewMockMyInterface(mockCtrl) +// mockObj.EXPECT().SomeMethod(4, "blah") +// // pass mockObj to a real object and play with it. +// } +// +// By default, expected calls are not enforced to run in any particular order. +// Call order dependency can be enforced by use of InOrder and/or Call.After. +// Call.After can create more varied call order dependencies, but InOrder is +// often more convenient. +// +// The following examples create equivalent call order dependencies. +// +// Example of using Call.After to chain expected call order: +// +// firstCall := mockObj.EXPECT().SomeMethod(1, "first") +// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall) +// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall) +// +// Example of using InOrder to declare expected call order: +// +// gomock.InOrder( +// mockObj.EXPECT().SomeMethod(1, "first"), +// mockObj.EXPECT().SomeMethod(2, "second"), +// mockObj.EXPECT().SomeMethod(3, "third"), +// ) +// +// TODO: +// - Handle different argument/return types (e.g. ..., chan, map, interface). +package gomock + +import ( + "context" + "fmt" + "reflect" + "runtime" + "sync" +) + +// A TestReporter is something that can be used to report test failures. It +// is satisfied by the standard library's *testing.T. +type TestReporter interface { + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) +} + +// TestHelper is a TestReporter that has the Helper method. It is satisfied +// by the standard library's *testing.T. +type TestHelper interface { + TestReporter + Helper() +} + +// A Controller represents the top-level control of a mock ecosystem. It +// defines the scope and lifetime of mock objects, as well as their +// expectations. It is safe to call Controller's methods from multiple +// goroutines. Each test should create a new Controller and invoke Finish via +// defer. +// +// func TestFoo(t *testing.T) { +// ctrl := gomock.NewController(st) +// defer ctrl.Finish() +// // .. +// } +// +// func TestBar(t *testing.T) { +// t.Run("Sub-Test-1", st) { +// ctrl := gomock.NewController(st) +// defer ctrl.Finish() +// // .. +// }) +// t.Run("Sub-Test-2", st) { +// ctrl := gomock.NewController(st) +// defer ctrl.Finish() +// // .. +// }) +// }) +type Controller struct { + // T should only be called within a generated mock. It is not intended to + // be used in user code and may be changed in future versions. T is the + // TestReporter passed in when creating the Controller via NewController. + // If the TestReporter does not implement a TestHelper it will be wrapped + // with a nopTestHelper. + T TestHelper + mu sync.Mutex + expectedCalls *callSet + finished bool +} + +// NewController returns a new Controller. It is the preferred way to create a +// Controller. +func NewController(t TestReporter) *Controller { + h, ok := t.(TestHelper) + if !ok { + h = nopTestHelper{t} + } + + return &Controller{ + T: h, + expectedCalls: newCallSet(), + } +} + +type cancelReporter struct { + TestHelper + cancel func() +} + +func (r *cancelReporter) Errorf(format string, args ...interface{}) { + r.TestHelper.Errorf(format, args...) +} +func (r *cancelReporter) Fatalf(format string, args ...interface{}) { + defer r.cancel() + r.TestHelper.Fatalf(format, args...) +} + +// WithContext returns a new Controller and a Context, which is cancelled on any +// fatal failure. +func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) { + h, ok := t.(TestHelper) + if !ok { + h = nopTestHelper{t} + } + + ctx, cancel := context.WithCancel(ctx) + return NewController(&cancelReporter{h, cancel}), ctx +} + +type nopTestHelper struct { + TestReporter +} + +func (h nopTestHelper) Helper() {} + +// RecordCall is called by a mock. It should not be called by user code. +func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call { + ctrl.T.Helper() + + recv := reflect.ValueOf(receiver) + for i := 0; i < recv.Type().NumMethod(); i++ { + if recv.Type().Method(i).Name == method { + return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...) + } + } + ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver) + panic("unreachable") +} + +// RecordCallWithMethodType is called by a mock. It should not be called by user code. +func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + ctrl.T.Helper() + + call := newCall(ctrl.T, receiver, method, methodType, args...) + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + ctrl.expectedCalls.Add(call) + + return call +} + +// Call is called by a mock. It should not be called by user code. +func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} { + ctrl.T.Helper() + + // Nest this code so we can use defer to make sure the lock is released. + actions := func() []func([]interface{}) []interface{} { + ctrl.T.Helper() + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args) + if err != nil { + origin := callerInfo(2) + ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err) + } + + // Two things happen here: + // * the matching call no longer needs to check prerequite calls, + // * and the prerequite calls are no longer expected, so remove them. + preReqCalls := expected.dropPrereqs() + for _, preReqCall := range preReqCalls { + ctrl.expectedCalls.Remove(preReqCall) + } + + actions := expected.call(args) + if expected.exhausted() { + ctrl.expectedCalls.Remove(expected) + } + return actions + }() + + var rets []interface{} + for _, action := range actions { + if r := action(args); r != nil { + rets = r + } + } + + return rets +} + +// Finish checks to see if all the methods that were expected to be called +// were called. It should be invoked for each Controller. It is not idempotent +// and therefore can only be invoked once. +func (ctrl *Controller) Finish() { + ctrl.T.Helper() + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + if ctrl.finished { + ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.") + } + ctrl.finished = true + + // If we're currently panicking, probably because this is a deferred call, + // pass through the panic. + if err := recover(); err != nil { + panic(err) + } + + // Check that all remaining expected calls are satisfied. + failures := ctrl.expectedCalls.Failures() + for _, call := range failures { + ctrl.T.Errorf("missing call(s) to %v", call) + } + if len(failures) != 0 { + ctrl.T.Fatalf("aborting test due to missing call(s)") + } +} + +func callerInfo(skip int) string { + if _, file, line, ok := runtime.Caller(skip + 1); ok { + return fmt.Sprintf("%s:%d", file, line) + } + return "unknown file" +} diff --git a/vendor/github.com/golang/mock/gomock/matchers.go b/vendor/github.com/golang/mock/gomock/matchers.go new file mode 100644 index 000000000..fbff06062 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/matchers.go @@ -0,0 +1,141 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "fmt" + "reflect" +) + +// A Matcher is a representation of a class of values. +// It is used to represent the valid or expected arguments to a mocked method. +type Matcher interface { + // Matches returns whether x is a match. + Matches(x interface{}) bool + + // String describes what the matcher matches. + String() string +} + +type anyMatcher struct{} + +func (anyMatcher) Matches(x interface{}) bool { + return true +} + +func (anyMatcher) String() string { + return "is anything" +} + +type eqMatcher struct { + x interface{} +} + +func (e eqMatcher) Matches(x interface{}) bool { + return reflect.DeepEqual(e.x, x) +} + +func (e eqMatcher) String() string { + return fmt.Sprintf("is equal to %v", e.x) +} + +type nilMatcher struct{} + +func (nilMatcher) Matches(x interface{}) bool { + if x == nil { + return true + } + + v := reflect.ValueOf(x) + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice: + return v.IsNil() + } + + return false +} + +func (nilMatcher) String() string { + return "is nil" +} + +type notMatcher struct { + m Matcher +} + +func (n notMatcher) Matches(x interface{}) bool { + return !n.m.Matches(x) +} + +func (n notMatcher) String() string { + // TODO: Improve this if we add a NotString method to the Matcher interface. + return "not(" + n.m.String() + ")" +} + +type assignableToTypeOfMatcher struct { + targetType reflect.Type +} + +func (m assignableToTypeOfMatcher) Matches(x interface{}) bool { + return reflect.TypeOf(x).AssignableTo(m.targetType) +} + +func (m assignableToTypeOfMatcher) String() string { + return "is assignable to " + m.targetType.Name() +} + +// Constructors +// Any returns a matcher that always matches. +func Any() Matcher { return anyMatcher{} } + +// Eq returns a matcher that matches on equality. +// +// Example usage: +// Eq(5).Matches(5) // returns true +// Eq(5).Matches(4) // returns false +func Eq(x interface{}) Matcher { return eqMatcher{x} } + +// Nil returns a matcher that matches if the received value is nil. +// +// Example usage: +// var x *bytes.Buffer +// Nil().Matches(x) // returns true +// x = &bytes.Buffer{} +// Nil().Matches(x) // returns false +func Nil() Matcher { return nilMatcher{} } + +// Not reverses the results of its given child matcher. +// +// Example usage: +// Not(Eq(5)).Matches(4) // returns true +// Not(Eq(5)).Matches(5) // returns false +func Not(x interface{}) Matcher { + if m, ok := x.(Matcher); ok { + return notMatcher{m} + } + return notMatcher{Eq(x)} +} + +// AssignableToTypeOf is a Matcher that matches if the parameter to the mock +// function is assignable to the type of the parameter to this function. +// +// Example usage: +// var s fmt.Stringer = &bytes.Buffer{} +// AssignableToTypeOf(s).Matches(time.Second) // returns true +// AssignableToTypeOf(s).Matches(99) // returns false +func AssignableToTypeOf(x interface{}) Matcher { + return assignableToTypeOfMatcher{reflect.TypeOf(x)} +} diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index 533438d91..9857fe53d 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -7,9 +7,8 @@ package errgroup import ( + "context" "sync" - - "golang.org/x/net/context" ) // A Group is a collection of goroutines working on subtasks that are part of diff --git a/vendor/golang.org/x/sync/singleflight/singleflight.go b/vendor/golang.org/x/sync/singleflight/singleflight.go index 9a4f8d59e..97a1aa4bb 100644 --- a/vendor/golang.org/x/sync/singleflight/singleflight.go +++ b/vendor/golang.org/x/sync/singleflight/singleflight.go @@ -17,6 +17,10 @@ type call struct { val interface{} err error + // forgotten indicates whether Forget was called with this call's key + // while the call was still in flight. + forgotten bool + // These fields are read and written with the singleflight // mutex held before the WaitGroup is done, and are read but // not written after the WaitGroup is done. @@ -94,7 +98,9 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { c.wg.Done() g.mu.Lock() - delete(g.m, key) + if !c.forgotten { + delete(g.m, key) + } for _, ch := range c.chans { ch <- Result{c.val, c.err, c.dups > 0} } @@ -106,6 +112,9 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { // an earlier call to complete. func (g *Group) Forget(key string) { g.mu.Lock() + if c, ok := g.m[key]; ok { + c.forgotten = true + } delete(g.m, key) g.mu.Unlock() } diff --git a/vendor/modules.txt b/vendor/modules.txt index 333d0f166..88f938565 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -219,6 +219,8 @@ github.com/gogo/protobuf/sortkeys github.com/gogo/protobuf/types # github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/glog +# github.com/golang/mock v1.3.1 +github.com/golang/mock/gomock # github.com/golang/protobuf v1.1.0 github.com/golang/protobuf/proto github.com/golang/protobuf/protoc-gen-go/descriptor @@ -431,7 +433,7 @@ golang.org/x/oauth2/google golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f +# golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/sync/errgroup golang.org/x/sync/singleflight golang.org/x/sync/syncmap From a9896d5c43cc0c620d04a6b082ee7f0f56d55811 Mon Sep 17 00:00:00 2001 From: Cole Wippern Date: Fri, 17 Jan 2020 14:32:36 -0800 Subject: [PATCH 4/6] update mocks with license --- pkg/mocks/go-containerregistry/mock_v1/mocks.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/mocks/go-containerregistry/mock_v1/mocks.go b/pkg/mocks/go-containerregistry/mock_v1/mocks.go index 0415fe721..b2e18db84 100644 --- a/pkg/mocks/go-containerregistry/mock_v1/mocks.go +++ b/pkg/mocks/go-containerregistry/mock_v1/mocks.go @@ -1,3 +1,17 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Code generated by MockGen. DO NOT EDIT. // Source: github.com/google/go-containerregistry/pkg/v1 (interfaces: Layer) From f96ea3bbfb0d3585ba808714cd92220bf3132849 Mon Sep 17 00:00:00 2001 From: Cole Wippern Date: Fri, 17 Jan 2020 14:56:12 -0800 Subject: [PATCH 5/6] hand edit mock license for some reason hack/boilerplate.sh failed after using `addlicense` so I copy/pasted the license header from another file --- .../go-containerregistry/mock_v1/mocks.go | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/pkg/mocks/go-containerregistry/mock_v1/mocks.go b/pkg/mocks/go-containerregistry/mock_v1/mocks.go index b2e18db84..d547f05a8 100644 --- a/pkg/mocks/go-containerregistry/mock_v1/mocks.go +++ b/pkg/mocks/go-containerregistry/mock_v1/mocks.go @@ -1,16 +1,18 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/google/go-containerregistry/pkg/v1 (interfaces: Layer) @@ -19,11 +21,12 @@ package mock_v1 import ( + io "io" + reflect "reflect" + gomock "github.com/golang/mock/gomock" v1 "github.com/google/go-containerregistry/pkg/v1" types "github.com/google/go-containerregistry/pkg/v1/types" - io "io" - reflect "reflect" ) // MockLayer is a mock of Layer interface From 96093359c16ae0e3a028e8e0ed2dd2c9f0c0df36 Mon Sep 17 00:00:00 2001 From: Cole Wippern Date: Fri, 17 Jan 2020 14:59:14 -0800 Subject: [PATCH 6/6] rename mock pkg for lint --- .../{mock_v1 => mockv1}/mocks.go | 4 ++-- pkg/util/fs_util_test.go | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) rename pkg/mocks/go-containerregistry/{mock_v1 => mockv1}/mocks.go (98%) diff --git a/pkg/mocks/go-containerregistry/mock_v1/mocks.go b/pkg/mocks/go-containerregistry/mockv1/mocks.go similarity index 98% rename from pkg/mocks/go-containerregistry/mock_v1/mocks.go rename to pkg/mocks/go-containerregistry/mockv1/mocks.go index d547f05a8..1d2cc4291 100644 --- a/pkg/mocks/go-containerregistry/mock_v1/mocks.go +++ b/pkg/mocks/go-containerregistry/mockv1/mocks.go @@ -17,8 +17,8 @@ limitations under the License. // Code generated by MockGen. DO NOT EDIT. // Source: github.com/google/go-containerregistry/pkg/v1 (interfaces: Layer) -// Package mock_v1 is a generated GoMock package. -package mock_v1 +// Package mockv1 is a generated GoMock package. +package mockv1 import ( io "io" diff --git a/pkg/util/fs_util_test.go b/pkg/util/fs_util_test.go index d2adaebaa..6757e2f22 100644 --- a/pkg/util/fs_util_test.go +++ b/pkg/util/fs_util_test.go @@ -29,7 +29,7 @@ import ( "strings" "testing" - "github.com/GoogleContainerTools/kaniko/pkg/mocks/go-containerregistry/mock_v1" + "github.com/GoogleContainerTools/kaniko/pkg/mocks/go-containerregistry/mockv1" "github.com/GoogleContainerTools/kaniko/testutil" "github.com/golang/mock/gomock" v1 "github.com/google/go-containerregistry/pkg/v1" @@ -924,7 +924,7 @@ func Test_GetFSFromLayers_with_whiteouts_include_whiteout_enabled(t *testing.T) f(expectedFiles, tw) - mockLayer := mock_v1.NewMockLayer(ctrl) + mockLayer := mockv1.NewMockLayer(ctrl) mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil) rc := ioutil.NopCloser(buf) @@ -939,7 +939,7 @@ func Test_GetFSFromLayers_with_whiteouts_include_whiteout_enabled(t *testing.T) f(secondLayerFiles, tw) - mockLayer2 := mock_v1.NewMockLayer(ctrl) + mockLayer2 := mockv1.NewMockLayer(ctrl) mockLayer2.EXPECT().MediaType().Return(types.OCILayer, nil) rc = ioutil.NopCloser(buf) @@ -1013,7 +1013,7 @@ func Test_GetFSFromLayers_with_whiteouts_include_whiteout_disabled(t *testing.T) f(expectedFiles, tw) - mockLayer := mock_v1.NewMockLayer(ctrl) + mockLayer := mockv1.NewMockLayer(ctrl) mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil) rc := ioutil.NopCloser(buf) @@ -1028,7 +1028,7 @@ func Test_GetFSFromLayers_with_whiteouts_include_whiteout_disabled(t *testing.T) f(secondLayerFiles, tw) - mockLayer2 := mock_v1.NewMockLayer(ctrl) + mockLayer2 := mockv1.NewMockLayer(ctrl) mockLayer2.EXPECT().MediaType().Return(types.OCILayer, nil) rc = ioutil.NopCloser(buf) @@ -1095,7 +1095,7 @@ func Test_GetFSFromLayers(t *testing.T) { t.Fatal(err) } - mockLayer := mock_v1.NewMockLayer(ctrl) + mockLayer := mockv1.NewMockLayer(ctrl) mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil) rc := ioutil.NopCloser(buf)