deriveProtoDirFromPath extracts the package from a gRPC path and searches protoInclude roots for a matching directory. This enables automatic proto directory resolution for multi-service scenarios where a single protoDir config is insufficient. It uses a multi-strategy approach following protobuf c
(grpcPath string, protoIncludes []string)
| 252 | // |
| 253 | // Returns the first matching directory path, or an error if none found. |
| 254 | func deriveProtoDirFromPath(grpcPath string, protoIncludes []string) (string, error) { |
| 255 | if grpcPath == "" || len(protoIncludes) == 0 { |
| 256 | return "", fmt.Errorf("grpcPath and protoIncludes are required") |
| 257 | } |
| 258 | |
| 259 | // Parse gRPC path to get service full name (e.g., "keploy.v1.keploy") |
| 260 | serviceFull, _, err := ParseGRPCPath(grpcPath) |
| 261 | if err != nil { |
| 262 | return "", fmt.Errorf("failed to parse gRPC path: %w", err) |
| 263 | } |
| 264 | |
| 265 | parts := strings.Split(serviceFull, ".") |
| 266 | |
| 267 | // Build search strategies in order of likelihood: |
| 268 | // 1. Full package path (minus service name): "keploy.v1.keploy" → "keploy/v1" |
| 269 | // 2. First segment only: "keploy" |
| 270 | var strategies []string |
| 271 | |
| 272 | // Strategy 1: Full package path (remove service name - last part) |
| 273 | if len(parts) > 1 { |
| 274 | packageParts := parts[:len(parts)-1] // ["keploy", "v1"] |
| 275 | strategies = append(strategies, filepath.Join(packageParts...)) |
| 276 | } |
| 277 | |
| 278 | // Strategy 2: First segment only |
| 279 | strategies = append(strategies, parts[0]) |
| 280 | |
| 281 | // Search protoInclude roots for matching directory |
| 282 | for _, root := range protoIncludes { |
| 283 | absRoot, err := mustAbs(root) |
| 284 | if err != nil || absRoot == "" { |
| 285 | continue |
| 286 | } |
| 287 | |
| 288 | for _, strategy := range strategies { |
| 289 | candidateDir := filepath.Join(absRoot, strategy) |
| 290 | if info, err := os.Stat(candidateDir); err == nil && info.IsDir() { |
| 291 | return candidateDir, nil |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | return "", fmt.Errorf("no proto directory found for service %q in protoInclude roots (tried: %v)", serviceFull, strategies) |
| 297 | } |
| 298 | |
| 299 | // ProtoTextToWire turns Protoscope text into wire bytes using the library (no exec). |
| 300 | func ProtoTextToWire(text string) ([]byte, error) { |
no test coverage detected