Example #1
0
// ParseSpec parses the given specification and returns an opened handle to an
// API Interface.  The following formats are currently supported:
//   - http:// URL pointed at a JSON web API
//   - https:// URL pointed at a JSON web API
//   - host:port pointed at a GRPC API
//   - local path to a LevelDB serving table
func ParseSpec(apiSpec string) (Interface, error) {
	api := &apiCloser{}
	if strings.HasPrefix(apiSpec, "http://") || strings.HasPrefix(apiSpec, "https://") {
		api.xs = xrefs.WebClient(apiSpec)
		api.ft = filetree.WebClient(apiSpec)
		api.idx = search.WebClient(apiSpec)
	} else if _, err := os.Stat(apiSpec); err == nil {
		db, err := leveldb.Open(apiSpec, nil)
		if err != nil {
			return nil, fmt.Errorf("error opening local DB at %q: %v", apiSpec, err)
		}
		api.closer = func() error { return db.Close() }

		tbl := table.ProtoBatchParallel{&table.KVProto{db}}
		api.xs = xsrv.NewCombinedTable(tbl)
		api.ft = &ftsrv.Table{tbl}
		api.idx = &srchsrv.Table{&table.KVInverted{db}}
	} else {
		conn, err := grpc.Dial(apiSpec)
		if err != nil {
			return nil, fmt.Errorf("error connecting to remote API %q: %v", apiSpec, err)
		}
		api.closer = func() error { conn.Close(); return nil }

		api.xs = xrefs.GRPC(xpb.NewXRefServiceClient(conn))
		api.ft = filetree.GRPC(ftpb.NewFileTreeServiceClient(conn))
		api.idx = search.GRPC(spb.NewSearchServiceClient(conn))
	}
	return api, nil
}
Example #2
0
func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(0)
	} else if *servingTable == "" && *remoteAPI == "" {
		log.Fatal("One of --serving_table or --api is required")
	}

	if *servingTable == "" {
		if strings.HasPrefix(*remoteAPI, "http://") || strings.HasPrefix(*remoteAPI, "https://") {
			xs = xrefs.WebClient(*remoteAPI)
			ft = filetree.WebClient(*remoteAPI)
			idx = search.WebClient(*remoteAPI)
		} else {
			conn, err := grpc.Dial(*remoteAPI)
			if err != nil {
				log.Fatalf("Error connecting to remote API %q: %v", *remoteAPI, err)
			}
			defer conn.Close()
			xs = xrefs.GRPC(xpb.NewXRefServiceClient(conn))
			ft = filetree.GRPC(ftpb.NewFileTreeServiceClient(conn))
			idx = search.GRPC(spb.NewSearchServiceClient(conn))
		}
	} else {
		db, err := leveldb.Open(*servingTable, nil)
		if err != nil {
			log.Fatalf("Error opening db at %q: %v", *servingTable, err)
		}
		defer db.Close()

		tbl := &table.KVProto{db}
		xs = &xsrv.Table{tbl}
		ft = &ftsrv.Table{tbl}
		idx = &srchsrv.Table{&table.KVInverted{db}}
	}

	if err := getCommand(flag.Arg(0)).run(); err != nil {
		log.Fatal("ERROR: ", err)
	}
}
Example #3
0
func main() {
	flag.Parse()
	if *offset < 0 {
		flagutil.UsageError("non-negative --offset required")
	} else if *signature == "" && *path == "" {
		flagutil.UsageError("must provide at least --path or --signature")
	}

	if strings.HasPrefix(*remoteAPI, "http://") || strings.HasPrefix(*remoteAPI, "https://") {
		xs = xrefs.WebClient(*remoteAPI)
		idx = search.WebClient(*remoteAPI)
	} else {
		conn, err := grpc.Dial(*remoteAPI)
		if err != nil {
			log.Fatalf("Error connecting to remote API %q: %v", *remoteAPI, err)
		}
		defer conn.Close()
		xs = xrefs.GRPC(xpb.NewXRefServiceClient(conn))
		idx = search.GRPC(spb.NewSearchServiceClient(conn))
	}

	relPath := *path
	if !*ignoreLocalRepo {
		if _, err := os.Stat(relPath); err == nil {
			absPath, err := filepath.Abs(relPath)
			if err != nil {
				log.Fatal(err)
			}
			kytheRoot := findKytheRoot(filepath.Dir(absPath))
			if kytheRoot != "" {
				relPath, err = filepath.Rel(filepath.Join(kytheRoot, *root), absPath)
				if err != nil {
					log.Fatal(err)
				}
			}
		}
	}
	partialFile := &spb.VName{
		Signature: *signature,
		Corpus:    *corpus,
		Root:      *root,
		Path:      relPath,
		Language:  *language,
	}
	reply, err := idx.Search(ctx, &spb.SearchRequest{
		Partial: partialFile,
		Fact:    fileFacts,
	})
	if err != nil {
		log.Fatalf("Error locating file {%v}: %v", partialFile, err)
	}
	if len(reply.Ticket) == 0 {
		log.Fatalf("Could not locate file {%v}", partialFile)
	} else if len(reply.Ticket) > 1 {
		log.Fatalf("Ambiguous file {%v}; multiple results: %v", partialFile, reply.Ticket)
	}

	fileTicket := reply.Ticket[0]
	decor, err := xs.Decorations(ctx, &xpb.DecorationsRequest{
		// TODO(schroederc): limit Location to a SPAN around *offset
		Location:    &xpb.Location{Ticket: fileTicket},
		References:  true,
		SourceText:  true,
		DirtyBuffer: readDirtyBuffer(ctx),
	})
	if err != nil {
		log.Fatal(err)
	}
	nodes := xrefs.NodesMap(decor.Node)

	en := json.NewEncoder(os.Stdout)
	for _, ref := range decor.Reference {
		start, end := parseAnchorSpan(nodes[ref.SourceTicket])

		if start <= *offset && *offset < end {
			var r reference
			r.Span.Start = start
			r.Span.End = end
			r.Span.Text = string(decor.SourceText[start:end])
			r.Kind = strings.TrimPrefix(ref.Kind, schema.EdgePrefix)
			r.Node.Ticket = ref.TargetTicket

			node := nodes[ref.TargetTicket]
			r.Node.Kind = string(node[schema.NodeKindFact])
			r.Node.Subkind = string(node[schema.SubkindFact])

			if eReply, err := xs.Edges(ctx, &xpb.EdgesRequest{
				Ticket: []string{ref.TargetTicket},
				Kind:   []string{schema.NamedEdge, definedAtEdge},
			}); err != nil {
				log.Printf("WARNING: error getting edges for %q: %v", ref.TargetTicket, err)
			} else {
				edges := xrefs.EdgesMap(eReply.EdgeSet)[ref.TargetTicket]
				for _, name := range edges[schema.NamedEdge] {
					if uri, err := kytheuri.Parse(name); err != nil {
						log.Printf("WARNING: named node ticket (%q) could not be parsed: %v", name, err)
					} else {
						r.Node.Names = append(r.Node.Names, uri.Signature)
					}
				}

				if !*skipDefinitions {
					for _, defAnchor := range edges[definedAtEdge] {
						def, err := completeDefinition(defAnchor)
						if err != nil {
							log.Printf("WARNING: failed to complete definition for %q: %v", defAnchor, err)
						} else {
							r.Node.Definitions = append(r.Node.Definitions, def)
						}
					}
				}
			}

			if err := en.Encode(r); err != nil {
				log.Fatal(err)
			}
		}
	}
}
Example #4
0
File: ktags.go Project: jwatt/kythe
func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		flagutil.UsageError("not given any files")
	}

	xs := xrefs.WebClient(*remoteAPI)
	idx := search.WebClient(*remoteAPI)

	for _, file := range flag.Args() {
		results, err := idx.Search(ctx, &spb.SearchRequest{
			Partial: &spb.VName{Path: file},
			Fact: []*spb.SearchRequest_Fact{{
				Name:  schema.NodeKindFact,
				Value: []byte(schema.FileKind),
			}},
		})
		if err != nil {
			log.Fatalf("Error searching for ticket of file %q", file)
		} else if len(results.Ticket) == 0 {
			log.Printf("Could not find ticket for file %q", file)
			continue
		} else if len(results.Ticket) != 1 {
			log.Printf("Multiple tickets found for file %q; choosing first from %v", file, results.Ticket)
		}

		ticket := results.Ticket[0]
		decor, err := xs.Decorations(ctx, &xpb.DecorationsRequest{
			Location:   &xpb.Location{Ticket: ticket},
			SourceText: true,
			References: true,
		})
		if err != nil {
			log.Fatalf("Failed to get decorations for file %q", file)
		}

		nodes := xrefs.NodesMap(decor.Node)
		emitted := stringset.New()

		for _, r := range decor.Reference {
			if r.Kind != schema.DefinesBindingEdge || emitted.Contains(r.TargetTicket) {
				continue
			}

			ident := string(nodes[r.TargetTicket][identifierFact])
			if ident == "" {
				continue
			}

			offset, err := strconv.Atoi(string(nodes[r.SourceTicket][schema.AnchorStartFact]))
			if err != nil {
				log.Printf("Invalid start offset for anchor %q", r.SourceTicket)
				continue
			}

			fields, err := getTagFields(xs, r.TargetTicket)
			if err != nil {
				log.Printf("Failed to get tagfields for %q: %v", r.TargetTicket, err)
			}

			fmt.Printf("%s\t%s\t%d;\"\t%s\n",
				ident, file, offsetLine(decor.SourceText, offset), strings.Join(fields, "\t"))
			emitted.Add(r.TargetTicket)
		}
	}
}