github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/diff.go (about) 1 package main 2 3 import ( 4 "fmt" 5 6 "github.com/containers/buildah/pkg/formats" 7 "github.com/containers/libpod/cmd/podman/cliconfig" 8 "github.com/containers/libpod/pkg/adapter" 9 "github.com/containers/storage/pkg/archive" 10 "github.com/pkg/errors" 11 "github.com/spf13/cobra" 12 ) 13 14 type diffJSONOutput struct { 15 Changed []string `json:"changed,omitempty"` 16 Added []string `json:"added,omitempty"` 17 Deleted []string `json:"deleted,omitempty"` 18 } 19 20 type diffOutputParams struct { 21 Change archive.ChangeType 22 Path string 23 } 24 25 type stdoutStruct struct { 26 output []diffOutputParams 27 } 28 29 func (so stdoutStruct) Out() error { 30 for _, d := range so.output { 31 fmt.Printf("%s %s\n", d.Change, d.Path) 32 } 33 return nil 34 } 35 36 var ( 37 diffCommand cliconfig.DiffValues 38 diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`) 39 40 _diffCommand = &cobra.Command{ 41 Use: "diff [flags] CONTAINER | IMAGE", 42 Short: "Inspect changes on container's file systems", 43 Long: diffDescription, 44 RunE: func(cmd *cobra.Command, args []string) error { 45 diffCommand.InputArgs = args 46 diffCommand.GlobalFlags = MainGlobalOpts 47 diffCommand.Remote = remoteclient 48 return diffCmd(&diffCommand) 49 }, 50 Example: `podman diff imageID 51 podman diff ctrID 52 podman diff --format json redis:alpine`, 53 } 54 ) 55 56 func init() { 57 diffCommand.Command = _diffCommand 58 diffCommand.SetHelpTemplate(HelpTemplate()) 59 diffCommand.SetUsageTemplate(UsageTemplate()) 60 flags := diffCommand.Flags() 61 62 flags.BoolVar(&diffCommand.Archive, "archive", true, "Save the diff as a tar archive") 63 flags.StringVar(&diffCommand.Format, "format", "", "Change the output format") 64 flags.BoolVarP(&diffCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") 65 markFlagHidden(flags, "archive") 66 markFlagHiddenForRemoteClient("latest", flags) 67 68 } 69 70 func formatJSON(output []diffOutputParams) (diffJSONOutput, error) { 71 jsonStruct := diffJSONOutput{} 72 for _, output := range output { 73 switch output.Change { 74 case archive.ChangeModify: 75 jsonStruct.Changed = append(jsonStruct.Changed, output.Path) 76 case archive.ChangeAdd: 77 jsonStruct.Added = append(jsonStruct.Added, output.Path) 78 case archive.ChangeDelete: 79 jsonStruct.Deleted = append(jsonStruct.Deleted, output.Path) 80 default: 81 return jsonStruct, errors.Errorf("output kind %q not recognized", output.Change.String()) 82 } 83 } 84 return jsonStruct, nil 85 } 86 87 func diffCmd(c *cliconfig.DiffValues) error { 88 if len(c.InputArgs) != 1 && !c.Latest { 89 return errors.Errorf("container, image, or layer name must be specified: podman diff [options [...]] ID-NAME") 90 } 91 92 runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) 93 if err != nil { 94 return errors.Wrapf(err, "could not get runtime") 95 } 96 defer runtime.DeferredShutdown(false) 97 98 var to string 99 if c.Latest { 100 ctr, err := runtime.GetLatestContainer() 101 if err != nil { 102 return errors.Wrapf(err, "unable to get latest container") 103 } 104 to = ctr.ID() 105 } else { 106 to = c.InputArgs[0] 107 } 108 changes, err := runtime.Diff(c, to) 109 if err != nil { 110 return errors.Wrapf(err, "could not get changes for %q", to) 111 } 112 diffOutput := []diffOutputParams{} 113 outputFormat := c.Format 114 115 for _, change := range changes { 116 117 params := diffOutputParams{ 118 Change: change.Kind, 119 Path: change.Path, 120 } 121 diffOutput = append(diffOutput, params) 122 } 123 124 var out formats.Writer 125 126 if outputFormat != "" { 127 switch outputFormat { 128 case formats.JSONString: 129 data, err := formatJSON(diffOutput) 130 if err != nil { 131 return err 132 } 133 out = formats.JSONStruct{Output: data} 134 default: 135 return errors.New("only valid format for diff is 'json'") 136 } 137 } else { 138 out = stdoutStruct{output: diffOutput} 139 } 140 return out.Out() 141 }