Commit 73e0be86 authored by Georges Racinet's avatar Georges Racinet 🦑
Browse files

MercurialRepositoryService, initial definition

This is the first definition of Mercurial (or Heptapod)
gRPC methods. It takes the form of a dedicated service,
in a separate `hgitaly` protobuf package.

## About the separate package

The protobufs `package` directive translates directly into a
the module name in Ruby generated code. This doesn't happen with
Python because Python modules and packages names are derived from
the file system layout, wich is obviously out of control of the
code generation.

Upstream's Ruby generated code is packaged in a separate gem,
historically from the `gitaly-proto` project, and soon to be
built from the bundled proto files within Gitaly. We are not
not going to fork either of those, and hence we need our own
package.

At some point, we may also need to generate a Go library,
which require a `option go_package` statement that we couldn't
provide right away because it means choosing the appropriate
full path (see examples in upstream GitLab proto files).

A consequence of using our own protobuf package for the declaration
itself is that we need to reference the Gitaly types with their
fully qualified name (`.gitaly.SomeType` in absolute form). Same applies
to the options.

References:

- https://developers.google.com/protocol-buffers/docs/proto3#packages

- https://developers.google.com/protocol-buffers/docs/proto#customoptions
  Quote: "Note that if you want to use a custom option in a package other
  than the one in which it was defined, you must prefix the option name
  with the package name, just as you would for type names." (example
  follows)

## About MercurialRepositoryService itself

This service is for Mercurial specific methods
that are considered to be global with respect to a given
repository.

It should cover the needs of #60 and #62

This follows the general Gitaly style: each method gets its own pair
of request/response messages, even if that looks to be redundant.
The main advantage should be to give unlimited room for future change
that would introduce actual changes.

Reference: https://gitlab.com/gitlab-org/gitaly/blob/master/proto/README.md#design-decisions
parent 2139fafefdff
......@@ -5,7 +5,7 @@ set -eu
PROTOS_DIR=./protos
STUBS_DIR=hgitaly/stub
for PROTO in lint shared blob commit diff ref repository-service server; do
for PROTO in lint shared blob commit diff ref repository-service server mercurial-repository; do
python -m grpc_tools.protoc \
-I${PROTOS_DIR} \
--python_out=${STUBS_DIR} \
......
This diff is collapsed.
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
from . import mercurial_repository_pb2 as mercurial__repository__pb2
class MercurialRepositoryServiceStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.InitConfig = channel.unary_unary(
'/hgitaly.MercurialRepositoryService/InitConfig',
request_serializer=mercurial__repository__pb2.InitConfigRequest.SerializeToString,
response_deserializer=mercurial__repository__pb2.InitConfigResponse.FromString,
)
self.GetConfigItem = channel.unary_unary(
'/hgitaly.MercurialRepositoryService/GetConfigItem',
request_serializer=mercurial__repository__pb2.GetConfigItemRequest.SerializeToString,
response_deserializer=mercurial__repository__pb2.GetConfigItemResponse.FromString,
)
self.GetManagedConfig = channel.unary_unary(
'/hgitaly.MercurialRepositoryService/GetManagedConfig',
request_serializer=mercurial__repository__pb2.GetManagedConfigRequest.SerializeToString,
response_deserializer=mercurial__repository__pb2.GetManagedConfigResponse.FromString,
)
self.SetManagedConfig = channel.unary_unary(
'/hgitaly.MercurialRepositoryService/SetManagedConfig',
request_serializer=mercurial__repository__pb2.SetManagedConfigRequest.SerializeToString,
response_deserializer=mercurial__repository__pb2.SetManagedConfigResponse.FromString,
)
class MercurialRepositoryServiceServicer(object):
"""Missing associated documentation comment in .proto file."""
def InitConfig(self, request, context):
"""Will back Rails method `hg_create_repository`,
currently implemented on `Gitlab::Mercurial::HgGitRepository`
Together with `RepositoryService.CreateRepository` (see hgitaly!64)
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def GetConfigItem(self, request, context):
"""Will back Rails method `hg_config_item_bool?` currently
implemented on `Gitlab::Mercurial::HgGitRepository`
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def GetManagedConfig(self, request, context):
"""
Managed configuration methods.
These are about the part of the repository-local configuration that is
entirely managed by Heptapod
(implemented as of this writing with the separate `.hg/hgrc.managed` file)
Will back Rails methods `get_hgrc` and `get_hg_heptapod_config` currently
implemented on `Gitlab::Mercurial::HgGitRepository`
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def SetManagedConfig(self, request, context):
"""Will back Rails methods `set_hgrc` currently implemented on
`Gitlab::Mercurial::HgGitRepository` (but will be more restrictive,
handling a closed list of sections and items, which is currently
implemented by the upper layers of the Rails application).
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_MercurialRepositoryServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'InitConfig': grpc.unary_unary_rpc_method_handler(
servicer.InitConfig,
request_deserializer=mercurial__repository__pb2.InitConfigRequest.FromString,
response_serializer=mercurial__repository__pb2.InitConfigResponse.SerializeToString,
),
'GetConfigItem': grpc.unary_unary_rpc_method_handler(
servicer.GetConfigItem,
request_deserializer=mercurial__repository__pb2.GetConfigItemRequest.FromString,
response_serializer=mercurial__repository__pb2.GetConfigItemResponse.SerializeToString,
),
'GetManagedConfig': grpc.unary_unary_rpc_method_handler(
servicer.GetManagedConfig,
request_deserializer=mercurial__repository__pb2.GetManagedConfigRequest.FromString,
response_serializer=mercurial__repository__pb2.GetManagedConfigResponse.SerializeToString,
),
'SetManagedConfig': grpc.unary_unary_rpc_method_handler(
servicer.SetManagedConfig,
request_deserializer=mercurial__repository__pb2.SetManagedConfigRequest.FromString,
response_serializer=mercurial__repository__pb2.SetManagedConfigResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'hgitaly.MercurialRepositoryService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
# This class is part of an EXPERIMENTAL API.
class MercurialRepositoryService(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def InitConfig(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/hgitaly.MercurialRepositoryService/InitConfig',
mercurial__repository__pb2.InitConfigRequest.SerializeToString,
mercurial__repository__pb2.InitConfigResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def GetConfigItem(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/hgitaly.MercurialRepositoryService/GetConfigItem',
mercurial__repository__pb2.GetConfigItemRequest.SerializeToString,
mercurial__repository__pb2.GetConfigItemResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def GetManagedConfig(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/hgitaly.MercurialRepositoryService/GetManagedConfig',
mercurial__repository__pb2.GetManagedConfigRequest.SerializeToString,
mercurial__repository__pb2.GetManagedConfigResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def SetManagedConfig(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/hgitaly.MercurialRepositoryService/SetManagedConfig',
mercurial__repository__pb2.SetManagedConfigRequest.SerializeToString,
mercurial__repository__pb2.SetManagedConfigResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
syntax = "proto3";
package hgitaly;
import "lint.proto";
import "shared.proto";
service MercurialRepositoryService {
// Will back Rails method `hg_create_repository`,
// currently implemented on `Gitlab::Mercurial::HgGitRepository`
// Together with `RepositoryService.CreateRepository` (see hgitaly!64)
rpc InitConfig(InitConfigRequest) returns (InitConfigResponse) {
option (.gitaly.op_type) = {
op: MUTATOR
};
}
// Will back Rails method `hg_config_item_bool?` currently
// implemented on `Gitlab::Mercurial::HgGitRepository`
rpc GetConfigItem(GetConfigItemRequest) returns (GetConfigItemResponse) {
option (.gitaly.op_type) = {
op: ACCESSOR
};
}
//
// Managed configuration methods.
//
// These are about the part of the repository-local configuration that is
// entirely managed by Heptapod
// (implemented as of this writing with the separate `.hg/hgrc.managed` file)
// Will back Rails methods `get_hgrc` and `get_hg_heptapod_config` currently
// implemented on `Gitlab::Mercurial::HgGitRepository`
rpc GetManagedConfig(GetManagedConfigRequest) returns (GetManagedConfigResponse) {
option (.gitaly.op_type) = {
op: ACCESSOR
};
}
// Will back Rails methods `set_hgrc` currently implemented on
// `Gitlab::Mercurial::HgGitRepository` (but will be more restrictive,
// handling a closed list of sections and items, which is currently
// implemented by the upper layers of the Rails application).
rpc SetManagedConfig(SetManagedConfigRequest) returns (SetManagedConfigResponse) {
option (.gitaly.op_type) = {
op: MUTATOR
};
}
}
message InitConfigRequest {
.gitaly.Repository repository = 1 [(.gitaly.target_repository)=true];
string namespace_path = 2;
}
message InitConfigResponse {}
message HeptapodConfigSection {
enum AutoPublish {
WITHOUT_TOPIC = 0;
NOTHING = 1;
ALL = 2;
}
bool allow_multiple_heads = 2;
bool allow_bookmarks = 3;
AutoPublish auto_publish = 4;
};
message GetManagedConfigRequest {
.gitaly.Repository repository = 1 [(.gitaly.target_repository)=true];
// if `local` is true, then instance-wide configuration is ignored.
bool local = 2;
}
// We chose to provide a typed field for all managed config items.
// Drawback: we will need a protocol change each time we introduce a new
// managed setting (which has been very infrequent in Heptapod history)
//
// Another option would be to return a generic mapping.
// Drawback: type conversion will have to be handled client-side, mostly
// duplicating the rules already provided by Mercurial, with less comfortable
// development contexts (at least for the current Heptapod team) than HGitaly.
// This is of course what `HgGitRepository#get_hg_heptapod_config` already
// does, but it's always been thought of as a temporary evil and it's poorly
// tested.
message GetManagedConfigResponse {
bool inherit = 1; // whether this Project inherits Group-level config
HeptapodConfigSection heptapod = 2;
}
message SetManagedConfigRequest {
.gitaly.Repository repository = 1 [(.gitaly.target_repository)=true];
bool inherit = 2;
HeptapodConfigSection heptapod = 3;
}
message SetManagedConfigResponse {}
// Of course, to be completed, but these are the two cases
// currently in use
enum ConfigItemType {
STRING = 0;
BOOL = 1;
}
message GetConfigItemRequest {
.gitaly.Repository repository = 1 [(.gitaly.target_repository)=true];
ConfigItemType as_type = 2;
// `section` is as in mercurial.ui.ui.config()
// In theory it could be arbitrary bytes, but that would be a pain
// on the client side as well and in practice, all config items we
// know of in Mercurial core and popular extensions are ASCII.
string section = 3;
// `name` is as in mercurial.ui.ui.config(). In particular, it
// can include dots.
// same remark as for `section` about bytes.
string name = 4;
}
message GetConfigItemResponse {
oneof value {
string as_string = 1;
bool as_bool = 2;
}
}
message RecoverRequest {
.gitaly.Repository repository = 1 [(.gitaly.target_repository)=true];
}
message RecoverResponse {
bool not_needed = 1;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment