-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reorganize the code under analyzer/.
This moves some disparate parts out of scan.go into {compare,graph}.go.
- Loading branch information
1 parent
84a70d6
commit 900918a
Showing
4 changed files
with
208 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.