mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
feat(cnbBuild): cache buildpacks during multi-image build (#3635)
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com> Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
This commit is contained in:
parent
f4f11dba7f
commit
1f750af16d
@ -11,7 +11,7 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/fake"
|
||||
)
|
||||
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/fake"
|
||||
|
||||
piperDocker "github.com/SAP/jenkins-library/pkg/docker"
|
||||
@ -298,3 +298,8 @@ func (c *dockerClientMock) DownloadImage(imageSource, filePath string) (v1.Image
|
||||
func (c *dockerClientMock) DownloadImageContent(imageSource, filePath string) (v1.Image, error) {
|
||||
return &fake.FakeImage{}, nil // fmt.Errorf("%s", filePath)
|
||||
}
|
||||
|
||||
// GetRemoteImageInfo return remote image information
|
||||
func (c *dockerClientMock) GetRemoteImageInfo(imageSoure string) (v1.Image, error) {
|
||||
return &fake.FakeImage{}, nil
|
||||
}
|
||||
|
@ -17,11 +17,10 @@ import (
|
||||
piperHttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/SAP/jenkins-library/pkg/protecode"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/fake"
|
||||
)
|
||||
|
||||
|
@ -14,7 +14,10 @@ import (
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
var registryURL = "localhost:5000"
|
||||
const (
|
||||
registryURL = "localhost:5000"
|
||||
baseBuilder = "paketobuildpacks/builder:0.2.17-base"
|
||||
)
|
||||
|
||||
func setupDockerRegistry(t *testing.T, ctx context.Context) testcontainers.Container {
|
||||
reqRegistry := testcontainers.ContainerRequest{
|
||||
@ -38,14 +41,14 @@ func TestNpmProject(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
})
|
||||
|
||||
container2 := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -79,7 +82,7 @@ func TestProjectDescriptor(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestCnbIntegration", "project"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -109,7 +112,7 @@ func TestZipPath(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestCnbIntegration", "zip"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -133,7 +136,7 @@ func TestNonZipPath(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestMtaIntegration", "npm"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -152,7 +155,7 @@ func TestNpmCustomBuildpacksFullProject(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestMtaIntegration", "npm"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -161,7 +164,7 @@ func TestNpmCustomBuildpacksFullProject(t *testing.T) {
|
||||
container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--buildpacks", "gcr.io/paketo-buildpacks/nodejs:0.14.0", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL)
|
||||
|
||||
container.assertHasOutput(t, "Setting custom buildpacks: '[gcr.io/paketo-buildpacks/nodejs:0.14.0]'")
|
||||
container.assertHasOutput(t, "Downloading buildpack 'gcr.io/paketo-buildpacks/nodejs:0.14.0' to /tmp/nodejs")
|
||||
container.assertHasOutput(t, "Downloading buildpack 'gcr.io/paketo-buildpacks/nodejs:0.14.0' to /tmp/buildpacks_cache/sha256:")
|
||||
container.assertHasOutput(t, "running command: /cnb/lifecycle/creator")
|
||||
container.assertHasOutput(t, "Paketo NPM Start Buildpack")
|
||||
container.assertHasOutput(t, fmt.Sprintf("Saving %s/not-found:0.0.1", registryURL))
|
||||
@ -186,7 +189,7 @@ func TestNpmCustomBuildpacksBuildpacklessProject(t *testing.T) {
|
||||
container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--buildpacks", "gcr.io/paketo-buildpacks/nodejs:0.14.0", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL)
|
||||
|
||||
container.assertHasOutput(t, "Setting custom buildpacks: '[gcr.io/paketo-buildpacks/nodejs:0.14.0]'")
|
||||
container.assertHasOutput(t, "Downloading buildpack 'gcr.io/paketo-buildpacks/nodejs:0.14.0' to /tmp/nodejs")
|
||||
container.assertHasOutput(t, "Downloading buildpack 'gcr.io/paketo-buildpacks/nodejs:0.14.0' to /tmp/buildpacks_cache/sha256:")
|
||||
container.assertHasOutput(t, "running command: /cnb/lifecycle/creator")
|
||||
container.assertHasOutput(t, "Paketo NPM Start Buildpack")
|
||||
container.assertHasOutput(t, fmt.Sprintf("Saving %s/not-found:0.0.1", registryURL))
|
||||
@ -215,7 +218,7 @@ func TestBindings(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -236,7 +239,7 @@ func TestMultiImage(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestCnbIntegration"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -248,6 +251,8 @@ func TestMultiImage(t *testing.T) {
|
||||
container.assertHasOutput(t, "Saving localhost:5000/io-buildpacks-my-app:latest...")
|
||||
container.assertHasOutput(t, "Previous image with name \"localhost:5000/go-app:v1.0.0\" not found")
|
||||
container.assertHasOutput(t, "Saving localhost:5000/go-app:v1.0.0...")
|
||||
container.assertHasOutput(t, "Using cached buildpack")
|
||||
container.assertHasOutput(t, "Saving localhost:5000/my-app2:latest...")
|
||||
container.terminate(t)
|
||||
}
|
||||
|
||||
@ -258,7 +263,7 @@ func TestPreserveFiles(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestCnbIntegration"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
@ -277,7 +282,7 @@ func TestPreserveFilesIgnored(t *testing.T) {
|
||||
defer registryContainer.Terminate(ctx)
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "paketobuildpacks/builder:0.1.342-full",
|
||||
Image: baseBuilder,
|
||||
User: "cnb",
|
||||
TestDir: []string{"testdata", "TestCnbIntegration"},
|
||||
Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()),
|
||||
|
@ -10,3 +10,5 @@ steps:
|
||||
- containerImageName: go-app
|
||||
containerImageTag: v1.0.0
|
||||
path: zip/go.zip
|
||||
- path: project
|
||||
containerImageName: my-app2
|
||||
|
@ -3,14 +3,15 @@ package cnbutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const bpCacheDir = "/tmp/buildpacks_cache"
|
||||
|
||||
type BuildPackMetadata struct {
|
||||
ID string `toml:"id,omitempty" json:"id,omitempty" yaml:"id,omitempty"`
|
||||
Name string `toml:"name,omitempty" json:"name,omitempty" yaml:"name,omitempty"`
|
||||
@ -37,33 +38,57 @@ func DownloadBuildpacks(path string, bpacks []string, dockerCreds string, utils
|
||||
Utils: utils,
|
||||
}
|
||||
|
||||
err := utils.MkdirAll(bpCacheDir, os.ModePerm)
|
||||
if err != nil {
|
||||
return Order{}, errors.Wrap(err, "failed to create temp directory for buildpack cache")
|
||||
}
|
||||
|
||||
for _, bpack := range bpacks {
|
||||
var bpackMeta BuildPackMetadata
|
||||
tempDir, err := utils.TempDir("", filepath.Base(bpack))
|
||||
imageInfo, err := utils.GetRemoteImageInfo(bpack)
|
||||
if err != nil {
|
||||
return Order{}, fmt.Errorf("failed to create temp directory, error: %s", err.Error())
|
||||
return Order{}, errors.Wrap(err, "failed to get remote image info of buildpack")
|
||||
}
|
||||
defer utils.RemoveAll(tempDir)
|
||||
|
||||
log.Entry().Infof("Downloading buildpack '%s' to %s", bpack, tempDir)
|
||||
img, err := utils.DownloadImageContent(bpack, tempDir)
|
||||
hash, err := imageInfo.Digest()
|
||||
if err != nil {
|
||||
return Order{}, fmt.Errorf("failed download buildpack image '%s', error: %s", bpack, err.Error())
|
||||
return Order{}, errors.Wrap(err, "failed to get image digest")
|
||||
}
|
||||
cacheDir := filepath.Join(bpCacheDir, hash.String())
|
||||
|
||||
cacheExists, err := utils.DirExists(cacheDir)
|
||||
if err != nil {
|
||||
return Order{}, errors.Wrapf(err, "failed to check if cache dir '%s' exists", cacheDir)
|
||||
}
|
||||
|
||||
imgConf, err := img.ConfigFile()
|
||||
if cacheExists {
|
||||
log.Entry().Infof("Using cached buildpack '%s'", bpack)
|
||||
} else {
|
||||
err := utils.MkdirAll(cacheDir, os.ModePerm)
|
||||
if err != nil {
|
||||
return Order{}, errors.Wrap(err, "failed to create temp directory for buildpack cache")
|
||||
}
|
||||
|
||||
log.Entry().Infof("Downloading buildpack '%s' to %s", bpack, cacheDir)
|
||||
img, err := utils.DownloadImageContent(bpack, cacheDir)
|
||||
if err != nil {
|
||||
return Order{}, errors.Wrapf(err, "failed download buildpack image '%s'", bpack)
|
||||
}
|
||||
imageInfo = img
|
||||
}
|
||||
|
||||
imgConf, err := imageInfo.ConfigFile()
|
||||
if err != nil {
|
||||
return Order{}, fmt.Errorf("failed to read '%s' image config, error: %s", bpack, err.Error())
|
||||
return Order{}, errors.Wrapf(err, "failed to read '%s' image config", bpack)
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(imgConf.Config.Labels["io.buildpacks.buildpackage.metadata"]), &bpackMeta)
|
||||
if err != nil {
|
||||
return Order{}, fmt.Errorf("failed unmarshal '%s' image label, error: %s", bpack, err.Error())
|
||||
return Order{}, errors.Wrapf(err, "failed unmarshal '%s' image label", bpack)
|
||||
}
|
||||
log.Entry().Debugf("Buildpack metadata: '%v'", bpackMeta)
|
||||
orderEntry.Group = append(orderEntry.Group, bpackMeta)
|
||||
|
||||
err = copyBuildPack(filepath.Join(tempDir, "cnb/buildpacks"), path, utils)
|
||||
err = CopyProject(filepath.Join(cacheDir, "cnb/buildpacks"), path, nil, nil, utils)
|
||||
if err != nil {
|
||||
return Order{}, err
|
||||
}
|
||||
@ -73,38 +98,3 @@ func DownloadBuildpacks(path string, bpacks []string, dockerCreds string, utils
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func copyBuildPack(src, dst string, utils BuildUtils) error {
|
||||
buildpacks, err := utils.Glob(filepath.Join(src, "*"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read directory: %s, error: %s", src, err.Error())
|
||||
}
|
||||
|
||||
for _, buildpack := range buildpacks {
|
||||
versions, err := utils.Glob(filepath.Join(buildpack, "*"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read directory: %s, error: %s", buildpack, err.Error())
|
||||
}
|
||||
for _, srcVersionPath := range versions {
|
||||
destVersionPath := filepath.Join(dst, strings.ReplaceAll(srcVersionPath, src, ""))
|
||||
|
||||
exists, err := utils.FileExists(destVersionPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if directory exists: '%s', error: '%s'", destVersionPath, err.Error())
|
||||
}
|
||||
if exists {
|
||||
utils.RemoveAll(destVersionPath)
|
||||
}
|
||||
|
||||
if err := utils.MkdirAll(filepath.Dir(destVersionPath), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory: '%s', error: '%s'", filepath.Dir(destVersionPath), err.Error())
|
||||
}
|
||||
|
||||
err = utils.FileRename(srcVersionPath, destVersionPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to move '%s' to '%s', error: %s", srcVersionPath, destVersionPath, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -14,11 +14,9 @@ func TestBuildpackDownload(t *testing.T) {
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
|
||||
t.Run("successfully downloads a buildpack", func(t *testing.T) {
|
||||
mockUtils.AddDir("/tmp/testtest")
|
||||
_, err := cnbutils.DownloadBuildpacks("/test", []string{"test"}, "/test/config.json", mockUtils)
|
||||
|
||||
t.Run("it creates an order object", func(t *testing.T) {
|
||||
order, err := cnbutils.DownloadBuildpacks("/destination", []string{"buildpack"}, "/tmp/config.json", mockUtils)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, mockUtils.HasRemovedFile("/tmp/testtest"))
|
||||
assert.Equal(t, 1, len(order.Order))
|
||||
})
|
||||
}
|
||||
|
@ -44,3 +44,17 @@ func (c *MockUtils) DownloadImage(src, dst string) (v1.Image, error) {
|
||||
func (c *MockUtils) GetImageSource() (string, error) {
|
||||
return "imageSource", nil
|
||||
}
|
||||
|
||||
func (c *MockUtils) GetRemoteImageInfo(imageSource string) (v1.Image, error) {
|
||||
fakeImage := fakeImage.FakeImage{}
|
||||
fakeImage.ConfigFileReturns(&v1.ConfigFile{
|
||||
Config: v1.Config{
|
||||
Labels: map[string]string{
|
||||
"io.buildpacks.buildpackage.metadata": "{\"id\": \"testbuildpack\", \"version\": \"0.0.1\"}",
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
fakeImage.DigestReturns(v1.Hash{}, nil)
|
||||
|
||||
return &fakeImage, nil
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package cnbutils
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/buildpacks/lifecycle/platform"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
@ -23,8 +22,6 @@ func DigestFromReport(utils BuildUtils) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Entry().Debugf("Image report: %#v\n", report)
|
||||
|
||||
if report.Image.Digest == "" {
|
||||
return "", fmt.Errorf("image digest is empty")
|
||||
}
|
||||
|
@ -11,11 +11,14 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
cranecmd "github.com/google/go-containerregistry/cmd/crane/cmd"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// AuthEntry defines base64 encoded username:password required inside a Docker config.json
|
||||
@ -94,6 +97,7 @@ type ClientOptions struct {
|
||||
type Download interface {
|
||||
DownloadImage(imageSource, targetFile string) (v1.Image, error)
|
||||
DownloadImageContent(imageSource, targetDir string) (v1.Image, error)
|
||||
GetRemoteImageInfo(string) (v1.Image, error)
|
||||
}
|
||||
|
||||
// SetOptions sets options used for the docker client
|
||||
@ -103,7 +107,7 @@ func (c *Client) SetOptions(options ClientOptions) {
|
||||
c.localPath = options.LocalPath
|
||||
}
|
||||
|
||||
//DownloadImageToPath downloads the image content into the given targetDir. Returns with an error if the targetDir doesnt exist
|
||||
//DownloadImageContent downloads the image content into the given targetDir. Returns with an error if the targetDir doesnt exist
|
||||
func (c *Client) DownloadImageContent(imageSource, targetDir string) (v1.Image, error) {
|
||||
if fileInfo, err := os.Stat(targetDir); err != nil {
|
||||
return nil, err
|
||||
@ -178,6 +182,16 @@ func (c *Client) DownloadImage(imageSource, targetFile string) (v1.Image, error)
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// GetRemoteImageInfo retrieves information about the image (e.g. digest) without actually downoading it
|
||||
func (c *Client) GetRemoteImageInfo(imageSource string) (v1.Image, error) {
|
||||
ref, err := c.getImageRef(imageSource)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "parsing image reference")
|
||||
}
|
||||
|
||||
return remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
|
||||
}
|
||||
|
||||
func (c *Client) getImageRef(image string) (name.Reference, error) {
|
||||
opts := []name.Option{}
|
||||
|
||||
|
@ -2,17 +2,20 @@ package mock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
// DownloadMock .
|
||||
type DownloadMock struct {
|
||||
FilePath string
|
||||
ImageRef string
|
||||
RegistryURL string
|
||||
FilePath string
|
||||
ImageRef string
|
||||
RemoteImageRef string
|
||||
RegistryURL string
|
||||
|
||||
ReturnImage v1.Image
|
||||
ReturnError string
|
||||
ReturnImage v1.Image
|
||||
RemoteImageInfo v1.Image
|
||||
ReturnError string
|
||||
|
||||
Stub func(imageRef, targetDir string) (v1.Image, error)
|
||||
}
|
||||
@ -42,3 +45,14 @@ func (c *DownloadMock) DownloadImageContent(imageRef, targetFile string) (v1.Ima
|
||||
}
|
||||
return c.ReturnImage, nil
|
||||
}
|
||||
|
||||
// GetRemoteImageInfo .
|
||||
func (c *DownloadMock) GetRemoteImageInfo(imageRef string) (v1.Image, error) {
|
||||
c.RemoteImageRef = imageRef
|
||||
|
||||
if len(c.ReturnError) > 0 {
|
||||
return nil, fmt.Errorf(c.ReturnError)
|
||||
}
|
||||
|
||||
return c.RemoteImageInfo, nil
|
||||
}
|
||||
|
@ -115,6 +115,12 @@ func (f Files) Copy(src, dst string) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
stats, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
os.Chmod(dst, stats.Mode())
|
||||
defer func() { _ = destination.Close() }()
|
||||
nBytes, err := CopyData(destination, source)
|
||||
return nBytes, err
|
||||
@ -236,7 +242,7 @@ func Untar(src string, dest string, stripComponentLevel int) error {
|
||||
defer file.Close()
|
||||
|
||||
if err != nil {
|
||||
fmt.Errorf("unable to open src: %v", err)
|
||||
return fmt.Errorf("unable to open src: %v", err)
|
||||
}
|
||||
|
||||
if b, err := isFileGzipped(src); err == nil && b {
|
||||
|
Loading…
Reference in New Issue
Block a user