diff --git a/cmd/geranos/cmd/auth.go b/cmd/geranos/cmd/auth.go index 44c7c92..9043684 100644 --- a/cmd/geranos/cmd/auth.go +++ b/cmd/geranos/cmd/auth.go @@ -11,7 +11,6 @@ import ( "log" "os" "strings" - "syscall" ) // Inspired by https://github.com/google/go-containerregistry/blob/main/cmd/crane/cmd/auth.go @@ -58,7 +57,7 @@ type loginOptions struct { func login(opts loginOptions) error { if opts.passwordStdin { - bytePassword, err := term.ReadPassword(syscall.Stdin) + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) if err != nil { return err } diff --git a/cmd/geranos/cmd/config.go b/cmd/geranos/cmd/config.go index 7da0e33..8c8d34a 100644 --- a/cmd/geranos/cmd/config.go +++ b/cmd/geranos/cmd/config.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/macvmio/geranos/pkg/appconfig" "github.com/spf13/viper" + "os" + "path" ) var flagConfigFile string @@ -15,7 +17,11 @@ func initConfig() error { if flagConfigFile != "" { viper.SetConfigFile(flagConfigFile) } else { - viper.AddConfigPath("$HOME/.geranos") + home, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("could not determine home directory: %w", err) + } + viper.AddConfigPath(path.Join(home, ".geranos")) viper.AddConfigPath(".") viper.SetConfigName("config") viper.SetConfigType("yaml") diff --git a/pkg/duplicator/file_windows.go b/pkg/duplicator/file_windows.go index 6086e09..d30cf6c 100644 --- a/pkg/duplicator/file_windows.go +++ b/pkg/duplicator/file_windows.go @@ -1,6 +1,9 @@ package duplicator import ( + "errors" + "fmt" + "io" "os" "unsafe" @@ -9,8 +12,25 @@ import ( const fsctlDuplicateExtentsToFile = 0x00094CF4 -// duplicateExtentsToFile is a wrapper around the FSCTL_DUPLICATE_EXTENTS_TO_FILE Windows API. -// It clones the data blocks from the source file handle to the destination file handle. +func CloneFileFallback(srcFile, dstFile string) error { + fmt.Printf("CloneFileFallback: %v -> %v\n", srcFile, dstFile) + src, err := os.Open(srcFile) + if err != nil { + return err + } + defer src.Close() + + dst, err := os.Create(dstFile) + if err != nil { + return err + } + defer dst.Close() + + _, err = io.Copy(dst, src) + return err +} + +// duplicateExtentsToFile clones data blocks from the source file handle to the destination file handle. func duplicateExtentsToFile(dst, src windows.Handle, srcLength int64) error { type DuplicateExtentsData struct { FileHandle windows.Handle @@ -24,22 +44,25 @@ func duplicateExtentsToFile(dst, src windows.Handle, srcLength int64) error { TargetFileOffset: 0, ByteCount: srcLength, } - return windows.DeviceIoControl( - dst, - fsctlDuplicateExtentsToFile, - (*byte)(unsafe.Pointer(&data)), - uint32(unsafe.Sizeof(data)), - nil, - 0, - nil, - nil, + return os.NewSyscallError("DeviceIoControl", + windows.DeviceIoControl( + dst, + fsctlDuplicateExtentsToFile, + (*byte)(unsafe.Pointer(&data)), + uint32(unsafe.Sizeof(data)), + nil, + 0, + nil, + nil, + ), ) } // CloneFile efficiently clones a file from srcFile to dstFile on Windows. func CloneFile(srcFile, dstFile string) error { srcHandle, err := windows.CreateFile(windows.StringToUTF16Ptr(srcFile), - windows.GENERIC_READ, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0) + windows.GENERIC_READ, windows.FILE_SHARE_READ, nil, + windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0) if err != nil { return os.NewSyscallError("CreateFile src", err) } @@ -58,5 +81,16 @@ func CloneFile(srcFile, dstFile string) error { } srcFileSize := srcFileInfo.Size() - return duplicateExtentsToFile(dstHandle, srcHandle, srcFileSize) + // Attempt to clone using duplicate extents + err = duplicateExtentsToFile(dstHandle, srcHandle, srcFileSize) + if err != nil { + windows.Close(srcHandle) + windows.Close(dstHandle) + if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_NOT_SUPPORTED) { + // Fallback to traditional file copy if access is denied or operation is not supported + return CloneFileFallback(srcFile, dstFile) + } + return err + } + return nil } diff --git a/pkg/layout/disk_usage.go b/pkg/layout/disk_usage.go index 873516a..a5cfb57 100644 --- a/pkg/layout/disk_usage.go +++ b/pkg/layout/disk_usage.go @@ -37,7 +37,11 @@ func DirectoryDiskUsage(path string) (string, error) { // Parse PowerShell output to get the size in a similar format to du -sh lines := strings.Split(result, "\n") lastLine := strings.TrimSpace(lines[len(lines)-1]) - sizeInBytes := strings.Fields(lastLine)[0] + fields := strings.Fields(lastLine) + sizeInBytes := "parsing error" + if len(fields) > 0 { + sizeInBytes = fields[0] + } size, err := formatBytesToHumanReadable(sizeInBytes) if err != nil { return "", err diff --git a/pkg/layout/layout.go b/pkg/layout/layout.go index 596bc5c..94adc89 100644 --- a/pkg/layout/layout.go +++ b/pkg/layout/layout.go @@ -16,6 +16,8 @@ import ( "strings" ) +const OSWindows = "windows" + type Mapper struct { rootDir string sketcher *sketch.Sketcher @@ -40,12 +42,21 @@ func NewMapper(rootDir string, opts ...dirimage.Option) *Mapper { func (lm *Mapper) refToDir(ref name.Reference) string { refStr := ref.String() - if runtime.GOOS == "windows" { + if runtime.GOOS == OSWindows { refStr = strings.ReplaceAll(refStr, ":", "@") } return filepath.Join(lm.rootDir, refStr) } +func (lm *Mapper) dirToRef(dir string) (name.Reference, error) { + processedPath := strings.TrimPrefix(filepath.Clean(dir), lm.rootDir) + processedPath = filepath.ToSlash(strings.Trim(processedPath, "/\\")) + if runtime.GOOS == OSWindows { + processedPath = strings.Replace(processedPath, "@", ":", -1) + } + return name.ParseReference(processedPath, name.StrictValidation) +} + func (lm *Mapper) WriteIfNotPresent(ctx context.Context, img v1.Image, ref name.Reference) error { originalDigest, err := img.Digest() if err != nil { @@ -207,10 +218,10 @@ func (lm *Mapper) List() ([]Properties, error) { if d == nil || !d.IsDir() { return nil } - processedPath := strings.TrimPrefix(path, lm.rootDir) - processedPath = strings.Trim(processedPath, "/") - ref, err := name.ParseReference(processedPath, name.StrictValidation) + + ref, err := lm.dirToRef(path) if err != nil { + // fmt.Printf("skipping error %v\n", err) return nil } dirSize, err := directorySize(path) diff --git a/pkg/layout/layout_test.go b/pkg/layout/layout_test.go index cb31422..f5482fc 100644 --- a/pkg/layout/layout_test.go +++ b/pkg/layout/layout_test.go @@ -17,10 +17,14 @@ import ( "os" "path" "path/filepath" + "runtime" + "strings" "testing" ) func hashFromFile(t *testing.T, filename string) string { + t.Helper() + filename = portableFilepath(filename) f, err := os.Open(filename) require.NoErrorf(t, err, "unexpected error while opening a file, got %v", err) defer f.Close() @@ -29,6 +33,30 @@ func hashFromFile(t *testing.T, filename string) string { return h.Hex } +// ReplaceLast replaces the last occurrence of old with new in the string s. +func ReplaceLast(s, old, new string) string { + index := strings.LastIndex(s, old) + if index == -1 { + return s // old not found, return original string + } + return s[:index] + new + s[index+len(old):] +} + +func portableFilepath(path string) string { + p := filepath.Clean(path) + if runtime.GOOS == OSWindows { + if strings.Contains(path, "@") { + return p + } + pos := strings.LastIndex(path, ":") + if pos != -1 && pos < 5 { + return p + } + p = ReplaceLast(p, ":", "@") + } + return p +} + func TestLayoutMapper_Read(t *testing.T) { lm := NewMapper("testdata") ref, err := name.ParseReference("vm1") @@ -43,10 +71,7 @@ func TestLayoutMapper_Read(t *testing.T) { func TestLayoutMapper_Read_VariousChunkSizes(t *testing.T) { hashBefore := hashFromFile(t, "testdata/vm1/disk.blob") - tempDir, err := os.MkdirTemp("", "oci-test-*") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - + tempDir := t.TempDir() lmDst := NewMapper(tempDir) srcRef, err := name.ParseReference("vm1") require.NoErrorf(t, err, "unable to parse source reference: %v", err) @@ -79,6 +104,7 @@ func TestLayoutMapper_Read_VariousChunkSizes(t *testing.T) { // using io.CopyN for efficient copying. func generateRandomFile(filename string, size int64) error { // Open a file for writing, creating it with 0666 permissions if it does not exist + filename = portableFilepath(filename) file, err := os.Create(filename) if err != nil { return fmt.Errorf("error creating file: %w", err) @@ -95,6 +121,7 @@ func generateRandomFile(filename string, size int64) error { } func appendRandomBytesToFile(filename string, numBytes int64) error { + filename = portableFilepath(filename) // Open file in append mode. If file doesn't exist, create it with permissions 0644 file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { @@ -114,21 +141,17 @@ func appendRandomBytesToFile(filename string, numBytes int64) error { func TestLayoutMapper_Write_MustOptimizeDiskSpace(t *testing.T) { ctx := context.Background() - tempDir, err := os.MkdirTemp("", "optimized-disk-*") - if err != nil { - t.Fatalf("unable to create temp dir: %v", err) - } - defer os.RemoveAll(tempDir) - testRepoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") - err = os.MkdirAll(path.Join(testRepoDir, "a:v1"), os.ModePerm) + tempDir := t.TempDir() + testRepoDir := filepath.Join(tempDir, "oci.jarosik.online", "testrepo") + err := os.MkdirAll(portableFilepath(filepath.Join(testRepoDir, "a:v1")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) - optimalRepoDir := path.Join(tempDir, "oci.jarosik.online/optimalrepo") - err = os.MkdirAll(path.Join(optimalRepoDir, "a:v1"), os.ModePerm) + optimalRepoDir := filepath.Join(tempDir, "oci.jarosik.online", "optimalrepo") + err = os.MkdirAll(portableFilepath(filepath.Join(optimalRepoDir, "a:v1")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) MB := int64(1024 * 1024) chunkSize := MB - randomFileName := path.Join(testRepoDir, "a:v1/disk.img") + randomFileName := portableFilepath(path.Join(testRepoDir, "a:v1/disk.img")) err = generateRandomFile(randomFileName, 32*MB) require.NoErrorf(t, err, "unable to generate file: %v", err) hashBefore := hashFromFile(t, randomFileName) @@ -141,9 +164,10 @@ func TestLayoutMapper_Write_MustOptimizeDiskSpace(t *testing.T) { r := mustParseRef(t, dir) err = lm.Write(ctx, img1, r) require.NoErrorf(t, err, "unable to write image %d: %v", i, err) - err = duplicator.CloneDirectory(path.Join(testRepoDir, "a:v1"), path.Join(optimalRepoDir, fmt.Sprintf("a:v%d", i)), false) + err = duplicator.CloneDirectory(portableFilepath(path.Join(testRepoDir, "a:v1")), + portableFilepath(path.Join(optimalRepoDir, fmt.Sprintf("a:v%d", i))), false) require.NoErrorf(t, err, "unable to clone directory: %v", err) - assert.Equal(t, hashBefore, hashFromFile(t, filepath.Join(testRepoDir, fmt.Sprintf("a:v%d", i), "disk.img"))) + assert.Equal(t, hashBefore, hashFromFile(t, portableFilepath(filepath.Join(testRepoDir, fmt.Sprintf("a:v%d", i), "disk.img")))) } for _, repo := range []string{testRepoDir, optimalRepoDir} { diskUsage, err := DirectoryDiskUsage(testRepoDir) @@ -159,11 +183,9 @@ func TestLayoutMapper_Write_MustOptimizeDiskSpace(t *testing.T) { func TestLayoutMapper_Write_MustAvoidWritingSameContent(t *testing.T) { ctx := context.Background() - tempDir, err := os.MkdirTemp("", "content-matches-*") - require.NoErrorf(t, err, "unable to create temp dir: %v", err) - defer os.RemoveAll(tempDir) + tempDir := t.TempDir() testRepoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") - err = os.MkdirAll(path.Join(testRepoDir, "a:v1"), os.ModePerm) + err := os.MkdirAll(portableFilepath(path.Join(testRepoDir, "a:v1")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) const chunkSize = 10 lm := NewMapper(tempDir, dirimage.WithChunkSize(chunkSize)) @@ -198,21 +220,19 @@ func TestLayoutMapper_Write_MustAvoidWritingSameContent(t *testing.T) { assert.Equal(t, int64(1000), lm.stats.BytesClonedCount.Load()) assert.Equal(t, int64(100), lm.stats.MatchedSegmentsCount.Load()) - afterHash := hashFromFile(t, path.Join(tempDir, "oci.jarosik.online/testrepo/a:v3/disk.img")) + afterHash := hashFromFile(t, portableFilepath(path.Join(tempDir, "oci.jarosik.online/testrepo/a:v3/disk.img"))) assert.Equal(t, beforeHash, afterHash) } func TestLayoutMapper_Write_MustOnlyWriteContentThatDiffersFromAlreadyWritten(t *testing.T) { ctx := context.Background() - tempDir, err := os.MkdirTemp("", "content-matches-*") - require.NoErrorf(t, err, "unable to create temp dir: %v", err) - defer os.RemoveAll(tempDir) + tempDir := t.TempDir() testRepoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") - err = os.MkdirAll(path.Join(testRepoDir, "a:v1"), os.ModePerm) + err := os.MkdirAll(portableFilepath(path.Join(testRepoDir, "a:v1")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) const chunkSize = 10 lm := NewMapper(tempDir, dirimage.WithChunkSize(chunkSize)) - randomFilename := path.Join(testRepoDir, "a:v1/disk.img") + randomFilename := portableFilepath(path.Join(testRepoDir, "a:v1/disk.img")) err = generateRandomFile(randomFilename, 100*chunkSize) require.NoErrorf(t, err, "unable to generate file: %v", err) @@ -264,21 +284,19 @@ func TestLayoutMapper_Write_MustOnlyWriteContentThatDiffersFromAlreadyWritten(t func TestLayoutMapper_Write_MultipleConcurrentWorkers(t *testing.T) { ctx := context.Background() - tempDir, err := os.MkdirTemp("", "content-matches-*") - require.NoErrorf(t, err, "unable to create temp dir: %v", err) - defer os.RemoveAll(tempDir) + tempDir := t.TempDir() testRepoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") - err = os.MkdirAll(path.Join(testRepoDir, "a:v1"), os.ModePerm) + err := os.MkdirAll(portableFilepath(path.Join(testRepoDir, "a:v1")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) logF := func(fmt string, argv ...any) {} const chunkSize = 11 lm := NewMapper(tempDir, dirimage.WithChunkSize(chunkSize), dirimage.WithLogFunction(logF)) - err = generateRandomFile(path.Join(testRepoDir, "a:v1/disk.img"), 200*chunkSize) + err = generateRandomFile(portableFilepath(path.Join(testRepoDir, "a:v1/disk.img")), 200*chunkSize) require.NoErrorf(t, err, "unable to generate file: %v", err) srcRef, err := name.ParseReference("oci.jarosik.online/testrepo/a:v1") require.NoErrorf(t, err, "unable to parse reference: %v", err) - beforeHash := hashFromFile(t, path.Join(tempDir, "oci.jarosik.online/testrepo/a:v1/disk.img")) + beforeHash := hashFromFile(t, portableFilepath(path.Join(tempDir, "oci.jarosik.online/testrepo/a:v1/disk.img"))) img1, err := lm.Read(ctx, srcRef) require.NoErrorf(t, err, "unable to read disk image: %v", err) @@ -298,11 +316,9 @@ func TestLayoutMapper_Write_MultipleConcurrentWorkers(t *testing.T) { func TestLayoutMapper_Write_MustOverwriteBiggerFileIfAlreadyExist(t *testing.T) { ctx := context.Background() - tempDir, err := os.MkdirTemp("", "content-matches-*") - require.NoErrorf(t, err, "unable to create temp dir: %v", err) - defer os.RemoveAll(tempDir) + tempDir := t.TempDir() testRepoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") - err = os.MkdirAll(path.Join(testRepoDir, "a:v1"), os.ModePerm) + err := os.MkdirAll(portableFilepath(path.Join(testRepoDir, "a:v1")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) logF := func(fmt string, argv ...any) {} const chunkSize = 5 @@ -346,7 +362,7 @@ func TestLayoutMapper_WriteIfNotPresent(t *testing.T) { defer os.RemoveAll(tempDir) testRepoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") - err = os.MkdirAll(path.Join(testRepoDir, "a:v1-origin"), os.ModePerm) + err = os.MkdirAll(portableFilepath(path.Join(testRepoDir, "a:v1-origin")), os.ModePerm) require.NoErrorf(t, err, "unable to create directory: %v", err) randomFileName := path.Join(testRepoDir, "a:v1-origin/disk.img") @@ -421,7 +437,7 @@ func TestLayoutMapper_Clone_SameFileDifferentNames(t *testing.T) { fileContent := []byte("same file content") images := make([]*dirimage.DirImage, 0) for _, x := range []string{"A", "B"} { - imgDir := path.Join(tempDir, "tmp"+x) + imgDir := filepath.Join(tempDir, "tmp"+x) err = os.MkdirAll(imgDir, os.ModePerm) require.NoErrorf(t, err, "unable to create directory for Image A: %v", err) err = os.WriteFile(filepath.Join(imgDir, fmt.Sprintf("disk%s.img", x)), fileContent, 0644) @@ -432,7 +448,6 @@ func TestLayoutMapper_Clone_SameFileDifferentNames(t *testing.T) { } // Write Image A and Image B to the same repo (simulating clone) - repoDir := path.Join(tempDir, "oci.jarosik.online/testrepo") lm := NewMapper(tempDir) // Write Image A @@ -455,12 +470,12 @@ func TestLayoutMapper_Clone_SameFileDifferentNames(t *testing.T) { assert.Equal(t, 0, int(stats2.BytesWrittenCount)) // Validate that both images are present with the correct file names - assert.FileExists(t, filepath.Join(repoDir, "a:v1/diskA.img")) - assert.FileExists(t, filepath.Join(repoDir, "b:v1/diskB.img")) + assert.FileExists(t, filepath.Join(lm.refToDir(srcRefA), "diskA.img")) + assert.FileExists(t, filepath.Join(lm.refToDir(srcRefB), "diskB.img")) // Validate that the contents of both files are still the same - hashAfterA := hashFromFile(t, filepath.Join(repoDir, "a:v1/diskA.img")) - hashAfterB := hashFromFile(t, filepath.Join(repoDir, "b:v1/diskB.img")) + hashAfterA := hashFromFile(t, filepath.Join(lm.refToDir(srcRefA), "diskA.img")) + hashAfterB := hashFromFile(t, filepath.Join(lm.refToDir(srcRefB), "diskB.img")) assert.Equal(t, hashAfterA, hashAfterB, "Both files should still have the same hash after cloning") } diff --git a/pkg/transporter/helpers_test.go b/pkg/transporter/helpers_test.go index bef266c..92f2f00 100644 --- a/pkg/transporter/helpers_test.go +++ b/pkg/transporter/helpers_test.go @@ -11,6 +11,7 @@ import ( "net/http" "os" "path/filepath" + "runtime" "strings" "sync" "testing" @@ -61,8 +62,16 @@ func makeFileAt(t *testing.T, filename, content string) { assert.NoError(t, err) } +func portableRef(ref string) string { + if runtime.GOOS == "windows" { + ref = strings.ReplaceAll(ref, ":", "@") + } + return ref +} + func makeTestVMAt(t *testing.T, tempDir, ref string) (sha string) { t.Helper() + ref = portableRef(ref) d := filepath.Join(tempDir, "images", ref) err := os.MkdirAll(d, os.ModePerm) assert.NoError(t, err) @@ -75,6 +84,7 @@ func makeTestVMAt(t *testing.T, tempDir, ref string) (sha string) { func makeTestVMWithContent(t *testing.T, tempDir, ref string, content string) (sha string) { t.Helper() + ref = portableRef(ref) d := filepath.Join(tempDir, "images", ref) err := os.MkdirAll(d, os.ModePerm) assert.NoError(t, err) @@ -104,6 +114,7 @@ func makeRandomFile(t *testing.T, fileName string, size int64) error { func makeBigTestVMAt(t *testing.T, tempDir, ref string) (sha string) { t.Helper() + ref = portableRef(ref) d := filepath.Join(tempDir, "images", ref) err := os.MkdirAll(d, os.ModePerm) assert.NoError(t, err) @@ -151,6 +162,7 @@ func modifyByteInFileToEnsureDifferent(t *testing.T, filePath string, offset int func modifyBigTestVMAt(t *testing.T, tempDir, ref string, offset int64) (sha string) { t.Helper() + ref = portableRef(ref) d := filepath.Join(tempDir, "images", ref) err := os.MkdirAll(d, os.ModePerm) assert.NoError(t, err) @@ -162,6 +174,7 @@ func modifyBigTestVMAt(t *testing.T, tempDir, ref string, offset int64) (sha str } func deleteTestVMAt(t *testing.T, tempDir, ref string) { + ref = portableRef(ref) d := filepath.Join(tempDir, "images", ref) err := os.RemoveAll(d) assert.NoError(t, err) diff --git a/pkg/transporter/pull_test.go b/pkg/transporter/pull_test.go index 0ef109e..cd9d6fd 100644 --- a/pkg/transporter/pull_test.go +++ b/pkg/transporter/pull_test.go @@ -47,7 +47,7 @@ func TestPullAndPush_pullingAgainShouldNotDownloadAnyBlob(t *testing.T) { t.Run("pulling reference for the first time", func(t *testing.T) { err = Pull(ref, opts...) assert.NoError(t, err) - shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", ref, "disk.img")) + shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ref), "disk.img")) assert.Equal(t, shaBefore, shaAfter) assert.Equal(t, 3, calculateAccessed(recordedRequests, "GET", "/blobs")) }) @@ -56,7 +56,7 @@ func TestPullAndPush_pullingAgainShouldNotDownloadAnyBlob(t *testing.T) { t.Run("pulling same reference second time", func(t *testing.T) { err = Pull(ref, opts...) assert.NoError(t, err) - shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", ref, "disk.img")) + shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ref), "disk.img")) assert.Equal(t, shaBefore, shaAfter) assert.Equal(t, 0, calculateAccessed(recordedRequests, "GET", "/blobs")) @@ -109,7 +109,7 @@ func TestPullAndPush_multipleSlightlyDifferentTags(t *testing.T) { err = Pull(ithRef, opts...) require.NoError(t, err) assert.Equal(t, expectedBlobDownloads[i], calculateAccessed(recordedRequests, "GET", "/blobs")) - checksumsDownloaded[i] = hashFromFile(t, filepath.Join(tempDir, "images", ithRef, "disk.img")) + checksumsDownloaded[i] = hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ithRef), "disk.img")) assert.Equal(t, checksumsUploaded[i], checksumsDownloaded[i]) } }) @@ -144,8 +144,8 @@ func TestPullAndPush_pullSmallerImageAfterPullingLargerImage(t *testing.T) { err = Pull(ref1, opts...) require.NoError(t, err) - hash1After := hashFromFile(t, filepath.Join(tempDir, "images", ref1, "disk.img")) - hash2After := hashFromFile(t, filepath.Join(tempDir, "images", ref2, "disk.img")) + hash1After := hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ref1), "disk.img")) + hash2After := hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ref2), "disk.img")) assert.Equal(t, hash1, hash1After) assert.Equal(t, hash2, hash2After) @@ -176,7 +176,7 @@ func TestPullAndPush_pullSameTagThatWasUpdatedOnRemote(t *testing.T) { err = Pull(latestRef, opts...) require.NoError(t, err) - hashesAfter[i] = hashFromFile(t, filepath.Join(tempDir, "images", latestRef, "disk.img")) + hashesAfter[i] = hashFromFile(t, filepath.Join(tempDir, "images", portableRef(latestRef), "disk.img")) } for i := 0; i < tagsCount; i++ { assert.Equal(t, hashesBefore[i], hashesAfter[i]) @@ -209,7 +209,7 @@ func TestPull_WithForceOption(t *testing.T) { // Verify that the image was written even though it already exists (Check by checking the number of requests) assert.Equal(t, 3, calculateAccessed(recordedRequests, "GET", "/blobs")) - shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", ref, "disk.img")) + shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ref), "disk.img")) assert.Equal(t, shaBefore, shaAfter) }) @@ -228,7 +228,7 @@ func TestPull_WithForceOption(t *testing.T) { // Ensure no blobs were downloaded since the image already exists assert.Equal(t, 0, calculateAccessed(recordedRequests, "GET", "/blobs")) - shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", ref, "disk.img")) + shaAfter := hashFromFile(t, filepath.Join(tempDir, "images", portableRef(ref), "disk.img")) assert.Equal(t, shaBefore, shaAfter) }) }