syntax = "proto3";

package gitaly;

import "lint.proto";
import "shared.proto";

option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb";

// BlobService is a service which provides RPCs to retrieve Git blobs from a
// specific repository.
service BlobService {

  // GetBlob returns the contents of a blob object referenced by its object
  // ID. We use a stream to return a chunked arbitrarily large binary
  // response
  rpc GetBlob(GetBlobRequest) returns (stream GetBlobResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

  // GetBlobs returns blobs identified via a revision and path.
  //
  // Note that the behaviour of this RPC is quite weird: it does not only return blobs, but will also return submodules
  // as commits and trees. It's use is thus discouraged in favor of ListBlobs, which behaves more sanely.
  rpc GetBlobs(GetBlobsRequest) returns (stream GetBlobsResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

  // ListBlobs will list all blobs reachable from a given set of revisions by
  // doing a graph walk. It is not valid to pass revisions which do not resolve
  // to an existing object.
  rpc ListBlobs(ListBlobsRequest) returns (stream ListBlobsResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

  // ListAllBlobs retrieves all blobs pointers in the repository, including
  // those not reachable by any reference.
  rpc ListAllBlobs(ListAllBlobsRequest) returns (stream ListAllBlobsResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

  // GetLFSPointers retrieves LFS pointers from a given set of object IDs.
  // This RPC filters all requested objects and only returns those which refer
  // to a valid LFS pointer.
  rpc GetLFSPointers(GetLFSPointersRequest) returns (stream GetLFSPointersResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

  // ListLFSPointers retrieves LFS pointers reachable from a given set of
  // revisions by doing a graph walk. This includes both normal revisions like
  // an object ID or branch, but also the pseudo-revisions "--all" and "--not"
  // as documented in git-rev-parse(1). Revisions which don't directly or
  // transitively reference any LFS pointers are ignored. It is not valid to
  // pass revisions which do not resolve to an existing object.
  rpc ListLFSPointers(ListLFSPointersRequest) returns (stream ListLFSPointersResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

  // ListAllLFSPointers retrieves all LFS pointers in the repository, including
  // those not reachable by any reference.
  rpc ListAllLFSPointers(ListAllLFSPointersRequest) returns (stream ListAllLFSPointersResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }

}

// GetBlobRequest is a request for the GetBlob RPC.
message GetBlobRequest {
  // repository is the repository that shall be searched.
  Repository repository = 1[(target_repository)=true];
  // oid is the object ID of the blob we want to get.
  string oid = 2;
  // limit is the maximum number of bytes we want to receive. Use '-1' to get the full blob no matter how big. Setting
  // this to `0` will return no data.
  int64 limit = 3;
}

// GetBlobResponse is a response for the GetBlob RPC. Multiple responses will be returned when the blob is large and
// thus doesn't fit into a single response.
message GetBlobResponse {
  // size is the size of the blob. Present only in first response message.
  int64 size = 1;
  // data is a chunk of data.
  bytes data = 2;
  // oid of the actual blob returned. Empty if no blob was found.
  string oid = 3;
}

// GetBlobsRequest is a request for the GetBlobs RPC.
message GetBlobsRequest {
  // RevisionPath is a combination of revision and path. All objects reachable in the subdirectory of the treeish
  // will be returned.
  message RevisionPath {
    // revision is the revision that identifies the tree-ish. Must not be empty.
    string revision = 1;
    // path is the path relative to the treeish revision that shall be searched for a blob. If the path is empty the
    // root directory of the tree-ish will be searched.
    bytes path = 2;
  }

  // repository is the repository that shall be searched.
  Repository repository = 1[(target_repository)=true];
  // revision_paths identifies the set of revision/path pairs that shall be searched for blobs.
  repeated RevisionPath revision_paths = 2;
  // limit is the maximum number of bytes we want to receive. Use '-1' to get the full blobs no matter how big.
  int64 limit = 3;
}

// GetBlobsResponse is a response for the GetBlobs RPC and identifies a single blob. Multiple responses can be returned
// for the same blob in case its data is longer than the gRPC message limit. Subsequent messages for the same blob will
// only have their data field set. Blobs which cannot be found will only have their path and revision set, but will
// otherwise be empty.
message GetBlobsResponse {
  // size is the size of the blob. Present only on the first message per blob
  int64 size = 1;
  // data is a chunk of blob data, which could span over multiple messages.
  bytes data = 2;
  // oid is the object ID of the current blob. Only present on the first message per blob. Empty if no blob was
  // found.
  string oid = 3;
  // is_submodule indicates whether the blob is a submodule.
  bool is_submodule = 4;
  // mode is the file mode of blob as present in the tree. It is typically one of:
  //
  // - 0o100644 for non-executable files.
  // - 0o100755 for executable files.
  // - 0o160000 for submodules.
  // - 0o040000 for subtrees.
  int32 mode = 5;
  // revision is the revision that this blob has been traversed from.
  string revision = 6;
  // path is the path of the blob inside of the tree.
  bytes path = 7;
  // type is the type of the "blob".
  ObjectType type = 8;
}

// ListBlobsRequest is a request for the ListBlobs RPC.
message ListBlobsRequest {
  // repository is the repository in which blobs should be enumerated.
  Repository repository = 1 [(target_repository)=true];
  // revisions is the list of revisions to retrieve blobs from. These revisions
  // will be walked. Supports pseudo-revisions `--all` and `--not` as well as
  // negated revisions via `^revision`. Revisions cannot start with a leading
  // dash. Please consult gitrevisions(7) for more info. Must not be empty.
  repeated string revisions = 2;
  // limit is the maximum number of blobs to return. If set to its default
  // (`0`), then all found blobs will be returned.
  uint32 limit = 3;
  // bytes_limit is the maximum number of bytes to receive for each blob. If set
  // to `0`, then no blob data will be sent. If `-1`, then all blob data will
  // be sent without any limits.
  int64 bytes_limit = 4;
  // with_paths determines whether paths of blobs should be returned. When
  // set to `true`, paths are returned on a best-effort basis: a path will only
  // exist if the blob was traversed via a tree.
  bool with_paths = 5;
}

// ListBlobsResponse is a response for the ListBlobs RPC.
message ListBlobsResponse {
  // Blob represents a Git blob object.
  message Blob {
    // oid is the object ID of the blob. Will only be set for the first
    // message of each specific blob.
    string oid = 1;
    // size is the size of the blob. Will only be set for the first message
    // of each specific blob.
    int64 size = 2;
    // data is the contents of the blob. This field is optional and depends on
    // the BytesLimit in the original request.
    bytes data = 3;
    // path is the path of the blob. May be unset depending on how the blob had
    // been traversed.
    bytes path = 4;
  }

  // blobs is the blobs which have been found. In case blob contents were
  // requested and contents of a blob exceed the maximum gRPC message size,
  // then this blob will be split up into multiple blob messages which span
  // across multiple responses. In that case, metadata of the blob will only be
  // sent on the first such message for this specific blob.
  repeated Blob blobs = 1;
}

// ListAllBlobsRequest is a request for the ListAllBlobs RPC.
message ListAllBlobsRequest {
  // repository is the repository in which blobs should be enumerated.
  Repository repository = 1 [(target_repository)=true];
  // limit is the maximum number of blobs to return. If set to its default
  // (`0`), then all found blobs will be returned.
  uint32 limit = 2;
  // bytes_limit is the maximum number of bytes to receive for each blob. If set
  // to `0`, then no blob data will be sent. If `-1`, then all blob data will
  // be sent without any limits.
  int64 bytes_limit = 3;
}

// ListAllBlobsResponse is a response for the ListAllBlobs RPC.
message ListAllBlobsResponse {
  // Blob represents a Git blob object.
  message Blob {
    // oid is the object ID of the blob. Will only be set for the first
    // message of each specific blob.
    string oid = 1;
    // size is the size of the blob. Will only be set for the first message
    // of each specific blob.
    int64 size = 2;
    // data is the contents of the blob. This field is optional and depends on
    // the BytesLimit in the original request.
    bytes data = 3;
  }

  // blobs is the blobs which have been found. In case blob contents were
  // requested and contents of a blob exceed the maximum gRPC message size,
  // then this blob will be split up into multiple blob messages which span
  // across multiple responses. In that case, metadata of the blob will only be
  // sent on the first such message for this specific blob.
  repeated Blob blobs = 1;
}

// LFSPointer is a git blob which points to an LFS object.
message LFSPointer {
  // size is the size of the blob. This is not the size of the LFS object
  // pointed to.
  int64 size = 1;
  // data is the bare data of the LFS pointer blob. It contains the pointer to
  // the LFS data in the format specified by the LFS project.
  bytes data = 2;
  // oid is the object ID of the blob.
  string oid = 3;
  // file_size is the size given when parsing the LFS pointer spec.
  int64 file_size = 4;
  // file_oid is the object id given when parsing the LFS pointer spec.
  bytes file_oid = 5;
}

// GetLFSPointersRequest is a request for the GetLFSPointers RPC.
message GetLFSPointersRequest {
  // repository is the repository for which LFS pointers should be retrieved
  // from.
  Repository repository = 1[(target_repository)=true];
  // blob_ids is the list of blobs to retrieve LFS pointers from. Must be a
  // non-empty list of blobs IDs to fetch.
  repeated string blob_ids = 2;
}

// GetLFSPointersResponse is a response for the GetLFSPointers RPC.
message GetLFSPointersResponse {
  // lfs_pointers is the list of LFS pointers which were requested.
  repeated LFSPointer lfs_pointers = 1;
}

// ListLFSPointersRequest is a request for the ListLFSPointers RPC.
message ListLFSPointersRequest {
  // repository is the repository for which LFS pointers should be retrieved
  // from.
  Repository repository = 1[(target_repository)=true];
  // revisions is the list of revisions to retrieve LFS pointers from. Must be
  // a non-empty list.
  repeated string revisions = 2;
  // limit limits the number of LFS pointers returned.
  int32 limit = 3;
}

// ListLFSPointersResponse is a response for the ListLFSPointers RPC.
message ListLFSPointersResponse {
  // lfs_pointers is the list of LFS pointers which were requested.
  repeated LFSPointer lfs_pointers = 1;
}

// ListAllLFSPointersRequest is a request for the ListAllLFSPointers RPC.
message ListAllLFSPointersRequest {
  // repository is the repository for which LFS pointers should be retrieved
  // from.
  Repository repository = 1[(target_repository)=true];
  // limit limits the number of LFS pointers returned.
  int32 limit = 3;
}

// ListAllLFSPointersResponse is a response for the ListAllLFSPointers RPC.
message ListAllLFSPointersResponse {
  // lfs_pointers is the list of LFS pointers which were requested.
  repeated LFSPointer lfs_pointers = 1;
}
