github.com/google/capslock@v0.2.3-0.20240517042941-dac19fc347c0/analyzer/compare.go (about) 1 // Copyright 2023 Google LLC 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file or at 5 // https://developers.google.com/open-source/licenses/bsd 6 7 package analyzer 8 9 import ( 10 "fmt" 11 "go/types" 12 "os" 13 "sort" 14 15 cpb "github.com/google/capslock/proto" 16 "golang.org/x/tools/go/packages" 17 "google.golang.org/protobuf/encoding/protojson" 18 ) 19 20 func compare(baselineFilename string, pkgs []*packages.Package, queriedPackages map[*types.Package]struct{}, config *Config) error { 21 compareData, err := os.ReadFile(baselineFilename) 22 if err != nil { 23 return fmt.Errorf("Comparison file should include output from running `%s -output=j`. Error from reading comparison file: %v", programName(), err.Error()) 24 } 25 baseline := new(cpb.CapabilityInfoList) 26 err = protojson.Unmarshal(compareData, baseline) 27 if err != nil { 28 return fmt.Errorf("Comparison file should include output from running `%s -output=j`. Error from parsing comparison file: %v", programName(), err.Error()) 29 } 30 cil := GetCapabilityInfo(pkgs, queriedPackages, config) 31 diffCapabilityInfoLists(baseline, cil) 32 return nil 33 } 34 35 type capabilitySet map[cpb.Capability]*cpb.CapabilityInfo 36 type capabilitiesMap map[string]capabilitySet 37 38 // populateMap takes a CapabilityInfoList and returns a map from package 39 // directory and capability to a pointer to the corresponding entry in the 40 // input. 41 func populateMap(cil *cpb.CapabilityInfoList) capabilitiesMap { 42 m := make(capabilitiesMap) 43 for _, ci := range cil.GetCapabilityInfo() { 44 dir := ci.GetPackageDir() 45 capmap := m[dir] 46 if capmap == nil { 47 capmap = make(capabilitySet) 48 m[dir] = capmap 49 } 50 capmap[ci.GetCapability()] = ci 51 } 52 return m 53 } 54 55 func diffCapabilityInfoLists(baseline, current *cpb.CapabilityInfoList) { 56 baselineMap := populateMap(baseline) 57 currentMap := populateMap(current) 58 var packages []string 59 for packageName := range baselineMap { 60 packages = append(packages, packageName) 61 } 62 for packageName := range currentMap { 63 if _, ok := baselineMap[packageName]; !ok { 64 packages = append(packages, packageName) 65 } 66 } 67 sort.Strings(packages) 68 var differenceFound bool 69 for _, packageName := range packages { 70 b := baselineMap[packageName] 71 c := currentMap[packageName] 72 for capability := range c { 73 if _, ok := b[capability]; !ok { 74 differenceFound = true 75 fmt.Printf("Package %s has new capability %s compared to the baseline.\n", 76 packageName, capability) 77 } 78 } 79 for capability := range b { 80 if _, ok := c[capability]; !ok { 81 differenceFound = true 82 fmt.Printf("Package %s no longer has capability %s which was in the baseline.\n", 83 packageName, capability) 84 } 85 } 86 } 87 if differenceFound { 88 os.Exit(1) 89 } 90 os.Exit(0) 91 }