From f6d74ecf004846832eaf4f8c98c25f53ec2a0b1f Mon Sep 17 00:00:00 2001 From: Sandipsinh Rathod <62684960+ssddOnTop@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:14:12 +0530 Subject: [PATCH] fix(grpc): import proto files relative to parent proto (#1705) --- src/grpc/tests/proto/cycle.proto | 4 +-- src/grpc/tests/proto/duplicate.proto | 4 +-- src/grpc/tests/proto/nested0.proto | 6 ++-- src/grpc/tests/proto/nested1.proto | 4 +-- src/proto_reader.rs | 41 ++++++++++++++++++++++------ 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/grpc/tests/proto/cycle.proto b/src/grpc/tests/proto/cycle.proto index e3db248fb1..3b948bf77c 100644 --- a/src/grpc/tests/proto/cycle.proto +++ b/src/grpc/tests/proto/cycle.proto @@ -2,5 +2,5 @@ syntax = "proto3"; package cycle; -import "src/grpc/tests/proto/nested0.proto"; -import "src/grpc/tests/proto/duplicate.proto"; +import "nested0.proto"; +import "duplicate.proto"; diff --git a/src/grpc/tests/proto/duplicate.proto b/src/grpc/tests/proto/duplicate.proto index 8d6aa8fcd3..54c9461118 100644 --- a/src/grpc/tests/proto/duplicate.proto +++ b/src/grpc/tests/proto/duplicate.proto @@ -2,5 +2,5 @@ syntax = "proto3"; package duplicate; -import "src/grpc/tests/proto/greetings.proto"; -import "src/grpc/tests/proto/news.proto"; +import "greetings.proto"; +import "news.proto"; diff --git a/src/grpc/tests/proto/nested0.proto b/src/grpc/tests/proto/nested0.proto index 54dd8017ce..bf6fd25a0e 100644 --- a/src/grpc/tests/proto/nested0.proto +++ b/src/grpc/tests/proto/nested0.proto @@ -2,6 +2,6 @@ syntax = "proto3"; package nested0; -import "src/grpc/tests/proto/greetings.proto"; -import "src/grpc/tests/proto/nested1.proto"; -import "src/grpc/tests/proto/news_no_pkg.proto"; \ No newline at end of file +import "greetings.proto"; +import "nested1.proto"; +import "news_no_pkg.proto"; \ No newline at end of file diff --git a/src/grpc/tests/proto/nested1.proto b/src/grpc/tests/proto/nested1.proto index 7f22d53a43..b4bf1a0560 100644 --- a/src/grpc/tests/proto/nested1.proto +++ b/src/grpc/tests/proto/nested1.proto @@ -2,5 +2,5 @@ syntax = "proto3"; package nested1; -import "src/grpc/tests/proto/news.proto"; -import "src/grpc/tests/proto/cycle.proto"; +import "news.proto"; +import "cycle.proto"; diff --git a/src/proto_reader.rs b/src/proto_reader.rs index 77d5087a86..53c45ac49a 100644 --- a/src/proto_reader.rs +++ b/src/proto_reader.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap, VecDeque}; +use std::path::{Path, PathBuf}; use anyhow::Context; use futures_util::future::join_all; @@ -30,12 +31,14 @@ impl ProtoReader { } pub async fn read>(&self, path: T) -> anyhow::Result { - let file_read = self.read_proto(path.as_ref()).await?; + let file_read = self.read_proto(path.as_ref(), None).await?; if file_read.package.is_none() { anyhow::bail!("Package name is required"); } - let descriptors = self.resolve_descriptors(file_read).await?; + let descriptors = self + .resolve_descriptors(file_read, PathBuf::from(path.as_ref()).parent()) + .await?; let metadata = ProtoMetadata { descriptor_set: FileDescriptorSet { file: descriptors }, path: path.as_ref().to_string(), @@ -47,6 +50,7 @@ impl ProtoReader { async fn resolve_descriptors( &self, parent_proto: FileDescriptorProto, + parent_path: Option<&Path>, ) -> anyhow::Result> { let mut descriptors: HashMap = HashMap::new(); let mut queue = VecDeque::new(); @@ -56,7 +60,7 @@ impl ProtoReader { let futures: Vec<_> = file .dependency .iter() - .map(|import| self.read_proto(import)) + .map(|import| self.read_proto(import, parent_path)) .collect(); let results = join_all(futures).await; @@ -79,15 +83,35 @@ impl ProtoReader { /// Tries to load well-known google proto files and if not found uses normal /// file and http IO to resolve them - async fn read_proto(&self, path: &str) -> anyhow::Result { - let content = if let Ok(file) = GoogleFileResolver::new().open_file(path) { + async fn read_proto>( + &self, + path: T, + parent_dir: Option<&Path>, + ) -> anyhow::Result { + let content = if let Ok(file) = GoogleFileResolver::new().open_file(path.as_ref()) { file.source() .context("Unable to extract content of google well-known proto file")? .to_string() } else { + let path = Self::resolve_path(path.as_ref(), parent_dir); self.resource_reader.read_file(path).await?.content }; - Ok(protox_parse::parse(path, &content)?) + Ok(protox_parse::parse(path.as_ref(), &content)?) + } + /// Checks if path is absolute else it joins file path with relative dir + /// path + fn resolve_path(src: &str, root_dir: Option<&Path>) -> String { + if src.starts_with("http") { + return src.to_string(); + } + + if Path::new(&src).is_absolute() { + src.to_string() + } else if let Some(path) = root_dir { + path.join(src).to_string_lossy().to_string() + } else { + src.to_string() + } } } @@ -108,7 +132,7 @@ mod test_proto_config { crate::runtime::test::init(None), )); reader - .read_proto("google/protobuf/empty.proto") + .read_proto("google/protobuf/empty.proto", None) .await .unwrap(); } @@ -136,8 +160,9 @@ mod test_proto_config { let file_rt = runtime.file.clone(); let reader = ProtoReader::init(ResourceReader::::cached(runtime)); + let pathbuf = PathBuf::from(&test_file); let helper_map = reader - .resolve_descriptors(reader.read_proto(&test_file).await?) + .resolve_descriptors(reader.read_proto(&test_file, None).await?, pathbuf.parent()) .await?; let files = test_dir.read_dir()?; for file in files {