Skip to content

Commit

Permalink
Merge pull request #10836 from Luap99/diff
Browse files Browse the repository at this point in the history
podman diff accept two images or containers
  • Loading branch information
openshift-merge-robot authored Jul 3, 2021
2 parents 0771613 + 8f6a024 commit 895b815
Show file tree
Hide file tree
Showing 28 changed files with 512 additions and 172 deletions.
42 changes: 12 additions & 30 deletions cmd/podman/containers/diff.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package containers

import (
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/diff"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand All @@ -13,11 +14,11 @@ import (
var (
// podman container _diff_
diffCmd = &cobra.Command{
Use: "diff [options] CONTAINER",
Args: validate.IDOrLatestArgs,
Use: "diff [options] CONTAINER [CONTAINER]",
Args: diff.ValidateContainerDiffArgs,
Short: "Inspect changes to the container's file systems",
Long: `Displays changes to the container filesystem's'. The container will be compared to its parent layer.`,
RunE: diff,
Long: `Displays changes to the container filesystem's'. The container will be compared to its parent layer or the second argument when given.`,
RunE: diffRun,
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman container diff myCtr
podman container diff -l --format json myCtr`,
Expand All @@ -33,41 +34,22 @@ func init() {

diffOpts = &entities.DiffOptions{}
flags := diffCmd.Flags()

// FIXME: Why does this exists? It is not used anywhere.
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
_ = flags.MarkHidden("archive")

formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))

validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
}

func diff(cmd *cobra.Command, args []string) error {
func diffRun(cmd *cobra.Command, args []string) error {
if len(args) == 0 && !diffOpts.Latest {
return errors.New("container must be specified: podman container diff [options [...]] ID-NAME")
}

var id string
if len(args) > 0 {
id = args[0]
}
results, err := registry.ContainerEngine().ContainerDiff(registry.GetContext(), id, *diffOpts)
if err != nil {
return err
}

switch {
case report.IsJSON(diffOpts.Format):
return common.ChangesToJSON(results)
case diffOpts.Format == "":
return common.ChangesToTable(results)
default:
return errors.New("only supported value for '--format' is 'json'")
}
}

func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
diffOpts = &options
return diff(cmd, args)
diffOpts.Type = define.DiffContainer
return diff.Diff(cmd, args, *diffOpts)
}
42 changes: 11 additions & 31 deletions cmd/podman/diff.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package main

import (
"fmt"

"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/containers"
"github.com/containers/podman/v3/cmd/podman/images"
"github.com/containers/podman/v3/cmd/podman/diff"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/spf13/cobra"
)
Expand All @@ -16,13 +14,13 @@ import (

var (
// Command: podman _diff_ Object_ID
diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`
diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer or the second argument when given.`
diffCmd = &cobra.Command{
Use: "diff [options] {CONTAINER|IMAGE}",
Args: validate.IDOrLatestArgs,
Use: "diff [options] {CONTAINER|IMAGE} [{CONTAINER|IMAGE}]",
Args: diff.ValidateContainerDiffArgs,
Short: "Display the changes to the object's file system",
Long: diffDescription,
RunE: diff,
RunE: diffRun,
ValidArgsFunction: common.AutocompleteContainersAndImages,
Example: `podman diff imageID
podman diff ctrID
Expand All @@ -37,36 +35,18 @@ func init() {
Command: diffCmd,
})
flags := diffCmd.Flags()
// FIXME: Why does this exists? It is not used anywhere.
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
_ = flags.MarkHidden("archive")

formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))

validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
}

func diff(cmd *cobra.Command, args []string) error {
// Latest implies looking for a container
if diffOpts.Latest {
return containers.Diff(cmd, args, diffOpts)
}

options := entities.ContainerExistsOptions{
External: true,
}
if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0], options); err != nil {
return err
} else if found.Value {
return containers.Diff(cmd, args, diffOpts)
}

if found, err := registry.ImageEngine().Exists(registry.GetContext(), args[0]); err != nil {
return err
} else if found.Value {
return images.Diff(cmd, args, diffOpts)
}

return fmt.Errorf("%s not found on system", args[0])
func diffRun(cmd *cobra.Command, args []string) error {
diffOpts.Type = define.DiffAll
return diff.Diff(cmd, args, diffOpts)
}
79 changes: 79 additions & 0 deletions cmd/podman/diff/diff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package diff

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

"github.com/containers/common/pkg/report"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/docker/docker/pkg/archive"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
results, err := registry.ContainerEngine().Diff(registry.GetContext(), args, options)
if err != nil {
return err
}

switch {
case report.IsJSON(options.Format):
return changesToJSON(results)
case options.Format == "":
return changesToTable(results)
default:
return errors.New("only supported value for '--format' is 'json'")
}
}

type ChangesReportJSON struct {
Changed []string `json:"changed,omitempty"`
Added []string `json:"added,omitempty"`
Deleted []string `json:"deleted,omitempty"`
}

func changesToJSON(diffs *entities.DiffReport) error {
body := ChangesReportJSON{}
for _, row := range diffs.Changes {
switch row.Kind {
case archive.ChangeAdd:
body.Added = append(body.Added, row.Path)
case archive.ChangeDelete:
body.Deleted = append(body.Deleted, row.Path)
case archive.ChangeModify:
body.Changed = append(body.Changed, row.Path)
default:
return errors.Errorf("output kind %q not recognized", row.Kind)
}
}

// Pull in configured json library
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(body)
}

func changesToTable(diffs *entities.DiffReport) error {
for _, row := range diffs.Changes {
fmt.Fprintln(os.Stdout, row.String())
}
return nil
}

// IDOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
func ValidateContainerDiffArgs(cmd *cobra.Command, args []string) error {
given, _ := cmd.Flags().GetBool("latest")
if len(args) > 0 && !given {
return cobra.RangeArgs(1, 2)(cmd, args)
}
if len(args) > 0 && given {
return errors.New("--latest and containers cannot be used together")
}
if len(args) == 0 && !given {
return errors.Errorf("%q requires a name, id, or the \"--latest\" flag", cmd.CommandPath())
}
return nil
}
40 changes: 10 additions & 30 deletions cmd/podman/images/diff.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package images

import (
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/diff"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

var (
// podman container _inspect_
diffCmd = &cobra.Command{
Use: "diff [options] IMAGE",
Args: cobra.ExactArgs(1),
Use: "diff [options] IMAGE [IMAGE]",
Args: cobra.RangeArgs(1, 2),
Short: "Inspect changes to the image's file systems",
Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer.`,
RunE: diff,
Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer or the second argument when given.`,
RunE: diffRun,
ValidArgsFunction: common.AutocompleteImages,
Example: `podman image diff myImage
podman image diff --format json redis:alpine`,
Expand All @@ -39,31 +39,11 @@ func diffFlags(flags *pflag.FlagSet) {
_ = flags.MarkDeprecated("archive", "Provided for backwards compatibility, has no impact on output.")

formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
}

func diff(cmd *cobra.Command, args []string) error {
if diffOpts.Latest {
return errors.New("image diff does not support --latest")
}

results, err := registry.ImageEngine().Diff(registry.GetContext(), args[0], *diffOpts)
if err != nil {
return err
}

switch {
case report.IsJSON(diffOpts.Format):
return common.ChangesToJSON(results)
case diffOpts.Format == "":
return common.ChangesToTable(results)
default:
return errors.New("only supported value for '--format' is 'json'")
}
}

func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
diffOpts = &options
return diff(cmd, args)
func diffRun(cmd *cobra.Command, args []string) error {
diffOpts.Type = define.DiffImage
return diff.Diff(cmd, args, *diffOpts)
}
1 change: 0 additions & 1 deletion docs/source/markdown/links/podman-container-diff.1

This file was deleted.

54 changes: 54 additions & 0 deletions docs/source/markdown/podman-container-diff.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
% podman-container-diff(1)

## NAME
podman\-container\-diff - Inspect changes on a container's filesystem

## SYNOPSIS
**podman container diff** [*options*] *container* [*container*]

## DESCRIPTION
Displays changes on a container's filesystem. The container will be compared to its parent layer or the second argument when given.

The output is prefixed with the following symbols:

| Symbol | Description |
|--------|-------------|
| A | A file or directory was added. |
| D | A file or directory was deleted. |
| C | A file or directory was changed. |

## OPTIONS

#### **--format**

Alter the output into a different format. The only valid format for **podman container diff** is `json`.

#### **--latest**, **-l**

Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods. (This option is not available with the remote Podman client)

## EXAMPLE

```
# podman container diff container1
C /usr
C /usr/local
C /usr/local/bin
A /usr/local/bin/docker-entrypoint.sh
```

```
$ podman container diff --format json container1 container2
{
"added": [
"/test"
]
}
```

## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-container(1)](podman-container.1.md)**

## HISTORY
July 2021, Originally compiled by Paul Holzinger <[email protected]>
2 changes: 1 addition & 1 deletion docs/source/markdown/podman-container.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The container command allows you to manage containers
| commit | [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. |
| cp | [podman-cp(1)](podman-cp.1.md) | Copy files/folders between a container and the local filesystem. |
| create | [podman-create(1)](podman-create.1.md) | Create a new container. |
| diff | [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. |
| diff | [podman-container-diff(1)](podman-container-diff.1.md) | Inspect changes on a container's filesystem |
| exec | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. |
| exists | [podman-container-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage |
| export | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. |
Expand Down
Loading

0 comments on commit 895b815

Please sign in to comment.