Skip to content

Commit b008ef1

Browse files
authored
Merge pull request #36 from nirs/convert-package
Add parallel convert
2 parents 5f33c4a + 46183d3 commit b008ef1

File tree

7 files changed

+589
-103
lines changed

7 files changed

+589
-103
lines changed

cmd/go-qcow2reader-example/convert.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"flag"
6+
"fmt"
7+
"os"
8+
9+
"github.com/lima-vm/go-qcow2reader"
10+
"github.com/lima-vm/go-qcow2reader/convert"
11+
"github.com/lima-vm/go-qcow2reader/log"
12+
)
13+
14+
func cmdConvert(args []string) error {
15+
var (
16+
// Required
17+
source, target string
18+
19+
// Options
20+
debug bool
21+
options convert.Options
22+
)
23+
24+
fs := flag.NewFlagSet("convert", flag.ExitOnError)
25+
fs.Usage = func() {
26+
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s convert [OPTIONS...] SOURCE TARGET\n", os.Args[0])
27+
flag.PrintDefaults()
28+
}
29+
fs.BoolVar(&debug, "debug", false, "enable printing debug messages")
30+
fs.Int64Var(&options.SegmentSize, "segment-size", convert.SegmentSize, "worker segment size in bytes")
31+
fs.IntVar(&options.BufferSize, "buffer-size", convert.BufferSize, "buffer size in bytes")
32+
fs.IntVar(&options.Workers, "workers", convert.Workers, "number of workers")
33+
if err := fs.Parse(args); err != nil {
34+
return err
35+
}
36+
37+
if debug {
38+
log.SetDebugFunc(logDebug)
39+
}
40+
41+
switch len(fs.Args()) {
42+
case 0:
43+
return errors.New("no file was specified")
44+
case 1:
45+
return errors.New("target file is required")
46+
case 2:
47+
source = fs.Arg(0)
48+
target = fs.Arg(1)
49+
default:
50+
return errors.New("too many files were specified")
51+
}
52+
53+
f, err := os.Open(source)
54+
if err != nil {
55+
return err
56+
}
57+
defer f.Close()
58+
59+
img, err := qcow2reader.Open(f)
60+
if err != nil {
61+
return err
62+
}
63+
defer img.Close()
64+
65+
t, err := os.Create(target)
66+
if err != nil {
67+
return err
68+
}
69+
defer t.Close()
70+
71+
if err := t.Truncate(img.Size()); err != nil {
72+
return err
73+
}
74+
75+
c, err := convert.New(options)
76+
if err != nil {
77+
return err
78+
}
79+
if err := c.Convert(t, img, img.Size()); err != nil {
80+
return err
81+
}
82+
83+
if err := t.Sync(); err != nil {
84+
return err
85+
}
86+
87+
return t.Close()
88+
}

cmd/go-qcow2reader-example/info.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"flag"
7+
"fmt"
8+
"os"
9+
10+
"github.com/lima-vm/go-qcow2reader"
11+
"github.com/lima-vm/go-qcow2reader/image"
12+
)
13+
14+
func cmdInfo(args []string) error {
15+
var (
16+
// Required
17+
filename string
18+
19+
// Options
20+
debug bool
21+
)
22+
23+
fs := flag.NewFlagSet("info", flag.ExitOnError)
24+
fs.Usage = func() {
25+
fmt.Fprintf(fs.Output(), "Usage: %s info [OPTIONS...] FILE\n", os.Args[0])
26+
fs.PrintDefaults()
27+
}
28+
fs.BoolVar(&debug, "debug", false, "enable printing debug messages")
29+
if err := fs.Parse(args); err != nil {
30+
return err
31+
}
32+
33+
switch len(fs.Args()) {
34+
case 0:
35+
return errors.New("no file was specified")
36+
case 1:
37+
filename = fs.Arg(0)
38+
default:
39+
return errors.New("too many files specified")
40+
}
41+
42+
f, err := os.Open(filename)
43+
if err != nil {
44+
return err
45+
}
46+
defer f.Close()
47+
48+
img, err := qcow2reader.Open(f)
49+
if err != nil {
50+
return err
51+
}
52+
defer img.Close()
53+
54+
imgInfo := image.NewImageInfo(img)
55+
j, err := json.MarshalIndent(imgInfo, "", " ")
56+
if err != nil {
57+
return err
58+
}
59+
if _, err = fmt.Println(string(j)); err != nil {
60+
return err
61+
}
62+
if err = img.Readable(); err != nil {
63+
logWarn(err.Error())
64+
}
65+
66+
return nil
67+
}

cmd/go-qcow2reader-example/main.go

Lines changed: 32 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
package main
22

33
import (
4-
"encoding/json"
5-
"errors"
6-
"flag"
74
"fmt"
85
"io"
96
"os"
107

118
"github.com/klauspost/compress/zstd"
12-
"github.com/lima-vm/go-qcow2reader"
13-
"github.com/lima-vm/go-qcow2reader/image"
149
"github.com/lima-vm/go-qcow2reader/image/qcow2"
1510
"github.com/lima-vm/go-qcow2reader/log"
1611
)
1712

18-
func warn(s string) {
13+
func logWarn(s string) {
1914
fmt.Fprintln(os.Stderr, "WARNING: "+s)
2015
}
2116

22-
func debugPrint(s string) {
17+
func logDebug(s string) {
2318
fmt.Fprintln(os.Stderr, "DEBUG: "+s)
2419
}
2520

@@ -40,82 +35,48 @@ func newZstdDecompressor(r io.Reader) (io.ReadCloser, error) {
4035
return &zstdDecompressor{dec}, nil
4136
}
4237

38+
func usage() {
39+
usage := `Usage: %s COMMAND [OPTIONS...]
40+
41+
Available commands:
42+
info show image information
43+
read read image data and print to stdout
44+
convert convert image to raw format
45+
`
46+
fmt.Fprintf(os.Stderr, usage, os.Args[0])
47+
os.Exit(1)
48+
}
49+
4350
func main() {
44-
log.SetWarnFunc(warn)
51+
log.SetWarnFunc(logWarn)
4552

4653
// zlib (deflate) decompressor is registered by default, but zstd is not.
4754
qcow2.SetDecompressor(qcow2.CompressionTypeZstd, newZstdDecompressor)
4855

49-
if err := xmain(); err != nil {
50-
fmt.Fprintln(os.Stderr, "ERROR: "+err.Error())
51-
os.Exit(1)
52-
}
53-
}
56+
var err error
5457

55-
func xmain() error {
56-
flag.Usage = func() {
57-
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [OPTIONS...] FILE\n", os.Args[0])
58-
flag.PrintDefaults()
58+
var cmd string
59+
if len(os.Args) > 1 {
60+
cmd = os.Args[1]
5961
}
60-
var (
61-
debug bool
62-
info bool
63-
bufferSize int
64-
offset int64
65-
length int64
66-
)
67-
flag.BoolVar(&debug, "debug", false, "enable printing debug messages")
68-
flag.BoolVar(&info, "info", false, "print the image info and exit")
69-
flag.IntVar(&bufferSize, "buffer", 65536, "buffer size")
70-
flag.Int64Var(&offset, "offset", 0, "offset to read")
71-
flag.Int64Var(&length, "length", -1, "length to read")
72-
flag.Parse()
73-
if debug {
74-
log.SetDebugFunc(debugPrint)
62+
var args []string
63+
if len(os.Args) > 2 {
64+
args = os.Args[2:]
7565
}
7666

77-
args := flag.Args()
78-
switch len(args) {
79-
case 0:
80-
return errors.New("no file was specified")
81-
case 1:
82-
// NOP
67+
switch cmd {
68+
case "info":
69+
err = cmdInfo(args)
70+
case "read":
71+
err = cmdRead(args)
72+
case "convert":
73+
err = cmdConvert(args)
8374
default:
84-
return errors.New("too many files were specified")
85-
}
86-
fName := args[0]
87-
88-
f, err := os.Open(fName)
89-
if err != nil {
90-
return err
75+
usage()
9176
}
92-
defer f.Close()
9377

94-
img, err := qcow2reader.Open(f)
9578
if err != nil {
96-
return err
97-
}
98-
99-
if info {
100-
imgInfo := image.NewImageInfo(img)
101-
j, err := json.MarshalIndent(imgInfo, "", " ")
102-
if err != nil {
103-
return err
104-
}
105-
if _, err = fmt.Println(string(j)); err != nil {
106-
return err
107-
}
108-
if err = img.Readable(); err != nil {
109-
warn(err.Error())
110-
}
111-
return nil
112-
}
113-
114-
if length < 0 {
115-
length = img.Size()
79+
fmt.Fprintln(os.Stderr, "ERROR: "+err.Error())
80+
os.Exit(1)
11681
}
117-
buf := make([]byte, bufferSize)
118-
sr := io.NewSectionReader(img, offset, length)
119-
_, err = io.CopyBuffer(os.Stdout, sr, buf)
120-
return err
12182
}

cmd/go-qcow2reader-example/read.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"flag"
6+
"fmt"
7+
"io"
8+
"os"
9+
10+
"github.com/lima-vm/go-qcow2reader"
11+
"github.com/lima-vm/go-qcow2reader/log"
12+
)
13+
14+
func cmdRead(args []string) error {
15+
var (
16+
// Required
17+
filename string
18+
19+
// Options
20+
debug bool
21+
bufferSize int
22+
offset int64
23+
length int64
24+
)
25+
26+
fs := flag.NewFlagSet("read", flag.ExitOnError)
27+
fs.Usage = func() {
28+
fmt.Fprintf(fs.Output(), "Usage: %s read [OPTIONS...] FILE\n", os.Args[0])
29+
flag.PrintDefaults()
30+
}
31+
fs.BoolVar(&debug, "debug", false, "enable printing debug messages")
32+
fs.IntVar(&bufferSize, "buffer-size", 65536, "buffer size")
33+
fs.Int64Var(&offset, "offset", 0, "offset to read")
34+
fs.Int64Var(&length, "length", -1, "length to read")
35+
if err := fs.Parse(args); err != nil {
36+
return err
37+
}
38+
39+
if debug {
40+
log.SetDebugFunc(logDebug)
41+
}
42+
43+
switch len(fs.Args()) {
44+
case 0:
45+
return errors.New("no file was specified")
46+
case 1:
47+
filename = fs.Arg(0)
48+
default:
49+
return errors.New("too many files were specified")
50+
}
51+
52+
f, err := os.Open(filename)
53+
if err != nil {
54+
return err
55+
}
56+
defer f.Close()
57+
58+
img, err := qcow2reader.Open(f)
59+
if err != nil {
60+
return err
61+
}
62+
defer img.Close()
63+
64+
if length < 0 {
65+
length = img.Size()
66+
}
67+
68+
buf := make([]byte, bufferSize)
69+
sr := io.NewSectionReader(img, offset, length)
70+
_, err = io.CopyBuffer(os.Stdout, sr, buf)
71+
72+
return err
73+
}

0 commit comments

Comments
 (0)