Skip to content

Commit 9fa6017

Browse files
committed
separate noop into OS specific code
noop contains funcs that are specific to different OS. This commit creates OS specific noop file that implements their logic. This cleans the noop file of all switches/if. This is a simple refactor, no logic is changed Signed-off-by: Luca Stocchi <lstocchi@redhat.com>
1 parent d54977b commit 9fa6017

File tree

4 files changed

+153
-125
lines changed

4 files changed

+153
-125
lines changed

pkg/imagepullers/noop.go

Lines changed: 3 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,13 @@ package imagepullers
22

33
import (
44
"bufio"
5-
"errors"
65
"fmt"
76
"io"
87
"os"
9-
"os/exec"
10-
"path/filepath"
11-
12-
"github.com/sirupsen/logrus"
138

149
"github.com/containers/podman/v5/pkg/machine/define"
1510

1611
"github.com/containers/podman/v5/pkg/machine/env"
17-
18-
"github.com/lima-vm/go-qcow2reader"
19-
"github.com/lima-vm/go-qcow2reader/convert"
20-
"github.com/lima-vm/go-qcow2reader/image"
21-
"github.com/lima-vm/go-qcow2reader/image/qcow2"
22-
"github.com/lima-vm/go-qcow2reader/image/raw"
2312
)
2413

2514
type NoopImagePuller struct {
@@ -40,21 +29,6 @@ func (puller *NoopImagePuller) SetSourceURI(sourcePath string) {
4029
puller.sourceURI = sourcePath
4130
}
4231

43-
func imageExtension(vmType define.VMType, sourceURI string) string {
44-
switch vmType {
45-
case define.WSLVirt:
46-
ext := filepath.Ext(sourceURI)
47-
if ext == ".wsl" {
48-
return ".wsl"
49-
}
50-
return ".tar.gz"
51-
case define.QemuVirt, define.HyperVVirt:
52-
return filepath.Ext(sourceURI)
53-
default:
54-
return "." + vmType.ImageFormat().Kind()
55-
}
56-
}
57-
5832
func (puller *NoopImagePuller) LocalPath() (*define.VMFile, error) {
5933
// if localPath has already been calculated returns it
6034
if puller.localPath != nil {
@@ -85,110 +59,14 @@ func (puller *NoopImagePuller) Download() error {
8559
if err != nil {
8660
return err
8761
}
88-
return doCopyFile(puller.sourceURI, localPath.Path, puller.vmType)
89-
}
90-
91-
func doCopyFile(src, dest string, vmType define.VMType) error {
92-
srcF, err := os.Open(src)
93-
if err != nil {
94-
return err
95-
}
96-
defer srcF.Close()
97-
98-
switch vmType {
99-
case define.AppleHvVirt, define.LibKrun:
100-
return copyFileMac(srcF, dest)
101-
case define.WSLVirt, define.HyperVVirt:
102-
return copyFileWin(srcF, dest)
103-
default:
104-
return copyFile(srcF, dest)
105-
}
106-
}
107-
108-
func copyFileMac(src *os.File, dest string) error {
109-
srcImg, err := qcow2reader.Open(src)
110-
if err != nil {
111-
return err
112-
}
113-
defer srcImg.Close()
114-
115-
switch srcImg.Type() {
116-
case raw.Type:
117-
// if the image is raw it performs a simple copy
118-
return copyFile(src, dest)
119-
case qcow2.Type:
120-
// if the image is qcow2 it performs a conversion to raw
121-
return convertToRaw(srcImg, dest)
122-
default:
123-
return fmt.Errorf("%s format not supported for conversion to raw", srcImg.Type())
124-
}
125-
}
126-
127-
func copyFileWin(srcF *os.File, dest string) error {
128-
binary, err := exec.LookPath("robocopy")
129-
if err != nil {
130-
logrus.Debugf("warning: failed to get robocopy binary: %v. Falling back to default file copy between %s and %s\n", err, srcF.Name(), dest)
131-
return copyFile(srcF, dest)
132-
}
133-
134-
srcDir, srcFile := filepath.Split(srcF.Name())
135-
destDir := filepath.Dir(dest)
136-
137-
// Executes the robocopy command with options optimized for a fast, single-file copy.
138-
// /J: Copies using unbuffered I/O (better for large files).
139-
// /MT: Enables multi-threaded copying for improved performance.
140-
// /R:0: Sets retries on failed copies to 0 to avoid long waits.
141-
// /IS: Includes Same files, which forces an overwrite even if the destination
142-
// file appears identical to the source.
143-
cmd := exec.Command(binary, "/J", "/MT", "/R:0", "/IS", srcDir, destDir, srcFile)
144-
if logrus.IsLevelEnabled(logrus.DebugLevel) {
145-
cmd.Stdout = os.Stdout
146-
cmd.Stderr = os.Stderr
147-
} else {
148-
cmd.Stdout = io.Discard
149-
cmd.Stderr = io.Discard
150-
}
151-
152-
err = cmd.Run()
153-
if err != nil {
154-
// robocopy does not use classic exit codes like linux commands, so we need to check for specific errors
155-
// Only exit code 8 is considered an error, all other exit codes are considered successful with exceptions
156-
// see https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy
157-
var exitErr *exec.ExitError
158-
if errors.As(err, &exitErr) {
159-
exitCode := exitErr.ExitCode()
160-
if exitCode >= 8 {
161-
return fmt.Errorf("failed to run robocopy: %w", err)
162-
}
163-
} else {
164-
return fmt.Errorf("failed to run robocopy: %w", err)
165-
}
166-
}
167-
168-
if err := os.Remove(dest); err != nil && !errors.Is(err, os.ErrNotExist) {
169-
return fmt.Errorf("failed to remove existing destination file: %w", err)
170-
}
171-
172-
err = os.Rename(filepath.Join(destDir, srcFile), dest)
173-
if err != nil {
174-
return fmt.Errorf("failed to rename file: %w", err)
175-
}
176-
177-
return nil
178-
}
17962

180-
func convertToRaw(srcImg image.Image, dest string) error {
181-
destF, err := os.Create(dest)
63+
src, err := os.Open(puller.sourceURI)
18264
if err != nil {
18365
return err
18466
}
185-
defer destF.Close()
186-
187-
if err := srcImg.Readable(); err != nil {
188-
return fmt.Errorf("source image is not readable: %w", err)
189-
}
67+
defer src.Close()
19068

191-
return convert.Convert(destF, srcImg, convert.Options{})
69+
return doCopyFile(src, localPath.Path)
19270
}
19371

19472
func copyFile(src *os.File, dest string) error {

pkg/imagepullers/noop_darwin.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//go:build darwin
2+
3+
package imagepullers
4+
5+
import (
6+
"fmt"
7+
"os"
8+
9+
"github.com/containers/podman/v5/pkg/machine/define"
10+
11+
"github.com/lima-vm/go-qcow2reader"
12+
"github.com/lima-vm/go-qcow2reader/convert"
13+
"github.com/lima-vm/go-qcow2reader/image"
14+
"github.com/lima-vm/go-qcow2reader/image/qcow2"
15+
"github.com/lima-vm/go-qcow2reader/image/raw"
16+
)
17+
18+
func imageExtension(vmType define.VMType, _ string) string {
19+
return "." + vmType.ImageFormat().Kind()
20+
}
21+
22+
func doCopyFile(src *os.File, dest string) error {
23+
srcImg, err := qcow2reader.Open(src)
24+
if err != nil {
25+
return err
26+
}
27+
defer srcImg.Close()
28+
29+
switch srcImg.Type() {
30+
case raw.Type:
31+
return copyFile(src, dest)
32+
case qcow2.Type:
33+
return convertToRaw(srcImg, dest)
34+
default:
35+
return fmt.Errorf("%s format not supported for conversion to raw", srcImg.Type())
36+
}
37+
}
38+
39+
func convertToRaw(srcImg image.Image, dest string) error {
40+
destF, err := os.Create(dest)
41+
if err != nil {
42+
return err
43+
}
44+
defer destF.Close()
45+
46+
if err := srcImg.Readable(); err != nil {
47+
return fmt.Errorf("source image is not readable: %w", err)
48+
}
49+
50+
return convert.Convert(destF, srcImg, convert.Options{})
51+
}

pkg/imagepullers/noop_unix.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//go:build !windows && !darwin
2+
3+
package imagepullers
4+
5+
import (
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/containers/podman/v5/pkg/machine/define"
10+
)
11+
12+
func imageExtension(_ define.VMType, sourceURI string) string {
13+
return filepath.Ext(sourceURI)
14+
}
15+
16+
func doCopyFile(src *os.File, dest string) error {
17+
return copyFile(src, dest)
18+
}

pkg/imagepullers/noop_windows.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//go:build windows
2+
3+
package imagepullers
4+
5+
import (
6+
"errors"
7+
"fmt"
8+
"io"
9+
"os"
10+
"os/exec"
11+
"path/filepath"
12+
13+
"github.com/containers/podman/v5/pkg/machine/define"
14+
"github.com/sirupsen/logrus"
15+
)
16+
17+
func imageExtension(vmType define.VMType, sourceURI string) string {
18+
switch vmType {
19+
case define.WSLVirt:
20+
ext := filepath.Ext(sourceURI)
21+
if ext == ".wsl" {
22+
return ".wsl"
23+
}
24+
return ".tar.gz"
25+
default:
26+
return filepath.Ext(sourceURI)
27+
}
28+
}
29+
30+
func doCopyFile(src *os.File, dest string) error {
31+
binary, err := exec.LookPath("robocopy")
32+
if err != nil {
33+
logrus.Debugf("warning: failed to get robocopy binary: %v. Falling back to default file copy between %s and %s\n", err, src.Name(), dest)
34+
return copyFile(src, dest)
35+
}
36+
37+
srcDir, srcFile := filepath.Split(src.Name())
38+
destDir := filepath.Dir(dest)
39+
40+
// Executes the robocopy command with options optimized for a fast, single-file copy.
41+
// /J: Copies using unbuffered I/O (better for large files).
42+
// /MT: Enables multi-threaded copying for improved performance.
43+
// /R:0: Sets retries on failed copies to 0 to avoid long waits.
44+
// /IS: Includes Same files, which forces an overwrite even if the destination
45+
// file appears identical to the source.
46+
cmd := exec.Command(binary, "/J", "/MT", "/R:0", "/IS", srcDir, destDir, srcFile)
47+
if logrus.IsLevelEnabled(logrus.DebugLevel) {
48+
cmd.Stdout = os.Stdout
49+
cmd.Stderr = os.Stderr
50+
} else {
51+
cmd.Stdout = io.Discard
52+
cmd.Stderr = io.Discard
53+
}
54+
55+
err = cmd.Run()
56+
if err != nil {
57+
// robocopy does not use classic exit codes like linux commands, so we need to check for specific errors
58+
// Only exit code 8 is considered an error, all other exit codes are considered successful with exceptions
59+
// see https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy
60+
var exitErr *exec.ExitError
61+
if errors.As(err, &exitErr) {
62+
exitCode := exitErr.ExitCode()
63+
if exitCode >= 8 {
64+
return fmt.Errorf("failed to run robocopy: %w", err)
65+
}
66+
} else {
67+
return fmt.Errorf("failed to run robocopy: %w", err)
68+
}
69+
}
70+
71+
if err := os.Remove(dest); err != nil && !errors.Is(err, os.ErrNotExist) {
72+
return fmt.Errorf("failed to remove existing destination file: %w", err)
73+
}
74+
75+
err = os.Rename(filepath.Join(destDir, srcFile), dest)
76+
if err != nil {
77+
return fmt.Errorf("failed to rename file: %w", err)
78+
}
79+
80+
return nil
81+
}

0 commit comments

Comments
 (0)