-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement cquery --output=graph #12248
Conversation
Thankfully, query already has most of the infrastructure necessary to make this easy. query implements graph output (in GraphOutputFormatter) over a Digraph<Target>, which is a generic graph data structure with Target payloads. All output logic then runs over this data structure. To opt query in, all we have to do is create an equivalent Digraph<ConfiguredTarget>, which is a simple transformation from the backing graph. This change creates a new generic class for that common logic: GraphOutputWriter. query's GraphOutputFormatter then becomes a simple wrapper over that, and the new GraphOutputFormatterCallback is cquery's equivalent. A few differences: - cquery output is always fully ordered (--order_output=full). We could match this with query's controllable version, but I don't see a reason to make this yet another bit to configured. - query output annotates edges with select() conditions. cquery doesn't do this because select()s are resolved and removed from the graph after analysis. I think we could annotate edges with the *chosen* condition if there was demand, but that'd be a followup effort. PiperOrigin-RevId: 336377123 Change-Id: Iea0802850d18f6b047f8f35a5aa51926b97289e5
@meisterT re: potential aquery integration. |
TODO:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM. Re: aquery integration: conceptually it makes sense, but in actuality aquery outputs are humongous and I'm not sure a visual representation of that is useful. Maybe with very specific scopes specified by the filters.
/////////////////////////////////////////////////////////// | ||
|
||
@Option( | ||
name = "graph:node_limit", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would interpret node_limit
as a limit to the number of nodes in the graph, but it's not the case here. Maybe node_string_limit
? It's consistent with the variable name on L287.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This carries over query
's --graph:node_limit
flag into a common location. However clear or not the flag is, I'd prefer to keep the existing API for the context of this change.
src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputWriter.java
Outdated
Show resolved
Hide resolved
I figured as much. Thanks for clarifying. I'm personally happy just that you're aware this is a thing now. |
Thankfully, query already has most of the infrastructure necessary to make this easy. query implements graph output (in GraphOutputFormatter) over a Digraph<Target>, which is a generic graph data structure with Target payloads. All output logic then runs over this data structure. To opt query in, all we have to do is create an equivalent Digraph<ConfiguredTarget>, which is a simple transformation from the backing graph. This change creates a new generic class for that common logic: GraphOutputWriter. query's GraphOutputFormatter then becomes a simple wrapper over that, and the new GraphOutputFormatterCallback is cquery's equivalent. A few differences: - cquery output is always fully ordered (--order_output=full). We could match this with query's controllable version, but I don't see a reason to make this yet another bit to configured. - query output annotates edges with select() conditions. cquery doesn't do this because select()s are resolved and removed from the graph after analysis. I think we could annotate edges with the *chosen* condition if there was demand, but that'd be a followup effort. PiperOrigin-RevId: 336377123 Change-Id: Iea0802850d18f6b047f8f35a5aa51926b97289e5
Added a long disclaimer to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM! Just minor nits/qs. Excited this is happening!
src/main/java/com/google/devtools/build/lib/buildtool/PostAnalysisQueryBuildTool.java
Outdated
Show resolved
Hide resolved
@@ -253,4 +270,30 @@ public AspectResolutionModeConverter() { | |||
+ "precise mode is not completely precise: the decision whether to compute an aspect " | |||
+ "is decided in the analysis phase, which is not run during 'bazel query'.") | |||
public AspectResolver.Mode aspectDeps; | |||
|
|||
/////////////////////////////////////////////////////////// | |||
// GRAPH OUTPUT FORMATTER OPTIONS // |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the proto: options above also graph output formatter options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to my knowledge? As far as I can see those only apply to --output=proto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I didn't quite read this as --output=graph output formatter options. makes sense.
import java.io.OutputStream; | ||
import java.util.Comparator; | ||
|
||
/** cquery output formatter that prints the result as factored graph in AT&T GraphViz format. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: just AT&T?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This inherits the same comment as in the query
version, which I believe follows Javadoc's "Comments are written in HTML" guidance: https://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javadoc.html#blockandinlinetags
Key snippet:
entities for the less-than (<) and greater-than (>) symbols should be written < and >. Likewise, the ampersand (&) should be written &
private final GraphOutputWriter.NodeReader<ConfiguredTarget> nodeReader = | ||
new NodeReader<ConfiguredTarget>() { | ||
|
||
private final Comparator<ConfiguredTarget> configuredTargetOrdering = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my own edification - reason to initialize this outside of the comparator method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original reasoning is that the comparator
method can be called multiple times whereas the actual comparator logic only needs to be defined once. So it theoretically saves unnecessary extra instantiation.
In practice I don't think that'd make a huge difference (and I'd hope the JDK could optimize that). So I don't have strong feelings on the subject.
for (ConfiguredTarget configuredTarget : partialResult) { | ||
Node<ConfiguredTarget> node = graph.createNode(configuredTarget); | ||
for (ConfiguredTarget dep : depsRetriever.getDirectDeps(configuredTarget)) { | ||
if (allNodes.contains(dep)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming this is for a situation like --noimplicit_deps or the like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reasoning here is that the query output may only contain a subset of all deps.
So if A depends on B, C, and D and some magical query expression filtered the results down to just A and C, depsRetriever.getDirectDeps
returns all of A's deps (B, C, and D). We only want to include the ones that are part of the query result (any target in partialResult
, which in this case is A and C).
src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputWriter.java
Outdated
Show resolved
Hide resolved
@Override | ||
public void beginVisit() { | ||
super.beginVisit(); | ||
// TODO(bazel-team): (2009) make this the default in Digraph. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
laughing at the date of this TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely noticed that too. :p
src/main/java/com/google/devtools/build/lib/buildtool/PostAnalysisQueryBuildTool.java
Outdated
Show resolved
Hide resolved
src/main/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallback.java
Show resolved
Hide resolved
src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
Show resolved
Hide resolved
|
That graph visualization is super-cool. |
Thankfully,
query
already has most of the infrastructure necessary to make thiseasy.
query implements graph output (in
GraphOutputFormatter
) over aDigraph<Target>
, which is a generic graph data structure withTarget
payloads.All output logic then runs over this data structure. To opt query in, all we have
to do is create an equivalent
Digraph<ConfiguredTarget>
, which is a simpletransformation from the backing graph.
This change creates a new generic class for that common logic:
GraphOutputWriter
. query'sGraphOutputFormatter
then becomes a simple wrapperover that, and the new
GraphOutputFormatterCallback
is cquery's equivalent.A few differences:
--order_output=full
). We could matchthis with query's controllable version, but I don't see a reason to make this
yet another bit to configured.
because select()s are resolved and removed from the graph after analysis. I
think we could annotate edges with the chosen condition if there was
demand, but that'd be a followup effort.
Fixes #10843 (for
cquery
, notaquery
)