From 70b814887b3fdc7692e87c6778e73842471ddd2b Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Tue, 8 Oct 2024 15:24:02 +1100 Subject: [PATCH] feat: add external plugin to build engine # Conflicts: # frontend/cli/cmd_new.go # internal/buildengine/deps.go # internal/buildengine/engine.go # internal/buildengine/languageplugin/go_integration_test.go # internal/buildengine/languageplugin/go_plugin_integration_test.go # internal/buildengine/languageplugin/go_plugin_tests.go # internal/buildengine/languageplugin/plugin.go # internal/buildengine/plugin_go_integration_test.go --- .../xyz/block/ftl/v1/language/language.pb.go | 1825 +++++++++++++++-- .../xyz/block/ftl/v1/language/language.proto | 176 ++ .../languagepbconnect/language.connect.go | 256 +++ frontend/cli/main.go | 6 +- .../ftl/v1/language.go/language_connect.ts | 98 + .../block/ftl/v1/language.go/language_pb.ts | 770 +++++++ .../block/ftl/v1/language/language_connect.ts | 87 + .../xyz/block/ftl/v1/language/language_pb.ts | 869 +++++++- internal/buildengine/engine.go | 2 +- .../languageplugin/external_plugin.go | 340 +++ .../languageplugin/external_plugin_client.go | 159 ++ .../languageplugin/external_plugin_test.go | 361 ++++ internal/buildengine/languageplugin/plugin.go | 28 +- 13 files changed, 4840 insertions(+), 137 deletions(-) create mode 100644 backend/protos/xyz/block/ftl/v1/language/languagepbconnect/language.connect.go create mode 100644 frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_connect.ts create mode 100644 frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_pb.ts create mode 100644 frontend/console/src/protos/xyz/block/ftl/v1/language/language_connect.ts create mode 100644 internal/buildengine/languageplugin/external_plugin.go create mode 100644 internal/buildengine/languageplugin/external_plugin_client.go create mode 100644 internal/buildengine/languageplugin/external_plugin_test.go diff --git a/backend/protos/xyz/block/ftl/v1/language/language.pb.go b/backend/protos/xyz/block/ftl/v1/language/language.pb.go index 236e9ef460..c38480dc3f 100644 --- a/backend/protos/xyz/block/ftl/v1/language/language.pb.go +++ b/backend/protos/xyz/block/ftl/v1/language/language.pb.go @@ -7,9 +7,11 @@ package languagepb import ( + v1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" schema "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/schema" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" reflect "reflect" sync "sync" ) @@ -21,6 +23,58 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type LogLevel int32 + +const ( + LogLevel_DEBUG LogLevel = 0 + LogLevel_INFO LogLevel = 1 + LogLevel_WARN LogLevel = 2 + LogLevel_ERROR LogLevel = 3 +) + +// Enum value maps for LogLevel. +var ( + LogLevel_name = map[int32]string{ + 0: "DEBUG", + 1: "INFO", + 2: "WARN", + 3: "ERROR", + } + LogLevel_value = map[string]int32{ + "DEBUG": 0, + "INFO": 1, + "WARN": 2, + "ERROR": 3, + } +) + +func (x LogLevel) Enum() *LogLevel { + p := new(LogLevel) + *p = x + return p +} + +func (x LogLevel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LogLevel) Descriptor() protoreflect.EnumDescriptor { + return file_xyz_block_ftl_v1_language_language_proto_enumTypes[0].Descriptor() +} + +func (LogLevel) Type() protoreflect.EnumType { + return &file_xyz_block_ftl_v1_language_language_proto_enumTypes[0] +} + +func (x LogLevel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LogLevel.Descriptor instead. +func (LogLevel) EnumDescriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{0} +} + type Error_ErrorLevel int32 const ( @@ -54,11 +108,11 @@ func (x Error_ErrorLevel) String() string { } func (Error_ErrorLevel) Descriptor() protoreflect.EnumDescriptor { - return file_xyz_block_ftl_v1_language_language_proto_enumTypes[0].Descriptor() + return file_xyz_block_ftl_v1_language_language_proto_enumTypes[1].Descriptor() } func (Error_ErrorLevel) Type() protoreflect.EnumType { - return &file_xyz_block_ftl_v1_language_language_proto_enumTypes[0] + return &file_xyz_block_ftl_v1_language_language_proto_enumTypes[1] } func (x Error_ErrorLevel) Number() protoreflect.EnumNumber { @@ -67,22 +121,24 @@ func (x Error_ErrorLevel) Number() protoreflect.EnumNumber { // Deprecated: Use Error_ErrorLevel.Descriptor instead. func (Error_ErrorLevel) EnumDescriptor() ([]byte, []int) { - return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{0, 0} + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{11, 0} } -type Error struct { +type Metadata struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` - Pos *schema.Position `protobuf:"bytes,2,opt,name=pos,proto3" json:"pos,omitempty"` - EndColumn int64 `protobuf:"varint,3,opt,name=endColumn,proto3" json:"endColumn,omitempty"` - Level Error_ErrorLevel `protobuf:"varint,4,opt,name=level,proto3,enum=xyz.block.ftl.v1.language.Error_ErrorLevel" json:"level,omitempty"` + // Universal metadata + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Language string `protobuf:"bytes,2,opt,name=language,proto3" json:"language,omitempty"` + // Language metadata contains any metadata specific to a specific language. + // TODO: revisit type... + LanguageMetadata *anypb.Any `protobuf:"bytes,3,opt,name=LanguageMetadata,proto3" json:"LanguageMetadata,omitempty"` } -func (x *Error) Reset() { - *x = Error{} +func (x *Metadata) Reset() { + *x = Metadata{} if protoimpl.UnsafeEnabled { mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -90,13 +146,13 @@ func (x *Error) Reset() { } } -func (x *Error) String() string { +func (x *Metadata) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Error) ProtoMessage() {} +func (*Metadata) ProtoMessage() {} -func (x *Error) ProtoReflect() protoreflect.Message { +func (x *Metadata) ProtoReflect() protoreflect.Message { mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -108,64 +164,129 @@ func (x *Error) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Error.ProtoReflect.Descriptor instead. -func (*Error) Descriptor() ([]byte, []int) { +// Deprecated: Use Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{0} } -func (x *Error) GetMsg() string { +func (x *Metadata) GetName() string { if x != nil { - return x.Msg + return x.Name } return "" } -func (x *Error) GetPos() *schema.Position { +func (x *Metadata) GetLanguage() string { if x != nil { - return x.Pos + return x.Language + } + return "" +} + +func (x *Metadata) GetLanguageMetadata() *anypb.Any { + if x != nil { + return x.LanguageMetadata } return nil } -func (x *Error) GetEndColumn() int64 { +type ProjectConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + NoGit bool `protobuf:"varint,3,opt,name=noGit,proto3" json:"noGit,omitempty"` + Hermit bool `protobuf:"varint,4,opt,name=hermit,proto3" json:"hermit,omitempty"` +} + +func (x *ProjectConfig) Reset() { + *x = ProjectConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProjectConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProjectConfig) ProtoMessage() {} + +func (x *ProjectConfig) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProjectConfig.ProtoReflect.Descriptor instead. +func (*ProjectConfig) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{1} +} + +func (x *ProjectConfig) GetPath() string { if x != nil { - return x.EndColumn + return x.Path } - return 0 + return "" } -func (x *Error) GetLevel() Error_ErrorLevel { +func (x *ProjectConfig) GetName() string { if x != nil { - return x.Level + return x.Name } - return Error_INFO + return "" } -type ErrorList struct { +func (x *ProjectConfig) GetNoGit() bool { + if x != nil { + return x.NoGit + } + return false +} + +func (x *ProjectConfig) GetHermit() bool { + if x != nil { + return x.Hermit + } + return false +} + +// TODO: docs +type GetCreateModuleFlagsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Errors []*Error `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"` + Language string `protobuf:"bytes,1,opt,name=language,proto3" json:"language,omitempty"` } -func (x *ErrorList) Reset() { - *x = ErrorList{} +func (x *GetCreateModuleFlagsRequest) Reset() { + *x = GetCreateModuleFlagsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[1] + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *ErrorList) String() string { +func (x *GetCreateModuleFlagsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ErrorList) ProtoMessage() {} +func (*GetCreateModuleFlagsRequest) ProtoMessage() {} -func (x *ErrorList) ProtoReflect() protoreflect.Message { - mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[1] +func (x *GetCreateModuleFlagsRequest) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -176,125 +297,1573 @@ func (x *ErrorList) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ErrorList.ProtoReflect.Descriptor instead. -func (*ErrorList) Descriptor() ([]byte, []int) { - return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{1} +// Deprecated: Use GetCreateModuleFlagsRequest.ProtoReflect.Descriptor instead. +func (*GetCreateModuleFlagsRequest) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{2} } -func (x *ErrorList) GetErrors() []*Error { +func (x *GetCreateModuleFlagsRequest) GetLanguage() string { if x != nil { - return x.Errors + return x.Language } - return nil + return "" } -var File_xyz_block_ftl_v1_language_language_proto protoreflect.FileDescriptor +type GetCreateModuleFlagsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var file_xyz_block_ftl_v1_language_language_proto_rawDesc = []byte{ - 0x0a, 0x28, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, - 0x76, 0x31, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2f, 0x6c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x79, 0x7a, 0x2e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, - 0x67, 0x75, 0x61, 0x67, 0x65, 0x1a, 0x24, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2f, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdc, 0x01, 0x0a, 0x05, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x33, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, - 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x09, - 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x41, 0x0a, 0x05, 0x6c, 0x65, - 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x79, 0x7a, 0x2e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, - 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2b, 0x0a, - 0x0a, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, - 0x4e, 0x46, 0x4f, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x01, 0x12, - 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x22, 0x45, 0x0a, 0x09, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x73, 0x42, 0x52, 0x50, 0x01, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x54, 0x42, 0x44, 0x35, 0x34, 0x35, 0x36, 0x36, 0x39, 0x37, 0x35, 0x2f, 0x66, 0x74, - 0x6c, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2f, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x76, - 0x31, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3b, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + Flags []*GetCreateModuleFlagsResponse_Flag `protobuf:"bytes,1,rep,name=flags,proto3" json:"flags,omitempty"` } -var ( - file_xyz_block_ftl_v1_language_language_proto_rawDescOnce sync.Once - file_xyz_block_ftl_v1_language_language_proto_rawDescData = file_xyz_block_ftl_v1_language_language_proto_rawDesc -) +func (x *GetCreateModuleFlagsResponse) Reset() { + *x = GetCreateModuleFlagsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} -func file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP() []byte { - file_xyz_block_ftl_v1_language_language_proto_rawDescOnce.Do(func() { - file_xyz_block_ftl_v1_language_language_proto_rawDescData = protoimpl.X.CompressGZIP(file_xyz_block_ftl_v1_language_language_proto_rawDescData) - }) - return file_xyz_block_ftl_v1_language_language_proto_rawDescData +func (x *GetCreateModuleFlagsResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -var file_xyz_block_ftl_v1_language_language_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_xyz_block_ftl_v1_language_language_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_xyz_block_ftl_v1_language_language_proto_goTypes = []any{ - (Error_ErrorLevel)(0), // 0: xyz.block.ftl.v1.language.Error.ErrorLevel - (*Error)(nil), // 1: xyz.block.ftl.v1.language.Error - (*ErrorList)(nil), // 2: xyz.block.ftl.v1.language.ErrorList - (*schema.Position)(nil), // 3: xyz.block.ftl.v1.schema.Position +func (*GetCreateModuleFlagsResponse) ProtoMessage() {} + +func (x *GetCreateModuleFlagsResponse) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var file_xyz_block_ftl_v1_language_language_proto_depIdxs = []int32{ - 3, // 0: xyz.block.ftl.v1.language.Error.pos:type_name -> xyz.block.ftl.v1.schema.Position - 0, // 1: xyz.block.ftl.v1.language.Error.level:type_name -> xyz.block.ftl.v1.language.Error.ErrorLevel - 1, // 2: xyz.block.ftl.v1.language.ErrorList.errors:type_name -> xyz.block.ftl.v1.language.Error - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + +// Deprecated: Use GetCreateModuleFlagsResponse.ProtoReflect.Descriptor instead. +func (*GetCreateModuleFlagsResponse) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{3} } -func init() { file_xyz_block_ftl_v1_language_language_proto_init() } -func file_xyz_block_ftl_v1_language_language_proto_init() { - if File_xyz_block_ftl_v1_language_language_proto != nil { - return +func (x *GetCreateModuleFlagsResponse) GetFlags() []*GetCreateModuleFlagsResponse_Flag { + if x != nil { + return x.Flags } - if !protoimpl.UnsafeEnabled { - file_xyz_block_ftl_v1_language_language_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*Error); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } + return nil +} + +// Request to create a new module. +type CreateModuleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + ProjectConfig *ProjectConfig `protobuf:"bytes,3,opt,name=projectConfig,proto3" json:"projectConfig,omitempty"` + // TODO: revisit type... + Flags *anypb.Any `protobuf:"bytes,4,opt,name=Flags,proto3" json:"Flags,omitempty"` +} + +func (x *CreateModuleRequest) Reset() { + *x = CreateModuleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateModuleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateModuleRequest) ProtoMessage() {} + +func (x *CreateModuleRequest) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } - file_xyz_block_ftl_v1_language_language_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*ErrorList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateModuleRequest.ProtoReflect.Descriptor instead. +func (*CreateModuleRequest) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{4} +} + +func (x *CreateModuleRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateModuleRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *CreateModuleRequest) GetProjectConfig() *ProjectConfig { + if x != nil { + return x.ProjectConfig + } + return nil +} + +func (x *CreateModuleRequest) GetFlags() *anypb.Any { + if x != nil { + return x.Flags + } + return nil +} + +// Response to a create module request. +type CreateModuleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CreateModuleResponse) Reset() { + *x = CreateModuleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateModuleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateModuleResponse) ProtoMessage() {} + +func (x *CreateModuleResponse) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateModuleResponse.ProtoReflect.Descriptor instead. +func (*CreateModuleResponse) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{5} +} + +type DependenciesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *DependenciesRequest) Reset() { + *x = DependenciesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DependenciesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DependenciesRequest) ProtoMessage() {} + +func (x *DependenciesRequest) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DependenciesRequest.ProtoReflect.Descriptor instead. +func (*DependenciesRequest) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{6} +} + +func (x *DependenciesRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *DependenciesRequest) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +type DependenciesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Modules []string `protobuf:"bytes,1,rep,name=modules,proto3" json:"modules,omitempty"` +} + +func (x *DependenciesResponse) Reset() { + *x = DependenciesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DependenciesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DependenciesResponse) ProtoMessage() {} + +func (x *DependenciesResponse) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DependenciesResponse.ProtoReflect.Descriptor instead. +func (*DependenciesResponse) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{7} +} + +func (x *DependenciesResponse) GetModules() []string { + if x != nil { + return x.Modules + } + return nil +} + +// Response to a dependency extraction request. +type DependencyUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Modules []string `protobuf:"bytes,1,rep,name=modules,proto3" json:"modules,omitempty"` +} + +func (x *DependencyUpdate) Reset() { + *x = DependencyUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DependencyUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DependencyUpdate) ProtoMessage() {} + +func (x *DependencyUpdate) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DependencyUpdate.ProtoReflect.Descriptor instead. +func (*DependencyUpdate) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{8} +} + +func (x *DependencyUpdate) GetModules() []string { + if x != nil { + return x.Modules + } + return nil +} + +// TODO: docs +type BuildContextUpdatedRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // TODO: explain + BuildRequestId string `protobuf:"bytes,1,opt,name=buildRequestId,proto3" json:"buildRequestId,omitempty"` + Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3,oneof" json:"metadata,omitempty"` + Schema *schema.Schema `protobuf:"bytes,3,opt,name=schema,proto3,oneof" json:"schema,omitempty"` +} + +func (x *BuildContextUpdatedRequest) Reset() { + *x = BuildContextUpdatedRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BuildContextUpdatedRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuildContextUpdatedRequest) ProtoMessage() {} + +func (x *BuildContextUpdatedRequest) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuildContextUpdatedRequest.ProtoReflect.Descriptor instead. +func (*BuildContextUpdatedRequest) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{9} +} + +func (x *BuildContextUpdatedRequest) GetBuildRequestId() string { + if x != nil { + return x.BuildRequestId + } + return "" +} + +func (x *BuildContextUpdatedRequest) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *BuildContextUpdatedRequest) GetSchema() *schema.Schema { + if x != nil { + return x.Schema + } + return nil +} + +type BuildContextUpdatedResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BuildContextUpdatedResponse) Reset() { + *x = BuildContextUpdatedResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BuildContextUpdatedResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuildContextUpdatedResponse) ProtoMessage() {} + +func (x *BuildContextUpdatedResponse) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuildContextUpdatedResponse.ProtoReflect.Descriptor instead. +func (*BuildContextUpdatedResponse) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{10} +} + +type Error struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` + Pos *schema.Position `protobuf:"bytes,2,opt,name=pos,proto3" json:"pos,omitempty"` + EndColumn int64 `protobuf:"varint,3,opt,name=endColumn,proto3" json:"endColumn,omitempty"` + Level Error_ErrorLevel `protobuf:"varint,4,opt,name=level,proto3,enum=xyz.block.ftl.v1.language.Error_ErrorLevel" json:"level,omitempty"` +} + +func (x *Error) Reset() { + *x = Error{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Error) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Error) ProtoMessage() {} + +func (x *Error) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Error.ProtoReflect.Descriptor instead. +func (*Error) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{11} +} + +func (x *Error) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *Error) GetPos() *schema.Position { + if x != nil { + return x.Pos + } + return nil +} + +func (x *Error) GetEndColumn() int64 { + if x != nil { + return x.EndColumn + } + return 0 +} + +func (x *Error) GetLevel() Error_ErrorLevel { + if x != nil { + return x.Level + } + return Error_INFO +} + +type ErrorList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Errors []*Error `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"` +} + +func (x *ErrorList) Reset() { + *x = ErrorList{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ErrorList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ErrorList) ProtoMessage() {} + +func (x *ErrorList) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ErrorList.ProtoReflect.Descriptor instead. +func (*ErrorList) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{12} +} + +func (x *ErrorList) GetErrors() []*Error { + if x != nil { + return x.Errors + } + return nil +} + +// Request to build a module. +type BuildRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // TODO: explain + BuildRequestId string `protobuf:"bytes,1,opt,name=buildRequestId,proto3" json:"buildRequestId,omitempty"` + // the root path for the module + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + // the root path for the FTL project + ProjectPath string `protobuf:"bytes,3,opt,name=project_path,json=projectPath,proto3" json:"project_path,omitempty"` + // indicates whether to watch for changes to the module + // TODO: rename to automaticRebuilds + Watch bool `protobuf:"varint,4,opt,name=watch,proto3" json:"watch,omitempty"` + Metadata *Metadata `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"` + Schema *schema.Schema `protobuf:"bytes,6,opt,name=schema,proto3" json:"schema,omitempty"` +} + +func (x *BuildRequest) Reset() { + *x = BuildRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BuildRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuildRequest) ProtoMessage() {} + +func (x *BuildRequest) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuildRequest.ProtoReflect.Descriptor instead. +func (*BuildRequest) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{13} +} + +func (x *BuildRequest) GetBuildRequestId() string { + if x != nil { + return x.BuildRequestId + } + return "" +} + +func (x *BuildRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *BuildRequest) GetProjectPath() string { + if x != nil { + return x.ProjectPath + } + return "" +} + +func (x *BuildRequest) GetWatch() bool { + if x != nil { + return x.Watch + } + return false +} + +func (x *BuildRequest) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *BuildRequest) GetSchema() *schema.Schema { + if x != nil { + return x.Schema + } + return nil +} + +type AutoRebuildStarted struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AutoRebuildStarted) Reset() { + *x = AutoRebuildStarted{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AutoRebuildStarted) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AutoRebuildStarted) ProtoMessage() {} + +func (x *AutoRebuildStarted) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AutoRebuildStarted.ProtoReflect.Descriptor instead. +func (*AutoRebuildStarted) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{14} +} + +// Response to a build request. +type BuildResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BuildRequestId *string `protobuf:"bytes,1,opt,name=buildRequestId,proto3,oneof" json:"buildRequestId,omitempty"` + // module schema for the built module + // only set if the build was successful + Module *schema.Module `protobuf:"bytes,2,opt,name=module,proto3,oneof" json:"module,omitempty"` + // paths for files/directories to be deployed + Deploy []string `protobuf:"bytes,3,rep,name=deploy,proto3" json:"deploy,omitempty"` + // errors and warnings encountered during the build + Errors *ErrorList `protobuf:"bytes,4,opt,name=errors,proto3" json:"errors,omitempty"` +} + +func (x *BuildResult) Reset() { + *x = BuildResult{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BuildResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuildResult) ProtoMessage() {} + +func (x *BuildResult) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuildResult.ProtoReflect.Descriptor instead. +func (*BuildResult) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{15} +} + +func (x *BuildResult) GetBuildRequestId() string { + if x != nil && x.BuildRequestId != nil { + return *x.BuildRequestId + } + return "" +} + +func (x *BuildResult) GetModule() *schema.Module { + if x != nil { + return x.Module + } + return nil +} + +func (x *BuildResult) GetDeploy() []string { + if x != nil { + return x.Deploy + } + return nil +} + +func (x *BuildResult) GetErrors() *ErrorList { + if x != nil { + return x.Errors + } + return nil +} + +// Log message from the language service. +type LogMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + Level LogLevel `protobuf:"varint,2,opt,name=level,proto3,enum=xyz.block.ftl.v1.language.LogLevel" json:"level,omitempty"` +} + +func (x *LogMessage) Reset() { + *x = LogMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LogMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LogMessage) ProtoMessage() {} + +func (x *LogMessage) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LogMessage.ProtoReflect.Descriptor instead. +func (*LogMessage) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{16} +} + +func (x *LogMessage) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *LogMessage) GetLevel() LogLevel { + if x != nil { + return x.Level + } + return LogLevel_DEBUG +} + +// Every type of message that can be streamed from the language service for a build. +type BuildEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Event: + // + // *BuildEvent_DependencyUpdate + // *BuildEvent_AutoRebuildStarted + // *BuildEvent_BuildResult + // *BuildEvent_LogMessage + Event isBuildEvent_Event `protobuf_oneof:"event"` +} + +func (x *BuildEvent) Reset() { + *x = BuildEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BuildEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuildEvent) ProtoMessage() {} + +func (x *BuildEvent) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuildEvent.ProtoReflect.Descriptor instead. +func (*BuildEvent) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{17} +} + +func (m *BuildEvent) GetEvent() isBuildEvent_Event { + if m != nil { + return m.Event + } + return nil +} + +func (x *BuildEvent) GetDependencyUpdate() *DependencyUpdate { + if x, ok := x.GetEvent().(*BuildEvent_DependencyUpdate); ok { + return x.DependencyUpdate + } + return nil +} + +func (x *BuildEvent) GetAutoRebuildStarted() *AutoRebuildStarted { + if x, ok := x.GetEvent().(*BuildEvent_AutoRebuildStarted); ok { + return x.AutoRebuildStarted + } + return nil +} + +func (x *BuildEvent) GetBuildResult() *BuildResult { + if x, ok := x.GetEvent().(*BuildEvent_BuildResult); ok { + return x.BuildResult + } + return nil +} + +func (x *BuildEvent) GetLogMessage() *LogMessage { + if x, ok := x.GetEvent().(*BuildEvent_LogMessage); ok { + return x.LogMessage + } + return nil +} + +type isBuildEvent_Event interface { + isBuildEvent_Event() +} + +type BuildEvent_DependencyUpdate struct { + DependencyUpdate *DependencyUpdate `protobuf:"bytes,1,opt,name=dependency_update,json=dependencyUpdate,proto3,oneof"` +} + +type BuildEvent_AutoRebuildStarted struct { + AutoRebuildStarted *AutoRebuildStarted `protobuf:"bytes,2,opt,name=auto_rebuild_started,json=autoRebuildStarted,proto3,oneof"` +} + +type BuildEvent_BuildResult struct { + BuildResult *BuildResult `protobuf:"bytes,3,opt,name=build_result,json=buildResult,proto3,oneof"` +} + +type BuildEvent_LogMessage struct { + LogMessage *LogMessage `protobuf:"bytes,4,opt,name=log_message,json=logMessage,proto3,oneof"` +} + +func (*BuildEvent_DependencyUpdate) isBuildEvent_Event() {} + +func (*BuildEvent_AutoRebuildStarted) isBuildEvent_Event() {} + +func (*BuildEvent_BuildResult) isBuildEvent_Event() {} + +func (*BuildEvent_LogMessage) isBuildEvent_Event() {} + +type GetCreateModuleFlagsResponse_Flag struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Help string `protobuf:"bytes,2,opt,name=help,proto3" json:"help,omitempty"` + Envar *string `protobuf:"bytes,3,opt,name=envar,proto3,oneof" json:"envar,omitempty"` + // short must be a single character + Short *string `protobuf:"bytes,4,opt,name=short,proto3,oneof" json:"short,omitempty"` + Placeholder *string `protobuf:"bytes,5,opt,name=placeholder,proto3,oneof" json:"placeholder,omitempty"` + Default *string `protobuf:"bytes,6,opt,name=default,proto3,oneof" json:"default,omitempty"` +} + +func (x *GetCreateModuleFlagsResponse_Flag) Reset() { + *x = GetCreateModuleFlagsResponse_Flag{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetCreateModuleFlagsResponse_Flag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCreateModuleFlagsResponse_Flag) ProtoMessage() {} + +func (x *GetCreateModuleFlagsResponse_Flag) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_language_language_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCreateModuleFlagsResponse_Flag.ProtoReflect.Descriptor instead. +func (*GetCreateModuleFlagsResponse_Flag) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *GetCreateModuleFlagsResponse_Flag) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GetCreateModuleFlagsResponse_Flag) GetHelp() string { + if x != nil { + return x.Help + } + return "" +} + +func (x *GetCreateModuleFlagsResponse_Flag) GetEnvar() string { + if x != nil && x.Envar != nil { + return *x.Envar + } + return "" +} + +func (x *GetCreateModuleFlagsResponse_Flag) GetShort() string { + if x != nil && x.Short != nil { + return *x.Short + } + return "" +} + +func (x *GetCreateModuleFlagsResponse_Flag) GetPlaceholder() string { + if x != nil && x.Placeholder != nil { + return *x.Placeholder + } + return "" +} + +func (x *GetCreateModuleFlagsResponse_Flag) GetDefault() string { + if x != nil && x.Default != nil { + return *x.Default + } + return "" +} + +var File_xyz_block_ftl_v1_language_language_proto protoreflect.FileDescriptor + +var file_xyz_block_ftl_v1_language_language_proto_rawDesc = []byte{ + 0x0a, 0x28, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, + 0x76, 0x31, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2f, 0x6c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x79, 0x7a, 0x2e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x1a, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, + 0x76, 0x31, 0x2f, 0x66, 0x74, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x24, 0x78, 0x79, + 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x7c, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x40, + 0x0a, 0x10, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x10, + 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x22, 0x65, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x47, + 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6e, 0x6f, 0x47, 0x69, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x06, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x22, 0x39, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x22, 0xcf, 0x02, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, + 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x6c, + 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x6c, 0x61, 0x67, + 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x1a, 0xda, 0x01, 0x0a, 0x04, 0x46, 0x6c, 0x61, 0x67, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x6e, 0x76, 0x61, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x61, 0x72, + 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x25, + 0x0a, 0x0b, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x0b, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, + 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x6e, 0x76, 0x61, 0x72, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x6c, 0x61, + 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x22, 0xb9, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x70, 0x61, 0x74, 0x68, 0x12, 0x4e, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x78, 0x79, + 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, + 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2a, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, + 0x22, 0x16, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6a, 0x0a, 0x13, 0x44, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, + 0x61, 0x74, 0x68, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x30, 0x0a, 0x14, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, + 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x10, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x73, 0x22, 0xe0, 0x01, 0x0a, 0x1a, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, + 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x48, 0x00, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, + 0x01, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x48, 0x01, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x88, 0x01, 0x01, 0x42, + 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x09, 0x0a, 0x07, + 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x1d, 0x0a, 0x1b, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xdc, 0x01, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, + 0x73, 0x67, 0x12, 0x33, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x41, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2b, 0x0a, 0x0a, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, + 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x02, 0x22, 0x45, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, + 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0xfd, 0x01, 0x0a, + 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, + 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, + 0x77, 0x61, 0x74, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x77, 0x61, 0x74, + 0x63, 0x68, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x14, 0x0a, 0x12, + 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x22, 0xec, 0x01, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x2b, 0x0a, 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, + 0x3c, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x48, 0x01, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, + 0x06, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x64, + 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x12, 0x3c, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x06, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x22, 0x61, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x39, 0x0a, 0x05, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x22, 0xeb, 0x02, 0x0a, 0x0a, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x5a, 0x0a, 0x11, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, + 0x79, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, + 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, + 0x64, 0x65, 0x6e, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x10, 0x64, + 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x61, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, + 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, + 0x61, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x48, 0x00, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x48, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x2e, 0x4c, 0x6f, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x6c, + 0x6f, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x2a, 0x34, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, + 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, + 0x4f, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x02, 0x12, 0x09, 0x0a, + 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x32, 0xae, 0x05, 0x0a, 0x0f, 0x4c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x04, + 0x50, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x87, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x6c, 0x61, 0x67, + 0x73, 0x12, 0x36, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x6c, 0x61, + 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x78, 0x79, 0x7a, 0x2e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x12, 0x2e, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, + 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, + 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2e, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x84, 0x01, 0x0a, 0x13, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x35, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, + 0x0a, 0x05, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x27, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, + 0x2e, 0x76, 0x31, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x52, 0x50, 0x01, 0x5a, 0x4e, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x42, 0x44, 0x35, 0x34, 0x35, + 0x36, 0x36, 0x39, 0x37, 0x35, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x3b, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_xyz_block_ftl_v1_language_language_proto_rawDescOnce sync.Once + file_xyz_block_ftl_v1_language_language_proto_rawDescData = file_xyz_block_ftl_v1_language_language_proto_rawDesc +) + +func file_xyz_block_ftl_v1_language_language_proto_rawDescGZIP() []byte { + file_xyz_block_ftl_v1_language_language_proto_rawDescOnce.Do(func() { + file_xyz_block_ftl_v1_language_language_proto_rawDescData = protoimpl.X.CompressGZIP(file_xyz_block_ftl_v1_language_language_proto_rawDescData) + }) + return file_xyz_block_ftl_v1_language_language_proto_rawDescData +} + +var file_xyz_block_ftl_v1_language_language_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_xyz_block_ftl_v1_language_language_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_xyz_block_ftl_v1_language_language_proto_goTypes = []any{ + (LogLevel)(0), // 0: xyz.block.ftl.v1.language.LogLevel + (Error_ErrorLevel)(0), // 1: xyz.block.ftl.v1.language.Error.ErrorLevel + (*Metadata)(nil), // 2: xyz.block.ftl.v1.language.Metadata + (*ProjectConfig)(nil), // 3: xyz.block.ftl.v1.language.ProjectConfig + (*GetCreateModuleFlagsRequest)(nil), // 4: xyz.block.ftl.v1.language.GetCreateModuleFlagsRequest + (*GetCreateModuleFlagsResponse)(nil), // 5: xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse + (*CreateModuleRequest)(nil), // 6: xyz.block.ftl.v1.language.CreateModuleRequest + (*CreateModuleResponse)(nil), // 7: xyz.block.ftl.v1.language.CreateModuleResponse + (*DependenciesRequest)(nil), // 8: xyz.block.ftl.v1.language.DependenciesRequest + (*DependenciesResponse)(nil), // 9: xyz.block.ftl.v1.language.DependenciesResponse + (*DependencyUpdate)(nil), // 10: xyz.block.ftl.v1.language.DependencyUpdate + (*BuildContextUpdatedRequest)(nil), // 11: xyz.block.ftl.v1.language.BuildContextUpdatedRequest + (*BuildContextUpdatedResponse)(nil), // 12: xyz.block.ftl.v1.language.BuildContextUpdatedResponse + (*Error)(nil), // 13: xyz.block.ftl.v1.language.Error + (*ErrorList)(nil), // 14: xyz.block.ftl.v1.language.ErrorList + (*BuildRequest)(nil), // 15: xyz.block.ftl.v1.language.BuildRequest + (*AutoRebuildStarted)(nil), // 16: xyz.block.ftl.v1.language.AutoRebuildStarted + (*BuildResult)(nil), // 17: xyz.block.ftl.v1.language.BuildResult + (*LogMessage)(nil), // 18: xyz.block.ftl.v1.language.LogMessage + (*BuildEvent)(nil), // 19: xyz.block.ftl.v1.language.BuildEvent + (*GetCreateModuleFlagsResponse_Flag)(nil), // 20: xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse.Flag + (*anypb.Any)(nil), // 21: google.protobuf.Any + (*schema.Schema)(nil), // 22: xyz.block.ftl.v1.schema.Schema + (*schema.Position)(nil), // 23: xyz.block.ftl.v1.schema.Position + (*schema.Module)(nil), // 24: xyz.block.ftl.v1.schema.Module + (*v1.PingRequest)(nil), // 25: xyz.block.ftl.v1.PingRequest + (*v1.PingResponse)(nil), // 26: xyz.block.ftl.v1.PingResponse +} +var file_xyz_block_ftl_v1_language_language_proto_depIdxs = []int32{ + 21, // 0: xyz.block.ftl.v1.language.Metadata.LanguageMetadata:type_name -> google.protobuf.Any + 20, // 1: xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse.flags:type_name -> xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse.Flag + 3, // 2: xyz.block.ftl.v1.language.CreateModuleRequest.projectConfig:type_name -> xyz.block.ftl.v1.language.ProjectConfig + 21, // 3: xyz.block.ftl.v1.language.CreateModuleRequest.Flags:type_name -> google.protobuf.Any + 2, // 4: xyz.block.ftl.v1.language.DependenciesRequest.metadata:type_name -> xyz.block.ftl.v1.language.Metadata + 2, // 5: xyz.block.ftl.v1.language.BuildContextUpdatedRequest.metadata:type_name -> xyz.block.ftl.v1.language.Metadata + 22, // 6: xyz.block.ftl.v1.language.BuildContextUpdatedRequest.schema:type_name -> xyz.block.ftl.v1.schema.Schema + 23, // 7: xyz.block.ftl.v1.language.Error.pos:type_name -> xyz.block.ftl.v1.schema.Position + 1, // 8: xyz.block.ftl.v1.language.Error.level:type_name -> xyz.block.ftl.v1.language.Error.ErrorLevel + 13, // 9: xyz.block.ftl.v1.language.ErrorList.errors:type_name -> xyz.block.ftl.v1.language.Error + 2, // 10: xyz.block.ftl.v1.language.BuildRequest.metadata:type_name -> xyz.block.ftl.v1.language.Metadata + 22, // 11: xyz.block.ftl.v1.language.BuildRequest.schema:type_name -> xyz.block.ftl.v1.schema.Schema + 24, // 12: xyz.block.ftl.v1.language.BuildResult.module:type_name -> xyz.block.ftl.v1.schema.Module + 14, // 13: xyz.block.ftl.v1.language.BuildResult.errors:type_name -> xyz.block.ftl.v1.language.ErrorList + 0, // 14: xyz.block.ftl.v1.language.LogMessage.level:type_name -> xyz.block.ftl.v1.language.LogLevel + 10, // 15: xyz.block.ftl.v1.language.BuildEvent.dependency_update:type_name -> xyz.block.ftl.v1.language.DependencyUpdate + 16, // 16: xyz.block.ftl.v1.language.BuildEvent.auto_rebuild_started:type_name -> xyz.block.ftl.v1.language.AutoRebuildStarted + 17, // 17: xyz.block.ftl.v1.language.BuildEvent.build_result:type_name -> xyz.block.ftl.v1.language.BuildResult + 18, // 18: xyz.block.ftl.v1.language.BuildEvent.log_message:type_name -> xyz.block.ftl.v1.language.LogMessage + 25, // 19: xyz.block.ftl.v1.language.LanguageService.Ping:input_type -> xyz.block.ftl.v1.PingRequest + 4, // 20: xyz.block.ftl.v1.language.LanguageService.GetCreateModuleFlags:input_type -> xyz.block.ftl.v1.language.GetCreateModuleFlagsRequest + 6, // 21: xyz.block.ftl.v1.language.LanguageService.CreateModule:input_type -> xyz.block.ftl.v1.language.CreateModuleRequest + 8, // 22: xyz.block.ftl.v1.language.LanguageService.GetDependencies:input_type -> xyz.block.ftl.v1.language.DependenciesRequest + 11, // 23: xyz.block.ftl.v1.language.LanguageService.BuildContextUpdated:input_type -> xyz.block.ftl.v1.language.BuildContextUpdatedRequest + 15, // 24: xyz.block.ftl.v1.language.LanguageService.Build:input_type -> xyz.block.ftl.v1.language.BuildRequest + 26, // 25: xyz.block.ftl.v1.language.LanguageService.Ping:output_type -> xyz.block.ftl.v1.PingResponse + 5, // 26: xyz.block.ftl.v1.language.LanguageService.GetCreateModuleFlags:output_type -> xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse + 7, // 27: xyz.block.ftl.v1.language.LanguageService.CreateModule:output_type -> xyz.block.ftl.v1.language.CreateModuleResponse + 9, // 28: xyz.block.ftl.v1.language.LanguageService.GetDependencies:output_type -> xyz.block.ftl.v1.language.DependenciesResponse + 12, // 29: xyz.block.ftl.v1.language.LanguageService.BuildContextUpdated:output_type -> xyz.block.ftl.v1.language.BuildContextUpdatedResponse + 19, // 30: xyz.block.ftl.v1.language.LanguageService.Build:output_type -> xyz.block.ftl.v1.language.BuildEvent + 25, // [25:31] is the sub-list for method output_type + 19, // [19:25] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name +} + +func init() { file_xyz_block_ftl_v1_language_language_proto_init() } +func file_xyz_block_ftl_v1_language_language_proto_init() { + if File_xyz_block_ftl_v1_language_language_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_xyz_block_ftl_v1_language_language_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*Metadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*ProjectConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*GetCreateModuleFlagsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*GetCreateModuleFlagsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*CreateModuleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*CreateModuleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[6].Exporter = func(v any, i int) any { + switch v := v.(*DependenciesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[7].Exporter = func(v any, i int) any { + switch v := v.(*DependenciesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[8].Exporter = func(v any, i int) any { + switch v := v.(*DependencyUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[9].Exporter = func(v any, i int) any { + switch v := v.(*BuildContextUpdatedRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[10].Exporter = func(v any, i int) any { + switch v := v.(*BuildContextUpdatedResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[11].Exporter = func(v any, i int) any { + switch v := v.(*Error); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[12].Exporter = func(v any, i int) any { + switch v := v.(*ErrorList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[13].Exporter = func(v any, i int) any { + switch v := v.(*BuildRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[14].Exporter = func(v any, i int) any { + switch v := v.(*AutoRebuildStarted); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[15].Exporter = func(v any, i int) any { + switch v := v.(*BuildResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[16].Exporter = func(v any, i int) any { + switch v := v.(*LogMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[17].Exporter = func(v any, i int) any { + switch v := v.(*BuildEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[18].Exporter = func(v any, i int) any { + switch v := v.(*GetCreateModuleFlagsResponse_Flag); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[9].OneofWrappers = []any{} + file_xyz_block_ftl_v1_language_language_proto_msgTypes[15].OneofWrappers = []any{} + file_xyz_block_ftl_v1_language_language_proto_msgTypes[17].OneofWrappers = []any{ + (*BuildEvent_DependencyUpdate)(nil), + (*BuildEvent_AutoRebuildStarted)(nil), + (*BuildEvent_BuildResult)(nil), + (*BuildEvent_LogMessage)(nil), } + file_xyz_block_ftl_v1_language_language_proto_msgTypes[18].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_xyz_block_ftl_v1_language_language_proto_rawDesc, - NumEnums: 1, - NumMessages: 2, + NumEnums: 2, + NumMessages: 19, NumExtensions: 0, - NumServices: 0, + NumServices: 1, }, GoTypes: file_xyz_block_ftl_v1_language_language_proto_goTypes, DependencyIndexes: file_xyz_block_ftl_v1_language_language_proto_depIdxs, diff --git a/backend/protos/xyz/block/ftl/v1/language/language.proto b/backend/protos/xyz/block/ftl/v1/language/language.proto index 951ee4b34e..09960f2f4b 100644 --- a/backend/protos/xyz/block/ftl/v1/language/language.proto +++ b/backend/protos/xyz/block/ftl/v1/language/language.proto @@ -2,11 +2,87 @@ syntax = "proto3"; package xyz.block.ftl.v1.language; +import "google/protobuf/any.proto"; +import "xyz/block/ftl/v1/ftl.proto"; import "xyz/block/ftl/v1/schema/schema.proto"; option go_package = "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/language;languagepb"; option java_multiple_files = true; +message Metadata { + // Universal metadata + string name = 1; + string language = 2; + + // Language metadata contains any metadata specific to a specific language. + // TODO: revisit type... + google.protobuf.Any LanguageMetadata = 3; +} + +message ProjectConfig { + string path = 1; + string name = 2; + bool noGit = 3; + bool hermit = 4; +} + +// TODO: docs +message GetCreateModuleFlagsRequest { + string language = 1; +} + +message GetCreateModuleFlagsResponse { + message Flag { + string name = 1; + string help = 2; + optional string envar = 3; + // short must be a single character + optional string short = 4; + optional string placeholder = 5; + optional string default = 6; + } + repeated Flag flags = 1; +} + +// Request to create a new module. +message CreateModuleRequest { + string name = 1; + string path = 2; + + ProjectConfig projectConfig = 3; + + // TODO: revisit type... + google.protobuf.Any Flags = 4; +} + +// Response to a create module request. +message CreateModuleResponse {} + +message DependenciesRequest { + string path = 1; + Metadata metadata = 2; +} + +message DependenciesResponse { + repeated string modules = 1; +} + +// Response to a dependency extraction request. +message DependencyUpdate { + repeated string modules = 1; +} + +// TODO: docs +message BuildContextUpdatedRequest { + // TODO: explain + string buildRequestId = 1; + + optional Metadata metadata = 2; + optional schema.Schema schema = 3; +} + +message BuildContextUpdatedResponse {} + message Error { enum ErrorLevel { INFO = 0; @@ -23,3 +99,103 @@ message Error { message ErrorList { repeated Error errors = 1; } + +// Request to build a module. +message BuildRequest { + // TODO: explain + string buildRequestId = 1; + + // the root path for the module + string path = 2; + // the root path for the FTL project + string project_path = 3; + // indicates whether to watch for changes to the module + // TODO: rename to automaticRebuilds + bool watch = 4; + + Metadata metadata = 5; + schema.Schema schema = 6; +} + +message AutoRebuildStarted {} + +// Response to a build request. +message BuildResult { + optional string buildRequestId = 1; + // module schema for the built module + // only set if the build was successful + optional schema.Module module = 2; + // paths for files/directories to be deployed + repeated string deploy = 3; + // errors and warnings encountered during the build + ErrorList errors = 4; + + // TODO: dockerfile or docker image name... + // TODO: add a way to return what schema / metadata version this was based on +} + +enum LogLevel { + DEBUG = 0; + INFO = 1; + WARN = 2; + ERROR = 3; +} + +// Log message from the language service. +message LogMessage { + string message = 1; + LogLevel level = 2; +} + +// Every type of message that can be streamed from the language service for a build. +message BuildEvent { + oneof event { + DependencyUpdate dependency_update = 1; + AutoRebuildStarted auto_rebuild_started = 2; + BuildResult build_result = 3; + LogMessage log_message = 4; + } +} + +// LanguageService allows a plugin to add support for a programming language. +service LanguageService { + // Ping service for readiness. + rpc Ping(xyz.block.ftl.v1.PingRequest) returns (xyz.block.ftl.v1.PingResponse) { + option idempotency_level = NO_SIDE_EFFECTS; + } + + // TODO: docs + rpc GetCreateModuleFlags(GetCreateModuleFlagsRequest) returns (GetCreateModuleFlagsResponse); + + // Generates files for a new empty module with the requested name + rpc CreateModule(CreateModuleRequest) returns (CreateModuleResponse); + + // Extract dependencies for a module + rpc GetDependencies(DependenciesRequest) returns (DependenciesResponse); + + // MetadataUpdated is called whenever the metadata for a module is updated. + // TODO: explain this only happens while watching? + // TODO: merge with schema updated... to avoid double builds if both change + // rpc MetadataUpdated(MetadataUpdatedRequest) returns (MetadataUpdatedResponse); + + // SchemaUpdated is called whenever the relevant part of a schema is updated. + // + // The schema is not the full schema, rather it only modules in this module's dependency graph. + // It does not contain the schema for this plugin's module. + // + // Language plugins should hold on to the latest schema they have seen. + // SchemaUpdated is called: + // - after ExtractDependencies and before Build (if there are any dependencies) + // - when a dependant module is updated + // - when the module's dependancies change + // + // TODO: explain this only happens while watching? + // rpc SchemaUpdated(SchemaUpdatedRequest) returns (SchemaUpdatedResponse); + + rpc BuildContextUpdated(BuildContextUpdatedRequest) returns (BuildContextUpdatedResponse); + + // Build the module + // The request can also indicate whether the plugin should watch for changes to the module and automatically rebuild + // The response stream can send LogMessages and BuildResults, and ends with a BuildResponse + rpc Build(BuildRequest) returns (stream BuildEvent); +} diff --git a/backend/protos/xyz/block/ftl/v1/language/languagepbconnect/language.connect.go b/backend/protos/xyz/block/ftl/v1/language/languagepbconnect/language.connect.go new file mode 100644 index 0000000000..3a12e790f1 --- /dev/null +++ b/backend/protos/xyz/block/ftl/v1/language/languagepbconnect/language.connect.go @@ -0,0 +1,256 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: xyz/block/ftl/v1/language/language.proto + +package languagepbconnect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" + language "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/language" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_7_0 + +const ( + // LanguageServiceName is the fully-qualified name of the LanguageService service. + LanguageServiceName = "xyz.block.ftl.v1.language.LanguageService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // LanguageServicePingProcedure is the fully-qualified name of the LanguageService's Ping RPC. + LanguageServicePingProcedure = "/xyz.block.ftl.v1.language.LanguageService/Ping" + // LanguageServiceGetCreateModuleFlagsProcedure is the fully-qualified name of the LanguageService's + // GetCreateModuleFlags RPC. + LanguageServiceGetCreateModuleFlagsProcedure = "/xyz.block.ftl.v1.language.LanguageService/GetCreateModuleFlags" + // LanguageServiceCreateModuleProcedure is the fully-qualified name of the LanguageService's + // CreateModule RPC. + LanguageServiceCreateModuleProcedure = "/xyz.block.ftl.v1.language.LanguageService/CreateModule" + // LanguageServiceGetDependenciesProcedure is the fully-qualified name of the LanguageService's + // GetDependencies RPC. + LanguageServiceGetDependenciesProcedure = "/xyz.block.ftl.v1.language.LanguageService/GetDependencies" + // LanguageServiceBuildContextUpdatedProcedure is the fully-qualified name of the LanguageService's + // BuildContextUpdated RPC. + LanguageServiceBuildContextUpdatedProcedure = "/xyz.block.ftl.v1.language.LanguageService/BuildContextUpdated" + // LanguageServiceBuildProcedure is the fully-qualified name of the LanguageService's Build RPC. + LanguageServiceBuildProcedure = "/xyz.block.ftl.v1.language.LanguageService/Build" +) + +// LanguageServiceClient is a client for the xyz.block.ftl.v1.language.LanguageService service. +type LanguageServiceClient interface { + // Ping service for readiness. + Ping(context.Context, *connect.Request[v1.PingRequest]) (*connect.Response[v1.PingResponse], error) + // TODO: docs + GetCreateModuleFlags(context.Context, *connect.Request[language.GetCreateModuleFlagsRequest]) (*connect.Response[language.GetCreateModuleFlagsResponse], error) + // Generates files for a new empty module with the requested name + CreateModule(context.Context, *connect.Request[language.CreateModuleRequest]) (*connect.Response[language.CreateModuleResponse], error) + // Extract dependencies for a module + GetDependencies(context.Context, *connect.Request[language.DependenciesRequest]) (*connect.Response[language.DependenciesResponse], error) + BuildContextUpdated(context.Context, *connect.Request[language.BuildContextUpdatedRequest]) (*connect.Response[language.BuildContextUpdatedResponse], error) + // Build the module + // The request can also indicate whether the plugin should watch for changes to the module and automatically rebuild + // The response stream can send LogMessages and BuildResults, and ends with a BuildResponse + Build(context.Context, *connect.Request[language.BuildRequest]) (*connect.ServerStreamForClient[language.BuildEvent], error) +} + +// NewLanguageServiceClient constructs a client for the xyz.block.ftl.v1.language.LanguageService +// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for +// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply +// the connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewLanguageServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) LanguageServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + return &languageServiceClient{ + ping: connect.NewClient[v1.PingRequest, v1.PingResponse]( + httpClient, + baseURL+LanguageServicePingProcedure, + connect.WithIdempotency(connect.IdempotencyNoSideEffects), + connect.WithClientOptions(opts...), + ), + getCreateModuleFlags: connect.NewClient[language.GetCreateModuleFlagsRequest, language.GetCreateModuleFlagsResponse]( + httpClient, + baseURL+LanguageServiceGetCreateModuleFlagsProcedure, + opts..., + ), + createModule: connect.NewClient[language.CreateModuleRequest, language.CreateModuleResponse]( + httpClient, + baseURL+LanguageServiceCreateModuleProcedure, + opts..., + ), + getDependencies: connect.NewClient[language.DependenciesRequest, language.DependenciesResponse]( + httpClient, + baseURL+LanguageServiceGetDependenciesProcedure, + opts..., + ), + buildContextUpdated: connect.NewClient[language.BuildContextUpdatedRequest, language.BuildContextUpdatedResponse]( + httpClient, + baseURL+LanguageServiceBuildContextUpdatedProcedure, + opts..., + ), + build: connect.NewClient[language.BuildRequest, language.BuildEvent]( + httpClient, + baseURL+LanguageServiceBuildProcedure, + opts..., + ), + } +} + +// languageServiceClient implements LanguageServiceClient. +type languageServiceClient struct { + ping *connect.Client[v1.PingRequest, v1.PingResponse] + getCreateModuleFlags *connect.Client[language.GetCreateModuleFlagsRequest, language.GetCreateModuleFlagsResponse] + createModule *connect.Client[language.CreateModuleRequest, language.CreateModuleResponse] + getDependencies *connect.Client[language.DependenciesRequest, language.DependenciesResponse] + buildContextUpdated *connect.Client[language.BuildContextUpdatedRequest, language.BuildContextUpdatedResponse] + build *connect.Client[language.BuildRequest, language.BuildEvent] +} + +// Ping calls xyz.block.ftl.v1.language.LanguageService.Ping. +func (c *languageServiceClient) Ping(ctx context.Context, req *connect.Request[v1.PingRequest]) (*connect.Response[v1.PingResponse], error) { + return c.ping.CallUnary(ctx, req) +} + +// GetCreateModuleFlags calls xyz.block.ftl.v1.language.LanguageService.GetCreateModuleFlags. +func (c *languageServiceClient) GetCreateModuleFlags(ctx context.Context, req *connect.Request[language.GetCreateModuleFlagsRequest]) (*connect.Response[language.GetCreateModuleFlagsResponse], error) { + return c.getCreateModuleFlags.CallUnary(ctx, req) +} + +// CreateModule calls xyz.block.ftl.v1.language.LanguageService.CreateModule. +func (c *languageServiceClient) CreateModule(ctx context.Context, req *connect.Request[language.CreateModuleRequest]) (*connect.Response[language.CreateModuleResponse], error) { + return c.createModule.CallUnary(ctx, req) +} + +// GetDependencies calls xyz.block.ftl.v1.language.LanguageService.GetDependencies. +func (c *languageServiceClient) GetDependencies(ctx context.Context, req *connect.Request[language.DependenciesRequest]) (*connect.Response[language.DependenciesResponse], error) { + return c.getDependencies.CallUnary(ctx, req) +} + +// BuildContextUpdated calls xyz.block.ftl.v1.language.LanguageService.BuildContextUpdated. +func (c *languageServiceClient) BuildContextUpdated(ctx context.Context, req *connect.Request[language.BuildContextUpdatedRequest]) (*connect.Response[language.BuildContextUpdatedResponse], error) { + return c.buildContextUpdated.CallUnary(ctx, req) +} + +// Build calls xyz.block.ftl.v1.language.LanguageService.Build. +func (c *languageServiceClient) Build(ctx context.Context, req *connect.Request[language.BuildRequest]) (*connect.ServerStreamForClient[language.BuildEvent], error) { + return c.build.CallServerStream(ctx, req) +} + +// LanguageServiceHandler is an implementation of the xyz.block.ftl.v1.language.LanguageService +// service. +type LanguageServiceHandler interface { + // Ping service for readiness. + Ping(context.Context, *connect.Request[v1.PingRequest]) (*connect.Response[v1.PingResponse], error) + // TODO: docs + GetCreateModuleFlags(context.Context, *connect.Request[language.GetCreateModuleFlagsRequest]) (*connect.Response[language.GetCreateModuleFlagsResponse], error) + // Generates files for a new empty module with the requested name + CreateModule(context.Context, *connect.Request[language.CreateModuleRequest]) (*connect.Response[language.CreateModuleResponse], error) + // Extract dependencies for a module + GetDependencies(context.Context, *connect.Request[language.DependenciesRequest]) (*connect.Response[language.DependenciesResponse], error) + BuildContextUpdated(context.Context, *connect.Request[language.BuildContextUpdatedRequest]) (*connect.Response[language.BuildContextUpdatedResponse], error) + // Build the module + // The request can also indicate whether the plugin should watch for changes to the module and automatically rebuild + // The response stream can send LogMessages and BuildResults, and ends with a BuildResponse + Build(context.Context, *connect.Request[language.BuildRequest], *connect.ServerStream[language.BuildEvent]) error +} + +// NewLanguageServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewLanguageServiceHandler(svc LanguageServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + languageServicePingHandler := connect.NewUnaryHandler( + LanguageServicePingProcedure, + svc.Ping, + connect.WithIdempotency(connect.IdempotencyNoSideEffects), + connect.WithHandlerOptions(opts...), + ) + languageServiceGetCreateModuleFlagsHandler := connect.NewUnaryHandler( + LanguageServiceGetCreateModuleFlagsProcedure, + svc.GetCreateModuleFlags, + opts..., + ) + languageServiceCreateModuleHandler := connect.NewUnaryHandler( + LanguageServiceCreateModuleProcedure, + svc.CreateModule, + opts..., + ) + languageServiceGetDependenciesHandler := connect.NewUnaryHandler( + LanguageServiceGetDependenciesProcedure, + svc.GetDependencies, + opts..., + ) + languageServiceBuildContextUpdatedHandler := connect.NewUnaryHandler( + LanguageServiceBuildContextUpdatedProcedure, + svc.BuildContextUpdated, + opts..., + ) + languageServiceBuildHandler := connect.NewServerStreamHandler( + LanguageServiceBuildProcedure, + svc.Build, + opts..., + ) + return "/xyz.block.ftl.v1.language.LanguageService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case LanguageServicePingProcedure: + languageServicePingHandler.ServeHTTP(w, r) + case LanguageServiceGetCreateModuleFlagsProcedure: + languageServiceGetCreateModuleFlagsHandler.ServeHTTP(w, r) + case LanguageServiceCreateModuleProcedure: + languageServiceCreateModuleHandler.ServeHTTP(w, r) + case LanguageServiceGetDependenciesProcedure: + languageServiceGetDependenciesHandler.ServeHTTP(w, r) + case LanguageServiceBuildContextUpdatedProcedure: + languageServiceBuildContextUpdatedHandler.ServeHTTP(w, r) + case LanguageServiceBuildProcedure: + languageServiceBuildHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedLanguageServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedLanguageServiceHandler struct{} + +func (UnimplementedLanguageServiceHandler) Ping(context.Context, *connect.Request[v1.PingRequest]) (*connect.Response[v1.PingResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("xyz.block.ftl.v1.language.LanguageService.Ping is not implemented")) +} + +func (UnimplementedLanguageServiceHandler) GetCreateModuleFlags(context.Context, *connect.Request[language.GetCreateModuleFlagsRequest]) (*connect.Response[language.GetCreateModuleFlagsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("xyz.block.ftl.v1.language.LanguageService.GetCreateModuleFlags is not implemented")) +} + +func (UnimplementedLanguageServiceHandler) CreateModule(context.Context, *connect.Request[language.CreateModuleRequest]) (*connect.Response[language.CreateModuleResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("xyz.block.ftl.v1.language.LanguageService.CreateModule is not implemented")) +} + +func (UnimplementedLanguageServiceHandler) GetDependencies(context.Context, *connect.Request[language.DependenciesRequest]) (*connect.Response[language.DependenciesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("xyz.block.ftl.v1.language.LanguageService.GetDependencies is not implemented")) +} + +func (UnimplementedLanguageServiceHandler) BuildContextUpdated(context.Context, *connect.Request[language.BuildContextUpdatedRequest]) (*connect.Response[language.BuildContextUpdatedResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("xyz.block.ftl.v1.language.LanguageService.BuildContextUpdated is not implemented")) +} + +func (UnimplementedLanguageServiceHandler) Build(context.Context, *connect.Request[language.BuildRequest], *connect.ServerStream[language.BuildEvent]) error { + return connect.NewError(connect.CodeUnimplemented, errors.New("xyz.block.ftl.v1.language.LanguageService.Build is not implemented")) +} diff --git a/frontend/cli/main.go b/frontend/cli/main.go index 240191565c..52b65646eb 100644 --- a/frontend/cli/main.go +++ b/frontend/cli/main.go @@ -79,13 +79,15 @@ type CLI struct { var cli CLI func main() { - ctx, cancel := context.WithCancel(context.Background()) + csm := ¤tStatusManager{} app := createKongApplication(&cli, csm) - app.FatalIfErrorf(prepareNewCmd(ctx, app, os.Args[1:])) + // TODO: fix ctx without a logger... + app.FatalIfErrorf(prepareNewCmd(log.ContextWithNewDefaultLogger(context.Background()), app, os.Args[1:])) kctx, err := app.Parse(os.Args[1:]) app.FatalIfErrorf(err) + ctx, cancel := context.WithCancel(context.Background()) if !cli.Plain { sm := terminal.NewStatusManager(ctx) csm.statusManager = optional.Some(sm) diff --git a/frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_connect.ts b/frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_connect.ts new file mode 100644 index 0000000000..da640cee3d --- /dev/null +++ b/frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_connect.ts @@ -0,0 +1,98 @@ +// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts" +// @generated from file xyz/block/ftl/v1/language.go/language.proto (package xyz.block.ftl.v1.language, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import { PingRequest, PingResponse } from "../ftl_pb.js"; +import { MethodIdempotency, MethodKind } from "@bufbuild/protobuf"; +import { BuildEvent, BuildRequest, CreateModuleRequest, CreateModuleResponse, DependenciesRequest, DependenciesResponse, MetadataUpdatedRequest, MetadataUpdatedResponse, SchemaUpdatedRequest, SchemaUpdatedResponse } from "./language_pb.js"; + +/** + * LanguageService allows a plugin to add support for a programming language. + * + * @generated from service xyz.block.ftl.v1.language.LanguageService + */ +export const LanguageService = { + typeName: "xyz.block.ftl.v1.language.LanguageService", + methods: { + /** + * Ping service for readiness. + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.Ping + */ + ping: { + name: "Ping", + I: PingRequest, + O: PingResponse, + kind: MethodKind.Unary, + idempotency: MethodIdempotency.NoSideEffects, + }, + /** + * Generates files for a new empty module with the requested name + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.CreateModule + */ + createModule: { + name: "CreateModule", + I: CreateModuleRequest, + O: CreateModuleResponse, + kind: MethodKind.Unary, + }, + /** + * Extract dependencies for a module + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.GetDependencies + */ + getDependencies: { + name: "GetDependencies", + I: DependenciesRequest, + O: DependenciesResponse, + kind: MethodKind.Unary, + }, + /** + * MetadataUpdated is called whenever the metadata for a module is updated. + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.MetadataUpdated + */ + metadataUpdated: { + name: "MetadataUpdated", + I: MetadataUpdatedRequest, + O: MetadataUpdatedResponse, + kind: MethodKind.Unary, + }, + /** + * SchemaUpdated is called whenever the relevant part of a schema is updated. + * + * The schema is not the full schema, rather it only modules in this module's dependency graph. + * It does not contain the schema for this plugin's module. + * + * Language plugins should hold on to the latest schema they have seen. + * SchemaUpdated is called: + * - after ExtractDependencies and before Build (if there are any dependencies) + * - when a dependant module is updated + * - when the module's dependancies change + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.SchemaUpdated + */ + schemaUpdated: { + name: "SchemaUpdated", + I: SchemaUpdatedRequest, + O: SchemaUpdatedResponse, + kind: MethodKind.Unary, + }, + /** + * Build the module + * The request can also indicate whether the plugin should watch for changes to the module and automatically rebuild + * The response stream can send LogMessages and BuildResults, and ends with a BuildResponse + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.Build + */ + build: { + name: "Build", + I: BuildRequest, + O: BuildEvent, + kind: MethodKind.ServerStreaming, + }, + } +} as const; + diff --git a/frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_pb.ts b/frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_pb.ts new file mode 100644 index 0000000000..ec78ef18ae --- /dev/null +++ b/frontend/console/src/protos/xyz/block/ftl/v1/language.go/language_pb.ts @@ -0,0 +1,770 @@ +// @generated by protoc-gen-es v1.10.0 with parameter "target=ts" +// @generated from file xyz/block/ftl/v1/language.go/language.proto (package xyz.block.ftl.v1.language, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; +import { Any, Message, proto3, protoInt64 } from "@bufbuild/protobuf"; +import { Module, Position, Schema } from "../schema/schema_pb.js"; + +/** + * @generated from enum xyz.block.ftl.v1.language.LogLevel + */ +export enum LogLevel { + /** + * @generated from enum value: DEBUG = 0; + */ + DEBUG = 0, + + /** + * @generated from enum value: INFO = 1; + */ + INFO = 1, + + /** + * @generated from enum value: WARN = 2; + */ + WARN = 2, + + /** + * @generated from enum value: ERROR = 3; + */ + ERROR = 3, +} +// Retrieve enum metadata with: proto3.getEnumType(LogLevel) +proto3.util.setEnumType(LogLevel, "xyz.block.ftl.v1.language.LogLevel", [ + { no: 0, name: "DEBUG" }, + { no: 1, name: "INFO" }, + { no: 2, name: "WARN" }, + { no: 3, name: "ERROR" }, +]); + +/** + * Log message from the language service. + * + * @generated from message xyz.block.ftl.v1.language.LogMessage + */ +export class LogMessage extends Message { + /** + * @generated from field: string message = 1; + */ + message = ""; + + /** + * @generated from field: xyz.block.ftl.v1.language.LogLevel level = 2; + */ + level = LogLevel.DEBUG; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.LogMessage"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "message", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "level", kind: "enum", T: proto3.getEnumType(LogLevel) }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): LogMessage { + return new LogMessage().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): LogMessage { + return new LogMessage().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): LogMessage { + return new LogMessage().fromJsonString(jsonString, options); + } + + static equals(a: LogMessage | PlainMessage | undefined, b: LogMessage | PlainMessage | undefined): boolean { + return proto3.util.equals(LogMessage, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.Metadata + */ +export class Metadata extends Message { + /** + * Universal metadata + * + * @generated from field: string name = 1; + */ + name = ""; + + /** + * Language metadata contains any metadata specific to a specific language. + * + * @generated from field: repeated google.protobuf.Any LanguageMetadata = 2; + */ + LanguageMetadata: Any[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.Metadata"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "LanguageMetadata", kind: "message", T: Any, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Metadata { + return new Metadata().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Metadata { + return new Metadata().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Metadata { + return new Metadata().fromJsonString(jsonString, options); + } + + static equals(a: Metadata | PlainMessage | undefined, b: Metadata | PlainMessage | undefined): boolean { + return proto3.util.equals(Metadata, a, b); + } +} + +/** + * Request to create a new module. + * + * @generated from message xyz.block.ftl.v1.language.CreateModuleRequest + */ +export class CreateModuleRequest extends Message { + /** + * @generated from field: string name = 1; + */ + name = ""; + + /** + * @generated from field: string path = 2; + */ + path = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.CreateModuleRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): CreateModuleRequest { + return new CreateModuleRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): CreateModuleRequest { + return new CreateModuleRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): CreateModuleRequest { + return new CreateModuleRequest().fromJsonString(jsonString, options); + } + + static equals(a: CreateModuleRequest | PlainMessage | undefined, b: CreateModuleRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(CreateModuleRequest, a, b); + } +} + +/** + * Response to a create module request. + * + * @generated from message xyz.block.ftl.v1.language.CreateModuleResponse + */ +export class CreateModuleResponse extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.CreateModuleResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): CreateModuleResponse { + return new CreateModuleResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): CreateModuleResponse { + return new CreateModuleResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): CreateModuleResponse { + return new CreateModuleResponse().fromJsonString(jsonString, options); + } + + static equals(a: CreateModuleResponse | PlainMessage | undefined, b: CreateModuleResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(CreateModuleResponse, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.DependenciesRequest + */ +export class DependenciesRequest extends Message { + /** + * @generated from field: string path = 1; + */ + path = ""; + + /** + * @generated from field: xyz.block.ftl.v1.language.Metadata metadata = 2; + */ + metadata?: Metadata; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.DependenciesRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "metadata", kind: "message", T: Metadata }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): DependenciesRequest { + return new DependenciesRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): DependenciesRequest { + return new DependenciesRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): DependenciesRequest { + return new DependenciesRequest().fromJsonString(jsonString, options); + } + + static equals(a: DependenciesRequest | PlainMessage | undefined, b: DependenciesRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(DependenciesRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.DependenciesResponse + */ +export class DependenciesResponse extends Message { + /** + * @generated from field: repeated string modules = 1; + */ + modules: string[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.DependenciesResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "modules", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): DependenciesResponse { + return new DependenciesResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): DependenciesResponse { + return new DependenciesResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): DependenciesResponse { + return new DependenciesResponse().fromJsonString(jsonString, options); + } + + static equals(a: DependenciesResponse | PlainMessage | undefined, b: DependenciesResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(DependenciesResponse, a, b); + } +} + +/** + * Response to a dependency extraction request. + * + * @generated from message xyz.block.ftl.v1.language.DependencyUpdate + */ +export class DependencyUpdate extends Message { + /** + * @generated from field: repeated string modules = 1; + */ + modules: string[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.DependencyUpdate"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "modules", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): DependencyUpdate { + return new DependencyUpdate().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): DependencyUpdate { + return new DependencyUpdate().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): DependencyUpdate { + return new DependencyUpdate().fromJsonString(jsonString, options); + } + + static equals(a: DependencyUpdate | PlainMessage | undefined, b: DependencyUpdate | PlainMessage | undefined): boolean { + return proto3.util.equals(DependencyUpdate, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.MetadataUpdatedRequest + */ +export class MetadataUpdatedRequest extends Message { + /** + * @generated from field: xyz.block.ftl.v1.language.Metadata metadata = 1; + */ + metadata?: Metadata; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.MetadataUpdatedRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "metadata", kind: "message", T: Metadata }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): MetadataUpdatedRequest { + return new MetadataUpdatedRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): MetadataUpdatedRequest { + return new MetadataUpdatedRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): MetadataUpdatedRequest { + return new MetadataUpdatedRequest().fromJsonString(jsonString, options); + } + + static equals(a: MetadataUpdatedRequest | PlainMessage | undefined, b: MetadataUpdatedRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(MetadataUpdatedRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.MetadataUpdatedResponse + */ +export class MetadataUpdatedResponse extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.MetadataUpdatedResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): MetadataUpdatedResponse { + return new MetadataUpdatedResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): MetadataUpdatedResponse { + return new MetadataUpdatedResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): MetadataUpdatedResponse { + return new MetadataUpdatedResponse().fromJsonString(jsonString, options); + } + + static equals(a: MetadataUpdatedResponse | PlainMessage | undefined, b: MetadataUpdatedResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(MetadataUpdatedResponse, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.SchemaUpdatedRequest + */ +export class SchemaUpdatedRequest extends Message { + /** + * @generated from field: xyz.block.ftl.v1.schema.Schema schema = 1; + */ + schema?: Schema; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.SchemaUpdatedRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "schema", kind: "message", T: Schema }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): SchemaUpdatedRequest { + return new SchemaUpdatedRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): SchemaUpdatedRequest { + return new SchemaUpdatedRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): SchemaUpdatedRequest { + return new SchemaUpdatedRequest().fromJsonString(jsonString, options); + } + + static equals(a: SchemaUpdatedRequest | PlainMessage | undefined, b: SchemaUpdatedRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(SchemaUpdatedRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.SchemaUpdatedResponse + */ +export class SchemaUpdatedResponse extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.SchemaUpdatedResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): SchemaUpdatedResponse { + return new SchemaUpdatedResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): SchemaUpdatedResponse { + return new SchemaUpdatedResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): SchemaUpdatedResponse { + return new SchemaUpdatedResponse().fromJsonString(jsonString, options); + } + + static equals(a: SchemaUpdatedResponse | PlainMessage | undefined, b: SchemaUpdatedResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(SchemaUpdatedResponse, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.Error + */ +export class Error extends Message { + /** + * @generated from field: string msg = 1; + */ + msg = ""; + + /** + * @generated from field: xyz.block.ftl.v1.schema.Position pos = 2; + */ + pos?: Position; + + /** + * @generated from field: int64 endColumn = 3; + */ + endColumn = protoInt64.zero; + + /** + * @generated from field: xyz.block.ftl.v1.language.Error.ErrorLevel level = 4; + */ + level = Error_ErrorLevel.INFO; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.Error"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "msg", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "pos", kind: "message", T: Position }, + { no: 3, name: "endColumn", kind: "scalar", T: 3 /* ScalarType.INT64 */ }, + { no: 4, name: "level", kind: "enum", T: proto3.getEnumType(Error_ErrorLevel) }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Error { + return new Error().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Error { + return new Error().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Error { + return new Error().fromJsonString(jsonString, options); + } + + static equals(a: Error | PlainMessage | undefined, b: Error | PlainMessage | undefined): boolean { + return proto3.util.equals(Error, a, b); + } +} + +/** + * @generated from enum xyz.block.ftl.v1.language.Error.ErrorLevel + */ +export enum Error_ErrorLevel { + /** + * @generated from enum value: INFO = 0; + */ + INFO = 0, + + /** + * @generated from enum value: WARN = 1; + */ + WARN = 1, + + /** + * @generated from enum value: ERROR = 2; + */ + ERROR = 2, +} +// Retrieve enum metadata with: proto3.getEnumType(Error_ErrorLevel) +proto3.util.setEnumType(Error_ErrorLevel, "xyz.block.ftl.v1.language.Error.ErrorLevel", [ + { no: 0, name: "INFO" }, + { no: 1, name: "WARN" }, + { no: 2, name: "ERROR" }, +]); + +/** + * @generated from message xyz.block.ftl.v1.language.ErrorList + */ +export class ErrorList extends Message { + /** + * @generated from field: repeated xyz.block.ftl.v1.language.Error errors = 1; + */ + errors: Error[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.ErrorList"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "errors", kind: "message", T: Error, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ErrorList { + return new ErrorList().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ErrorList { + return new ErrorList().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ErrorList { + return new ErrorList().fromJsonString(jsonString, options); + } + + static equals(a: ErrorList | PlainMessage | undefined, b: ErrorList | PlainMessage | undefined): boolean { + return proto3.util.equals(ErrorList, a, b); + } +} + +/** + * Request to build a module. + * + * @generated from message xyz.block.ftl.v1.language.BuildRequest + */ +export class BuildRequest extends Message { + /** + * the root path for the module + * + * @generated from field: string path = 1; + */ + path = ""; + + /** + * the root path for the FTL project + * + * @generated from field: string project_path = 2; + */ + projectPath = ""; + + /** + * indicates whether to watch for changes to the module + * + * @generated from field: bool watch = 3; + */ + watch = false; + + /** + * @generated from field: xyz.block.ftl.v1.language.Metadata metadata = 4; + */ + metadata?: Metadata; + + /** + * @generated from field: xyz.block.ftl.v1.schema.Schema schema = 5; + */ + schema?: Schema; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "project_path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "watch", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 4, name: "metadata", kind: "message", T: Metadata }, + { no: 5, name: "schema", kind: "message", T: Schema }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildRequest { + return new BuildRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildRequest { + return new BuildRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildRequest { + return new BuildRequest().fromJsonString(jsonString, options); + } + + static equals(a: BuildRequest | PlainMessage | undefined, b: BuildRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildRequest, a, b); + } +} + +/** + * Response to a build request. + * + * @generated from message xyz.block.ftl.v1.language.BuildResult + */ +export class BuildResult extends Message { + /** + * module schema for the built module + * only set if the build was successful + * + * @generated from field: optional xyz.block.ftl.v1.schema.Module module = 1; + */ + module?: Module; + + /** + * paths for files/directories to be deployed + * + * @generated from field: repeated string deploy = 2; + */ + deploy: string[] = []; + + /** + * errors and warnings encountered during the build + * + * @generated from field: xyz.block.ftl.v1.language.ErrorList errors = 3; + */ + errors?: ErrorList; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildResult"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "module", kind: "message", T: Module, opt: true }, + { no: 2, name: "deploy", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + { no: 3, name: "errors", kind: "message", T: ErrorList }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildResult { + return new BuildResult().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildResult { + return new BuildResult().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildResult { + return new BuildResult().fromJsonString(jsonString, options); + } + + static equals(a: BuildResult | PlainMessage | undefined, b: BuildResult | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildResult, a, b); + } +} + +/** + * Every type of message that can be streamed from the language service for a build. + * + * @generated from message xyz.block.ftl.v1.language.BuildEvent + */ +export class BuildEvent extends Message { + /** + * @generated from oneof xyz.block.ftl.v1.language.BuildEvent.event + */ + event: { + /** + * @generated from field: xyz.block.ftl.v1.language.DependencyUpdate dependency_update = 1; + */ + value: DependencyUpdate; + case: "dependencyUpdate"; + } | { + /** + * @generated from field: xyz.block.ftl.v1.language.BuildResult build_result = 2; + */ + value: BuildResult; + case: "buildResult"; + } | { + /** + * @generated from field: xyz.block.ftl.v1.language.LogMessage log_message = 3; + */ + value: LogMessage; + case: "logMessage"; + } | { case: undefined; value?: undefined } = { case: undefined }; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildEvent"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "dependency_update", kind: "message", T: DependencyUpdate, oneof: "event" }, + { no: 2, name: "build_result", kind: "message", T: BuildResult, oneof: "event" }, + { no: 3, name: "log_message", kind: "message", T: LogMessage, oneof: "event" }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildEvent { + return new BuildEvent().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildEvent { + return new BuildEvent().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildEvent { + return new BuildEvent().fromJsonString(jsonString, options); + } + + static equals(a: BuildEvent | PlainMessage | undefined, b: BuildEvent | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildEvent, a, b); + } +} + diff --git a/frontend/console/src/protos/xyz/block/ftl/v1/language/language_connect.ts b/frontend/console/src/protos/xyz/block/ftl/v1/language/language_connect.ts new file mode 100644 index 0000000000..5861e8e6f2 --- /dev/null +++ b/frontend/console/src/protos/xyz/block/ftl/v1/language/language_connect.ts @@ -0,0 +1,87 @@ +// @generated by protoc-gen-connect-es v1.5.0 with parameter "target=ts" +// @generated from file xyz/block/ftl/v1/language/language.proto (package xyz.block.ftl.v1.language, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import { PingRequest, PingResponse } from "../ftl_pb.js"; +import { MethodIdempotency, MethodKind } from "@bufbuild/protobuf"; +import { BuildContextUpdatedRequest, BuildContextUpdatedResponse, BuildEvent, BuildRequest, CreateModuleRequest, CreateModuleResponse, DependenciesRequest, DependenciesResponse, GetCreateModuleFlagsRequest, GetCreateModuleFlagsResponse } from "./language_pb.js"; + +/** + * LanguageService allows a plugin to add support for a programming language. + * + * @generated from service xyz.block.ftl.v1.language.LanguageService + */ +export const LanguageService = { + typeName: "xyz.block.ftl.v1.language.LanguageService", + methods: { + /** + * Ping service for readiness. + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.Ping + */ + ping: { + name: "Ping", + I: PingRequest, + O: PingResponse, + kind: MethodKind.Unary, + idempotency: MethodIdempotency.NoSideEffects, + }, + /** + * TODO: docs + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.GetCreateModuleFlags + */ + getCreateModuleFlags: { + name: "GetCreateModuleFlags", + I: GetCreateModuleFlagsRequest, + O: GetCreateModuleFlagsResponse, + kind: MethodKind.Unary, + }, + /** + * Generates files for a new empty module with the requested name + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.CreateModule + */ + createModule: { + name: "CreateModule", + I: CreateModuleRequest, + O: CreateModuleResponse, + kind: MethodKind.Unary, + }, + /** + * Extract dependencies for a module + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.GetDependencies + */ + getDependencies: { + name: "GetDependencies", + I: DependenciesRequest, + O: DependenciesResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.BuildContextUpdated + */ + buildContextUpdated: { + name: "BuildContextUpdated", + I: BuildContextUpdatedRequest, + O: BuildContextUpdatedResponse, + kind: MethodKind.Unary, + }, + /** + * Build the module + * The request can also indicate whether the plugin should watch for changes to the module and automatically rebuild + * The response stream can send LogMessages and BuildResults, and ends with a BuildResponse + * + * @generated from rpc xyz.block.ftl.v1.language.LanguageService.Build + */ + build: { + name: "Build", + I: BuildRequest, + O: BuildEvent, + kind: MethodKind.ServerStreaming, + }, + } +} as const; + diff --git a/frontend/console/src/protos/xyz/block/ftl/v1/language/language_pb.ts b/frontend/console/src/protos/xyz/block/ftl/v1/language/language_pb.ts index 14fa9143e8..849978eb16 100644 --- a/frontend/console/src/protos/xyz/block/ftl/v1/language/language_pb.ts +++ b/frontend/console/src/protos/xyz/block/ftl/v1/language/language_pb.ts @@ -4,8 +4,589 @@ // @ts-nocheck import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; -import { Message, proto3, protoInt64 } from "@bufbuild/protobuf"; -import { Position } from "../schema/schema_pb.js"; +import { Any, Message, proto3, protoInt64 } from "@bufbuild/protobuf"; +import { Module, Position, Schema } from "../schema/schema_pb.js"; + +/** + * @generated from enum xyz.block.ftl.v1.language.LogLevel + */ +export enum LogLevel { + /** + * @generated from enum value: DEBUG = 0; + */ + DEBUG = 0, + + /** + * @generated from enum value: INFO = 1; + */ + INFO = 1, + + /** + * @generated from enum value: WARN = 2; + */ + WARN = 2, + + /** + * @generated from enum value: ERROR = 3; + */ + ERROR = 3, +} +// Retrieve enum metadata with: proto3.getEnumType(LogLevel) +proto3.util.setEnumType(LogLevel, "xyz.block.ftl.v1.language.LogLevel", [ + { no: 0, name: "DEBUG" }, + { no: 1, name: "INFO" }, + { no: 2, name: "WARN" }, + { no: 3, name: "ERROR" }, +]); + +/** + * @generated from message xyz.block.ftl.v1.language.Metadata + */ +export class Metadata extends Message { + /** + * Universal metadata + * + * @generated from field: string name = 1; + */ + name = ""; + + /** + * @generated from field: string language = 2; + */ + language = ""; + + /** + * Language metadata contains any metadata specific to a specific language. + * TODO: revisit type... + * + * @generated from field: google.protobuf.Any LanguageMetadata = 3; + */ + LanguageMetadata?: Any; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.Metadata"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "language", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "LanguageMetadata", kind: "message", T: Any }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Metadata { + return new Metadata().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Metadata { + return new Metadata().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Metadata { + return new Metadata().fromJsonString(jsonString, options); + } + + static equals(a: Metadata | PlainMessage | undefined, b: Metadata | PlainMessage | undefined): boolean { + return proto3.util.equals(Metadata, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.ProjectConfig + */ +export class ProjectConfig extends Message { + /** + * @generated from field: string path = 1; + */ + path = ""; + + /** + * @generated from field: string name = 2; + */ + name = ""; + + /** + * @generated from field: bool noGit = 3; + */ + noGit = false; + + /** + * @generated from field: bool hermit = 4; + */ + hermit = false; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.ProjectConfig"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "noGit", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 4, name: "hermit", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ProjectConfig { + return new ProjectConfig().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ProjectConfig { + return new ProjectConfig().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ProjectConfig { + return new ProjectConfig().fromJsonString(jsonString, options); + } + + static equals(a: ProjectConfig | PlainMessage | undefined, b: ProjectConfig | PlainMessage | undefined): boolean { + return proto3.util.equals(ProjectConfig, a, b); + } +} + +/** + * TODO: docs + * + * @generated from message xyz.block.ftl.v1.language.GetCreateModuleFlagsRequest + */ +export class GetCreateModuleFlagsRequest extends Message { + /** + * @generated from field: string language = 1; + */ + language = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.GetCreateModuleFlagsRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "language", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): GetCreateModuleFlagsRequest { + return new GetCreateModuleFlagsRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): GetCreateModuleFlagsRequest { + return new GetCreateModuleFlagsRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): GetCreateModuleFlagsRequest { + return new GetCreateModuleFlagsRequest().fromJsonString(jsonString, options); + } + + static equals(a: GetCreateModuleFlagsRequest | PlainMessage | undefined, b: GetCreateModuleFlagsRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(GetCreateModuleFlagsRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse + */ +export class GetCreateModuleFlagsResponse extends Message { + /** + * @generated from field: repeated xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse.Flag flags = 1; + */ + flags: GetCreateModuleFlagsResponse_Flag[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "flags", kind: "message", T: GetCreateModuleFlagsResponse_Flag, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): GetCreateModuleFlagsResponse { + return new GetCreateModuleFlagsResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): GetCreateModuleFlagsResponse { + return new GetCreateModuleFlagsResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): GetCreateModuleFlagsResponse { + return new GetCreateModuleFlagsResponse().fromJsonString(jsonString, options); + } + + static equals(a: GetCreateModuleFlagsResponse | PlainMessage | undefined, b: GetCreateModuleFlagsResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(GetCreateModuleFlagsResponse, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse.Flag + */ +export class GetCreateModuleFlagsResponse_Flag extends Message { + /** + * @generated from field: string name = 1; + */ + name = ""; + + /** + * @generated from field: string help = 2; + */ + help = ""; + + /** + * @generated from field: optional string envar = 3; + */ + envar?: string; + + /** + * short must be a single character + * + * @generated from field: optional string short = 4; + */ + short?: string; + + /** + * @generated from field: optional string placeholder = 5; + */ + placeholder?: string; + + /** + * @generated from field: optional string default = 6; + */ + default?: string; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.GetCreateModuleFlagsResponse.Flag"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "help", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "envar", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, + { no: 4, name: "short", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, + { no: 5, name: "placeholder", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, + { no: 6, name: "default", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): GetCreateModuleFlagsResponse_Flag { + return new GetCreateModuleFlagsResponse_Flag().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): GetCreateModuleFlagsResponse_Flag { + return new GetCreateModuleFlagsResponse_Flag().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): GetCreateModuleFlagsResponse_Flag { + return new GetCreateModuleFlagsResponse_Flag().fromJsonString(jsonString, options); + } + + static equals(a: GetCreateModuleFlagsResponse_Flag | PlainMessage | undefined, b: GetCreateModuleFlagsResponse_Flag | PlainMessage | undefined): boolean { + return proto3.util.equals(GetCreateModuleFlagsResponse_Flag, a, b); + } +} + +/** + * Request to create a new module. + * + * @generated from message xyz.block.ftl.v1.language.CreateModuleRequest + */ +export class CreateModuleRequest extends Message { + /** + * @generated from field: string name = 1; + */ + name = ""; + + /** + * @generated from field: string path = 2; + */ + path = ""; + + /** + * @generated from field: xyz.block.ftl.v1.language.ProjectConfig projectConfig = 3; + */ + projectConfig?: ProjectConfig; + + /** + * TODO: revisit type... + * + * @generated from field: google.protobuf.Any Flags = 4; + */ + Flags?: Any; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.CreateModuleRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "projectConfig", kind: "message", T: ProjectConfig }, + { no: 4, name: "Flags", kind: "message", T: Any }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): CreateModuleRequest { + return new CreateModuleRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): CreateModuleRequest { + return new CreateModuleRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): CreateModuleRequest { + return new CreateModuleRequest().fromJsonString(jsonString, options); + } + + static equals(a: CreateModuleRequest | PlainMessage | undefined, b: CreateModuleRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(CreateModuleRequest, a, b); + } +} + +/** + * Response to a create module request. + * + * @generated from message xyz.block.ftl.v1.language.CreateModuleResponse + */ +export class CreateModuleResponse extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.CreateModuleResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): CreateModuleResponse { + return new CreateModuleResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): CreateModuleResponse { + return new CreateModuleResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): CreateModuleResponse { + return new CreateModuleResponse().fromJsonString(jsonString, options); + } + + static equals(a: CreateModuleResponse | PlainMessage | undefined, b: CreateModuleResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(CreateModuleResponse, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.DependenciesRequest + */ +export class DependenciesRequest extends Message { + /** + * @generated from field: string path = 1; + */ + path = ""; + + /** + * @generated from field: xyz.block.ftl.v1.language.Metadata metadata = 2; + */ + metadata?: Metadata; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.DependenciesRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "metadata", kind: "message", T: Metadata }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): DependenciesRequest { + return new DependenciesRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): DependenciesRequest { + return new DependenciesRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): DependenciesRequest { + return new DependenciesRequest().fromJsonString(jsonString, options); + } + + static equals(a: DependenciesRequest | PlainMessage | undefined, b: DependenciesRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(DependenciesRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.DependenciesResponse + */ +export class DependenciesResponse extends Message { + /** + * @generated from field: repeated string modules = 1; + */ + modules: string[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.DependenciesResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "modules", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): DependenciesResponse { + return new DependenciesResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): DependenciesResponse { + return new DependenciesResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): DependenciesResponse { + return new DependenciesResponse().fromJsonString(jsonString, options); + } + + static equals(a: DependenciesResponse | PlainMessage | undefined, b: DependenciesResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(DependenciesResponse, a, b); + } +} + +/** + * Response to a dependency extraction request. + * + * @generated from message xyz.block.ftl.v1.language.DependencyUpdate + */ +export class DependencyUpdate extends Message { + /** + * @generated from field: repeated string modules = 1; + */ + modules: string[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.DependencyUpdate"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "modules", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): DependencyUpdate { + return new DependencyUpdate().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): DependencyUpdate { + return new DependencyUpdate().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): DependencyUpdate { + return new DependencyUpdate().fromJsonString(jsonString, options); + } + + static equals(a: DependencyUpdate | PlainMessage | undefined, b: DependencyUpdate | PlainMessage | undefined): boolean { + return proto3.util.equals(DependencyUpdate, a, b); + } +} + +/** + * TODO: docs + * + * @generated from message xyz.block.ftl.v1.language.BuildContextUpdatedRequest + */ +export class BuildContextUpdatedRequest extends Message { + /** + * TODO: explain + * + * @generated from field: string buildRequestId = 1; + */ + buildRequestId = ""; + + /** + * @generated from field: optional xyz.block.ftl.v1.language.Metadata metadata = 2; + */ + metadata?: Metadata; + + /** + * @generated from field: optional xyz.block.ftl.v1.schema.Schema schema = 3; + */ + schema?: Schema; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildContextUpdatedRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "buildRequestId", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "metadata", kind: "message", T: Metadata, opt: true }, + { no: 3, name: "schema", kind: "message", T: Schema, opt: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildContextUpdatedRequest { + return new BuildContextUpdatedRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildContextUpdatedRequest { + return new BuildContextUpdatedRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildContextUpdatedRequest { + return new BuildContextUpdatedRequest().fromJsonString(jsonString, options); + } + + static equals(a: BuildContextUpdatedRequest | PlainMessage | undefined, b: BuildContextUpdatedRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildContextUpdatedRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.BuildContextUpdatedResponse + */ +export class BuildContextUpdatedResponse extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildContextUpdatedResponse"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildContextUpdatedResponse { + return new BuildContextUpdatedResponse().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildContextUpdatedResponse { + return new BuildContextUpdatedResponse().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildContextUpdatedResponse { + return new BuildContextUpdatedResponse().fromJsonString(jsonString, options); + } + + static equals(a: BuildContextUpdatedResponse | PlainMessage | undefined, b: BuildContextUpdatedResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildContextUpdatedResponse, a, b); + } +} /** * @generated from message xyz.block.ftl.v1.language.Error @@ -125,3 +706,287 @@ export class ErrorList extends Message { } } +/** + * Request to build a module. + * + * @generated from message xyz.block.ftl.v1.language.BuildRequest + */ +export class BuildRequest extends Message { + /** + * TODO: explain + * + * @generated from field: string buildRequestId = 1; + */ + buildRequestId = ""; + + /** + * the root path for the module + * + * @generated from field: string path = 2; + */ + path = ""; + + /** + * the root path for the FTL project + * + * @generated from field: string project_path = 3; + */ + projectPath = ""; + + /** + * indicates whether to watch for changes to the module + * TODO: rename to automaticRebuilds + * + * @generated from field: bool watch = 4; + */ + watch = false; + + /** + * @generated from field: xyz.block.ftl.v1.language.Metadata metadata = 5; + */ + metadata?: Metadata; + + /** + * @generated from field: xyz.block.ftl.v1.schema.Schema schema = 6; + */ + schema?: Schema; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "buildRequestId", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "project_path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "watch", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 5, name: "metadata", kind: "message", T: Metadata }, + { no: 6, name: "schema", kind: "message", T: Schema }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildRequest { + return new BuildRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildRequest { + return new BuildRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildRequest { + return new BuildRequest().fromJsonString(jsonString, options); + } + + static equals(a: BuildRequest | PlainMessage | undefined, b: BuildRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildRequest, a, b); + } +} + +/** + * @generated from message xyz.block.ftl.v1.language.AutoRebuildStarted + */ +export class AutoRebuildStarted extends Message { + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.AutoRebuildStarted"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): AutoRebuildStarted { + return new AutoRebuildStarted().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): AutoRebuildStarted { + return new AutoRebuildStarted().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): AutoRebuildStarted { + return new AutoRebuildStarted().fromJsonString(jsonString, options); + } + + static equals(a: AutoRebuildStarted | PlainMessage | undefined, b: AutoRebuildStarted | PlainMessage | undefined): boolean { + return proto3.util.equals(AutoRebuildStarted, a, b); + } +} + +/** + * Response to a build request. + * + * @generated from message xyz.block.ftl.v1.language.BuildResult + */ +export class BuildResult extends Message { + /** + * @generated from field: optional string buildRequestId = 1; + */ + buildRequestId?: string; + + /** + * module schema for the built module + * only set if the build was successful + * + * @generated from field: optional xyz.block.ftl.v1.schema.Module module = 2; + */ + module?: Module; + + /** + * paths for files/directories to be deployed + * + * @generated from field: repeated string deploy = 3; + */ + deploy: string[] = []; + + /** + * errors and warnings encountered during the build + * + * @generated from field: xyz.block.ftl.v1.language.ErrorList errors = 4; + */ + errors?: ErrorList; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildResult"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "buildRequestId", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, + { no: 2, name: "module", kind: "message", T: Module, opt: true }, + { no: 3, name: "deploy", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + { no: 4, name: "errors", kind: "message", T: ErrorList }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildResult { + return new BuildResult().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildResult { + return new BuildResult().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildResult { + return new BuildResult().fromJsonString(jsonString, options); + } + + static equals(a: BuildResult | PlainMessage | undefined, b: BuildResult | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildResult, a, b); + } +} + +/** + * Log message from the language service. + * + * @generated from message xyz.block.ftl.v1.language.LogMessage + */ +export class LogMessage extends Message { + /** + * @generated from field: string message = 1; + */ + message = ""; + + /** + * @generated from field: xyz.block.ftl.v1.language.LogLevel level = 2; + */ + level = LogLevel.DEBUG; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.LogMessage"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "message", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "level", kind: "enum", T: proto3.getEnumType(LogLevel) }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): LogMessage { + return new LogMessage().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): LogMessage { + return new LogMessage().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): LogMessage { + return new LogMessage().fromJsonString(jsonString, options); + } + + static equals(a: LogMessage | PlainMessage | undefined, b: LogMessage | PlainMessage | undefined): boolean { + return proto3.util.equals(LogMessage, a, b); + } +} + +/** + * Every type of message that can be streamed from the language service for a build. + * + * @generated from message xyz.block.ftl.v1.language.BuildEvent + */ +export class BuildEvent extends Message { + /** + * @generated from oneof xyz.block.ftl.v1.language.BuildEvent.event + */ + event: { + /** + * @generated from field: xyz.block.ftl.v1.language.DependencyUpdate dependency_update = 1; + */ + value: DependencyUpdate; + case: "dependencyUpdate"; + } | { + /** + * @generated from field: xyz.block.ftl.v1.language.AutoRebuildStarted auto_rebuild_started = 2; + */ + value: AutoRebuildStarted; + case: "autoRebuildStarted"; + } | { + /** + * @generated from field: xyz.block.ftl.v1.language.BuildResult build_result = 3; + */ + value: BuildResult; + case: "buildResult"; + } | { + /** + * @generated from field: xyz.block.ftl.v1.language.LogMessage log_message = 4; + */ + value: LogMessage; + case: "logMessage"; + } | { case: undefined; value?: undefined } = { case: undefined }; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.language.BuildEvent"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "dependency_update", kind: "message", T: DependencyUpdate, oneof: "event" }, + { no: 2, name: "auto_rebuild_started", kind: "message", T: AutoRebuildStarted, oneof: "event" }, + { no: 3, name: "build_result", kind: "message", T: BuildResult, oneof: "event" }, + { no: 4, name: "log_message", kind: "message", T: LogMessage, oneof: "event" }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BuildEvent { + return new BuildEvent().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BuildEvent { + return new BuildEvent().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BuildEvent { + return new BuildEvent().fromJsonString(jsonString, options); + } + + static equals(a: BuildEvent | PlainMessage | undefined, b: BuildEvent | PlainMessage | undefined): boolean { + return proto3.util.equals(BuildEvent, a, b); + } +} + diff --git a/internal/buildengine/engine.go b/internal/buildengine/engine.go index 47807e6f35..bf8bfb2e88 100644 --- a/internal/buildengine/engine.go +++ b/internal/buildengine/engine.go @@ -482,7 +482,7 @@ func (e *Engine) watchForModuleChanges(ctx context.Context, period time.Duration } if meta, ok := e.moduleMetas.Load(event.Config.Module); ok { meta.plugin.Updates().Unsubscribe(meta.events) - err := meta.plugin.Kill(ctx) + err := meta.plugin.Kill() if err != nil { didError = true e.reportBuildFailed(err) diff --git a/internal/buildengine/languageplugin/external_plugin.go b/internal/buildengine/languageplugin/external_plugin.go new file mode 100644 index 0000000000..ef11de9615 --- /dev/null +++ b/internal/buildengine/languageplugin/external_plugin.go @@ -0,0 +1,340 @@ +package languageplugin + +import ( + "context" + "fmt" + "net/url" + "time" + + "connectrpc.com/connect" + "github.com/alecthomas/kong" + "github.com/alecthomas/types/either" + "github.com/alecthomas/types/optional" + "github.com/alecthomas/types/pubsub" + + langpb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/language" + schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/schema" + "github.com/TBD54566975/ftl/internal/builderrors" + "github.com/TBD54566975/ftl/internal/moduleconfig" + "github.com/TBD54566975/ftl/internal/projectconfig" + "github.com/TBD54566975/ftl/internal/schema" +) + +const launchTimeout = 10 * time.Second + +//sumtype:decl +type externalPluginCommand interface { + externalPluginCmd() +} + +type externalBuildCommand struct { + projectRoot string + config moduleconfig.ModuleConfig + schema *schema.Schema + buildEnv []string + devMode bool + + result chan either.Either[BuildResult, error] +} + +func (externalBuildCommand) externalPluginCmd() {} + +type externalPlugin struct { + client externalPluginClient + + // commands to execute + commands chan externalPluginCommand + + updates *pubsub.Topic[PluginEvent] +} + +var _ LanguagePlugin = &externalPlugin{} + +func newExternalPlugin(ctx context.Context, bind *url.URL, config moduleconfig.ModuleConfig) (*externalPlugin, error) { + impl, err := newExternalPluginImpl(ctx, bind, config) + if err != nil { + return nil, err + } + return newExternalPluginForTesting(ctx, impl), nil +} + +func newExternalPluginForTesting(ctx context.Context, client externalPluginClient) *externalPlugin { + plugin := &externalPlugin{ + client: client, + commands: make(chan externalPluginCommand, 64), + updates: pubsub.New[PluginEvent](), + } + + // TODO: need a cancellable context + go plugin.run(ctx) + + return plugin +} + +// TODO: make sure we call this +func (p *externalPlugin) Kill() error { + // TODO: cancel run() ctx + // if p.cmd == nil { + // return nil + // } + // return p.cmd.Kill(syscall.SIGINT) + return p.client.kill() +} + +func (p *externalPlugin) Updates() *pubsub.Topic[PluginEvent] { + return p.updates +} + +func (p *externalPlugin) GetCreateModuleFlags(ctx context.Context) ([]*kong.Flag, error) { + res, err := p.client.getCreateModuleFlags(ctx, connect.NewRequest(&langpb.GetCreateModuleFlagsRequest{})) + if err != nil { + return nil, err + } + flags := []*kong.Flag{} + shorts := map[rune]string{} + for _, f := range res.Msg.Flags { + flag := &kong.Flag{ + Value: &kong.Value{ + Name: f.Name, + Help: f.Help, + Tag: &kong.Tag{}, + }, + } + if f.Envar != nil && *f.Envar != "" { + flag.Value.Tag.Envs = []string{*f.Envar} + } + if f.Default != nil && *f.Default != "" { + flag.Value.HasDefault = true + flag.Value.Default = *f.Default + } + if f.Short != nil && *f.Short != "" { + if len(*f.Short) > 1 { + return nil, fmt.Errorf("invalid flag declared: short flag %q for %v must be a single character", *f.Short, f.Name) + } + short := rune((*f.Short)[0]) + if existingFullName, ok := shorts[short]; ok { + return nil, fmt.Errorf("multiple flags declared with the same short name: %v and %v", existingFullName, f.Name) + } + flag.Short = short + shorts[short] = f.Name + + } + if f.Placeholder != nil && *f.Placeholder != "" { + flag.PlaceHolder = *f.Placeholder + } + flags = append(flags, flag) + } + return flags, nil +} + +// CreateModule creates a new module in the given directory with the given name and language. +func (p *externalPlugin) CreateModule(ctx context.Context, projConfig projectconfig.Config, moduleConfig moduleconfig.ModuleConfig, flags map[string]string) error { + _, err := p.client.createModule(ctx, connect.NewRequest(&langpb.CreateModuleRequest{ + Name: moduleConfig.Module, + Path: moduleConfig.Dir, + ProjectConfig: &langpb.ProjectConfig{ + NoGit: projConfig.NoGit, + Hermit: projConfig.Hermit, + }, + })) + return err +} + +// TODO: docs +func (p *externalPlugin) GetDependencies(ctx context.Context, config moduleconfig.ModuleConfig) ([]string, error) { + resp, err := p.client.getDependencies(ctx, connect.NewRequest(&langpb.DependenciesRequest{ + Metadata: metadataProtoFromModuleConfig(config), + Path: config.Dir, + })) + if err != nil { + return nil, err + } + return resp.Msg.Modules, nil +} + +// TODO: docs +func (p *externalPlugin) Build(ctx context.Context, projectRoot string, config moduleconfig.ModuleConfig, sch *schema.Schema, buildEnv []string, devMode bool) (BuildResult, error) { + cmd := externalBuildCommand{ + projectRoot: projectRoot, + config: config, + schema: sch, + buildEnv: buildEnv, + devMode: devMode, + result: make(chan either.Either[BuildResult, error]), + } + p.commands <- cmd + select { + case result := <-cmd.result: + switch result := result.(type) { + case either.Left[BuildResult, error]: + return result.Get(), nil + case either.Right[BuildResult, error]: + return BuildResult{}, result.Get() //nolint:wrapcheck + default: + panic(fmt.Sprintf("unexpected result type %T", result)) + } + case <-ctx.Done(): + return BuildResult{}, fmt.Errorf("error waiting for build to complete: %w", ctx.Err()) + } +} + +func metadataProtoFromModuleConfig(config moduleconfig.ModuleConfig) *langpb.Metadata { + return &langpb.Metadata{ + Name: config.Module, + } +} + +func (p *externalPlugin) run(ctx context.Context) { + // State + var config moduleconfig.ModuleConfig + var projectRoot string + var sch *schema.Schema + // var buildEnv []string + devMode := false + + // TODO: clean up! + // current build stream, nil if no build call is active + // var stream optional.Option[*connect.ServerStreamForClient[langpb.BuildEvent]] + streaming := false + // can be nil + var streamChan chan *langpb.BuildEvent + + // TODO: document + var activeBuildCmd optional.Option[externalBuildCommand] + + var buildCounter = 0 + + for { + select { + case cmd := <-p.commands: + switch c := cmd.(type) { + case externalBuildCommand: + // // update state + projectRoot = c.projectRoot + config = c.config + sch = c.schema + // buildEnv = c.buildEnv + devMode = c.devMode + + if _, ok := activeBuildCmd.Get(); ok { + c.result <- either.RightOf[BuildResult](fmt.Errorf("build already in progress")) + continue + } + + activeBuildCmd = optional.Some[externalBuildCommand](c) + buildCounter++ + + if streaming { + if !devMode { + // TODO: error, or is this handled above? + activeBuildCmd = optional.None[externalBuildCommand]() + continue + } + + // tell plugin about new build context so that it rebuilds in existing build stream + p.client.buildContextUpdated(ctx, connect.NewRequest(&langpb.BuildContextUpdatedRequest{ + BuildRequestId: buildRequestId(config, buildCounter), + Metadata: metadataProtoFromModuleConfig(config), + Schema: sch.ToProto().(*schemapb.Schema), //nolint:forcetypeassert + })) + continue + } + + newStreamChan, err := p.client.build(ctx, connect.NewRequest(&langpb.BuildRequest{ + BuildRequestId: buildRequestId(config, buildCounter), + Path: config.Dir, + ProjectPath: projectRoot, + Watch: devMode, + Metadata: metadataProtoFromModuleConfig(config), + Schema: sch.ToProto().(*schemapb.Schema), //nolint:forcetypeassert + })) + if err != nil { + // TODO: error + continue + } + streaming = true + streamChan = newStreamChan + } + case e := <-streamChan: + if e == nil { + streaming = false + streamChan = nil + continue + } + switch event := e.Event.(type) { + case *langpb.BuildEvent_LogMessage: + // TODO: handle + case *langpb.BuildEvent_DependencyUpdate: + // TODO: handle + case *langpb.BuildEvent_AutoRebuildStarted: + if _, ok := activeBuildCmd.Get(); ok { + // ignore + // TODO: log? + continue + } + p.updates.Publish(AutoRebuildStartedEvent{ + Module: config.Module, + }) + case *langpb.BuildEvent_BuildResult: + requestId := optional.Ptr(event.BuildResult.BuildRequestId) + if cmd, ok := activeBuildCmd.Get(); ok { + if optional.Some(buildRequestId(cmd.config, buildCounter)) != requestId { + // TODO: warn. or just debug if auto rebuild? + continue + } + result, err := buildResultFromProto(event.BuildResult) + if err != nil { + cmd.result <- either.RightOf[BuildResult](err) + } else { + cmd.result <- either.LeftOf[error](result) + } + activeBuildCmd = optional.None[externalBuildCommand]() + continue + } + + // handle auto rebuild + if requestId.Ok() { + // TODO: warn? + continue + } + result, err := buildResultFromProto(event.BuildResult) + if err != nil { + p.updates.Publish(AutoRebuildEndedEvent{ + Module: config.Module, + Result: either.RightOf[BuildResult](err), + }) + } else { + p.updates.Publish(AutoRebuildEndedEvent{ + Module: config.Module, + Result: either.LeftOf[error](result), + }) + } + } + + case <-ctx.Done(): + return + } + } +} + +func buildResultFromProto(pb *langpb.BuildResult) (BuildResult, error) { + var moduleSch *schema.Module + if pb.Module != nil { + sch, err := schema.ModuleFromProto(pb.Module) + if err != nil { + return BuildResult{}, fmt.Errorf("failed to parse schema: %w", err) + } + moduleSch = sch + } + + errs := langpb.ErrorsFromProto(pb.Errors) + builderrors.SortErrorsByPosition(errs) + return BuildResult{ + Errors: errs, + Schema: moduleSch, + }, nil +} + +func buildRequestId(config moduleconfig.ModuleConfig, counter int) string { + return fmt.Sprintf("%v-%v", config.Module, counter) +} diff --git a/internal/buildengine/languageplugin/external_plugin_client.go b/internal/buildengine/languageplugin/external_plugin_client.go new file mode 100644 index 0000000000..9b120e21ee --- /dev/null +++ b/internal/buildengine/languageplugin/external_plugin_client.go @@ -0,0 +1,159 @@ +package languageplugin + +import ( + "context" + "fmt" + "net/url" + "syscall" + + "connectrpc.com/connect" + "github.com/jpillora/backoff" + + langpb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/language" + langconnect "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/language/languagepbconnect" + "github.com/TBD54566975/ftl/internal/exec" + "github.com/TBD54566975/ftl/internal/log" + "github.com/TBD54566975/ftl/internal/moduleconfig" + "github.com/TBD54566975/ftl/internal/rpc" +) + +// TODO: rename all this! + +type externalPluginClient interface { + getCreateModuleFlags(context.Context, *connect.Request[langpb.GetCreateModuleFlagsRequest]) (*connect.Response[langpb.GetCreateModuleFlagsResponse], error) + createModule(context.Context, *connect.Request[langpb.CreateModuleRequest]) (*connect.Response[langpb.CreateModuleResponse], error) + getDependencies(context.Context, *connect.Request[langpb.DependenciesRequest]) (*connect.Response[langpb.DependenciesResponse], error) + + // TODO: when not watching, does plugin need a way of closing the stream / chan? + build(context.Context, *connect.Request[langpb.BuildRequest]) (chan *langpb.BuildEvent, error) + buildContextUpdated(context.Context, *connect.Request[langpb.BuildContextUpdatedRequest]) (*connect.Response[langpb.BuildContextUpdatedResponse], error) + + kill() error +} + +var _ externalPluginClient = &externalPluginImpl{} + +type externalPluginImpl struct { + cmd *exec.Cmd + client langconnect.LanguageServiceClient +} + +func newExternalPluginImpl(ctx context.Context, bind *url.URL, config moduleconfig.ModuleConfig) (*externalPluginImpl, error) { + impl := &externalPluginImpl{ + client: rpc.Dial(langconnect.NewLanguageServiceClient, bind.String(), log.Error), + } + err := impl.start(ctx, bind, config) + if err != nil { + return nil, fmt.Errorf("failed to start plugin: %w", err) + } + return impl, nil +} + +// Start launches the plugin and blocks until the plugin is ready. +func (p *externalPluginImpl) start(ctx context.Context, bind *url.URL, config moduleconfig.ModuleConfig) error { + // TODO: think more about whether this is a good log level + // TODO: think more about whether cmd's path should be the current directory, or the module's + cmdName := "ftl-language-" + config.Language + p.cmd = exec.Command(ctx, log.Debug, ".", cmdName, "--bind", bind.String(), "--path", config.Dir) + _, err := exec.LookPath(cmdName) + if err != nil { + return fmt.Errorf("failed to find plugin for %s: %w", config.Language, err) + } + + runCtx, cancel := context.WithCancel(ctx) + + cmdErr := make(chan error) + pingErr := make(chan error) + + // run the plugin and wait for it to finish executing + go func() { + err := p.cmd.RunBuffered(runCtx) + if err != nil { + cmdErr <- fmt.Errorf("language plugin failed: %w", err) + cancel() + } + close(cmdErr) + }() + // TODO: bring this back + // kill the plugin when the context is cancelled + // go func() { + // <-runCtx.Done() + + // p.Kill() + // }() + + go func() { + // wait for the plugin to be ready + if err := p.ping(runCtx); err != nil { + cancel() + pingErr <- fmt.Errorf("failed to ping plugin") + } + close(pingErr) + }() + + select { + case err := <-cmdErr: + return err + case err := <-pingErr: + if err != nil { + return nil + } + return fmt.Errorf("failed to start plugin: %w", err) + case <-ctx.Done(): + return fmt.Errorf("failed to start plugin: %w", ctx.Err()) + } +} + +func (p *externalPluginImpl) ping(ctx context.Context) error { + retry := backoff.Backoff{} + heartbeatCtx, cancel := context.WithTimeout(ctx, launchTimeout) + defer cancel() + err := rpc.Wait(heartbeatCtx, retry, p.client) + if err != nil { + return connect.NewError(connect.CodeUnavailable, fmt.Errorf("failed to connect to runner: %w", err)) + } + return nil +} + +func (p *externalPluginImpl) kill() error { + // TODO: cancel run() ctx + // if p.cmd == nil { + // return nil + // } + return p.cmd.Kill(syscall.SIGINT) +} + +func (p *externalPluginImpl) getCreateModuleFlags(ctx context.Context, req *connect.Request[langpb.GetCreateModuleFlagsRequest]) (*connect.Response[langpb.GetCreateModuleFlagsResponse], error) { + return p.client.GetCreateModuleFlags(ctx, req) +} + +func (p *externalPluginImpl) createModule(ctx context.Context, req *connect.Request[langpb.CreateModuleRequest]) (*connect.Response[langpb.CreateModuleResponse], error) { + return p.client.CreateModule(ctx, req) +} + +func (p *externalPluginImpl) getDependencies(ctx context.Context, req *connect.Request[langpb.DependenciesRequest]) (*connect.Response[langpb.DependenciesResponse], error) { + return p.client.GetDependencies(ctx, req) +} + +func (p *externalPluginImpl) build(ctx context.Context, req *connect.Request[langpb.BuildRequest]) (chan *langpb.BuildEvent, error) { + stream, err := p.client.Build(ctx, req) + if err != nil { + return nil, err + } + + streamChan := make(chan *langpb.BuildEvent, 64) + go streamToChan(stream, streamChan) + + return streamChan, err +} + +func streamToChan(stream *connect.ServerStreamForClient[langpb.BuildEvent], ch chan *langpb.BuildEvent) { + for stream.Receive() { + ch <- stream.Msg() + } + close(ch) +} + +func (p *externalPluginImpl) buildContextUpdated(ctx context.Context, req *connect.Request[langpb.BuildContextUpdatedRequest]) (*connect.Response[langpb.BuildContextUpdatedResponse], error) { + return p.client.BuildContextUpdated(ctx, req) +} diff --git a/internal/buildengine/languageplugin/external_plugin_test.go b/internal/buildengine/languageplugin/external_plugin_test.go new file mode 100644 index 0000000000..ce0193d582 --- /dev/null +++ b/internal/buildengine/languageplugin/external_plugin_test.go @@ -0,0 +1,361 @@ +package languageplugin + +import ( + "context" + "testing" + "time" + + "github.com/alecthomas/assert/v2" + "github.com/alecthomas/atomic" + "github.com/alecthomas/kong" + "github.com/alecthomas/types/either" + "github.com/alecthomas/types/optional" + + "connectrpc.com/connect" + langpb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/language" + "github.com/TBD54566975/ftl/internal/builderrors" + "github.com/TBD54566975/ftl/internal/moduleconfig" + "github.com/TBD54566975/ftl/internal/schema" +) + +type buildContext struct { + buildRequestId string + schema *schema.Schema + metadata *langpb.Metadata + + isRebuild bool +} + +type mockExternalPluginClient struct { + flags []*langpb.GetCreateModuleFlagsResponse_Flag + + buildEvents chan *langpb.BuildEvent + latestBuildContext atomic.Value[buildContext] +} + +var _ externalPluginClient = &mockExternalPluginClient{} + +func newMockExternalPlugin() *mockExternalPluginClient { + return &mockExternalPluginClient{ + buildEvents: make(chan *langpb.BuildEvent, 64), + } +} + +func (p *mockExternalPluginClient) getCreateModuleFlags(context.Context, *connect.Request[langpb.GetCreateModuleFlagsRequest]) (*connect.Response[langpb.GetCreateModuleFlagsResponse], error) { + return &connect.Response[langpb.GetCreateModuleFlagsResponse]{ + Msg: &langpb.GetCreateModuleFlagsResponse{ + Flags: p.flags, + }, + }, nil +} + +func (p *mockExternalPluginClient) createModule(context.Context, *connect.Request[langpb.CreateModuleRequest]) (*connect.Response[langpb.CreateModuleResponse], error) { + panic("not implemented") +} + +func (p *mockExternalPluginClient) getDependencies(context.Context, *connect.Request[langpb.DependenciesRequest]) (*connect.Response[langpb.DependenciesResponse], error) { + panic("not implemented") +} + +func (p *mockExternalPluginClient) build(ctx context.Context, req *connect.Request[langpb.BuildRequest]) (chan *langpb.BuildEvent, error) { + sch, err := schema.FromProto(req.Msg.Schema) + if err != nil { + return nil, err + } + p.latestBuildContext.Store(buildContext{ + buildRequestId: req.Msg.BuildRequestId, + schema: sch, + metadata: req.Msg.Metadata, + }) + return p.buildEvents, nil +} + +func (p *mockExternalPluginClient) buildContextUpdated(ctx context.Context, req *connect.Request[langpb.BuildContextUpdatedRequest]) (*connect.Response[langpb.BuildContextUpdatedResponse], error) { + sch, err := schema.FromProto(req.Msg.Schema) + if err != nil { + return nil, err + } + p.latestBuildContext.Store(buildContext{ + buildRequestId: req.Msg.BuildRequestId, + schema: sch, + metadata: req.Msg.Metadata, + isRebuild: true, + }) + return connect.NewResponse(&langpb.BuildContextUpdatedResponse{}), nil +} + +func (p *mockExternalPluginClient) kill() error { + return nil +} + +func setUp() (context.Context, *externalPlugin, *mockExternalPluginClient, moduleconfig.ModuleConfig, *schema.Schema) { + ctx := context.Background() + + mockImpl := newMockExternalPlugin() + plugin := newExternalPluginForTesting(ctx, mockImpl) + + config := moduleconfig.ModuleConfig{ + Module: "name", + Dir: "test/dir", + Language: "test-lang", + } + sch := &schema.Schema{} + return ctx, plugin, mockImpl, config, sch +} + +func TestCreateModuleFlags(t *testing.T) { + for _, tt := range []struct { + protoFlags []*langpb.GetCreateModuleFlagsResponse_Flag + expectedFlags []*kong.Flag + expectedError optional.Option[string] + }{ + { + protoFlags: []*langpb.GetCreateModuleFlagsResponse_Flag{ + { + Name: "full-flag", + Help: "This has all the fields set", + Envar: optional.Some("full-flag").Ptr(), + Short: optional.Some("f").Ptr(), + Placeholder: optional.Some("placeholder").Ptr(), + Default: optional.Some("defaultValue").Ptr(), + }, + { + Name: "sparse-flag", + Help: "This has only the minimum fields set", + }, + }, + expectedFlags: []*kong.Flag{ + { + Value: &kong.Value{ + Name: "full-flag", + Help: "This has all the fields set", + HasDefault: true, + Default: "defaultValue", + Tag: &kong.Tag{ + Envs: []string{ + "full-flag", + }, + }, + }, + PlaceHolder: "placeholder", + Short: 'f', + }, + { + Value: &kong.Value{ + Name: "sparse-flag", + Help: "This has only the minimum fields set", + Tag: &kong.Tag{}, + }, + }, + }, + }, + { + protoFlags: []*langpb.GetCreateModuleFlagsResponse_Flag{ + { + Name: "multi-char-short", + Help: "This has all the fields set", + Short: optional.Some("multi").Ptr(), + }, + }, + expectedError: optional.Some(`invalid flag declared: short flag "multi" for multi-char-short must be a single character`), + }, + { + protoFlags: []*langpb.GetCreateModuleFlagsResponse_Flag{ + { + Name: "dupe-short-1", + Help: "Short must be unique", + Short: optional.Some("d").Ptr(), + }, + { + Name: "dupe-short-2", + Help: "Short must be unique", + Short: optional.Some("d").Ptr(), + }, + }, + expectedError: optional.Some(`multiple flags declared with the same short name: dupe-short-1 and dupe-short-2`), + }, + } { + t.Run(tt.protoFlags[0].Name, func(t *testing.T) { + t.Parallel() + + ctx, plugin, mockImpl, _, _ := setUp() + mockImpl.flags = tt.protoFlags + kongFlags, err := plugin.GetCreateModuleFlags(ctx) + if expectedError, ok := tt.expectedError.Get(); ok { + assert.Contains(t, err.Error(), expectedError) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.expectedFlags, kongFlags) + }) + } +} + +func TestSimultaneousBuild(t *testing.T) { + t.Parallel() + ctx, plugin, _, config, sch := setUp() + _ = beginBuild(ctx, plugin, config, sch, false) + r := beginBuild(ctx, plugin, config, sch, false) + result, ok := (<-r).(either.Right[BuildResult, error]) + assert.True(t, ok, "expected error, got %v", result) + assert.Contains(t, result.Get().Error(), "build already in progress") +} + +func TestMismatchedBuildRequestId(t *testing.T) { + t.Parallel() + ctx, plugin, mockImpl, config, sch := setUp() + + // build + result := beginBuild(ctx, plugin, config, sch, false) + + // send mismatched build result (eg: a different build attempt completing) + mockImpl.buildEvents <- buildEventWithBuildError(optional.Some("fake"), "this is not the result you are looking for") + + // send real build result + realId := mockImpl.latestBuildContext.Load().buildRequestId + mockImpl.buildEvents <- buildEventWithBuildError(optional.Some(realId), "this is the correct result") + + // check result + checkResult(t, <-result, "this is the correct result") +} + +func TestRebuilds(t *testing.T) { + t.Parallel() + ctx, plugin, mockImpl, config, sch := setUp() + + // build and activate automatic rebuilds + result := beginBuild(ctx, plugin, config, sch, true) + + // send first build result + buildCtx := mockImpl.latestBuildContext.Load() + mockImpl.buildEvents <- buildEventWithBuildError(optional.Some(buildCtx.buildRequestId), "first build") + + // check result + checkResult(t, <-result, "first build") + + // send rebuild request with updated schema + sch.Modules = append(sch.Modules, &schema.Module{Name: "another"}) + sch, err := schema.ValidateSchema(sch) + assert.NoError(t, err, "schema should be valid") + result = beginBuild(ctx, plugin, config, sch, true) + + // send rebuild result + buildCtx = mockImpl.latestBuildContext.Load() + assert.Equal(t, buildCtx.schema, sch, "schema should have been updated") + mockImpl.buildEvents <- buildEventWithBuildError(optional.Some(buildCtx.buildRequestId), "second build") + + // check rebuild result + checkResult(t, <-result, "second build") +} + +func TestAutomaticRebuilds(t *testing.T) { + t.Parallel() + ctx, plugin, mockImpl, config, sch := setUp() + + updates := make(chan PluginEvent, 64) + plugin.Updates().Subscribe(updates) + + // build and activate automatic rebuilds + result := beginBuild(ctx, plugin, config, sch, true) + + // plugin sends auto rebuild has started event (should be ignored) + mockImpl.buildEvents <- &langpb.BuildEvent{ + Event: &langpb.BuildEvent_AutoRebuildStarted{}, + } + // plugin sends auto rebuild event (should be ignored) + mockImpl.buildEvents <- buildEventWithBuildError(optional.None[string](), "auto rebuild to ignore") + + // send first build result + buildCtx := mockImpl.latestBuildContext.Load() + time.Sleep(200 * time.Millisecond) + mockImpl.buildEvents <- buildEventWithBuildError(optional.Some(buildCtx.buildRequestId), "first build") + + // check result + checkResult(t, <-result, "first build") + + // confirm that nothing was posted to Updates() (ie: the auto-rebuilds events were ignored) + select { + case <-updates: + t.Fatalf("expected auto rebuilds events to not get published while build is in progress") + case <-time.After(2 * time.Second): + // as expected, no events published plugin + } + + // plugin sends auto rebuild events + mockImpl.buildEvents <- &langpb.BuildEvent{ + Event: &langpb.BuildEvent_AutoRebuildStarted{}, + } + mockImpl.buildEvents <- buildEventWithBuildError(optional.None[string](), "first real auto rebuild") + // plugin sends auto rebuild events again (this time with no rebuild started event) + mockImpl.buildEvents <- buildEventWithBuildError(optional.None[string](), "second real auto rebuild") + + // confirm that auto rebuilds events were published + events := eventsFromChannel(updates) + assert.Equal(t, len(events), 3, "expected 3 events") + assert.Equal(t, PluginEvent(AutoRebuildStartedEvent{Module: config.Module}), events[0]) + checkAutoRebuildResult(t, events[1], "first real auto rebuild") + checkAutoRebuildResult(t, events[2], "second real auto rebuild") +} + +func eventsFromChannel(updates chan PluginEvent) []PluginEvent { + // wait a bit to let events get published + time.Sleep(200 * time.Millisecond) + + events := []PluginEvent{} + for { + select { + case e := <-updates: + events = append(events, e) + default: + // no more events available right now + return events + } + } +} + +func buildEventWithBuildError(buildRequestId optional.Option[string], msg string) *langpb.BuildEvent { + return &langpb.BuildEvent{ + Event: &langpb.BuildEvent_BuildResult{ + BuildResult: &langpb.BuildResult{ + BuildRequestId: buildRequestId.Ptr(), + Errors: langpb.ErrorsToProto([]builderrors.Error{ + { + Msg: msg, + }, + }), + }, + }, + } +} + +func beginBuild(ctx context.Context, plugin *externalPlugin, config moduleconfig.ModuleConfig, sch *schema.Schema, autoRebuild bool) chan either.Either[BuildResult, error] { + result := make(chan either.Either[BuildResult, error]) + go func() { + r, err := plugin.Build(ctx, "", config, sch, []string{}, autoRebuild) + if err != nil { + result <- either.RightOf[BuildResult](err) + } else { + result <- either.LeftOf[error](r) + } + }() + // sleep to make sure impl has received the build context + time.Sleep(200 * time.Millisecond) + return result +} + +func checkResult(t *testing.T, r either.Either[BuildResult, error], expectedMsg string) { + t.Helper() + left, ok := r.(either.Left[BuildResult, error]) + assert.True(t, ok, "expected build result, got %v", r) + + buildResult := left.Get() + assert.Equal(t, len(buildResult.Errors), 1) + assert.Equal(t, buildResult.Errors[0].Msg, expectedMsg) +} + +func checkAutoRebuildResult(t *testing.T, e PluginEvent, expectedMsg string) { + t.Helper() + event, ok := e.(AutoRebuildEndedEvent) + assert.True(t, ok, "expected auto rebuild event, got %v", e) + checkResult(t, event.Result, expectedMsg) +} diff --git a/internal/buildengine/languageplugin/plugin.go b/internal/buildengine/languageplugin/plugin.go index 1964dddf98..ec4405beae 100644 --- a/internal/buildengine/languageplugin/plugin.go +++ b/internal/buildengine/languageplugin/plugin.go @@ -3,6 +3,7 @@ package languageplugin import ( "context" "fmt" + "net/url" "os" "path/filepath" "time" @@ -31,6 +32,19 @@ type BuildResult struct { StartTime time.Time } +// TODO: rethink this? +type CompilerBuildError struct { + err error +} + +func (e CompilerBuildError) Error() string { + return e.err.Error() +} + +func (e CompilerBuildError) Unwrap() error { + return e.err +} + // PluginEvent is used to notify of updates from the plugin. // //sumtype:decl @@ -78,15 +92,16 @@ type LanguagePlugin interface { CreateModule(ctx context.Context, projConfig projectconfig.Config, moduleConfig moduleconfig.ModuleConfig, flags map[string]string) error // GetDependencies returns the dependencies of the module. - GetDependencies(ctx context.Context, config moduleconfig.ModuleConfig) ([]string, error) + GetDependencies(ctx context.Context, moduleConfig moduleconfig.ModuleConfig) ([]string, error) // Build builds the module with the latest config and schema. // In dev mode, plugin is responsible for automatically rebuilding as relevant files within the module change, // and publishing these automatic builds updates to Updates(). + // TODO: build env needed? Build(ctx context.Context, projectRoot string, config moduleconfig.ModuleConfig, sch *schema.Schema, buildEnv []string, devMode bool) (BuildResult, error) // Kill stops the plugin and cleans up any resources. - Kill(ctx context.Context) error + Kill() error } // PluginFromConfig creates a new language plugin from the given config. @@ -99,7 +114,12 @@ func New(ctx context.Context, language string) (p LanguagePlugin, err error) { case "rust": return newRustPlugin(ctx), nil default: - return p, fmt.Errorf("unknown language %q", language) + // TODO: get bind url + bind, err := url.Parse("localhost:80123") + if err != nil { + return nil, fmt.Errorf("could not parse bind url: %w", err) + } + return newExternalPlugin(ctx, bind, config), nil } } @@ -174,7 +194,7 @@ func (p *internalPlugin) Updates() *pubsub.Topic[PluginEvent] { return p.updates } -func (p *internalPlugin) Kill(ctx context.Context) error { +func (p *internalPlugin) Kill() error { p.cancel() return nil }