Skip to content
This repository has been 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 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion cmd/diff.go
Expand Up @@ -158,7 +158,11 @@ 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")
vsoch marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

Expand Down
43 changes: 40 additions & 3 deletions cmd/root.go
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 @@ -70,27 +73,35 @@ Tarballs can also be specified by simply providing the path to the .tar, .tar.gz
}

func outputResults(resultMap map[string]util.Result) {

vsoch marked this conversation as resolved.
Show resolved Hide resolved
// Outputs diff/analysis results in alphabetical order by analyzer name
sortedTypes := []string{}
for analyzerType := range resultMap {
sortedTypes = append(sortedTypes, analyzerType)
}
sort.Strings(sortedTypes)

// Get the writer
writer, err := getWriter(outputFile)
if err != nil {
logrus.Error(err)
vsoch marked this conversation as resolved.
Show resolved Hide resolved
}

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)

vsoch marked this conversation as resolved.
Show resolved Hide resolved
err := util.JSONify(writer, results)
if err != nil {
logrus.Error(err)
}
Expand Down Expand Up @@ -162,6 +173,31 @@ 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

vsoch marked this conversation as resolved.
Show resolved Hide resolved
// If the user specifies an output file, ensure exists
if outputFile != "" {

vsoch marked this conversation as resolved.
Show resolved Hide resolved
// Don't overwrite a file that exists, unless given --force
if _, err := os.Stat(outputFile); !os.IsNotExist(err) {
vsoch marked this conversation as resolved.
Show resolved Hide resolved
if !forceWrite {
logrus.Error("file exist, will not overwrite.")
vsoch marked this conversation as resolved.
Show resolved Hide resolved
}
}

// Otherwise, output file is an io.writer
outWriter, err = os.Create(outputFile)

vsoch marked this conversation as resolved.
Show resolved Hide resolved
}
// 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 +237,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
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)
}