11/*
2- * Copyright (C) 2018-2024 smart-doc
2+ * Copyright (C) 2018-2025 smart-doc
33 *
44 * Licensed to the Apache Software Foundation (ASF) under one
55 * or more contributor license agreements. See the NOTICE file
3434import com .ly .doc .model .grpc .GrpcApiDoc ;
3535import com .ly .doc .model .grpc .GrpcJavaMethod ;
3636import com .ly .doc .model .grpc .ProtoInfo ;
37- import com .ly .doc .model .grpc .proto .*;
37+ import com .ly .doc .model .grpc .proto .EnumDefinition ;
38+ import com .ly .doc .model .grpc .proto .EnumValue ;
39+ import com .ly .doc .model .grpc .proto .Message ;
40+ import com .ly .doc .model .grpc .proto .MessageField ;
41+ import com .ly .doc .model .grpc .proto .ProtoJson ;
42+ import com .ly .doc .model .grpc .proto .Service ;
43+ import com .ly .doc .model .grpc .proto .ServiceMethod ;
3844import com .ly .doc .utils .DocUtil ;
3945import com .power .common .util .FileUtil ;
46+ import com .power .common .util .StringUtil ;
4047import com .thoughtworks .qdox .model .JavaClass ;
4148
42- import java .io .*;
49+ import java .io .BufferedReader ;
50+ import java .io .File ;
51+ import java .io .IOException ;
52+ import java .io .InputStream ;
53+ import java .io .InputStreamReader ;
4354import java .nio .file .Files ;
4455import java .nio .file .Path ;
4556import java .nio .file .Paths ;
4657import java .nio .file .StandardCopyOption ;
4758import java .nio .file .attribute .PosixFilePermissions ;
48- import java .util .*;
59+ import java .util .ArrayList ;
60+ import java .util .Collection ;
61+ import java .util .Collections ;
62+ import java .util .List ;
63+ import java .util .Map ;
64+ import java .util .Objects ;
65+ import java .util .Set ;
4966import java .util .concurrent .atomic .AtomicInteger ;
5067import java .util .function .Consumer ;
5168import java .util .function .Function ;
@@ -315,6 +332,9 @@ private void copyResourceFile(String resourcePath, String targetPath) {
315332 */
316333 public void executeProtocCommands (Set <String > protoFiles , ProtoInfo protoInfo ) {
317334 List <String > command = this .buildProtocCommand (protoFiles , protoInfo );
335+ if (command .isEmpty ()) {
336+ return ;
337+ }
318338 this .executeCommand (command , protoInfo );
319339 }
320340
@@ -344,7 +364,8 @@ private void executeCommand(List<String> command, ProtoInfo protoInfo) {
344364 try {
345365 Process process = processBuilder .start ();
346366
347- StreamGobbler outputGobbler = new StreamGobbler (process .getInputStream (), log ::warning );
367+ StreamGobbler outputGobbler = new StreamGobbler (process .getInputStream (),
368+ line -> log .warning ("[protoc] " + line ));
348369 Thread outputThread = new Thread (outputGobbler );
349370 outputThread .start ();
350371
@@ -354,7 +375,7 @@ private void executeCommand(List<String> command, ProtoInfo protoInfo) {
354375 outputThread .join ();
355376
356377 if (exitCode != 0 ) {
357- log .warning ("Error executing command for files" );
378+ log .warning ("protoc command failed with exit code: " + exitCode );
358379 }
359380 }
360381 catch (IOException | InterruptedException e ) {
@@ -370,24 +391,71 @@ private void executeCommand(List<String> command, ProtoInfo protoInfo) {
370391 */
371392 private List <String > buildProtocCommand (Set <String > protoFiles , ProtoInfo protoInfo ) {
372393 List <String > command = new ArrayList <>();
373- command .add (protoInfo .getProtocPath ());
374- command .add ("--proto_path=" + String .join (";" , this .getUniqueParentDirectories (protoFiles )));
375- command .add ("--doc_out=" + protoInfo .getTargetJsonDirectoryPath ());
394+
395+ // Add the protoc executable (using absolute path)
396+ command .add (Paths .get (protoInfo .getProtocPath ()).toAbsolutePath ().toString ());
397+
398+ // Find the common root directory for all .proto files
399+ String commonRootPath = this .findCommonRootDirectory (protoFiles );
400+ if (StringUtil .isEmpty (commonRootPath )) {
401+ log .warning ("No common root directory found for proto files." );
402+ return Collections .emptyList ();
403+ }
404+
405+ // Set --proto_path to the common root directory
406+ command .add ("--proto_path=" + commonRootPath );
407+
408+ // Set output options
409+ command .add ("--doc_out=" + Paths .get (protoInfo .getTargetJsonDirectoryPath ()).toAbsolutePath ());
376410 command .add ("--doc_opt=json," + protoInfo .getJsonName ());
377- command .addAll (protoFiles );
378- command .add ("--plugin=protoc-gen-doc=" + protoInfo .getProtocGenDocPath ());
411+
412+ // Set the plugin path (using absolute path)
413+ command .add ("--plugin=protoc-gen-doc=" + Paths .get (protoInfo .getProtocGenDocPath ()).toAbsolutePath ());
414+
415+ // Add the absolute paths of the .proto files
416+ for (String filePath : protoFiles ) {
417+ Path file = Paths .get (filePath ).toAbsolutePath ().normalize ();
418+ command .add (file .toString ());
419+ }
420+
379421 return command ;
380422 }
381423
382424 /**
383- * Get the unique parent directories of the given set of files.
384- * @param files The set of files .
385- * @return The set of unique parent directories .
425+ * Find the deepest common ancestor directory for the given set of files.
426+ * @param files The set of .proto file paths .
427+ * @return The common root directory path, or null if the set is empty .
386428 */
387- private Set <String > getUniqueParentDirectories (Set <String > files ) {
388- Set <String > directories = new HashSet <>();
389- files .forEach (file -> directories .add (new File (file ).getParent ()));
390- return directories ;
429+ private String findCommonRootDirectory (Set <String > files ) {
430+ if (files .isEmpty ()) {
431+ return null ;
432+ }
433+
434+ // Convert all paths to Path objects
435+ List <Path > filePaths = files .stream ()
436+ .map (Paths ::get )
437+ .map (Path ::toAbsolutePath )
438+ .map (Path ::normalize )
439+ .collect (Collectors .toList ());
440+
441+ // Use the first path as the initial common root
442+ Path commonRoot = filePaths .get (0 );
443+
444+ // Compare with all other paths, gradually shorten commonRoot until it is a prefix
445+ // of all paths
446+ for (Path path : filePaths ) {
447+ while (!path .startsWith (commonRoot )) {
448+ commonRoot = commonRoot .getParent ();
449+ if (commonRoot == null ) {
450+ // If we've gone up to null, there's no common parent, return the root
451+ // of the path
452+ commonRoot = path .getRoot ();
453+ break ;
454+ }
455+ }
456+ }
457+
458+ return commonRoot .toString ();
391459 }
392460
393461 /**
0 commit comments