blob: 8ca74654dbf0631a2bd66a5ddc904c74a7db409c [file] [log] [blame]
// Copyright 2015 The Kythe Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Kythe's Command-line Tool
=========================
:Author: Cody Schroeder
Every good interface deserves a good command-line tool.
NOTE: This post has been edited 2015/05/19 to reflect changes in the way to build Kythe.
Along with the sample web UI, Kythe also provides a basic command-line tool for
the xrefs, filetree, and search interfaces. The Kythe tool can use serving
tables directly or communicate with a remote API service. By default, it talks
to the API at https://xrefs-dot-kythe-repo.appspot.com/ which serves a
recent index of Kythe's own sources. (The serving data for the sample web UI is
currently updated manually which can lead to stale data over time.)
All of the information surfaced by the sample web UI, and *more*, can be
retrieved with the Kythe command-line tool. It's simply a wrapper around the
protobuf service APIs that exist in
https://kythe.io/repo/kythe/go/services/[kythe/go/services] with some extra
usability features.
So, what _exactly_ can the tool do? Let's build it and then check its `help`
command.
[source,shell]
----
$ bazel build //kythe/go/serving/tools:kythe
$ alias kythe="$PWD/bazel-bin/kythe/go/serving/tools/kythe"
$ kythe help --short
----
.Output
----
Usage: kythe <global-flags> <command> <flags>
Examples:
kythe ls --uris kythe://kythe?path=kythe/cxx/common
kythe search --path kythe/cxx/common/CommandLineUtils.h /kythe/node/kind file
kythe node kythe:?lang=java#java.util.List
Commands:
# Retrieve outward edges from a node
edges [--count_only] [--kinds edgeKind1,edgeKind2,...] [--page_token token] [--page_size num] <ticket>
# Print help information for the given command
help [command]
# List a directory's contents
ls [--uris] [directory-uri]
# Retrieve a node's facts
node [--filters factFilter1,factFilter2,...] [--max_fact_size] <ticket>
# List a file's anchor references
refs [--format spec] [--dirty file] [--span span] <file-ticket>
# Search for nodes based on partial components and fact values.
search [--corpus c] [--sig s] [--root r] [--lang l] [--path p] [factName factValue]...
# Retrieve a file's source text
source [--span span] <file-ticket>
----
Even with these _basic_ commands, one can build sophisticated queries and gather
rich data about Kythe indexed source code. (Special attention should be
made that this tool is built to be *very simple*. It is entirely meant to be
built upon to provide better abstractions for clients.) The tool can browse all
known node facts, edges, directories, files, and file anchor references. By
combining these commands, one can begin to uncover larger structures within the
graph and then use that knowledge to better maintain, refactor, and otherwise
understand source code.
As a simple example, we can list the link:/docs/schema/#name[names] of all
defined classes within the files of a directory. It's important to note that
the following script is *completely language-agnostic*; it works for any Kythe
supported language with classes.
[source,shell]
----
print_classes() {
kythe ls --uris --files "kythe://kythe?path=$1" \
| parallel kythe refs --format "'@target@ @edgeKind@ @nodeKind@ @subkind@'" \
| awk '$2 == "/kythe/edge/defines" && $3 == "record" && $4 == "class" { print $1 }' \
| xargs kythe edges --targets_only --kinds /kythe/edge/named \
| awk '{ print substr($0, index($0, "#")+1) }' \
| parallel python -c '"import urllib, sys; print urllib.unquote(sys.argv[1])"'
}
print_classes kythe/java/com/google/devtools/kythe/analyzers/java/
print_classes kythe/cxx/tools/fyi/
----
.Output
----
com.google.devtools.kythe.analyzers.java.JavaEntrySets
com.google.devtools.kythe.analyzers.java.KytheTreeScanner
com.google.devtools.kythe.analyzers.java.JavaNode
com.google.devtools.kythe.analyzers.java.JavaIndexer.StreamFactEmitter
com.google.devtools.kythe.analyzers.java.FilePositions
com.google.devtools.kythe.analyzers.java.JavaIndexer
com.google.devtools.kythe.analyzers.java.KytheJavacAnalyzer
Action:fyi:kythe#c
FileTracker:fyi:kythe#c
ActionFactory:fyi:kythe#c
PreprocessorHooks:fyi:kythe#c
----
There are many higher-level data that can be easily collected by using the
Kythe. The rest of this post gives a small collection of such use cases to
spark the imagination, but there are many, many more (including the sample web
UI). We hope that the greater community helps us in creating the many tools,
fostering a large Kythe ecosystem that supports a vast range of editors,
refactoring tools, source browsers, code health analyzers, and everything in
between.
'''
== Example Usages
=== Finding a file's ticket
[source,shell]
----
# Direct search
$ kythe search --path kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java /kythe/node/kind file
# Lookup by directory listing
$ kythe ls --uris kythe://kythe?path=kythe/java/com/google/devtools/kythe/analyzers/base \
| grep EntrySet.java
----
.Output
----
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#03e35c4ead4f300d85f196e988d1d0d649577c178b8d2acd38c9762693afdb1e
Total Results: 1
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#03e35c4ead4f300d85f196e988d1d0d649577c178b8d2acd38c9762693afdb1e
----
=== Displaying a file's decorations
[source,shell]
----
# Get the file's ticket
$ ticket="$(kythe search --path kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java /kythe/node/kind file)"
# Display source text references from line 17 to 25
$ kythe refs --span 17-25 "$ticket" | column -t
# Display the corresponding source text
$ kythe source --span 17-25 "$ticket"
----
.Output
----
/kythe/edge/ref 17:8-17:48 package kythe:?lang=java#23d9461e1b9e98e148846d9f763afea35ec1ff1fd5a8b2a53ac6d0a3b955fed4
/kythe/edge/ref 19:30-19:43 record kythe://third_party?lang=java?path=com/google/common/base/Preconditions.java?root=guava#e3d7e3936e1ca0e14dd144b2c808c8aa6dea41bf0bd5d7fd5064b2412d534857
/kythe/edge/ref 20:33-20:46 record kythe://third_party?lang=java?path=com/google/common/collect/ImmutableList.java?root=guava#a56c3e772d6b788f59bd09b07071dac5904672b5a188b7cd1c68db3f5dccbf9a
/kythe/edge/ref 21:33-21:45 record kythe://third_party?lang=java?path=com/google/common/collect/ImmutableMap.java?root=guava#2c303ad6afb24776d0d929b7c4f371a8181da961889ac682c8bdb75635d1819f
/kythe/edge/ref 22:33-22:51 record kythe://third_party?lang=java?path=com/google/common/collect/ImmutableSortedMap.java?root=guava#e3069c27a68c90e1bd1cd89ef951ac5a7b750cb8bf85cbd9acd59cd8b9478bc3
/kythe/edge/ref 23:30-23:42 interface kythe://third_party?lang=java?path=com/google/common/hash/HashFunction.java?root=guava#6563a67450f299c8c72644d0aa7df11cf97590c87457fcc6892247a71c1fe455
/kythe/edge/ref 24:30-24:36 interface kythe://third_party?lang=java?path=com/google/common/hash/Hasher.java?root=guava#9848e20c021347330cf46021309886b174594183413a67de10c98d444455da87
package com.google.devtools.kythe.analyzers.base;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hasher;
----
=== List all definitions in a file
[source,shell]
----
$ ticket="$(kythe search --path kythe/cxx/common/path_utils.h /kythe/node/kind file)"
$ kythe refs "$ticket" \
| awk '$1 == "/kythe/edge/defines"' \
| column -t
----
.Output
----
/kythe/edge/defines 18:8-18:38 macro kythe://kythe?lang=c%2B%2B?path=kythe/cxx/common/path_utils.h#KYTHE_CXX_COMMON_PATH_UTILS_H_%23m%40662%23kythe%23kythe%2Fcxx%2Fcommon%2Fpath_utils.h
/kythe/edge/defines 32:12-32:26 function kythe:?lang=c%2B%2B#RelativizePath%3Akythe%23n%401118kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1243%40.0
/kythe/edge/defines 32:46-32:59 variable kythe:?lang=c%2B%2B#to_relativize%3ARelativizePath%3Akythe%23n%401145kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1164%40.0
/kythe/edge/defines 33:46-33:64 variable kythe:?lang=c%2B%2B#relativize_against%3ARelativizePath%3Akythe%23n%401206kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1225%40.0
/kythe/edge/defines 37:12-37:33 function kythe:?lang=c%2B%2B#MakeCleanAbsolutePath%3Akythe%23n%401363kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1423%40.0
/kythe/edge/defines 37:53-37:60 variable kythe:?lang=c%2B%2B#in_path%3AMakeCleanAbsolutePath%3Akythe%23n%401397kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1416%40.0
/kythe/edge/defines 44:12-44:21 function kythe:?lang=c%2B%2B#CleanPath%3Akythe%23n%401586kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1631%40.0
/kythe/edge/defines 44:38-44:45 variable kythe:?lang=c%2B%2B#in_path%3ACleanPath%3Akythe%23n%401608kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1624%40.0
/kythe/edge/defines 47:12-47:20 function kythe:?lang=c%2B%2B#JoinPath%3Akythe%23n%401710kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1767%40.0
/kythe/edge/defines 47:37-47:38 variable kythe:?lang=c%2B%2B#a%3AJoinPath%3Akythe%23n%401731kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1747%40.0
/kythe/edge/defines 47:56-47:57 variable kythe:?lang=c%2B%2B#b%3AJoinPath%3Akythe%23n%401750kythe%2Fkythe%2Fcxx%2Fcommon%2Fpath_utils.h1766%40.0
----
=== List the members of a class
[source,shell]
----
$ java_class="com.google.devtools.kythe.analyzers.base.EntrySet"
$ ticket="$(kythe edges --targets_only --kinds %/kythe/edge/named "kythe:?lang=java#$java_class" \
| head -n1)"
# Display the ticket of EntrySet's members
$ kythe edges --targets_only --kinds %/kythe/edge/childof "$ticket"
# Display the names of EntrySet's members
$ kythe edges --targets_only --kinds %/kythe/edge/childof "$ticket" \
| xargs kythe edges --targets_only --kinds /kythe/edge/named \
| awk '{ print substr($0, index($0, "#")+1) }' \
| parallel python -c '"import urllib, sys; print urllib.unquote(sys.argv[1])"'
----
.Output
----
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#03956569bc7dc10ac1e5a0a0741d96ed2e53c530d12bd612b018dd1b295678ca
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#b5a90d2374e67e6ad8ace2f68e428709fdad6b4ac36f5286f2342163f079c7d8
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#bbbfed76e2abaaa205e91e1899709c3bb6a38db41dc8e8da4b5884bd3691462f
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#d0d8765e65a21cbd017083f5229dc9c916f5d4b85ba2a8ee151bca27d0b87930
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#d2eb72c69845bd1de760e2b93875bd5fe8c5dd93fa5d9ff75c82f60bc122eb48
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#2c10b781b8bee2c8025ed19098d03421933aa3a758fa883875449a71b49b99cc
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#3c7cd053fe0421c8993224faaf9ca8e91dfbe9d1fc6a8dd3051f3c01bc6fe34c
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#68acb557454500d179da5c797ebd51d32a531fa29c0642afb566fdafa01c313a
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#ab1b40fa4e30078a73ab9eab6f818a4d5124dfdf0940632c670ada67d54958de
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#52969240cab340ec9a881af2e884e7274cd295324a6f11856a963b86265928e0
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#899236dd842ccee0e9c185f492173903dcf6616ba720ea3142023ff59276e03e
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#c198d5ff2b91ce95bd5283e8c29abcb69427228278762df8b5d799f090aa55cf
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#0889c55a216de6ec548a0e7488a11deed63b7df53442d708232640e69dac0537
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#373ee49c099b6dac68c0815f7b307b3bcb42da27f272d02b9fb77cfab1f2ddbd
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#7fa73e034f622297d64d4c9d9506c4e167811440021acdc5e94603e74ccb5597
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#d30c6440fe0cfe25af5c2234d30797250b7e80274b327863d7dcb1738d289ed0
kythe://kythe?lang=java?path=kythe/java/com/google/devtools/kythe/analyzers/base/EntrySet.java#fbca931303f0057b49d4a945dea9ae9529353beb471be9e870b0b8690b61ce15
com.google.devtools.kythe.analyzers.base.EntrySet.toString()
com.google.devtools.kythe.analyzers.base.EntrySet.SIGNATURE_HASH_FUNCTION
com.google.devtools.kythe.analyzers.base.EntrySet.buildSignature(com.google.common.collect.ImmutableList<java.lang.String>,com.google.common.collect.ImmutableSortedMap<java.lang.String,byte[]>)
com.google.devtools.kythe.analyzers.base.EntrySet.EMPTY_PROPERTIES
com.google.devtools.kythe.analyzers.base.EntrySet.source
com.google.devtools.kythe.analyzers.base.EntrySet.emitted
com.google.devtools.kythe.analyzers.base.EntrySet.finalize()
com.google.devtools.kythe.analyzers.base.EntrySet.getVName()
com.google.devtools.kythe.analyzers.base.EntrySet.properties
com.google.devtools.kythe.analyzers.base.EntrySet.EntrySet(com.google.devtools.kythe.proto.Storage.VName,java.lang.String,com.google.devtools.kythe.proto.Storage.VName,com.google.common.collect.ImmutableMap<java.lang.String,byte[]>)
com.google.devtools.kythe.analyzers.base.EntrySet.emit(com.google.devtools.kythe.analyzers.base.FactEmitter)
com.google.devtools.kythe.analyzers.base.EntrySet.edgeKind
com.google.devtools.kythe.analyzers.base.EntrySet.extendVName(com.google.devtools.kythe.proto.Storage.VName,com.google.devtools.kythe.proto.Storage.VName)
com.google.devtools.kythe.analyzers.base.EntrySet.PROPERTY_VALUE_CHARSET
com.google.devtools.kythe.analyzers.base.EntrySet.Builder
com.google.devtools.kythe.analyzers.base.EntrySet.logger
com.google.devtools.kythe.analyzers.base.EntrySet.target
----