From 05c387406c3e13bcac070302082fdc9230c1855f Mon Sep 17 00:00:00 2001 From: Priec Date: Thu, 3 Sep 2026 19:21:54 +0200 Subject: [PATCH] copy profile to another server1 --- client-gui2 | 2 +- common/proto/table_definition.proto | 61 ++++ common/src/proto/descriptor.bin | Bin 241604 -> 245342 bytes common/src/proto/komp_ac.table_definition.rs | 351 +++++++++++++++++++ komp-app/src/grpc.rs | 27 ++ prod_data_parse_scripts/parse_uctovnictvo.sh | 13 + server | 2 +- 7 files changed, 454 insertions(+), 2 deletions(-) diff --git a/client-gui2 b/client-gui2 index e87bff75..27d9d487 160000 --- a/client-gui2 +++ b/client-gui2 @@ -1 +1 @@ -Subproject commit e87bff759a1e398ca0ac08e3c66921cc2ca98858 +Subproject commit 27d9d487fe2d8bc7ce20a5e1ddb2c72b9ad8b1a3 diff --git a/common/proto/table_definition.proto b/common/proto/table_definition.proto index 3444dbea..64d93d15 100644 --- a/common/proto/table_definition.proto +++ b/common/proto/table_definition.proto @@ -55,6 +55,17 @@ service TableDefinition { // Copies one complete profile into a new profile without copying table data. rpc CopyProfile(CopyProfileRequest) returns (CopyProfileResponse); + // Serializes selected table structure and every required structural dependency. + // Dynamic table rows and deployment-local security state are never included. + rpc ExportProfileBlueprint(ExportProfileBlueprintRequest) returns (ExportProfileBlueprintResponse); + + // Reconciles a portable blueprint against a destination profile without writing. + rpc PlanProfileBlueprintImport(PlanProfileBlueprintImportRequest) returns (PlanProfileBlueprintImportResponse); + + // Applies a previously reviewed blueprint plan atomically. The plan hash protects + // against both a changed package and destination drift between preview and apply. + rpc ImportProfileBlueprint(ImportProfileBlueprintRequest) returns (ImportProfileBlueprintResponse); + // Returns the unified append-only history for column and option aliases. rpc GetAliasChangeHistory(GetAliasChangeHistoryRequest) returns (GetAliasChangeHistoryResponse); @@ -482,6 +493,56 @@ message CopyProfileResponse { int32 scripts_copied = 4; } +message ExportProfileBlueprintRequest { + string profile_name = 1; + // Empty exports every dynamic table in the profile. Otherwise only these tables + // are created by import; their unselected local dependencies become requirements. + repeated string table_names = 2; +} + +message ExportProfileBlueprintResponse { + string blueprint_json = 1; + string blueprint_sha256 = 2; + int32 tables = 3; + int32 required_local_tables = 4; + int32 required_global_tables = 5; + int32 templates = 6; +} + +message PlanProfileBlueprintImportRequest { + string target_profile_name = 1; + string blueprint_json = 2; +} + +message ProfileBlueprintImportAction { + // One of create, reuse, add, or conflict. + string action = 1; + string resource = 2; + string detail = 3; +} + +message PlanProfileBlueprintImportResponse { + bool can_import = 1; + string plan_sha256 = 2; + repeated ProfileBlueprintImportAction actions = 3; +} + +message ImportProfileBlueprintRequest { + string target_profile_name = 1; + string blueprint_json = 2; + string expected_plan_sha256 = 3; +} + +message ImportProfileBlueprintResponse { + bool success = 1; + string message = 2; + int32 tables_created = 3; + int32 globals_created = 4; + int32 globals_reused = 5; + int32 templates_created = 6; + int32 templates_reused = 7; +} + enum AliasChangeKind { ALIAS_CHANGE_KIND_UNSPECIFIED = 0; ALIAS_CHANGE_KIND_COLUMN = 1; diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index b217b0a03c7e397e581f1a4739360ee1b3f4c44e..0bddda4a7d400d107828b60b33793fda71d15825 100644 GIT binary patch delta 21706 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 delta 18276 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, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ExportProfileBlueprintResponse { + #[prost(string, tag = "1")] + pub blueprint_json: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub blueprint_sha256: ::prost::alloc::string::String, + #[prost(int32, tag = "3")] + pub tables: i32, + #[prost(int32, tag = "4")] + pub required_local_tables: i32, + #[prost(int32, tag = "5")] + pub required_global_tables: i32, + #[prost(int32, tag = "6")] + pub templates: i32, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PlanProfileBlueprintImportRequest { + #[prost(string, tag = "1")] + pub target_profile_name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub blueprint_json: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ProfileBlueprintImportAction { + /// One of create, reuse, add, or conflict. + #[prost(string, tag = "1")] + pub action: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub resource: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub detail: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PlanProfileBlueprintImportResponse { + #[prost(bool, tag = "1")] + pub can_import: bool, + #[prost(string, tag = "2")] + pub plan_sha256: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "3")] + pub actions: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ImportProfileBlueprintRequest { + #[prost(string, tag = "1")] + pub target_profile_name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub blueprint_json: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub expected_plan_sha256: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ImportProfileBlueprintResponse { + #[prost(bool, tag = "1")] + pub success: bool, + #[prost(string, tag = "2")] + pub message: ::prost::alloc::string::String, + #[prost(int32, tag = "3")] + pub tables_created: i32, + #[prost(int32, tag = "4")] + pub globals_created: i32, + #[prost(int32, tag = "5")] + pub globals_reused: i32, + #[prost(int32, tag = "6")] + pub templates_created: i32, + #[prost(int32, tag = "7")] + pub templates_reused: i32, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetAliasChangeHistoryRequest { #[prost(string, tag = "1")] pub profile_name: ::prost::alloc::string::String, @@ -1533,6 +1616,98 @@ pub mod table_definition_client { ); self.inner.unary(req, path, codec).await } + /// Serializes selected table structure and every required structural dependency. + /// Dynamic table rows and deployment-local security state are never included. + pub async fn export_profile_blueprint( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.table_definition.TableDefinition/ExportProfileBlueprint", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.table_definition.TableDefinition", + "ExportProfileBlueprint", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Reconciles a portable blueprint against a destination profile without writing. + pub async fn plan_profile_blueprint_import( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.table_definition.TableDefinition/PlanProfileBlueprintImport", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.table_definition.TableDefinition", + "PlanProfileBlueprintImport", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Applies a previously reviewed blueprint plan atomically. The plan hash protects + /// against both a changed package and destination drift between preview and apply. + pub async fn import_profile_blueprint( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.table_definition.TableDefinition/ImportProfileBlueprint", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.table_definition.TableDefinition", + "ImportProfileBlueprint", + ), + ); + self.inner.unary(req, path, codec).await + } /// Returns the unified append-only history for column and option aliases. pub async fn get_alias_change_history( &mut self, @@ -1927,6 +2102,32 @@ pub mod table_definition_server { tonic::Response, tonic::Status, >; + /// Serializes selected table structure and every required structural dependency. + /// Dynamic table rows and deployment-local security state are never included. + async fn export_profile_blueprint( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Reconciles a portable blueprint against a destination profile without writing. + async fn plan_profile_blueprint_import( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Applies a previously reviewed blueprint plan atomically. The plan hash protects + /// against both a changed package and destination drift between preview and apply. + async fn import_profile_blueprint( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Returns the unified append-only history for column and option aliases. async fn get_alias_change_history( &self, @@ -2619,6 +2820,156 @@ pub mod table_definition_server { }; Box::pin(fut) } + "/komp_ac.table_definition.TableDefinition/ExportProfileBlueprint" => { + #[allow(non_camel_case_types)] + struct ExportProfileBlueprintSvc(pub Arc); + impl< + T: TableDefinition, + > tonic::server::UnaryService + for ExportProfileBlueprintSvc { + type Response = super::ExportProfileBlueprintResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::export_profile_blueprint( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ExportProfileBlueprintSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/komp_ac.table_definition.TableDefinition/PlanProfileBlueprintImport" => { + #[allow(non_camel_case_types)] + struct PlanProfileBlueprintImportSvc(pub Arc); + impl< + T: TableDefinition, + > tonic::server::UnaryService< + super::PlanProfileBlueprintImportRequest, + > for PlanProfileBlueprintImportSvc { + type Response = super::PlanProfileBlueprintImportResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::PlanProfileBlueprintImportRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::plan_profile_blueprint_import( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = PlanProfileBlueprintImportSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/komp_ac.table_definition.TableDefinition/ImportProfileBlueprint" => { + #[allow(non_camel_case_types)] + struct ImportProfileBlueprintSvc(pub Arc); + impl< + T: TableDefinition, + > tonic::server::UnaryService + for ImportProfileBlueprintSvc { + type Response = super::ImportProfileBlueprintResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::import_profile_blueprint( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ImportProfileBlueprintSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/komp_ac.table_definition.TableDefinition/GetAliasChangeHistory" => { #[allow(non_camel_case_types)] struct GetAliasChangeHistorySvc(pub Arc); diff --git a/komp-app/src/grpc.rs b/komp-app/src/grpc.rs index d3119a89..ffc3a431 100644 --- a/komp-app/src/grpc.rs +++ b/komp-app/src/grpc.rs @@ -1335,6 +1335,33 @@ impl GrpcClient { .into_inner()) } + pub async fn export_profile_blueprint( + &mut self, + request: common::proto::komp_ac::table_definition::ExportProfileBlueprintRequest, + ) -> Result { + let request = self.authenticated_request(request)?; + Ok(self.table_definition_client.export_profile_blueprint(request).await + .context("gRPC ExportProfileBlueprint call failed")?.into_inner()) + } + + pub async fn plan_profile_blueprint_import( + &mut self, + request: common::proto::komp_ac::table_definition::PlanProfileBlueprintImportRequest, + ) -> Result { + let request = self.authenticated_request(request)?; + Ok(self.table_definition_client.plan_profile_blueprint_import(request).await + .context("gRPC PlanProfileBlueprintImport call failed")?.into_inner()) + } + + pub async fn import_profile_blueprint( + &mut self, + request: common::proto::komp_ac::table_definition::ImportProfileBlueprintRequest, + ) -> Result { + let request = self.authenticated_request(request)?; + Ok(self.table_definition_client.import_profile_blueprint(request).await + .context("gRPC ImportProfileBlueprint call failed")?.into_inner()) + } + pub async fn get_alias_change_history( &mut self, request: common::proto::komp_ac::table_definition::GetAliasChangeHistoryRequest, diff --git a/prod_data_parse_scripts/parse_uctovnictvo.sh b/prod_data_parse_scripts/parse_uctovnictvo.sh index 37e0433a..7ec0e3c2 100755 --- a/prod_data_parse_scripts/parse_uctovnictvo.sh +++ b/prod_data_parse_scripts/parse_uctovnictvo.sh @@ -34,12 +34,20 @@ process_csv() { OFS = FS } + { + sub(/\r$/, "", $0) + } + NR == 1 { print next } { + if ($6 == "- -") { + $6 = "" + } + cleaned = clean_account($10) if (cleaned == "") { @@ -47,6 +55,11 @@ process_csv() { } key = cleaned + + if (key == "000") { + next + } + key_count[key]++ if (!(key in key_order)) { key_order[key] = ++key_total diff --git a/server b/server index cfc19981..9325e5b5 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit cfc199812191284cf00ec06d731565e0e52bffa1 +Subproject commit 9325e5b53776ae14016cb227cba4982237b937ba