// EnsureReverseEdges checks if gs contains reverse edges. If it doesn't, it // will scan gs for all forward edges, adding a reverse for each back into the // GraphStore. This is necessary for a GraphStoreService to work properly. func EnsureReverseEdges(ctx context.Context, gs graphstore.Service) error { var edge *spb.Entry if err := gs.Scan(ctx, &spb.ScanRequest{}, func(e *spb.Entry) error { if graphstore.IsEdge(e) { edge = e return io.EOF } return nil }); err != nil { return err } if edge == nil { log.Println("No edges found in GraphStore") return nil } else if edges.IsReverse(edge.EdgeKind) { return nil } var foundReverse bool if err := gs.Read(ctx, &spb.ReadRequest{ Source: edge.Target, EdgeKind: edges.Mirror(edge.EdgeKind), }, func(entry *spb.Entry) error { foundReverse = true return nil }); err != nil { return fmt.Errorf("error checking for reverse edge: %v", err) } if foundReverse { return nil } return addReverseEdges(ctx, gs) }
// expandEdgeKind prefixes unrooted (not starting with "/") edge kinds with the // standard Kythe edge prefix ("/kythe/edge/"). func expandEdgeKind(kind string) string { ck := edges.Canonical(kind) if strings.HasPrefix(ck, "/") { return kind } expansion := edges.Prefix + ck if edges.IsReverse(kind) { return edges.Mirror(expansion) } return expansion }
func main() { flag.Parse() if len(flag.Args()) > 2 || (gs != nil && len(flag.Args()) > 1) { fmt.Fprintf(os.Stderr, "ERROR: too many arguments %v\n", flag.Args()) flag.Usage() os.Exit(1) } if gs != nil { defer gsutil.LogClose(context.Background(), gs) } var in io.ReadCloser = os.Stdin if gs == nil && len(flag.Args()) > 0 { file, err := vfs.Open(context.Background(), flag.Arg(0)) if err != nil { log.Fatalf("Failed to open input file %q: %v", flag.Arg(0), err) } defer file.Close() in = file } outIdx := 1 if gs != nil { outIdx = 0 } var out io.WriteCloser = os.Stdout if len(flag.Args()) > outIdx { file, err := vfs.Create(context.Background(), flag.Arg(outIdx)) if err != nil { log.Fatalf("Failed to create output file %q: %v", flag.Arg(outIdx), err) } defer file.Close() out = file } var ( entries <-chan *spb.Entry reverseEdges int triples int ) if gs == nil { entries = stream.ReadEntries(in) } else { ch := make(chan *spb.Entry) entries = ch go func() { defer close(ch) if err := gs.Scan(context.Background(), &spb.ScanRequest{}, func(e *spb.Entry) error { ch <- e return nil }); err != nil { log.Fatalf("Error scanning graphstore: %v", err) } }() } for entry := range entries { if edges.IsReverse(entry.EdgeKind) && !*keepReverseEdges { reverseEdges++ continue } t, err := toTriple(entry) if err != nil { log.Fatal(err) } fmt.Fprintln(out, t) triples++ } if !*quiet { if !*keepReverseEdges { log.Printf("Skipped %d reverse edges", reverseEdges) } log.Printf("Wrote %d triples", triples) } }
func displayEdgeGraph(reply *gpb.EdgesReply) error { nodes := xrefs.NodesMap(reply.Nodes) esets := make(map[string]map[string]stringset.Set) for source, es := range reply.EdgeSets { for gKind, g := range es.Groups { for _, edge := range g.Edge { tgt := edge.TargetTicket src, kind := source, gKind if edges.IsReverse(kind) { src, kind, tgt = tgt, edges.Mirror(kind), src } groups, ok := esets[src] if !ok { groups = make(map[string]stringset.Set) esets[src] = groups } targets, ok := groups[kind] if ok { targets.Add(tgt) } else { groups[kind] = stringset.New(tgt) } } } } if _, err := fmt.Println("digraph kythe {"); err != nil { return err } for ticket, node := range nodes { if _, err := fmt.Printf(` %q [label=<<table><tr><td colspan="2">%s</td></tr>`, ticket, html.EscapeString(ticket)); err != nil { return err } var facts []string for fact := range node { facts = append(facts, fact) } sort.Strings(facts) for _, fact := range facts { if _, err := fmt.Printf("<tr><td>%s</td><td>%s</td></tr>", html.EscapeString(fact), html.EscapeString(string(node[fact]))); err != nil { return err } } if _, err := fmt.Println("</table>> shape=plaintext];"); err != nil { return err } } if _, err := fmt.Println(); err != nil { return err } for src, groups := range esets { for kind, targets := range groups { for tgt := range targets { if _, err := fmt.Printf("\t%q -> %q [label=%q];\n", src, tgt, kind); err != nil { return err } } } } if _, err := fmt.Println("}"); err != nil { return err } return nil }