dev/depgraph: add summary -deps.sum -deps.only for detecting binary changes (#35379)

This commit is contained in:
Robert Lin 2022-05-19 15:46:10 -07:00 committed by GitHub
parent c348526e42
commit b05bc39e3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 49 deletions

View File

@ -1,12 +1,7 @@
package graph
import (
"os"
"path/filepath"
"sort"
"strings"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
// DependencyGraph encodes the import relationships between packages within
@ -27,12 +22,7 @@ type DependencyGraph struct {
// Load returns a dependency graph constructed by walking the source tree of the
// sg/sg repository and parsing the imports out of all file with a .go extension.
func Load() (*DependencyGraph, error) {
root, err := findRoot()
if err != nil {
return nil, err
}
func Load(root string) (*DependencyGraph, error) {
packageMap, err := listPackages(root)
if err != nil {
return nil, err
@ -72,36 +62,6 @@ func Load() (*DependencyGraph, error) {
}, nil
}
// findRoot finds root path of the sourcegraph/sourcegraph repository from
// the current working directory. Is it an error to run this binary outside
// of the repository.
func findRoot() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
for {
contents, err := os.ReadFile(filepath.Join(wd, "go.mod"))
if err == nil {
for _, line := range strings.Split(string(contents), "\n") {
if line == "module github.com/sourcegraph/sourcegraph" {
return wd, nil
}
}
} else if !os.IsNotExist(err) {
return "", err
}
if parent := filepath.Dir(wd); parent != wd {
wd = parent
continue
}
return "", errors.Errorf("not running inside sourcegraph/sourcegraph")
}
}
// reverseGraph returns the given graph with all edges reversed.
func reverseGraph(graph map[string][]string) map[string][]string {
reverseGraph := make(map[string][]string, len(graph))

View File

@ -24,7 +24,12 @@ func lint(ctx context.Context, args []string) error {
args = lints.DefaultLints
}
graph, err := graph.Load()
root, err := findRoot()
if err != nil {
return err
}
graph, err := graph.Load(root)
if err != nil {
return err
}

39
dev/depgraph/root.go Normal file
View File

@ -0,0 +1,39 @@
package main
import (
"os"
"path/filepath"
"strings"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
// findRoot finds root path of the sourcegraph/sourcegraph repository from
// the current working directory. Is it an error to run this binary outside
// of the repository.
func findRoot() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
for {
contents, err := os.ReadFile(filepath.Join(wd, "go.mod"))
if err == nil {
for _, line := range strings.Split(string(contents), "\n") {
if line == "module github.com/sourcegraph/sourcegraph" {
return wd, nil
}
}
} else if !os.IsNotExist(err) {
return "", err
}
if parent := filepath.Dir(wd); parent != wd {
wd = parent
continue
}
return "", errors.Errorf("not running inside sourcegraph/sourcegraph")
}
}

View File

@ -5,19 +5,26 @@ import (
"flag"
"fmt"
"sort"
"strings"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/sourcegraph/run"
"github.com/sourcegraph/sourcegraph/dev/depgraph/internal/graph"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
var summaryFlagSet = flag.NewFlagSet("depgraph summary", flag.ExitOnError)
var (
summaryFlagSet = flag.NewFlagSet("depgraph summary", flag.ExitOnError)
summaryDepsSum = summaryFlagSet.Bool("deps.sum", false, "generate md5sum of each dependency")
summaryDepsOnly = summaryFlagSet.Bool("deps.only", false, "only display dependencies")
)
var summaryCommand = &ffcli.Command{
Name: "summary",
ShortUsage: "depgraph summary {package}",
ShortHelp: "Outputs a DOT-formatted graph of the given package dependency and dependents",
ShortHelp: "Outputs a text summary of the given package dependency and dependents",
FlagSet: summaryFlagSet,
Exec: summary,
}
@ -28,11 +35,19 @@ func summary(ctx context.Context, args []string) error {
}
pkg := args[0]
graph, err := graph.Load()
root, err := findRoot()
if err != nil {
return err
}
graph, err := graph.Load(root)
if err != nil {
return err
}
if _, ok := graph.PackageNames[pkg]; !ok {
return errors.Newf("pkg %q not found", pkg)
}
dependencyMap := summaryTraverse(pkg, graph.Dependencies)
dependencies := make([]string, 0, len(dependencyMap))
for dependency := range dependencyMap {
@ -47,11 +62,15 @@ func summary(ctx context.Context, args []string) error {
}
sort.Strings(dependents)
fmt.Printf("Target package:\n")
printPkg(ctx, root, pkg)
fmt.Printf("\n")
fmt.Printf("Direct dependencies:\n")
for _, dependency := range dependencies {
if dependencyMap[dependency] {
fmt.Printf("\t> %s\n", dependency)
printPkg(ctx, root, dependency)
}
}
@ -60,10 +79,14 @@ func summary(ctx context.Context, args []string) error {
for _, dependency := range dependencies {
if !dependencyMap[dependency] {
fmt.Printf("\t> %s\n", dependency)
printPkg(ctx, root, dependency)
}
}
if *summaryDepsOnly {
return nil
}
fmt.Printf("\n")
fmt.Printf("Dependent commands:\n")
@ -132,3 +155,21 @@ func isMain(graph *graph.DependencyGraph, pkg string) bool {
return false
}
func printPkg(ctx context.Context, root string, pkg string) error {
fmt.Printf("\t> %s", pkg)
if *summaryDepsSum {
dir := "./" + pkg
lines, err := run.Bash(ctx, "tar c", dir, "| md5sum").
Dir(root).
Run().
Lines()
if err != nil {
return err
}
sum := strings.Split(lines[0], " ")[0]
fmt.Printf("\t%s", sum)
}
fmt.Println()
return nil
}

View File

@ -31,11 +31,19 @@ func trace(ctx context.Context, args []string) error {
}
pkg := args[0]
graph, err := graph.Load()
root, err := findRoot()
if err != nil {
return err
}
graph, err := graph.Load(root)
if err != nil {
return err
}
if _, ok := graph.PackageNames[pkg]; !ok {
return errors.Newf("pkg %q not found", pkg)
}
packages, dependencyEdges, dependentEdges := traceWalkGraph(graph, pkg, *dependencyMaxDepthFlag, *dependentMaxDepthFlag)
fmt.Printf("%s\n", visualization.Dotify(packages, dependencyEdges, dependentEdges))
return nil

View File

@ -29,11 +29,19 @@ func traceInternal(ctx context.Context, args []string) error {
}
pkg := args[0]
graph, err := graph.Load()
root, err := findRoot()
if err != nil {
return err
}
graph, err := graph.Load(root)
if err != nil {
return err
}
if _, ok := graph.PackageNames[pkg]; !ok {
return errors.Newf("pkg %q not found", pkg)
}
packages, dependencyEdges := filterExternalReferences(graph, pkg)
fmt.Printf("%s\n", visualization.Dotify(packages, dependencyEdges, nil))
return nil