/* * Copyright 2023 The Bazel 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. */ package com.google.idea.blaze.qsync.query import com.google.common.annotations.VisibleForTesting import com.google.devtools.build.lib.query2.proto.proto2api.Build import com.google.idea.blaze.common.Interners import com.google.idea.blaze.common.Label import com.google.idea.blaze.common.Label.Companion.fromWorkspacePackageAndName import java.io.BufferedInputStream import java.io.File import java.io.FileInputStream import java.io.IOException import java.io.InputStream import java.nio.file.Path /** * Summaries the output from a `query` invocation into just the data needed by the rest of * querysync. * * * The main purpose of the summarized output is to allow the outputs from multiple `query` * invocations to be combined. This enables delta updates to the project. * * * If extra data from the `query` invocation is needed by later stages of sync, that data * should be added to the [Query.Summary] proto and this code should be updated accordingly. * The proto should remain a simple mapping of data from the build proto, i.e. no complex * functionality should be added to this class. Non-trivial calculations based on the output of the * query belong in [com.google.idea.blaze.qsync.BlazeQueryParser] instead. * * * Instances of the the [Query.Summary] proto are maintained in memory so data should not * be added to it unnecessarily. */ data class QuerySummaryImpl( private val proto: Query.Summary, ) : QuerySummary { override val isCompatibleWithCurrentPluginVersion get(): Boolean = proto.version == PROTO_VERSION /** Do not generate toString, this object is too large */ override fun toString(): String { return super.toString() } /** * An opaque proto buffer to be serialized with the project state and re-create the [ ] using [QuerySummaryImpl.create]. */ override fun protoForSerializationOnly(): Query.Summary = proto private class StringIndexer { private val strings: MutableMap = hashMapOf() private val list: MutableList = mutableListOf() init { strings.put("", 0) list.add("") } fun ruleToStoredRule(r: QueryData.Rule): Query.StoredRule { val builder = Query.StoredRule.newBuilder() .setLabel(indexLabel(r.label)) .setRuleClass(index(r.ruleClass)) .addAllSources(indexLabels(r.sources)) .addAllDeps(indexLabels(r.deps)) .addAllIdlSources(indexLabels(r.idlSources)) .addAllRuntimeDeps(indexLabels(r.runtimeDeps)) .addAllResourceFiles(indexLabels(r.resourceFiles)) .setTestApp(index(r.testApp)) .setInstruments(index(r.instruments)) .setCustomPackage(index(r.customPackage)) .addAllHdrs(indexLabels(r.hdrs)) .addAllCopts(index(r.copts)) .addAllTags(index(r.tags)) .setMainClass(index(r.mainClass)) if (r.manifest != null) { builder.setManifest(indexLabel(r.manifest)) } return builder.build() } fun addStringAndGetIndex(s: String): Int { list.add(intern(s)) return list.size - 1 } fun index(s: String): Int { return strings.getOrPut(s) { this.addStringAndGetIndex(s) } } fun indexLabel(l: Label): Query.StoredLabel { return Query.StoredLabel.newBuilder() .setWorkspace(index(l.workspace)) .setBuildPackage(index(l.buildPackage)) .setName(index(l.name)) .build() } fun indexLabels(labels: Collection