| package packagediff |
| |
| import ( |
| "fmt" |
| |
| "cos.googlesource.com/cos/tools.git/src/cmd/cos_image_analyzer/internal/input" |
| ) |
| |
| // PkgDiff is used to hold package difference between the two images |
| type PkgDiff struct { |
| category []string |
| name []string |
| version []string |
| revision []string |
| typeOFDiff string // "image1" or "image2" if package is unique to image1 or image2, "shared" if package is shared in both images |
| } |
| |
| // Differences is an intermediate struct used to store package lists and differences |
| type Differences struct { |
| PackageDiff []PkgDiff // If two images are passed in, this is a slice of all package differences |
| PackageList []Package // If only one image is passed in, return full package list |
| } |
| |
| // searchPackageList determines whether a package name appears in a package list |
| func searchPackageList(packageName string, packageList []Package) (Package, bool) { |
| for _, p := range packageList { |
| if p.Name == packageName { |
| return p, true |
| } |
| } |
| return Package{}, false |
| } |
| |
| // packageListDiff calculates the package list difference the two images |
| // Input: |
| // ([]Package) packagesImage1 - Image1's package list |
| // ([]Package) packagesImage2 - Image2's package list |
| // (*FlagInfo) flagInfo - A struct that holds input preference from the user |
| // Output: nil on success, else err |
| func (d *Differences) packageListDiff(packagesImage1, packagesImage2 []Package, flagInfo *input.FlagInfo) error { |
| if flagInfo.Image2 != "" { |
| for _, p1 := range packagesImage1 { |
| pkdDiff := PkgDiff{} |
| p2, ok := searchPackageList(p1.Name, packagesImage2) |
| if !ok { // Unique package to image 1 |
| pkdDiff.typeOFDiff = "image1" |
| pkdDiff.name = []string{p1.Name} |
| pkdDiff.category = []string{p1.Category} |
| pkdDiff.version = []string{p1.Version} |
| pkdDiff.revision = []string{p1.Revision} |
| d.PackageDiff = append(d.PackageDiff, pkdDiff) |
| } else { // Shared package to image1 and image2 |
| if p1.Category != p2.Category { |
| pkdDiff.category = []string{p1.Category, p2.Category} |
| } |
| if p1.Version != p2.Version { |
| pkdDiff.version = []string{p1.Version, p2.Version} |
| } |
| if p1.Revision != p2.Revision { |
| pkdDiff.revision = []string{p1.Revision, p2.Revision} |
| } |
| if len(pkdDiff.category) == 2 || len(pkdDiff.version) == 2 || len(pkdDiff.revision) == 2 { |
| pkdDiff.typeOFDiff = "shared" |
| pkdDiff.name = []string{p1.Name, p2.Name} |
| d.PackageDiff = append(d.PackageDiff, pkdDiff) |
| } |
| } |
| } |
| |
| for _, p2 := range packagesImage2 { |
| pkdDiff := PkgDiff{} |
| if _, ok := searchPackageList(p2.Name, packagesImage1); !ok { // Unique package to image2 |
| pkdDiff.typeOFDiff = "image2" |
| pkdDiff.category = []string{p2.Category} |
| pkdDiff.name = []string{p2.Name} |
| pkdDiff.version = []string{p2.Version} |
| pkdDiff.revision = []string{p2.Revision} |
| d.PackageDiff = append(d.PackageDiff, pkdDiff) |
| } |
| } |
| } else { |
| d.PackageList = packagesImage1 |
| } |
| return nil |
| } |
| |
| // FormatPackageListDiff returns a formated string of the package list difference |
| // (string) image1 - Temp directory name of image1 |
| // (string) image2 - Temp directory name of image2 |
| func (d *Differences) FormatPackageListDiff(image1, image2 string) string { |
| if len(d.PackageList) > 0 { // One image is passed in, return full package list |
| pkgList := "" |
| for _, p := range d.PackageList { |
| pkgStr := "Package " + p.Name + "\n" + "category: " + p.Category + "\n" + "version: " + p.Version + "\n" + "revision: " + p.Revision + "\n\n" |
| pkgList += pkgStr |
| } |
| return pkgList |
| } else if len(d.PackageDiff) > 0 { // Two images are passed in, compare based on Differences |
| pkgDiff := "" |
| for _, pd := range d.PackageDiff { |
| pkgStr := "" |
| if pd.typeOFDiff == "shared" { // Compare shared packages |
| if len(pd.category) == 2 { |
| pkgStr += "category:\n" + "< " + pd.category[0] + "\n" + "> " + pd.category[1] + "\n" |
| } |
| if len(pd.version) == 2 { |
| pkgStr += "version:\n" + "< " + pd.version[0] + "\n" + "> " + pd.version[1] + "\n" |
| } |
| if len(pd.revision) == 2 { |
| pkgStr += "revision:\n" + "< " + pd.revision[0] + "\n" + "> " + pd.revision[1] + "\n" |
| } |
| if pkgStr != "" && len(pd.name) == 2 { |
| pkgStr = "Package " + pd.name[0] + " in " + image1 + " and " + image2 + " differ\n" + pkgStr + "\n" |
| pkgDiff += pkgStr |
| } |
| } else { // Unique package, return all info |
| if len(pd.name) == 1 && len(pd.category) == 1 && len(pd.version) == 1 && len(pd.revision) == 1 { |
| if pd.typeOFDiff == "image1" { |
| pkgStr += "Only in " + image1 |
| } else if pd.typeOFDiff == "image2" { |
| pkgStr += "Only in " + image2 |
| } |
| pkgStr += ": " + pd.name[0] + "\ncategory: " + pd.category[0] + "\nversion: " + pd.version[0] + "\nrevision: " + pd.revision[0] + "\n\n" |
| pkgDiff += pkgStr |
| } |
| } |
| } |
| return pkgDiff |
| } |
| return "" |
| } |
| |
| // Diff is a tool that finds all package differences of two COS images |
| // (Category, Name, Version, Revision) |
| // Input: |
| // (*ImageInfo) image1 - A struct that will store package info for image1 |
| // (*ImageInfo) image2 - A struct that will store package info for image2 |
| // (*FlagInfo) flagInfo - A struct that holds input preference from the user |
| // Output: |
| // (*Differences) packageDiff - A struct that will store the package differences |
| func Diff(packagesImage1, packagesImage2 []Package, flagInfo *input.FlagInfo) (*Differences, error) { |
| packageDiff := &Differences{} |
| |
| if flagInfo.PackageSelected { |
| if err := packageDiff.packageListDiff(packagesImage1, packagesImage2, flagInfo); err != nil { |
| return packageDiff, fmt.Errorf("failed to take package list difference: %v", err) |
| } |
| } |
| return packageDiff, nil |
| } |