Skip to content

Commit

Permalink
refactor(crit): pass proto struct as argument
Browse files Browse the repository at this point in the history
The proto struct required for encoding or decoding the images was
previously being inferred from the `images.ProtoHandler()` function.
Now, it is inferred using that only in the CLI, and is passed to the
actual CRIT functions as a parameter. This eliminates the redundant
protobuf bindings being imported when using CRIT as a library.

Signed-off-by: Prajwal S N <prajwalnadig21@gmail.com>
  • Loading branch information
snprajwal committed May 13, 2023
1 parent 854004d commit e69417e
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 171 deletions.
2 changes: 1 addition & 1 deletion crit/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GO ?= go
CRIU ?= criu

bin/crit: cmd/cli.go
bin/crit: cmd/main.go
$(GO) build ${GOFLAGS} -o $@ $^

../test/loop/loop:
Expand Down
130 changes: 104 additions & 26 deletions crit/cmd/cli.go → crit/cli/cli.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package cli

import (
"encoding/json"
Expand Down Expand Up @@ -40,11 +40,29 @@ var decodeCmd = &cobra.Command{
Long: `Convert the input binary image to JSON and write it to a file.
If no output file is provided, the JSON is printed to stdout.`,
Run: func(cmd *cobra.Command, args []string) {
c = crit.NewCli(inputFilePath, outputFilePath,
var (
inputFile *os.File
err error
)
if inputFilePath == "" {
inputFile = os.Stdin
} else {
inputFile, err = os.Open(inputFilePath)
if err != nil {
log.Fatal(fmt.Errorf("error opening input file: %w", err))
}

Check warning on line 53 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L52-L53

Added lines #L52 - L53 were not covered by tests
defer inputFile.Close()
}

c = crit.New(inputFile, nil,
inputDirPath, pretty, noPayload)
img, err := c.Decode()
entryType, err := GetEntryTypeFromImg(inputFile)
if err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error getting protobuf binding: %w", err))
}
img, err := c.Decode(entryType)
if err != nil {
log.Fatal(fmt.Errorf("error decoding image: %w", err))

Check warning on line 65 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L65

Added line #L65 was not covered by tests
}

var jsonData []byte
Expand All @@ -54,7 +72,7 @@ If no output file is provided, the JSON is printed to stdout.`,
jsonData, err = json.Marshal(img)
}
if err != nil {
log.Fatal(errors.New(fmt.Sprint("Error processing data into JSON: ", err)))
log.Fatal(fmt.Errorf("error processing data into JSON: %w", err))

Check warning on line 75 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L75

Added line #L75 was not covered by tests
}
// If no output file, print to stdout
if outputFilePath == "" {
Expand All @@ -64,12 +82,13 @@ If no output file is provided, the JSON is printed to stdout.`,
// Write to output file
jsonFile, err := os.Create(outputFilePath)
if err != nil {
log.Fatal(errors.New(fmt.Sprint("Error opening destination file: ", err)))
log.Fatal(fmt.Errorf("error opening destination file: %w", err))

Check warning on line 85 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L85

Added line #L85 was not covered by tests
}
defer jsonFile.Close()

_, err = jsonFile.Write(jsonData)
if err != nil {
log.Fatal(errors.New(fmt.Sprint("Error writing JSON data: ", err)))
log.Fatal(fmt.Errorf("error writing JSON data: %w", err))

Check warning on line 91 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L91

Added line #L91 was not covered by tests
}
},
}
Expand All @@ -80,16 +99,43 @@ var encodeCmd = &cobra.Command{
Short: "Convert JSON to binary image file",
Long: "Convert the input JSON to a CRIU image file.",
Run: func(cmd *cobra.Command, args []string) {
c = crit.NewCli(inputFilePath, outputFilePath,
var (
inputFile, outputFile *os.File
err error
)
if inputFilePath == "" {
inputFile = os.Stdin
} else {
inputFile, err = os.Open(inputFilePath)
if err != nil {
log.Fatal(fmt.Errorf("error opening input file: %w", err))
}

Check warning on line 112 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L111-L112

Added lines #L111 - L112 were not covered by tests
defer inputFile.Close()
}
if outputFilePath == "" {
outputFile = os.Stdout
} else {
outputFile, err = os.Create(outputFilePath)
if err != nil {
log.Fatal(fmt.Errorf("error opening output file: %w", err))
}

Check warning on line 121 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L120-L121

Added lines #L120 - L121 were not covered by tests
defer outputFile.Close()
}

c = crit.New(inputFile, outputFile,
inputDirPath, pretty, noPayload)
entryType, err := GetEntryTypeFromJSON(inputFile)
if err != nil {
log.Fatal(fmt.Errorf("error getting protobuf binding: %w", err))
}
// Convert JSON to Go struct
img, err := c.Parse()
img, err := c.Parse(entryType)
if err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error parsing JSON: %w", err))

Check warning on line 134 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L134

Added line #L134 was not covered by tests
}
// Write Go struct to binary image file
if err := c.Encode(img); err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error writing to file: %w", err))

Check warning on line 138 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L138

Added line #L138 was not covered by tests
}
},
}
Expand All @@ -103,16 +149,34 @@ var showCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
inputFilePath = args[0]
pretty = true
c = crit.NewCli(inputFilePath, outputFilePath,
var (
inputFile *os.File
err error
)
if inputFilePath == "" {
inputFile = os.Stdin

Check warning on line 157 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L157

Added line #L157 was not covered by tests
} else {
inputFile, err = os.Open(inputFilePath)
if err != nil {
log.Fatal(fmt.Errorf("error opening input file: %w", err))
}

Check warning on line 162 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L161-L162

Added lines #L161 - L162 were not covered by tests
defer inputFile.Close()
}

c = crit.New(inputFile, nil,
inputDirPath, pretty, noPayload)
img, err := c.Decode()
entryType, err := GetEntryTypeFromImg(inputFile)
if err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error getting protobuf binding: %w", err))
}

Check warning on line 171 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L170-L171

Added lines #L170 - L171 were not covered by tests
img, err := c.Decode(entryType)
if err != nil {
log.Fatal(fmt.Errorf("error decoding image: %w", err))

Check warning on line 174 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L174

Added line #L174 was not covered by tests
}

jsonData, err := json.MarshalIndent(img, "", " ")
if err != nil {
log.Fatal(errors.New(fmt.Sprint("Error processing data into JSON: ", err)))
log.Fatal(fmt.Errorf("error processing data into JSON: %w", err))

Check warning on line 179 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L179

Added line #L179 was not covered by tests
}
fmt.Println(string(jsonData))
},
Expand All @@ -125,16 +189,30 @@ var infoCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
inputFilePath = args[0]
c = crit.NewCli(inputFilePath, outputFilePath,
var (
inputFile *os.File
err error
)
if inputFilePath == "" {
inputFile = os.Stdin

Check warning on line 197 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L197

Added line #L197 was not covered by tests
} else {
inputFile, err = os.Open(inputFilePath)
if err != nil {
log.Fatal(fmt.Errorf("error opening input file: %w", err))
}

Check warning on line 202 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L201-L202

Added lines #L201 - L202 were not covered by tests
defer inputFile.Close()
}

c = crit.New(inputFile, nil,
inputDirPath, pretty, noPayload)
img, err := c.Info()
if err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error decoding image: %w", err))

Check warning on line 210 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L210

Added line #L210 was not covered by tests
}

jsonData, err := json.MarshalIndent(img, "", " ")
if err != nil {
log.Fatal(errors.New(fmt.Sprint("Error processing data into JSON: ", err)))
log.Fatal(fmt.Errorf("error processing data into JSON: %w", err))

Check warning on line 215 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L215

Added line #L215 was not covered by tests
}
fmt.Println(string(jsonData))
},
Expand All @@ -155,10 +233,10 @@ var xCmd = &cobra.Command{
// returned object since we don't really care
// about the data itself, as long as we can
// marshal it into JSON and display it.
var xData interface{}
var xData any
var err error

c = crit.NewCli(inputFilePath, outputFilePath,
c = crit.New(nil, nil,
inputDirPath, pretty, noPayload)
// Switch the explore type and call the handler.
switch args[1] {
Expand All @@ -171,22 +249,22 @@ var xCmd = &cobra.Command{
case "rss":
xData, err = c.ExploreRss()
default:
err = errors.New("error exploring directory: Invalid explore type")
err = errors.New("error exploring directory: invalid explore type")

Check warning on line 252 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L252

Added line #L252 was not covered by tests
}
if err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error exploring directory: %w", err))

Check warning on line 255 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L255

Added line #L255 was not covered by tests
}

jsonData, err := json.MarshalIndent(xData, "", " ")
if err != nil {
log.Fatal(errors.New(fmt.Sprint("Error processing data into JSON: ", err)))
log.Fatal(fmt.Errorf("error processing data into JSON: %w", err))

Check warning on line 260 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L260

Added line #L260 was not covered by tests
}
fmt.Println(string(jsonData))
},
}

// Add all commands to the root command and configure flags
func init() {
func Init() {
// Disable completion generation
rootCmd.CompletionOptions.DisableDefaultCmd = true
// Decode options
Expand All @@ -212,8 +290,8 @@ func init() {
rootCmd.AddCommand(xCmd)
}

func main() {
func Run() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
log.Fatal(fmt.Errorf("error running CLI: %w", err))

Check warning on line 295 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L295

Added line #L295 was not covered by tests
}
}
52 changes: 49 additions & 3 deletions crit/images/handler.go → crit/cli/handler.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package images
package cli

import (
"encoding/json"
"fmt"
"io"
"os"

"github.com/checkpoint-restore/go-criu/v6/crit"
"github.com/checkpoint-restore/go-criu/v6/crit/images/apparmor"
"github.com/checkpoint-restore/go-criu/v6/crit/images/autofs"
binfmt_misc "github.com/checkpoint-restore/go-criu/v6/crit/images/binfmt-misc"
Expand Down Expand Up @@ -59,7 +63,41 @@ import (
"google.golang.org/protobuf/proto"
)

func ProtoHandler(magic string) (proto.Message, error) {
func GetEntryTypeFromImg(imgFile *os.File) (proto.Message, error) {
magic, err := crit.ReadMagic(imgFile)
if err != nil {
return nil, err
}
// Seek to the beginning of the file
_, err = imgFile.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}

Check warning on line 75 in crit/cli/handler.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/handler.go#L74-L75

Added lines #L74 - L75 were not covered by tests

return protoHandler(magic)
}

func GetEntryTypeFromJSON(jsonFile *os.File) (proto.Message, error) {
jsonData, err := io.ReadAll(jsonFile)
if err != nil {
return nil, err
}

Check warning on line 84 in crit/cli/handler.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/handler.go#L83-L84

Added lines #L83 - L84 were not covered by tests
// Seek to the beginning of the file
_, err = jsonFile.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}

Check warning on line 89 in crit/cli/handler.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/handler.go#L88-L89

Added lines #L88 - L89 were not covered by tests

var img map[string]any
err = json.Unmarshal(jsonData, &img)
if err != nil {
return nil, err
}

return protoHandler(img["magic"].(string))
}

func protoHandler(magic string) (proto.Message, error) {
switch magic {
case "APPARMOR":
return &apparmor.ApparmorEntry{}, nil
Expand Down Expand Up @@ -189,6 +227,14 @@ func ProtoHandler(magic string) (proto.Message, error) {
return &utsns.UtsnsEntry{}, nil
case "VMAS":
return &vma.VmaEntry{}, nil

Check warning on line 229 in crit/cli/handler.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/handler.go#L212-L229

Added lines #L212 - L229 were not covered by tests
/* Pagemap and ghost file have custom handlers
and cannot use a single proto struct to be
encoded or decoded. Hence, for these two
image types, nil is returned. */
case "PAGEMAP":
return nil, nil
case "GHOST_FILE":
return nil, nil

Check warning on line 237 in crit/cli/handler.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/handler.go#L236-L237

Added lines #L236 - L237 were not covered by tests
}
return nil, fmt.Errorf("no handler found for magic 0x%x", magic)
return nil, fmt.Errorf("no protobuf binding found for magic 0x%x", magic)

Check warning on line 239 in crit/cli/handler.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/handler.go#L239

Added line #L239 was not covered by tests
}
8 changes: 8 additions & 0 deletions crit/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package main

import "github.com/checkpoint-restore/go-criu/v6/crit/cli"

func main() {
cli.Init()
cli.Run()
}
Loading

0 comments on commit e69417e

Please sign in to comment.