diff --git a/README.rst b/README.rst index 374d3483..03a44fc1 100644 --- a/README.rst +++ b/README.rst @@ -412,6 +412,33 @@ Example:: Snapshot snap-deb-main-w-xorg successfully created. You can run 'aptly publish snapshot snap-deb-main-w-xorg' to publish snapshot as Debian repository. +``aptly snapshot diff`` +^^^^^^^^^^^^^^^^^^^^^^^ + +Displays difference in packages between two snapshots. Snapshot is a list of packages, so difference between +snapshots is a difference between package lists. Package could be either completely missing in one snapshot, +or package is present in both snapshots with different versions. + +Usage:: + + aptly snapshot diff + +Options: + +* ``-only-matching=false``: display diff only for matching packages (don't display missing packages) + +Example:: + + $ aptly snapshot diff snap-deb2-main snap-deb-main-w-xorg + Arch | Package | Version in A | Version in B + ! amd64 | libxfont1 | 1:1.4.1-3 | 1:1.4.4-1~bpo60+1 + ! i386 | libxfont1 | 1:1.4.1-3 | 1:1.4.4-1~bpo60+1 + ! all | xserver-common | 2:1.7.7-16 | 2:1.10.4-1~bpo60+2 + ! amd64 | xserver-xorg | 1:7.5+8+squeeze1 | 1:7.6+8~bpo60+1 + ! i386 | xserver-xorg | 1:7.5+8+squeeze1 | 1:7.6+8~bpo60+1 + ! amd64 | xserver-xorg-core | 2:1.7.7-16 | 2:1.10.4-1~bpo60+2 + ! i386 | xserver-xorg-core | 2:1.7.7-16 | 2:1.10.4-1~bpo60+2 + Command ``publish`` ~~~~~~~~~~~~~~~~~~~ diff --git a/cmd_snapshot.go b/cmd_snapshot.go index 62bafd07..fd6862f0 100644 --- a/cmd_snapshot.go +++ b/cmd_snapshot.go @@ -343,6 +343,90 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error { return err } +func aptlySnapshotDiff(cmd *commander.Command, args []string) error { + var err error + if len(args) != 2 { + cmd.Usage() + return err + } + + onlyMatching := cmd.Flag.Lookup("only-matching").Value.Get().(bool) + + snapshotCollection := debian.NewSnapshotCollection(context.database) + packageCollection := debian.NewPackageCollection(context.database) + + // Load snapshot + snapshotA, err := snapshotCollection.ByName(args[0]) + if err != nil { + return fmt.Errorf("unable to load snapshot A: %s", err) + } + + err = snapshotCollection.LoadComplete(snapshotA) + if err != nil { + return fmt.Errorf("unable to load snapshot A: %s", err) + } + + // Load snapshot + snapshotB, err := snapshotCollection.ByName(args[1]) + if err != nil { + return fmt.Errorf("unable to load snapshot B: %s", err) + } + + err = snapshotCollection.LoadComplete(snapshotB) + if err != nil { + return fmt.Errorf("unable to load snapshot B: %s", err) + } + + // Calculate diff + diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), packageCollection) + if err != nil { + return fmt.Errorf("unable to calculate diff: %s", err) + } + + if len(diff) == 0 { + fmt.Printf("Snapshots are identical.\n") + } else { + fmt.Printf(" Arch | Package | Version in A | Version in B\n") + for _, pdiff := range diff { + if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) { + continue + } + + var verA, verB, pkg, arch, code string + + if pdiff.Left == nil { + verA = "-" + verB = pdiff.Right.Version + pkg = pdiff.Right.Name + arch = pdiff.Right.Architecture + } else { + pkg = pdiff.Left.Name + arch = pdiff.Left.Architecture + verA = pdiff.Left.Version + if pdiff.Right == nil { + verB = "-" + } else { + verB = pdiff.Right.Version + } + } + + if pdiff.Left == nil { + code = "@g+@|" + } else { + if pdiff.Right == nil { + code = "@r-@|" + } else { + code = "@y!@|" + } + } + + color.Printf(code+" %-6s | %-40s | %-40s | %-40s\n", arch, pkg, verA, verB) + } + } + + return err +} + func makeCmdSnapshotCreate() *commander.Command { cmd := &commander.Command{ Run: aptlySnapshotCreate, @@ -424,6 +508,22 @@ process. return cmd } +func makeCmdSnapshotDiff() *commander.Command { + cmd := &commander.Command{ + Run: aptlySnapshotDiff, + UsageLine: "diff ", + Short: "calculates difference in packages between two snapshots", + Long: ` +Displays list of missing and new packages, difference in package versions between two snapshots. +`, + Flag: *flag.NewFlagSet("aptly-snapshot-diff", flag.ExitOnError), + } + + cmd.Flag.Bool("only-matching", false, "display diff only for matching packages (don't display missing packages)") + + return cmd +} + func makeCmdSnapshot() *commander.Command { return &commander.Command{ UsageLine: "snapshot", @@ -434,6 +534,7 @@ func makeCmdSnapshot() *commander.Command { makeCmdSnapshotShow(), makeCmdSnapshotVerify(), makeCmdSnapshotPull(), + makeCmdSnapshotDiff(), //makeCmdSnapshotDestroy(), }, Flag: *flag.NewFlagSet("aptly-snapshot", flag.ExitOnError),