blob: 268e266bf892d97a87e743bdf3910dfc01fbc408 [file] [log] [blame]
// Copyright 2024 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.
//
// This file contains the protocol buffer representation of a list of supported
// flags for Bazel commands.
syntax = "proto3";
package bazel_output_service;
import "google/protobuf/any.proto";
import "google/rpc/status.proto";
option java_package = "com.google.devtools.build.lib.remote";
option java_outer_classname = "BazelOutputServiceProto";
option go_package = "bazeloutputservice";
// The Bazel Output Service may be used by users of the Remote Execution API to
// assist Bazel in constructing the output tree: a directory on the local system
// containing all output files produced by a build.
//
// Primitive implementations of this API may simply download files from the
// Content Addressable Storage (CAS) and store them at their designated
// location. Complex implementations may use a pseudo file system (e.g., FUSE)
// to support deduplication, lazy loading and snapshotting.
//
// Details:
// https://github.com/bazelbuild/proposals/blob/master/designs/2021-02-09-remote-output-service.md
// https://groups.google.com/g/remote-execution-apis/c/qOSWWwBLPzo
// https://groups.google.com/g/bazel-dev/c/lKzENsNd1Do
// https://docs.google.com/document/d/1W6Tqq8cndssnDI0yzFSoj95oezRKcIhU57nwLHaN1qk/edit
service BazelOutputService {
// Clean all data associated with an output tree, so that the next invocation
// of StartBuild() yields an empty output tree. This MAY be implemented in a
// way that's faster than removing the contents manually.
rpc Clean(CleanRequest) returns (CleanResponse);
// Signal that a new build is about to start.
//
// Bazel uses this call to obtain a directory where outputs of the build may
// be stored, called the output tree. Based on the parameters provided, the
// server may provide an empty output tree, or one containing the result of
// a previous build of the same workspace.
//
// In case the output tree contains data from a previous build, server is
// responsible for calling ContentAddressableStorage.FindMissingBlobs() for
// all of the objects that are stored remotely. This ensures that these
// objects don't disappear from the Content Addressable Storage during the
// build. Objects that are no longer available MUST be removed from the output
// tree and reported through InitialOutputPathContents.modified_path_prefixes,
// unless the field has been omitted because it would have been too large.
rpc StartBuild(StartBuildRequest) returns (StartBuildResponse);
// Stage build artifacts at the given paths with digests that are known to the
// Content Addressable Storage. The file contents MAY be lazily downloaded
// when they're accessed in the future, and are not guaranteed to have already
// been downloaded upon return.
rpc StageArtifacts(StageArtifactsRequest) returns (StageArtifactsResponse);
// Notify the server that a set of paths are not expected to be modified
// further by Bazel or a local build action within the current build.
//
// For each of these paths, the server MAY decide to store a dirty bit,
// initially unset. Any subsequent modification, deletion or recreation of
// that path causes the dirty bit to be set. If the server chooses to store
// the dirty bit, any paths with the dirty bit set MUST be reported back in
// the next InitialOutputPathContents.modified_path_prefixes.
//
// As an alternative to tracking modifications via a dirty bit, a server MAY
// choose to freeze finalized paths, preventing them from being modified
// until the next StartBuildRequest or CleanRequest.
rpc FinalizeArtifacts(FinalizeArtifactsRequest)
returns (FinalizeArtifactsResponse);
// Signal that a build has been completed.
rpc FinalizeBuild(FinalizeBuildRequest) returns (FinalizeBuildResponse);
// Obtain the status of one or more files, directories or symbolic links
// stored in the output tree.
rpc BatchStat(BatchStatRequest) returns (BatchStatResponse);
}
message CleanRequest {
// The workspace identifier that was provided to
// StartBuildRequest.output_base_id whose data needs to be removed.
string output_base_id = 1;
}
message CleanResponse {
// Intentionally empty for future extensibility.
}
message StartBuildRequest {
// The version of the protocol Bazel currently uses. The service MUST return
// an error if it doesn't recognize the version.
//
// A future Bazel version may introduce incompatible changes and increment
// this version number. The incompatible change will be first made in the
// development tree for the next major Bazel release, and the new version thus
// introduced should be considered unstable until that major Bazel release
// occurs. At that time, the new version becomes stable, and the old one is
// immediately retired.
//
// In particular, version 1 must not be considered stable until Bazel 8.0.0 is
// released.
//
// Current version: 1 (experimental).
int32 version = 1;
// A client-chosen value that uniquely identifies the workspace where a build
// is being started. Each workspace corresponds to a separately managed output
// tree. This value MAY be used by the server to manage multiple output trees
// concurrently.
//
// Bazel sets this value to the MD5 sum of the absolute path of the output
// base.
//
// Starting a build finalizes any previous build with the same output_base_id
// that has not been finalized yet as if a FinalizeBuildRequest had been sent
// with build_successful set to false.
string output_base_id = 2;
// A client-chosen value that uniquely identifies this build. This value must
// be provided to most other methods to ensure that operations are targeted
// against the right output tree. If the server receives a subsequent request
// with a non-matching build_id, it SHOULD send back an error response.
//
// Bazel sets this value to --invocation_id.
string build_id = 3;
// Additional arguments to pass depending on how Bazel communicates with the
// Content Addressable Storage.
//
// In case of a REv2 CAS, the type is
// [StartBuildArgs][bazel_output_service_rev2.StartBuildArgs].
google.protobuf.Any args = 4;
// The absolute path at which the server exposes its output tree, as seen from
// the perspective of the client.
//
// This value needs to be provided by the client because file system namespace
// virtualization may cause this directory to appear at different locations
// as seen by the client and the server.
//
// In addition, this field is used to ensure the server is capable of
// expanding symbolic links containing absolute paths into the output tree.
//
// If unset or empty, the server must determine where to expose its output
// tree and return an absolute path in StartBuildResponse.output_path_suffix.
string output_path_prefix = 5;
// A map of paths on the system that will become symbolic links pointing to
// locations inside the output tree. Similar to output_path_prefix, this
// option is used to ensure the server is capable of expanding additional
// symbolic links.
//
// Map keys are absolute paths, while map values are paths that are
// relative to the output tree.
map<string, string> output_path_aliases = 6;
}
message StartBuildResponse {
// If set, the contents of the output tree are almost entirely identical on
// the results of a previous build. This information may be used by Bazel to
// prevent unnecessary scanning of the file system.
//
// The server MUST leave this field unset in case the contents of the output
// path are empty, not based on a previous build, if no modification tracking
// is performed. It MAY leave it unset if the number of changes made to the
// output path is too large to be expressed.
InitialOutputPathContents initial_output_path_contents = 1;
// A path that the client must append to StartBuildRequest.output_path_prefix
// to obtain the full path at which the output tree is available.
//
// Bazel replaces bazel-out/ with a symlink targeting this path.
string output_path_suffix = 2;
}
message InitialOutputPathContents {
// The identifier of a previously finalized build whose results are stored in
// the output tree.
string build_id = 1;
// Path prefixes relative to StartBuildResponse.output_path that have been
// modified, deleted or recreated since they were finalized. Any path exactly
// matching or starting with one of these prefixes MUST be assumed by Bazel to
// have been modified or deleted. Any other path MAY be assumed by Bazel to
// have remained unchanged since it was last finalized.
//
// In the interest of performance, the server SHOULD only include path
// prefixes that contain at least one of the paths that were previously
// finalized.
repeated string modified_path_prefixes = 2;
}
message StageArtifactsRequest {
message Artifact {
// Path relative to StartBuildResponse.output_path.
string path = 1;
// Describe how to stage the artifact.
//
// The concrete type of the locator depending on the CAS Bazel connects to.
// In case of a REv2 CAS, the type is
// [FileArtifactLocator][bazel_output_service_rev2.FileArtifactLocator].
google.protobuf.Any locator = 2;
}
// The identifier of the build. Server uses this to determine which output
// path needs to be modified.
string build_id = 1;
repeated Artifact artifacts = 2;
}
message StageArtifactsResponse {
message Response {
// If the status has a code other than `OK`, it indicates that the artifact
// could not be staged.
//
// Errors:
// * `NOT_FOUND`: The requested Artifact is not in the CAS.
google.rpc.Status status = 1;
}
// The response for each of the requested artifacts, using the same order as
// requested. This means that this list has the same length as
// StageArtifactsRequest.artifacts.
repeated Response responses = 1;
}
message FinalizeArtifactsRequest {
message Artifact {
// Path relative to StartBuildResponse.output_path.
string path = 1;
// Expected digest for this path. This allows the server to detect changes
// the path has been changed after the client finished creating the path and
// the corresponding FinalizeArtifactsRequest is processed.
//
// The concrete type of the locator depending on the CAS Bazel connects to.
// In case of a REv2 CAS, the type is
// [FileArtifactLocator][bazel_output_service_rev2.FileArtifactLocator].
google.protobuf.Any locator = 2;
}
// The identifier of the build. Server uses this to determine which output
// path needs to be modified.
string build_id = 1;
repeated Artifact artifacts = 2;
}
message FinalizeArtifactsResponse {
// Intentionally empty for future extensibility.
}
message FinalizeBuildRequest {
// The identifier of the build that should be finalized.
string build_id = 1;
// Whether the build completed successfully. The server MAY, for example, use
// this option to apply different retention policies that take the outcome of
// the build into account.
bool build_successful = 2;
}
message FinalizeBuildResponse {
// Intentionally empty for future extensibility.
}
message BatchStatRequest {
// The identifier of the build. The server uses this to determine which output
// tree needs to be inspected.
string build_id = 1;
// Paths whose status is to be obtained. The server MUST canonicalize each
// path using lstat semantics, i.e., all components except the last must be
// resolved if they are symlinks. If a symlink pointing to a location outside
// of the output tree is encountered at any point during the canonicalization
// process, the server MAY use the information in
// StartBuildRequest.output_path_aliases map to continue the canonicalization.
//
// Refer to Stat.type for how to handle a situation where canonicalization
// fails due to a symlink pointing to a location outside of the output tree.
//
// Path is relative to StartBuildResponse.output_path.
repeated string paths = 2;
}
message BatchStatResponse {
message StatResponse {
// The status of the path. If the path does not exist, this field MUST be
// unset.
Stat stat = 1;
}
message Stat {
message File {
// The file digest.
//
// The server MAY leave this field unset if it is unable to compute the
// digest.
//
// The concrete type of the digest depending on the CAS Bazel connects to.
// In case of a REv2 CAS, the type is
// [FileArtifactLocator][bazel_output_service_rev2.FileArtifactLocator].
google.protobuf.Any locator = 1;
}
message Symlink {
// The target of the symbolic link.
string target = 1;
}
message Directory {}
// If the path cannot be canonicalized, the server MUST NOT set any of the
// type fields.
//
// If the path resolves to a special file, the server MUST NOT set any of
// the type fields.
oneof type {
// The path resolves to a regular file.
File file = 1;
// The path resolves to a symbolic link.
Symlink symlink = 2;
// The path resolves to a directory.
Directory directory = 3;
}
}
// The status response for each of the requested paths, using the same
// order as requested. This means that this list has the same length
// as BatchStatRequest.paths.
repeated StatResponse responses = 1;
}