Skip to content

Commit

Permalink
iDiff refactor with interfaces (GoogleCloudPlatform#243)
Browse files Browse the repository at this point in the history
* Differ + image refactor

* Output and DiffResult refactor

* Breaking up JSON and text outputs

* Refactored if branch chains to use reflection for image source determination

* Extracted out eng
  • Loading branch information
cftorres committed Aug 2, 2017
1 parent ec6f665 commit 5d2c1e0
Show file tree
Hide file tree
Showing 19 changed files with 456 additions and 349 deletions.
2 changes: 1 addition & 1 deletion iDiff/.iDiffTests.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
go run iDiff/main.go iDiff file gcr.io/google_containers/busybox:1.24 gcr.io/google_containers/busybox:latest -j > iDiff/tests/busybox_diff_actual.json
go run iDiff/main.go file gcr.io/google_containers/busybox:1.24 gcr.io/google_containers/busybox:latest -j > iDiff/tests/busybox_diff_actual.json
if [[ $? -ne 0 ]]; then
echo "iDiff simple run failed"
exit 1
Expand Down
60 changes: 56 additions & 4 deletions iDiff/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,50 @@ var json bool
var eng bool

var RootCmd = &cobra.Command{
Use: "[differ] [container1] [container2]",
Use: "[differ] [image1] [image2]",
Short: "Compare two images.",
Long: `Compares two images using the specifed differ (see iDiff documentation for available differs).`,
Run: func(cmd *cobra.Command, args []string) {
if validArgs, err := validateArgs(args[1:]); !validArgs {
if validArgs, err := validateArgs(args); !validArgs {
glog.Error(err.Error())
os.Exit(1)
}
if diff, err := differs.Diff(args[2], args[3], args[1], json, eng); err == nil {
fmt.Println(diff)
utils.SetDockerEngine(eng)
image1, err := utils.ImagePrepper{args[1]}.GetImage()
if err != nil {
glog.Error(err.Error())
os.Exit(1)
}
image2, err := utils.ImagePrepper{args[2]}.GetImage()
if err != nil {
glog.Error(err.Error())
os.Exit(1)
}
differ, err := differs.GetDiffer(args[0])
if err != nil {
glog.Error(err.Error())
os.Exit(1)
}

diff := differs.DiffRequest{image1, image2, differ}
if diff, err := diff.GetDiff(); err == nil {
if json {
err = diff.OutputJSON()
if err != nil {
glog.Error(err)
}
} else {
err = diff.OutputText()
if err != nil {
glog.Error(err)
}
}

errMsg := remove(image1.FSPath, true)
errMsg += remove(image2.FSPath, true)
if errMsg != "" {
glog.Error(errMsg)
}
} else {
glog.Error(err.Error())
os.Exit(1)
Expand Down Expand Up @@ -103,6 +137,24 @@ func checkArgType(args []string) (bool, error) {
return true, nil
}

func remove(path string, dir bool) string {
var errStr string
if path == "" {
return ""
}

var err error
if dir {
err = os.RemoveAll(path)
} else {
err = os.Remove(path)
}
if err != nil {
errStr = "\nUnable to remove " + path
}
return errStr
}

func init() {
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
RootCmd.Flags().BoolVarP(&json, "json", "j", false, "JSON Output defines if the diff should be returned in a human readable format (false) or a JSON (true).")
Expand Down
23 changes: 11 additions & 12 deletions iDiff/differs/aptDiff.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@ import (
"github.com/golang/glog"
)

type AptDiffer struct {
}

// AptDiff compares the packages installed by apt-get.
func AptDiff(img1, img2 string, json bool, eng bool) (string, error) {
func (d AptDiffer) Diff(image1, image2 utils.Image) (DiffResult, error) {
img1 := image1.FSPath
img2 := image2.FSPath

pack1, err := getPackages(img1)
if err != nil {
return "", err
return &utils.PackageDiffResult{}, err
}
pack2, err := getPackages(img2)
if err != nil {
return "", err
return &utils.PackageDiffResult{}, err
}

diff := utils.GetMapDiff(pack1, pack2)
diff.Image1 = img1
diff.Image2 = img2

if json {
return utils.JSONify(diff)
}
utils.Output(diff)
return "", nil
diff := utils.GetMapDiff(pack1, pack2, img1, img2)
return &diff, nil
}

func getPackages(path string) (map[string]utils.PackageInfo, error) {
Expand Down
96 changes: 29 additions & 67 deletions iDiff/differs/differs.go
Original file line number Diff line number Diff line change
@@ -1,86 +1,48 @@
package differs

import (
"bytes"
"errors"
"os"
"reflect"

"github.com/GoogleCloudPlatform/runtimes-common/iDiff/utils"
)

var diffs = map[string]func(string, string, bool, bool) (string, error){
"hist": HistoryDiff,
"history": HistoryDiff,
"file": FileDiff,
"apt": AptDiff,
"linux": AptDiff,
"pip": PipDiff,
"node": NodeDiff,
type DiffRequest struct {
Image1 utils.Image
Image2 utils.Image
DiffType Differ
}

func Diff(arg1, arg2, differ string, json bool, eng bool) (string, error) {
if f, exists := diffs[differ]; exists {
fValue := reflect.ValueOf(f)
histValue := reflect.ValueOf(HistoryDiff)
fileValue := reflect.ValueOf(FileDiff)
if fValue.Pointer() == histValue.Pointer() || fValue.Pointer() == fileValue.Pointer() {
return f(arg1, arg2, json, eng)
}
return specificDiffer(f, arg1, arg2, json, eng)
}
return "", errors.New("Unknown differ")
type DiffResult interface {
OutputJSON() error
OutputText() error
}

func specificDiffer(f func(string, string, bool, bool) (string, error), img1, img2 string, json bool, eng bool) (string, error) {
var buffer bytes.Buffer
validDiff := true
imgPath1, err := utils.ImageToFS(img1, eng)
if err != nil {
buffer.WriteString(err.Error())
validDiff = false
}
imgPath2, err := utils.ImageToFS(img2, eng)
if err != nil {
buffer.WriteString(err.Error())
validDiff = false
}

var diff string
if validDiff {
output, err := f(imgPath1, imgPath2, json, eng)
if err != nil {
buffer.WriteString(err.Error())
}
diff = output
}

errStr := remove(imgPath1, true)
errStr += remove(imgPath2, true)
if errStr != "" {
buffer.WriteString(errStr)
}
type Differ interface {
Diff(image1, image2 utils.Image) (DiffResult, error)
}

if buffer.String() != "" {
return diff, errors.New(buffer.String())
}
return diff, nil
var diffs = map[string]Differ{
"hist": HistoryDiffer{},
"history": HistoryDiffer{},
"file": FileDiffer{},
"apt": AptDiffer{},
"linux": AptDiffer{},
"pip": PipDiffer{},
"node": NodeDiffer{},
}

func remove(path string, dir bool) string {
var errStr string
if path == "" {
return ""
}
func (diff DiffRequest) GetDiff() (DiffResult, error) {
img1 := diff.Image1
img2 := diff.Image2
differ := diff.DiffType
return differ.Diff(img1, img2)
}

var err error
if dir {
err = os.RemoveAll(path)
func GetDiffer(diffName string) (differ Differ, err error) {
if d, exists := diffs[diffName]; exists {
differ = d
} else {
err = os.Remove(path)
}
if err != nil {
errStr = "\nUnable to remove " + path
errors.New("Unknown differ")
}
return errStr
return
}
66 changes: 10 additions & 56 deletions iDiff/differs/fileDiff.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package differs

import (
"bytes"
"fmt"
"os"
"path/filepath"
Expand All @@ -10,74 +9,29 @@ import (
"github.com/GoogleCloudPlatform/runtimes-common/iDiff/utils"
)

// FileDiff diffs two packages and compares their contents
func FileDiff(img1, img2 string, json bool, eng bool) (string, error) {
diff, err := diffImageFiles(img1, img2, eng)

if err != nil {
return "", err
}

output, err := getDiffOutput(diff, json)
if err != nil {
return "", err
}
return output, nil
type FileDiffer struct {
}

func getDiffOutput(dirDiff utils.DirDiff, json bool) (string, error) {
if json {
return utils.JSONify(dirDiff)
}

var buffer bytes.Buffer

s := fmt.Sprintf("These entries have been added to %s\n", dirDiff.Image1)
buffer.WriteString(s)
if len(dirDiff.Adds) == 0 {
buffer.WriteString("\tNo files have been added\n")
} else {
for _, f := range dirDiff.Adds {
s = fmt.Sprintf("\t%s\n", f)
buffer.WriteString(s)
}
}

s = fmt.Sprintf("These entries have been deleted from %s\n", dirDiff.Image1)
buffer.WriteString(s)
if len(dirDiff.Dels) == 0 {
buffer.WriteString("\tNo files have been deleted\n")
} else {
for _, f := range dirDiff.Dels {
s = fmt.Sprintf("\t%s\n", f)
buffer.WriteString(s)
}
}
// FileDiff diffs two packages and compares their contents
func (d FileDiffer) Diff(image1, image2 utils.Image) (DiffResult, error) {
img1 := image1.FSPath
img2 := image2.FSPath

return buffer.String(), nil
diff, err := diffImageFiles(img1, img2)
return &utils.DirDiffResult{Diff: diff}, err
}

func diffImageFiles(img1, img2 string, eng bool) (utils.DirDiff, error) {
func diffImageFiles(img1, img2 string) (utils.DirDiff, error) {
var diff utils.DirDiff
img1FS, err := utils.ImageToFS(img1, eng)
if err != nil {
return diff, fmt.Errorf("Error retrieving image %s file system: %s", img1, err)
}
img2FS, err := utils.ImageToFS(img2, eng)
if err != nil {
return diff, fmt.Errorf("Error retrieving image %s file system: %s", img2, err)
}

img1Contents, err := getImageContents(img1FS)
img1Contents, err := getImageContents(img1)
if err != nil {
return diff, fmt.Errorf("Error parsing image %s contents: %s", img1, err)
}
img2Contents, err := getImageContents(img2FS)
img2Contents, err := getImageContents(img2)
if err != nil {
return diff, fmt.Errorf("Error parsing image %s contents: %s", img2, err)
}
defer os.RemoveAll(img1FS)
defer os.RemoveAll(img2FS)

for layer1, contents1 := range img1Contents {
sameLayer := false
Expand Down

0 comments on commit 5d2c1e0

Please sign in to comment.