diff --git a/bindings-go/ctf/comp_test.go b/bindings-go/ctf/comp_test.go new file mode 100644 index 00000000..eb2dc47f --- /dev/null +++ b/bindings-go/ctf/comp_test.go @@ -0,0 +1,207 @@ +// Copyright 2020 Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file. +// +// 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 ctf_test + +import ( + "bytes" + "context" + "io" + "io/ioutil" + "os" + + "github.com/gardener/component-spec/bindings-go/ctf" + "github.com/mandelsoft/vfs/pkg/layerfs" + "github.com/mandelsoft/vfs/pkg/osfs" + "github.com/mandelsoft/vfs/pkg/projectionfs" + "github.com/mandelsoft/vfs/pkg/vfs" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + v2 "github.com/gardener/component-spec/bindings-go/apis/v2" + "github.com/mandelsoft/vfs/pkg/memoryfs" + "github.com/opencontainers/go-digest" +) + +func OpenTestComponent(path string) (*ctf.ComponentArchive, error) { + fs, err := projectionfs.New(osfs.New(), path) + if err != nil { + return nil, err + } + layer := memoryfs.New() // osfs.NewTempFileSystem() + fs = layerfs.New(layer, fs) + return ctf.NewComponentArchiveFromFilesystem(fs) +} + +var _ = Describe("ComponentArchive", func() { + + Context("build", func() { + It("should build a component archive from path", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := OpenTestComponent("./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) + + var data bytes.Buffer + info, err := ca.Resolve(ctx, ca.ComponentDescriptor.Resources[0], &data) + Expect(err).ToNot(HaveOccurred()) + Expect(info.MediaType).To(Equal("json")) + Expect(data.Bytes()).To(Equal([]byte("{\"some\": \"data\"}"))) + }) + + It("should build a component archive from a tar", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := OpenTestComponent("./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + + file, err := ioutil.TempFile(os.TempDir(), "ca-tar-") + Expect(err).ToNot(HaveOccurred()) + defer func() { + Expect(os.Remove(file.Name())).ToNot(HaveOccurred()) + }() + Expect(ca.WriteTar(file)).To(Succeed()) + + ca, err = ctf.ComponentArchiveFromCTF(file.Name()) + Expect(err).ToNot(HaveOccurred()) + + var data bytes.Buffer + info, err := ca.Resolve(ctx, ca.ComponentDescriptor.Resources[0], &data) + Expect(err).ToNot(HaveOccurred()) + Expect(info.MediaType).To(Equal("json")) + Expect(data.Bytes()).To(Equal([]byte("{\"some\": \"data\"}"))) + }) + }) + + It("should build a tar from a component archive", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := OpenTestComponent("./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + + var data bytes.Buffer + Expect(ca.WriteTar(&data)).To(Succeed()) + + fs := memoryfs.New() + Expect(ctf.ExtractTarToFs(fs, &data)).To(Succeed()) + + _, err = fs.Stat(ctf.ComponentDescriptorFileName) + Expect(err).ToNot(HaveOccurred()) + blobData, err := vfs.ReadFile(fs, "blobs/myblob") + Expect(err).ToNot(HaveOccurred()) + Expect(blobData).To(Equal([]byte("{\"some\": \"data\"}"))) + }) + + It("should write a component archive to a filesystem", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := OpenTestComponent("./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + + fs := memoryfs.New() + Expect(ca.WriteToFilesystem(fs, "test")).To(Succeed()) + + _, err = fs.Stat(vfs.Join(fs, "test", ctf.ComponentDescriptorFileName)) + Expect(err).ToNot(HaveOccurred()) + blobData, err := vfs.ReadFile(fs, "test/blobs/myblob") + Expect(err).ToNot(HaveOccurred()) + Expect(blobData).To(Equal([]byte("{\"some\": \"data\"}"))) + }) + + It("should add a resource to the component archive from a data reader", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := OpenTestComponent("./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) + + data := []byte("test") + info := &ctf.BlobInfo{ + MediaType: "txt", + Digest: digest.FromBytes(data).String(), + Size: int64(len(data)), + } + res := v2.Resource{ + IdentityObjectMeta: v2.IdentityObjectMeta{ + Name: "res1", + Type: "txt", + Version: "v1.1", + }, + Relation: v2.ExternalRelation, + } + Expect(ca.AddResource(&res, *info, bytes.NewBuffer(data))) + + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(2)) + var result bytes.Buffer + info, err = ca.Resolve(ctx, res, &result) + Expect(err).ToNot(HaveOccurred()) + Expect(info.MediaType).To(Equal("txt")) + Expect(result.Bytes()).To(Equal(data)) + }) + + It("should add a resource to the component archive from a blobresolver", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := OpenTestComponent("./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) + + data := []byte("test") + info := &ctf.BlobInfo{ + MediaType: "txt", + Digest: digest.FromBytes(data).String(), + Size: int64(len(data)), + } + res := v2.Resource{ + IdentityObjectMeta: v2.IdentityObjectMeta{ + Name: "res1", + Type: "txt", + Version: "v1.1", + }, + + Relation: v2.ExternalRelation, + } + blobresolver := &testBlobResolver{ + info: func(ctx context.Context, res v2.Resource) (*ctf.BlobInfo, error) { return info, nil }, + resolve: func(ctx context.Context, res v2.Resource, writer io.Writer) (*ctf.BlobInfo, error) { + if _, err := io.Copy(writer, bytes.NewBuffer(data)); err != nil { + return nil, err + } + return info, nil + }, + } + Expect(ca.AddResourceFromResolver(ctx, &res, blobresolver)) + + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(2)) + var result bytes.Buffer + info, err = ca.Resolve(ctx, res, &result) + Expect(err).ToNot(HaveOccurred()) + Expect(info.MediaType).To(Equal("txt")) + Expect(result.Bytes()).To(Equal(data)) + }) + +}) + +type testBlobResolver struct { + info func(ctx context.Context, res v2.Resource) (*ctf.BlobInfo, error) + resolve func(ctx context.Context, res v2.Resource, writer io.Writer) (*ctf.BlobInfo, error) +} + +func (t *testBlobResolver) Info(ctx context.Context, res v2.Resource) (*ctf.BlobInfo, error) { + return t.info(ctx, res) +} +func (t *testBlobResolver) Resolve(ctx context.Context, res v2.Resource, writer io.Writer) (*ctf.BlobInfo, error) { + return t.resolve(ctx, res, writer) +} diff --git a/bindings-go/ctf/componentarchive.go b/bindings-go/ctf/componentarchive.go index a4a70ce5..103e3141 100644 --- a/bindings-go/ctf/componentarchive.go +++ b/bindings-go/ctf/componentarchive.go @@ -47,6 +47,46 @@ func NewComponentArchive(cd *v2.ComponentDescriptor, fs vfs.FileSystem) *Compone } } +func NewComponentArchiveFromPath(fs vfs.FileSystem, path string) (*ComponentArchive, error) { + return OpenComponentArchive(fs, path) +} + +func OpenComponentArchive(fs vfs.FileSystem, path string) (*ComponentArchive, error) { + if fs == nil { + fs = osfs.New() + } + fi, err := fs.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return nil, vfs.ErrNotExist + } + return nil, err + } + if fi.IsDir() { + cfs, err := projectionfs.New(fs, path) + if err != nil { + return nil, fmt.Errorf("unable to create projected filesystem from path %s: %w", path, err) + } + return NewComponentArchiveFromFilesystem(cfs) + } + + file, err := fs.Open(path) + if err != nil { + return nil, fmt.Errorf("unable to open tar archive from %s: %w", path, err) + } + + reader, err := gzip.NewReader(file) + if err == nil { + defer file.Close() + return NewComponentArchiveFromTarReader(reader) + } + file.Close() + file, err = fs.Open(path) + + defer file.Close() + return NewComponentArchiveFromTarReader(file) +} + // ComponentArchiveFromPath creates a component archive from a path func ComponentArchiveFromPath(path string) (*ComponentArchive, error) { fs, err := projectionfs.New(osfs.New(), path) @@ -98,7 +138,7 @@ func NewComponentArchiveFromTarReader(in io.Reader) (*ComponentArchive, error) { // NewComponentArchiveFromFilesystem creates a new component archive from a filesystem. func NewComponentArchiveFromFilesystem(fs vfs.FileSystem, decodeOpts ...codec.DecodeOption) (*ComponentArchive, error) { - data, err := vfs.ReadFile(fs, filepath.Join("/", ComponentDescriptorFileName)) + data, err := vfs.ReadFile(fs, vfs.Join(fs, "/", ComponentDescriptorFileName)) if err != nil { return nil, fmt.Errorf("unable to read the component descriptor from %s: %w", ComponentDescriptorFileName, err) } @@ -133,6 +173,17 @@ func (ca *ComponentArchive) Digest() (string, error) { return digest.FromBytes(data).String(), nil } +func (ca *ComponentArchive) writeCD() error { + cdBytes, err := codec.Encode(ca.ComponentDescriptor) + if err != nil { + return fmt.Errorf("unable to encode component descriptor: %w", err) + } + if err := vfs.WriteFile(ca.fs, ComponentDescriptorFileName, cdBytes, os.ModePerm); err != nil { + return fmt.Errorf("unable to copy component descritptor to %q: %w", ComponentDescriptorFileName, err) + } + return nil +} + // AddResource adds a blob resource to the current archive. // If the specified resource already exists it will be overwritten. func (ca *ComponentArchive) AddResource(res *v2.Resource, info BlobInfo, reader io.Reader) error { @@ -173,7 +224,7 @@ func (ca *ComponentArchive) AddResource(res *v2.Resource, info BlobInfo, reader } else { ca.ComponentDescriptor.Resources[id] = *res } - return nil + return ca.writeCD() } // AddSource adds a blob source to the current archive. @@ -216,7 +267,7 @@ func (ca *ComponentArchive) AddSource(src *v2.Source, info BlobInfo, reader io.R } else { ca.ComponentDescriptor.Sources[id] = *src } - return nil + return ca.writeCD() } // AddResourceFromResolver adds a blob resource to the current archive. @@ -264,7 +315,7 @@ func (ca *ComponentArchive) AddResourceFromResolver(ctx context.Context, res *v2 } else { ca.ComponentDescriptor.Resources[id] = *res } - return nil + return ca.writeCD() } // ensureBlobsPath ensures that the blob directory exists @@ -278,6 +329,17 @@ func (ca *ComponentArchive) ensureBlobsPath() error { return nil } +// WriteToArchive writes an archive of the given type. +func (ca *ComponentArchive) WriteToArchive(writer io.Writer, format ArchiveFormat) error { + if format == ArchiveFormatTar { + return ca.WriteTar(writer) + } + if format == ArchiveFormatTarGzip { + return ca.WriteTarGzip(writer) + } + return fmt.Errorf("invalid archive format '%s'", format) +} + // WriteTarGzip tars the current components descriptor and its artifacts. func (ca *ComponentArchive) WriteTarGzip(writer io.Writer) error { gw := gzip.NewWriter(writer) @@ -358,7 +420,7 @@ func (ca *ComponentArchive) WriteTar(writer io.Writer) error { // WriteToFilesystem writes the current component archive to a filesystem func (ca *ComponentArchive) WriteToFilesystem(fs vfs.FileSystem, path string) error { // create the directory structure with the blob directory - if err := fs.MkdirAll(filepath.Join(path, BlobsDirectoryName), os.ModePerm); err != nil { + if err := fs.MkdirAll(vfs.Join(fs, path, BlobsDirectoryName), os.ModePerm); err != nil { return fmt.Errorf("unable to create output directory %q: %s", path, err.Error()) } // copy component-descriptor @@ -366,8 +428,8 @@ func (ca *ComponentArchive) WriteToFilesystem(fs vfs.FileSystem, path string) er if err != nil { return fmt.Errorf("unable to encode component descriptor: %w", err) } - if err := vfs.WriteFile(fs, filepath.Join(path, ComponentDescriptorFileName), cdBytes, os.ModePerm); err != nil { - return fmt.Errorf("unable to copy component descritptor to %q: %w", filepath.Join(path, ComponentDescriptorFileName), err) + if err := vfs.WriteFile(fs, vfs.Join(fs, path, ComponentDescriptorFileName), cdBytes, os.ModePerm); err != nil { + return fmt.Errorf("unable to copy component descritptor to %q: %w", vfs.Join(fs, path, ComponentDescriptorFileName), err) } // copy all blobs @@ -383,7 +445,7 @@ func (ca *ComponentArchive) WriteToFilesystem(fs vfs.FileSystem, path string) er continue } inpath := BlobPath(blobInfo.Name()) - outpath := filepath.Join(path, BlobsDirectoryName, blobInfo.Name()) + outpath := vfs.Join(fs, path, BlobsDirectoryName, blobInfo.Name()) blob, err := ca.fs.Open(inpath) if err != nil { return fmt.Errorf("unable to open input blob %q: %w", inpath, err) diff --git a/bindings-go/ctf/ctf.go b/bindings-go/ctf/ctf.go index 9c6ffe63..fe999c75 100644 --- a/bindings-go/ctf/ctf.go +++ b/bindings-go/ctf/ctf.go @@ -16,12 +16,14 @@ package ctf import ( "archive/tar" + "compress/gzip" "context" "errors" "fmt" "io" "os" + "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/projectionfs" "github.com/mandelsoft/vfs/pkg/vfs" @@ -91,32 +93,112 @@ const ( ) type CTF struct { - fs vfs.FileSystem + fs vfs.FileSystem ctfPath string + format ArchiveFormat tempDir string - tempFs vfs.FileSystem + ctfFS vfs.FileSystem } // NewCTF reads a CTF archive from a file. // The use should call "Close" to remove all temporary files func NewCTF(fs vfs.FileSystem, ctfPath string) (*CTF, error) { - tempDir, err := vfs.TempDir(fs, "", "ctf-") - if err != nil { - return nil, err + return OpenCTF(fs, ctfPath, CTF_OPEN) +} + +type CTFMode int + +const ( + CTF_OPEN CTFMode = 0 + CTF_DIR = 1 + CTF_TAR = 2 + CTF_TGZ = 3 +) + +// OpenCTF opens an existing or newly created ctf +func OpenCTF(fs vfs.FileSystem, ctfPath string, mode CTFMode) (*CTF, error) { + if fs == nil { + fs = osfs.New() } - tempFs, err := projectionfs.New(fs, tempDir) + var format ArchiveFormat = "" + // fmt.Println("open archive "+ctfPath) + fi, err := fs.Stat(ctfPath) + if err != nil { - return nil, fmt.Errorf("unable to create fs for temporary directory %q: %w", tempDir, err) + if mode == CTF_OPEN || !os.IsNotExist(err) { + return nil, err + } + if mode == CTF_DIR { + // fmt.Println("creating dir "+ctfPath) + err = fs.Mkdir(ctfPath, os.ModePerm) + if err != nil { + return nil, fmt.Errorf("unable to create directory %s: %w", ctfPath, err) + } + } else { + // fmt.Println("creating archive "+ctfPath) + file, err := fs.OpenFile(ctfPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660) + if err != nil { + return nil, fmt.Errorf("unable to open file for %s: %w", ctfPath, err) + } + var w io.Writer = file + if mode == CTF_TGZ { + w = gzip.NewWriter(w) + format = ArchiveFormatTarGzip + } else { + format = ArchiveFormatTar + } + tw := tar.NewWriter(file) + if err := tw.Close(); err != nil { + return nil, fmt.Errorf("unable to close tarwriter for emtpy tar: %w", err) + } + if err := file.Close(); err != nil { + return nil, fmt.Errorf("unable to close tarwriter for emtpy tar: %w", err) + } + } + fi, err = fs.Stat(ctfPath) + if err != nil { + return nil, fmt.Errorf("unable to get info for %s: %w", ctfPath, err) + } } + if err != nil { + if os.IsNotExist(err) { + return nil, vfs.ErrNotExist + } + return nil, err + } ctf := &CTF{ fs: fs, ctfPath: ctfPath, - tempDir: tempDir, - tempFs: tempFs, + format: format, } - if err := ctf.extract(); err != nil { - return nil, fmt.Errorf("unable to read ctf: %w", err) + if fi.IsDir() { + if mode == CTF_TAR || mode == CTF_TGZ { + return nil, fmt.Errorf("archive requested, but found directory") + } + tempFs, err := projectionfs.New(fs, ctfPath) + if err != nil { + return nil, fmt.Errorf("unable to create fs for directory %q: %w", ctfPath, err) + } + ctf.ctfFS = tempFs + } else { + if mode == CTF_DIR { + return nil, fmt.Errorf("directory requested, but found tar") + } + tempDir, err := vfs.TempDir(fs, "", "ctf-") + if err != nil { + return nil, err + } + tempFs, err := projectionfs.New(fs, tempDir) + if err != nil { + return nil, fmt.Errorf("unable to create fs for temporary directory %q: %w", tempDir, err) + } + + ctf.tempDir = tempDir + ctf.ctfFS = tempFs + if err := ctf.extract(); err != nil { + return nil, fmt.Errorf("unable to read ctf: %w", err) + } } return ctf, nil } @@ -125,7 +207,7 @@ type WalkFunc = func(ca *ComponentArchive) error // Walk traverses through all component archives that are included in the ctf. func (ctf *CTF) Walk(walkFunc WalkFunc) error { - err := vfs.Walk(ctf.tempFs, "/", func(path string, info os.FileInfo, err error) error { + err := vfs.Walk(ctf.ctfFS, "/", func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -133,15 +215,10 @@ func (ctf *CTF) Walk(walkFunc WalkFunc) error { return nil } - file, err := ctf.tempFs.Open(path) - if err != nil { - return fmt.Errorf("unable to read component archive file %q: %w", path, err) - } - ca, err := NewComponentArchiveFromTarReader(file) + ca, err := OpenComponentArchive(ctf.ctfFS, path) if err != nil { return err } - return walkFunc(ca) }) return err @@ -159,7 +236,7 @@ func (ctf *CTF) AddComponentArchive(ca *ComponentArchive, format ArchiveFormat) // AddComponentArchiveWithName adds or updates a component archive in the ctf archive. // The archive is added to the ctf with the given name func (ctf *CTF) AddComponentArchiveWithName(filename string, ca *ComponentArchive, format ArchiveFormat) error { - file, err := ctf.tempFs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) + file, err := ctf.ctfFS.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { return err } @@ -187,21 +264,83 @@ func (ctf *CTF) extract() error { if err != nil { return err } + var reader io.Reader + reader, err = gzip.NewReader(file) + if err != nil { + file.Close() + reader, err = ctf.fs.Open(ctf.ctfPath) + if err != nil { + return err + } + ctf.format = ArchiveFormatTar + } else { + ctf.format = ArchiveFormatTarGzip + } defer file.Close() - return ExtractTarToFs(ctf.tempFs, file) + return ExtractTarToFs(ctf.ctfFS, reader) } // Write writes the current changes back to the original ctf. func (ctf *CTF) Write() error { - file, err := ctf.fs.OpenFile(ctf.ctfPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) + if ctf.tempDir == "" { + return nil + } + return ctf.WriteToArchive(ctf.fs, ctf.ctfPath, ctf.format) +} + +func (ctf *CTF) WriteToFilesystem(fs vfs.FileSystem, ctfpath string) error { + fi, err := fs.Stat(ctfpath) + if err != nil && !vfs.IsErrNotExist(err) { + return err + } + if err == nil { + if !fi.IsDir() { + return vfs.ErrNotDir + } + /* + err = fs.RemoveAll(path) + if err != nil { + return err + } + */ + } + err = fs.Mkdir(ctfpath, 0770) + if err != nil && !vfs.IsErrExist(err) { + return err + } + + err = vfs.Walk(ctf.ctfFS, "/", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + fmt.Printf("copying %s to %s\n", path, vfs.Join(fs, ctfpath, path)) + return vfs.CopyFile(ctf.ctfFS, path, fs, vfs.Join(fs, ctfpath, path)) + }) + return err +} + +func (ctf *CTF) WriteToArchive(fs vfs.FileSystem, path string, format ArchiveFormat) error { + if fs == nil { + fs = osfs.New() + } + file, err := fs.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { return err } + var writer io.Writer = file defer file.Close() - tw := tar.NewWriter(file) + if format == ArchiveFormatTarGzip { + zw := gzip.NewWriter(writer) + defer zw.Close() + writer = zw + } + tw := tar.NewWriter(writer) defer tw.Close() - err = vfs.Walk(ctf.tempFs, "/", func(path string, info os.FileInfo, err error) error { + err = vfs.Walk(ctf.ctfFS, "/", func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -216,7 +355,7 @@ func (ctf *CTF) Write() error { return fmt.Errorf("unable to write header for %q: %w", path, err) } - blob, err := ctf.tempFs.Open(path) + blob, err := ctf.ctfFS.Open(path) if err != nil { return fmt.Errorf("unable to open blob %q: %w", path, err) } @@ -231,7 +370,10 @@ func (ctf *CTF) Write() error { // Close closes the CTF that deletes all temporary files func (ctf *CTF) Close() error { - return ctf.fs.RemoveAll(ctf.tempDir) + if ctf.tempDir != "" { + return ctf.fs.RemoveAll(ctf.tempDir) + } + return nil } // AggregatedBlobResolver combines multiple blob resolver. diff --git a/bindings-go/ctf/ctf_suite_test.go b/bindings-go/ctf/ctf_suite_test.go index a03ed289..9ced8f7f 100644 --- a/bindings-go/ctf/ctf_suite_test.go +++ b/bindings-go/ctf/ctf_suite_test.go @@ -15,174 +15,13 @@ package ctf_test import ( - "bytes" - "context" - "io" - "io/ioutil" - "os" - "path/filepath" "testing" - "github.com/mandelsoft/vfs/pkg/memoryfs" - "github.com/mandelsoft/vfs/pkg/vfs" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/opencontainers/go-digest" - - v2 "github.com/gardener/component-spec/bindings-go/apis/v2" - "github.com/gardener/component-spec/bindings-go/ctf" ) func TestConfig(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "ctf Test Suite") } - -var _ = Describe("ComponentArchive", func() { - - Context("build", func() { - It("should build a component archive from path", func() { - ctx := context.Background() - defer ctx.Done() - ca, err := ctf.ComponentArchiveFromPath("./testdata/component-01") - Expect(err).ToNot(HaveOccurred()) - Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) - - var data bytes.Buffer - info, err := ca.Resolve(ctx, ca.ComponentDescriptor.Resources[0], &data) - Expect(err).ToNot(HaveOccurred()) - Expect(info.MediaType).To(Equal("json")) - Expect(data.Bytes()).To(Equal([]byte("{\"some\": \"data\"}"))) - }) - - It("should build a component archive from a tar", func() { - ctx := context.Background() - defer ctx.Done() - ca, err := ctf.ComponentArchiveFromPath("./testdata/component-01") - Expect(err).ToNot(HaveOccurred()) - - file, err := ioutil.TempFile(os.TempDir(), "ca-tar-") - Expect(err).ToNot(HaveOccurred()) - defer func() { - Expect(os.Remove(file.Name())).ToNot(HaveOccurred()) - }() - Expect(ca.WriteTar(file)).To(Succeed()) - - ca, err = ctf.ComponentArchiveFromCTF(file.Name()) - Expect(err).ToNot(HaveOccurred()) - - var data bytes.Buffer - info, err := ca.Resolve(ctx, ca.ComponentDescriptor.Resources[0], &data) - Expect(err).ToNot(HaveOccurred()) - Expect(info.MediaType).To(Equal("json")) - Expect(data.Bytes()).To(Equal([]byte("{\"some\": \"data\"}"))) - }) - }) - - It("should build a tar from a component archive", func() { - ctx := context.Background() - defer ctx.Done() - ca, err := ctf.ComponentArchiveFromPath("./testdata/component-01") - Expect(err).ToNot(HaveOccurred()) - - var data bytes.Buffer - Expect(ca.WriteTar(&data)).To(Succeed()) - - fs := memoryfs.New() - Expect(ctf.ExtractTarToFs(fs, &data)).To(Succeed()) - - _, err = fs.Stat(ctf.ComponentDescriptorFileName) - Expect(err).ToNot(HaveOccurred()) - blobData, err := vfs.ReadFile(fs, "blobs/myblob") - Expect(err).ToNot(HaveOccurred()) - Expect(blobData).To(Equal([]byte("{\"some\": \"data\"}"))) - }) - - It("should add a resource to the component archive from a data reader", func() { - ctx := context.Background() - defer ctx.Done() - ca, err := ctf.ComponentArchiveFromPath("./testdata/component-01") - Expect(err).ToNot(HaveOccurred()) - Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) - - data := []byte("test") - info := &ctf.BlobInfo{ - MediaType: "txt", - Digest: digest.FromBytes(data).String(), - Size: int64(len(data)), - } - res := v2.Resource{ - IdentityObjectMeta: v2.IdentityObjectMeta{ - Name: "res1", - Type: "txt", - }, - Relation: v2.ExternalRelation, - } - Expect(ca.AddResource(&res, *info, bytes.NewBuffer(data))) - defer func() { - Expect(os.Remove(filepath.Join("./testdata/component-01", ctf.BlobPath(info.Digest)))).To(Succeed()) - }() - - Expect(ca.ComponentDescriptor.Resources).To(HaveLen(2)) - var result bytes.Buffer - info, err = ca.Resolve(ctx, res, &result) - Expect(err).ToNot(HaveOccurred()) - Expect(info.MediaType).To(Equal("txt")) - Expect(result.Bytes()).To(Equal(data)) - }) - - It("should add a resource to the component archive from a blobresolver", func() { - ctx := context.Background() - defer ctx.Done() - ca, err := ctf.ComponentArchiveFromPath("./testdata/component-01") - Expect(err).ToNot(HaveOccurred()) - Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) - - data := []byte("test") - info := &ctf.BlobInfo{ - MediaType: "txt", - Digest: digest.FromBytes(data).String(), - Size: int64(len(data)), - } - res := v2.Resource{ - IdentityObjectMeta: v2.IdentityObjectMeta{ - Name: "res1", - Type: "txt", - }, - Relation: v2.ExternalRelation, - } - blobresolver := &testBlobResolver{ - info: func(ctx context.Context, res v2.Resource) (*ctf.BlobInfo, error) { return info, nil }, - resolve: func(ctx context.Context, res v2.Resource, writer io.Writer) (*ctf.BlobInfo, error) { - if _, err := io.Copy(writer, bytes.NewBuffer(data)); err != nil { - return nil, err - } - return info, nil - }, - } - Expect(ca.AddResourceFromResolver(ctx, &res, blobresolver)) - defer func() { - Expect(os.Remove(filepath.Join("./testdata/component-01", ctf.BlobPath(info.Digest)))).To(Succeed()) - }() - - Expect(ca.ComponentDescriptor.Resources).To(HaveLen(2)) - var result bytes.Buffer - info, err = ca.Resolve(ctx, res, &result) - Expect(err).ToNot(HaveOccurred()) - Expect(info.MediaType).To(Equal("txt")) - Expect(result.Bytes()).To(Equal(data)) - }) - -}) - -type testBlobResolver struct { - info func(ctx context.Context, res v2.Resource) (*ctf.BlobInfo, error) - resolve func(ctx context.Context, res v2.Resource, writer io.Writer) (*ctf.BlobInfo, error) -} - -func (t *testBlobResolver) Info(ctx context.Context, res v2.Resource) (*ctf.BlobInfo, error) { - return t.info(ctx, res) -} -func (t *testBlobResolver) Resolve(ctx context.Context, res v2.Resource, writer io.Writer) (*ctf.BlobInfo, error) { - return t.resolve(ctx, res, writer) -} diff --git a/bindings-go/ctf/ctf_test.go b/bindings-go/ctf/ctf_test.go new file mode 100644 index 00000000..98139765 --- /dev/null +++ b/bindings-go/ctf/ctf_test.go @@ -0,0 +1,126 @@ +// Copyright 2020 Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file. +// +// 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 ctf_test + +import ( + "context" + "fmt" + "io/ioutil" + "os" + + "github.com/gardener/component-spec/bindings-go/ctf" + "github.com/mandelsoft/vfs/pkg/memoryfs" + "github.com/mandelsoft/vfs/pkg/vfs" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("CTF Archive", func() { + + Context("build", func() { + It("should build a ctf archive", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := ctf.OpenComponentArchive(nil, "./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) + + file, err := ioutil.TempFile("", ".ctf") + Expect(err).ToNot(HaveOccurred()) + + name := file.Name() + file.Close() + os.Remove(name) + defer os.Remove(name) + + fmt.Println("file: " + name) + c, err := ctf.OpenCTF(nil, name, ctf.CTF_TAR) + Expect(err).ToNot(HaveOccurred()) + err = c.AddComponentArchive(ca, ctf.ArchiveFormatTar) + Expect(err).ToNot(HaveOccurred()) + err = c.Write() + Expect(err).ToNot(HaveOccurred()) + c.Close() + checkCTF(nil, name) + }) + + It("should build a ctf archive and write it to a filesystem", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := ctf.OpenComponentArchive(nil, "./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) + + fs := memoryfs.New() + + c, err := ctf.OpenCTF(fs, "archive", ctf.CTF_TAR) + Expect(err).ToNot(HaveOccurred()) + err = c.AddComponentArchive(ca, ctf.ArchiveFormatTarGzip) + Expect(err).ToNot(HaveOccurred()) + err = c.Write() + Expect(err).ToNot(HaveOccurred()) + Expect(c.WriteToFilesystem(fs, "folder")).To(Succeed()) + c.Close() + fis, err := vfs.ReadDir(fs, "folder") + Expect(err).To(Succeed()) + fmt.Printf("found %d entries\n", len(fis)) + Expect(len(fis)).To(Equal(1)) + checkCTF(fs, "folder") + //checkCTF(fs, "archive") + }) + + It("should build a ctf folder", func() { + ctx := context.Background() + defer ctx.Done() + ca, err := ctf.OpenComponentArchive(nil, "./testdata/component-01") + Expect(err).ToNot(HaveOccurred()) + Expect(ca.ComponentDescriptor.Resources).To(HaveLen(1)) + + file, err := ioutil.TempFile("", ".ctf") + Expect(err).ToNot(HaveOccurred()) + + name := file.Name() + tar := "name" + ".tar" + file.Close() + os.Remove(name) + defer os.Remove(name) + defer os.Remove(tar) + + fmt.Println("file: " + name) + c, err := ctf.OpenCTF(nil, name, ctf.CTF_DIR) + Expect(err).ToNot(HaveOccurred()) + err = c.AddComponentArchive(ca, ctf.ArchiveFormatTar) + Expect(err).ToNot(HaveOccurred()) + err = c.WriteToArchive(nil, tar, ctf.ArchiveFormatTarGzip) + Expect(err).ToNot(HaveOccurred()) + c.Close() + checkCTF(nil, name) + checkCTF(nil, tar) + }) + }) +}) + +func checkCTF(fs vfs.FileSystem, name string) { + c, err := ctf.OpenCTF(fs, name, ctf.CTF_OPEN) + Expect(err).ToNot(HaveOccurred()) + defer c.Close() + cnt := 0 + c.Walk(func(ca *ctf.ComponentArchive) error { + fmt.Println(ca.Digest()) + cnt++ + return nil + }) + Expect(cnt).To(Equal(1)) +} diff --git a/bindings-go/ctf/listresolver.go b/bindings-go/ctf/listresolver.go index dd130fc7..b7bbfc52 100644 --- a/bindings-go/ctf/listresolver.go +++ b/bindings-go/ctf/listresolver.go @@ -12,7 +12,7 @@ import ( // ListResolver describes a ComponentResolver using a list of Component Descriptors type ListResolver struct { - List *cdv2.ComponentDescriptorList + List *cdv2.ComponentDescriptorList blobResolver *AggregatedBlobResolver } diff --git a/bindings-go/go.sum b/bindings-go/go.sum index 0f52cda8..c2108d51 100644 --- a/bindings-go/go.sum +++ b/bindings-go/go.sum @@ -1,3 +1,4 @@ +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= @@ -5,15 +6,19 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366 h1:FVAkDbBxovi2ID0vaxY7vCGvdKASt9r0TGPM1u4YQyg= github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366/go.mod h1:1ymsiQNa3qebVEEVtuIdhtAXRfjO4qFCFq1bBUOT2HE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= @@ -39,7 +44,9 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -56,21 +63,30 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/joncalhoun/pipe v0.0.0-20170510025636-72505674a733 h1:/wtaMDeVpoAUkqZl/GT3lvM9nDBmRApu/Uvl7EUc9Ao= github.com/joncalhoun/pipe v0.0.0-20170510025636-72505674a733/go.mod h1:2MNFZhLx2HMHTN4xKH6FhpoQWqmD8Ato8QOE2hp5hY4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -89,7 +105,9 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -114,6 +132,7 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -128,9 +147,11 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -144,6 +165,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -183,8 +205,11 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/pipe.v2 v2.0.0-20140414041502-3c2ca4d52544 h1:WJH1qsOB4/zb/li+zLMn0vaAUJ5FqPv6HYLI3aQVg1k= gopkg.in/pipe.v2 v2.0.0-20140414041502-3c2ca4d52544/go.mod h1:UhTeH/yXCK/KY7TX24mqPkaQ7gZeqmWd/8SSS8B3aHw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -208,6 +233,7 @@ k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= diff --git a/bindings-go/oci/manifest.go b/bindings-go/oci/manifest.go index f04cc44a..856e047b 100644 --- a/bindings-go/oci/manifest.go +++ b/bindings-go/oci/manifest.go @@ -41,8 +41,8 @@ type BlobStore interface { // ManifestBuilder converts a component descriptor with local defined blobs // into a oci component descriptor with blobs as layers of the component descriptor. type ManifestBuilder struct { - store BlobStore - archive *ctf.ComponentArchive + store BlobStore + archive *ctf.ComponentArchive componentDescriptorStorageType string } @@ -127,10 +127,10 @@ func (b *ManifestBuilder) addComponentDescriptorDesc() (ocispecv1.Descriptor, er var buf bytes.Buffer tw := tar.NewWriter(&buf) if err := tw.WriteHeader(&tar.Header{ - Typeflag: tar.TypeReg, - Name: ctf.ComponentDescriptorFileName, - Size: int64(len(data)), - ModTime: time.Now(), + Typeflag: tar.TypeReg, + Name: ctf.ComponentDescriptorFileName, + Size: int64(len(data)), + ModTime: time.Now(), }); err != nil { return ocispecv1.Descriptor{}, fmt.Errorf("unable to add component descriptor header: %w", err) } diff --git a/bindings-go/oci/oci_suite_test.go b/bindings-go/oci/oci_suite_test.go index d546c980..60caa1b5 100644 --- a/bindings-go/oci/oci_suite_test.go +++ b/bindings-go/oci/oci_suite_test.go @@ -22,7 +22,7 @@ func TestConfig(t *testing.T) { RunSpecs(t, "oci Test Suite") } -var _ = Describe("helper", func(){ +var _ = Describe("helper", func() { Context("OCIRef", func() { @@ -56,7 +56,7 @@ var _ = Describe("helper", func(){ It("should correctly parse a repository url with a sha256-digest name mapping", func() { repoCtx := cdv2.OCIRegistryRepository{ - BaseURL: "example.com:443", + BaseURL: "example.com:443", ComponentNameMapping: cdv2.OCIRegistryDigestMapping, } ref, err := oci.OCIRef(repoCtx, "somecomp", "v0.0.0") @@ -71,7 +71,7 @@ var _ = Describe("helper", func(){ // testClient describes a test oci client. type testClient struct { getManifest func(ctx context.Context, ref string) (*ocispecv1.Manifest, error) - fetch func(ctx context.Context, ref string, desc ocispecv1.Descriptor, writer io.Writer) error + fetch func(ctx context.Context, ref string, desc ocispecv1.Descriptor, writer io.Writer) error } var _ oci.Client = &testClient{} @@ -86,7 +86,7 @@ func (t testClient) Fetch(ctx context.Context, ref string, desc ocispecv1.Descri // testCache describes a test resolve cache. type testCache struct { - get func (ctx context.Context, repoCtx cdv2.OCIRegistryRepository, name, version string) (*cdv2.ComponentDescriptor, error) + get func(ctx context.Context, repoCtx cdv2.OCIRegistryRepository, name, version string) (*cdv2.ComponentDescriptor, error) store func(ctx context.Context, descriptor *cdv2.ComponentDescriptor) error } @@ -99,4 +99,3 @@ func (t testCache) Get(ctx context.Context, repoCtx cdv2.OCIRegistryRepository, func (t testCache) Store(ctx context.Context, descriptor *cdv2.ComponentDescriptor) error { return t.store(ctx, descriptor) } - diff --git a/bindings-go/oci/resolve.go b/bindings-go/oci/resolve.go index d518e2df..1b728842 100644 --- a/bindings-go/oci/resolve.go +++ b/bindings-go/oci/resolve.go @@ -91,17 +91,17 @@ type Cache interface { // Resolver is a generic resolve to resolve a component descriptor from a oci registry. // This resolver implements the ctf.ComponentResolver interface. type Resolver struct { - log logr.Logger - client Client - cache Cache + log logr.Logger + client Client + cache Cache decodeOpts []codec.DecodeOption } // NewResolver creates a new resolver. func NewResolver(client Client, decodeOpts ...codec.DecodeOption) *Resolver { return &Resolver{ - log: logr.Discard(), - client: client, + log: logr.Discard(), + client: client, decodeOpts: decodeOpts, } } @@ -162,7 +162,7 @@ func (r *Resolver) resolve(ctx context.Context, repoCtx v2.Repository, name, ver } } else { if withBlobResolver { - manifest, ref , err := r.fetchManifest(ctx, repo, name, version) + manifest, ref, err := r.fetchManifest(ctx, repo, name, version) if err != nil { return nil, nil, err } @@ -172,7 +172,7 @@ func (r *Resolver) resolve(ctx context.Context, repoCtx v2.Repository, name, ver } } - manifest, ref , err := r.fetchManifest(ctx, repo, name, version) + manifest, ref, err := r.fetchManifest(ctx, repo, name, version) if err != nil { return nil, nil, err } diff --git a/bindings-go/oci/resolve_test.go b/bindings-go/oci/resolve_test.go index d5b08ab3..e7bf3dad 100644 --- a/bindings-go/oci/resolve_test.go +++ b/bindings-go/oci/resolve_test.go @@ -21,7 +21,7 @@ import ( "github.com/gardener/component-spec/bindings-go/oci" ) -var _ = Describe("resolve", func(){ +var _ = Describe("resolve", func() { Context("Resolve", func() { @@ -32,12 +32,12 @@ var _ = Describe("resolve", func(){ return &ocispecv1.Manifest{ Config: ocispecv1.Descriptor{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("config"), + Digest: digest.FromString("config"), }, Layers: []ocispecv1.Descriptor{ { MediaType: oci.ComponentDescriptorJSONMimeType, - Digest: digest.FromString("cd"), + Digest: digest.FromString("cd"), }, }, }, nil @@ -48,7 +48,7 @@ var _ = Describe("resolve", func(){ config := oci.ComponentDescriptorConfig{ ComponentDescriptorLayer: &oci.OciBlobRef{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("cd").String(), + Digest: digest.FromString("cd").String(), }, } return json.NewEncoder(writer).Encode(config) @@ -116,12 +116,12 @@ var _ = Describe("resolve", func(){ return &ocispecv1.Manifest{ Config: ocispecv1.Descriptor{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("config"), + Digest: digest.FromString("config"), }, Layers: []ocispecv1.Descriptor{ { MediaType: oci.ComponentDescriptorJSONMimeType, - Digest: digest.FromString("cd"), + Digest: digest.FromString("cd"), }, }, }, nil @@ -132,7 +132,7 @@ var _ = Describe("resolve", func(){ config := oci.ComponentDescriptorConfig{ ComponentDescriptorLayer: &oci.OciBlobRef{ MediaType: oci.ComponentDescriptorConfigMimeType, - Digest: digest.FromString("cd").String(), + Digest: digest.FromString("cd").String(), }, } return json.NewEncoder(writer).Encode(config) diff --git a/bindings-go/utils/selector/selector.go b/bindings-go/utils/selector/selector.go index 93f104eb..c502d7a9 100644 --- a/bindings-go/utils/selector/selector.go +++ b/bindings-go/utils/selector/selector.go @@ -39,7 +39,7 @@ func (s SelectorFunc) Match(obj map[string]string) (bool, error) { // MatchSelectors checks whether all selectors matches the given obj. func MatchSelectors(obj map[string]string, selectors ...Interface) (bool, error) { for _, sel := range selectors { - ok, err:= sel.Match(obj) + ok, err := sel.Match(obj) if err != nil { return false, err }