Skip to content

Commit

Permalink
Reorganize the code under analyzer/.
Browse files Browse the repository at this point in the history
This moves some disparate parts out of scan.go into {compare,graph}.go.
  • Loading branch information
jcd authored and jessmcclintock committed Oct 9, 2023
1 parent 84a70d6 commit 900918a
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 169 deletions.
86 changes: 86 additions & 0 deletions analyzer/compare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2023 Google LLC
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

package analyzer

import (
"fmt"
"go/types"
"os"
"sort"

"github.com/google/capslock/interesting"
cpb "github.com/google/capslock/proto"
"golang.org/x/tools/go/packages"
"google.golang.org/protobuf/encoding/protojson"
)

func compare(baselineFilename string, pkgs []*packages.Package, queriedPackages map[*types.Package]struct{}, classifier *interesting.Classifier) error {
compareData, err := os.ReadFile(baselineFilename)
if err != nil {
return fmt.Errorf("Comparison file should include output from running `%s -output=j`. Error from reading comparison file: %v", programName(), err.Error())
}
baseline := new(cpb.CapabilityInfoList)
err = protojson.Unmarshal(compareData, baseline)
if err != nil {
return fmt.Errorf("Comparison file should include output from running `%s -output=j`. Error from parsing comparison file: %v", programName(), err.Error())
}
cil := GetCapabilityInfo(pkgs, queriedPackages, classifier)
diffCapabilityInfoLists(baseline, cil)
return nil
}

type capabilitySet map[cpb.Capability]*cpb.CapabilityInfo
type capabilitiesMap map[string]capabilitySet

// populateMap takes a CapabilityInfoList and returns a map from package
// directory and capability to a pointer to the corresponding entry in the
// input.
func populateMap(cil *cpb.CapabilityInfoList) capabilitiesMap {
m := make(capabilitiesMap)
for _, ci := range cil.GetCapabilityInfo() {
dir := ci.GetPackageDir()
capmap := m[dir]
if capmap == nil {
capmap = make(capabilitySet)
m[dir] = capmap
}
capmap[ci.GetCapability()] = ci
}
return m
}

func diffCapabilityInfoLists(baseline, current *cpb.CapabilityInfoList) {
baselineMap := populateMap(baseline)
currentMap := populateMap(current)
var packages []string
for packageName := range baselineMap {
packages = append(packages, packageName)
}
for packageName := range currentMap {
if _, ok := baselineMap[packageName]; !ok {
packages = append(packages, packageName)
}
}
sort.Strings(packages)
for _, packageName := range packages {
b := baselineMap[packageName]
c := currentMap[packageName]
for capability := range c {
if _, ok := b[capability]; !ok {
fmt.Printf("Package %s has new capability %s compared to the baseline.\n",
packageName, capability)
}
}
for capability := range b {
if _, ok := c[capability]; !ok {
fmt.Printf("Package %s no longer has capability %s which was in the baseline.\n",
packageName, capability)
}
}
}
os.Exit(0)
}
85 changes: 85 additions & 0 deletions analyzer/graph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2023 Google LLC
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

package analyzer

import (
"bufio"
"go/types"
"io"
"os"
"strconv"
"strings"

"github.com/google/capslock/interesting"
cpb "github.com/google/capslock/proto"
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/packages"
)

func graphOutput(pkgs []*packages.Package, queriedPackages map[*types.Package]struct{}, classifier *interesting.Classifier) error {
w := bufio.NewWriterSize(os.Stdout, 1<<20)
gb := newGraphBuilder(w, func(v interface{}) string {
switch v := v.(type) {
case *callgraph.Node:
if v.Func != nil {
return v.Func.String()
}
return strconv.Itoa(v.ID)
case cpb.Capability:
return v.String()
default:
panic("unexpected node type")
}
})
callEdge := func(caller, callee *callgraph.Node) {
gb.Edge(caller, callee)
}
capabilityEdge := func(fn *callgraph.Node, c cpb.Capability) {
gb.Edge(fn, c)
}
CapabilityGraph(pkgs, queriedPackages, classifier, callEdge, capabilityEdge)
gb.Done()
return w.Flush()
}

type graphBuilder struct {
io.Writer
nodeNamer func(any) string
started bool
done bool
}

func newGraphBuilder(w io.Writer, nodeNamer func(any) string) graphBuilder {
return graphBuilder{
Writer: w,
nodeNamer: nodeNamer,
}
}

func (gb *graphBuilder) Edge(from, to interface{}) {
if gb.done {
panic("done")
}
if !gb.started {
gb.Write([]byte("digraph {\n"))
gb.started = true
}
gb.Write([]byte("\t"))
gb.Write([]byte(`"`))
gb.Write([]byte(strings.ReplaceAll(gb.nodeNamer(from), `"`, `\"`)))
gb.Write([]byte(`" -> "`))
gb.Write([]byte(strings.ReplaceAll(gb.nodeNamer(to), `"`, `\"`)))
gb.Write([]byte("\"\n"))
}

func (gb *graphBuilder) Done() {
if gb.done {
panic("done")
}
gb.Write([]byte("}\n"))
gb.done = true
}
Loading

0 comments on commit 900918a

Please sign in to comment.