Skip to content
This repository was archived by the owner on Mar 27, 2024. It is now read-only.

Enhancement - save to file #279

Merged
merged 3 commits into from
Dec 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion cmd/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,15 @@ func diffFile(image1, image2 *pkgutil.Image) error {
if err != nil {
return err
}
util.TemplateOutput(diff, "FilenameDiff")
writer, err := getWriter(outputFile)
if err != nil {
return err
}
util.TemplateOutput(writer, diff, "FilenameDiff")
if err != nil {
logrus.Error(err)
return err
}
return nil
}

Expand Down
35 changes: 32 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package cmd
import (
goflag "flag"
"fmt"
"io"
"os"
"path/filepath"
"sort"
Expand All @@ -40,6 +41,8 @@ var save bool
var types diffTypes
var noCache bool

var outputFile string
var forceWrite bool
var cacheDir string
var LogLevel string
var format string
Expand Down Expand Up @@ -77,20 +80,26 @@ func outputResults(resultMap map[string]util.Result) {
}
sort.Strings(sortedTypes)

// Get the writer
writer, err := getWriter(outputFile)
if err != nil {
errors.Wrap(err, "getting writer for output file")
}

results := make([]interface{}, len(resultMap))
for i, analyzerType := range sortedTypes {
result := resultMap[analyzerType]
if json {
results[i] = result.OutputStruct()
} else {
err := result.OutputText(analyzerType, format)
err := result.OutputText(writer, analyzerType, format)
if err != nil {
logrus.Error(err)
}
}
}
if json {
err := util.JSONify(results)
err := util.JSONify(writer, results)
if err != nil {
logrus.Error(err)
}
Expand Down Expand Up @@ -162,6 +171,25 @@ func getCacheDir(imageName string) (string, error) {
return filepath.Join(rootDir, filepath.Clean(imageName)), nil
}

func getWriter(outputFile string) (io.Writer, error) {
var err error
var outWriter io.Writer
// If the user specifies an output file, ensure exists
if outputFile != "" {
// Don't overwrite a file that exists, unless given --force
if _, err := os.Stat(outputFile); !os.IsNotExist(err) && !forceWrite {
errors.Wrap(err, "file exist, will not overwrite.")
}
// Otherwise, output file is an io.writer
outWriter, err = os.Create(outputFile)
}
// If still doesn't exist, return stdout as the io.Writer
if outputFile == "" {
outWriter = os.Stdout
}
return outWriter, err
}

func init() {
RootCmd.PersistentFlags().StringVarP(&LogLevel, "verbosity", "v", "warning", "This flag controls the verbosity of container-diff.")
RootCmd.PersistentFlags().StringVarP(&format, "format", "", "", "Format to output diff in.")
Expand Down Expand Up @@ -201,5 +229,6 @@ func addSharedFlags(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&util.SortSize, "order", "o", false, "Set this flag to sort any file/package results by descending size. Otherwise, they will be sorted by name.")
cmd.Flags().BoolVarP(&noCache, "no-cache", "n", false, "Set this to force retrieval of image filesystem on each run.")
cmd.Flags().StringVarP(&cacheDir, "cache-dir", "c", "", "cache directory base to create .container-diff (default is $HOME).")

cmd.Flags().StringVarP(&outputFile, "output", "w", "", "output file to write to (default writes to the screen).")
cmd.Flags().BoolVar(&forceWrite, "force", false, "force overwrite output file, if exists already.")
}
35 changes: 18 additions & 17 deletions util/analyze_output_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ package util
import (
"errors"
"fmt"
"io"

"github.com/GoogleContainerTools/container-diff/pkg/util"
"github.com/sirupsen/logrus"
)

type Result interface {
OutputStruct() interface{}
OutputText(resultType string, format string) error
OutputText(writer io.Writer, resultType string, format string) error
}

type AnalyzeResult struct {
Expand All @@ -41,14 +42,14 @@ func (r ListAnalyzeResult) OutputStruct() interface{} {
return r
}

func (r ListAnalyzeResult) OutputText(resultType string, format string) error {
func (r ListAnalyzeResult) OutputText(writer io.Writer, resultType string, format string) error {
analysis, valid := r.Analysis.([]string)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type []string")
return fmt.Errorf("Could not output %s analysis result", r.AnalyzeType)
}
r.Analysis = analysis
return TemplateOutputFromFormat(r, "ListAnalyze", format)
return TemplateOutputFromFormat(writer, r, "ListAnalyze", format)

}

Expand All @@ -73,7 +74,7 @@ func (r MultiVersionPackageAnalyzeResult) OutputStruct() interface{} {
return output
}

func (r MultiVersionPackageAnalyzeResult) OutputText(resultType string, format string) error {
func (r MultiVersionPackageAnalyzeResult) OutputText(writer io.Writer, resultType string, format string) error {
analysis, valid := r.Analysis.(map[string]map[string]PackageInfo)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type map[string]map[string]PackageInfo")
Expand All @@ -91,7 +92,7 @@ func (r MultiVersionPackageAnalyzeResult) OutputText(resultType string, format s
AnalyzeType: r.AnalyzeType,
Analysis: strAnalysis,
}
return TemplateOutputFromFormat(strResult, "MultiVersionPackageAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "MultiVersionPackageAnalyze", format)
}

type SingleVersionPackageAnalyzeResult AnalyzeResult
Expand All @@ -115,7 +116,7 @@ func (r SingleVersionPackageAnalyzeResult) OutputStruct() interface{} {
return output
}

func (r SingleVersionPackageAnalyzeResult) OutputText(diffType string, format string) error {
func (r SingleVersionPackageAnalyzeResult) OutputText(writer io.Writer, diffType string, format string) error {
analysis, valid := r.Analysis.(map[string]PackageInfo)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type map[string]PackageInfo")
Expand All @@ -133,7 +134,7 @@ func (r SingleVersionPackageAnalyzeResult) OutputText(diffType string, format st
AnalyzeType: r.AnalyzeType,
Analysis: strAnalysis,
}
return TemplateOutputFromFormat(strResult, "SingleVersionPackageAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "SingleVersionPackageAnalyze", format)
}

type SingleVersionPackageLayerAnalyzeResult AnalyzeResult
Expand Down Expand Up @@ -173,7 +174,7 @@ func (r SingleVersionPackageLayerAnalyzeResult) OutputStruct() interface{} {
return output
}

func (r SingleVersionPackageLayerAnalyzeResult) OutputText(diffType string, format string) error {
func (r SingleVersionPackageLayerAnalyzeResult) OutputText(writer io.Writer, diffType string, format string) error {
analysis, valid := r.Analysis.(PackageLayerDiff)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type PackageLayerDiff")
Expand Down Expand Up @@ -205,7 +206,7 @@ func (r SingleVersionPackageLayerAnalyzeResult) OutputText(diffType string, form
AnalyzeType: r.AnalyzeType,
Analysis: analysisOutput,
}
return TemplateOutputFromFormat(strResult, "SingleVersionPackageLayerAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "SingleVersionPackageLayerAnalyze", format)
}

type PackageOutput struct {
Expand Down Expand Up @@ -263,7 +264,7 @@ func (r FileAnalyzeResult) OutputStruct() interface{} {
return r
}

func (r FileAnalyzeResult) OutputText(analyzeType string, format string) error {
func (r FileAnalyzeResult) OutputText(writer io.Writer, analyzeType string, format string) error {
analysis, valid := r.Analysis.([]util.DirectoryEntry)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type []DirectoryEntry")
Expand All @@ -286,7 +287,7 @@ func (r FileAnalyzeResult) OutputText(analyzeType string, format string) error {
AnalyzeType: r.AnalyzeType,
Analysis: strAnalysis,
}
return TemplateOutputFromFormat(strResult, "FileAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "FileAnalyze", format)
}

type FileLayerAnalyzeResult AnalyzeResult
Expand All @@ -310,7 +311,7 @@ func (r FileLayerAnalyzeResult) OutputStruct() interface{} {
return r
}

func (r FileLayerAnalyzeResult) OutputText(analyzeType string, format string) error {
func (r FileLayerAnalyzeResult) OutputText(writer io.Writer, analyzeType string, format string) error {
analysis, valid := r.Analysis.([][]util.DirectoryEntry)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type []DirectoryEntry")
Expand Down Expand Up @@ -338,7 +339,7 @@ func (r FileLayerAnalyzeResult) OutputText(analyzeType string, format string) er
AnalyzeType: r.AnalyzeType,
Analysis: strDirectoryEntries,
}
return TemplateOutputFromFormat(strResult, "FileLayerAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "FileLayerAnalyze", format)
}

type SizeAnalyzeResult AnalyzeResult
Expand All @@ -353,7 +354,7 @@ func (r SizeAnalyzeResult) OutputStruct() interface{} {
return r
}

func (r SizeAnalyzeResult) OutputText(analyzeType string, format string) error {
func (r SizeAnalyzeResult) OutputText(writer io.Writer, analyzeType string, format string) error {
analysis, valid := r.Analysis.([]SizeEntry)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type []SizeEntry")
Expand All @@ -371,7 +372,7 @@ func (r SizeAnalyzeResult) OutputText(analyzeType string, format string) error {
AnalyzeType: r.AnalyzeType,
Analysis: strAnalysis,
}
return TemplateOutputFromFormat(strResult, "SizeAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "SizeAnalyze", format)
}

type SizeLayerAnalyzeResult AnalyzeResult
Expand All @@ -386,7 +387,7 @@ func (r SizeLayerAnalyzeResult) OutputStruct() interface{} {
return r
}

func (r SizeLayerAnalyzeResult) OutputText(analyzeType string, format string) error {
func (r SizeLayerAnalyzeResult) OutputText(writer io.Writer, analyzeType string, format string) error {
analysis, valid := r.Analysis.([]SizeEntry)
if !valid {
logrus.Error("Unexpected structure of Analysis. Should be of type []SizeEntry")
Expand All @@ -404,5 +405,5 @@ func (r SizeLayerAnalyzeResult) OutputText(analyzeType string, format string) er
AnalyzeType: r.AnalyzeType,
Analysis: strAnalysis,
}
return TemplateOutputFromFormat(strResult, "SizeLayerAnalyze", format)
return TemplateOutputFromFormat(writer, strResult, "SizeLayerAnalyze", format)
}
Loading