@@ -43,20 +43,41 @@ var (
4343// the entire generation process.
4444func Generate (ctx context.Context , cfg * generate.Config ) error {
4545 slog .Debug ("librariangen: generate command started" )
46+ libraryID := cfg .Request .ID
47+ for _ , api := range cfg .Request .APIs {
48+ if err := processAPI (ctx , cfg , libraryID , api ); err != nil {
49+ return err
50+ }
51+ }
52+
53+ // Generate pom.xml files
54+ if err := pom .Generate (cfg .Context .OutputDir , libraryID ); err != nil {
55+ return fmt .Errorf ("librariangen: failed to generate poms for API %s: %w" , libraryID , err )
56+ }
57+
58+ slog .Debug ("librariangen: generate command finished" )
59+ return nil
60+ }
61+
62+ func processAPI (ctx context.Context , cfg * generate.Config , libraryID string , api message.API ) error {
63+ version := extractVersion (api .Path )
64+ if version == "" {
65+ slog .Warn ("skipping api with no version" , "api" , api .Path )
66+ return nil
67+ }
68+ slog .Info ("processing api" , "path" , api .Path , "version" , version )
4669 outputConfig := & protoc.OutputConfig {
47- GAPICDir : filepath .Join (cfg .Context .OutputDir , "gapic" ),
48- GRPCDir : filepath .Join (cfg .Context .OutputDir , "grpc" ),
49- ProtoDir : filepath .Join (cfg .Context .OutputDir , "proto" ),
70+ GAPICDir : filepath .Join (cfg .Context .OutputDir , version , "gapic" ),
71+ GRPCDir : filepath .Join (cfg .Context .OutputDir , version , "grpc" ),
72+ ProtoDir : filepath .Join (cfg .Context .OutputDir , version , "proto" ),
5073 }
5174 defer func () {
5275 if err := cleanupIntermediateFiles (outputConfig ); err != nil {
53- slog .Error ("librariangen: failed to clean up intermediate files " , "error " , err )
76+ slog .Error ("failed to cleanup " , "err " , err )
5477 }
5578 }()
5679
57- generateReq := cfg .Request
58-
59- if err := invokeProtoc (ctx , cfg .Context , generateReq , outputConfig ); err != nil {
80+ if err := invokeProtoc (ctx , cfg .Context , & api , outputConfig ); err != nil {
6081 return fmt .Errorf ("librariangen: gapic generation failed: %w" , err )
6182 }
6283 // Unzip the temp-codegen.srcjar.
@@ -66,45 +87,47 @@ func Generate(ctx context.Context, cfg *generate.Config) error {
6687 return fmt .Errorf ("librariangen: failed to unzip %s: %w" , srcjarPath , err )
6788 }
6889
69- if err := restructureOutput (cfg .Context .OutputDir , generateReq . ID ); err != nil {
90+ if err := restructureOutput (cfg .Context .OutputDir , libraryID , version ); err != nil {
7091 return fmt .Errorf ("librariangen: failed to restructure output: %w" , err )
7192 }
7293
73- // Generate pom.xml files
74- if err := pom .Generate (cfg .Context .OutputDir , generateReq .ID ); err != nil {
75- return fmt .Errorf ("librariangen: failed to generate poms for API %s: %w" , generateReq .ID , err )
76- }
77-
78- slog .Debug ("librariangen: generate command finished" )
7994 return nil
8095}
8196
97+ func extractVersion (path string ) string {
98+ parts := strings .Split (path , "/" )
99+ for i := len (parts ) - 1 ; i >= 0 ; i -- {
100+ if strings .HasPrefix (parts [i ], "v" ) {
101+ return parts [i ]
102+ }
103+ }
104+ return ""
105+ }
106+
82107// invokeProtoc handles the protoc GAPIC generation logic for the 'generate' CLI command.
83108// It reads a request file, and for each API specified, it invokes protoc
84109// to generate the client library. It returns the module path and the path to the service YAML.
85- func invokeProtoc (ctx context.Context , genCtx * generate.Context , generateReq * message.Library , outputConfig * protoc.OutputConfig ) error {
86- for _ , api := range generateReq .APIs {
87- apiServiceDir := filepath .Join (genCtx .SourceDir , api .Path )
88- slog .Info ("processing api" , "service_dir" , apiServiceDir )
89- bazelConfig , err := bazelParse (apiServiceDir )
90- if err != nil {
91- return fmt .Errorf ("librariangen: failed to parse BUILD.bazel for %s: %w" , apiServiceDir , err )
92- }
93- args , err := protocBuild (apiServiceDir , bazelConfig , genCtx .SourceDir , outputConfig )
94- if err != nil {
95- return fmt .Errorf ("librariangen: failed to build protoc command for api %q in library %q: %w" , api .Path , generateReq .ID , err )
96- }
110+ func invokeProtoc (ctx context.Context , genCtx * generate.Context , api * message.API , outputConfig * protoc.OutputConfig ) error {
111+ apiServiceDir := filepath .Join (genCtx .SourceDir , api .Path )
112+ slog .Info ("processing api" , "service_dir" , apiServiceDir )
113+ bazelConfig , err := bazelParse (apiServiceDir )
114+ if err != nil {
115+ return fmt .Errorf ("librariangen: failed to parse BUILD.bazel for %s: %w" , apiServiceDir , err )
116+ }
117+ args , err := protocBuild (apiServiceDir , bazelConfig , genCtx .SourceDir , outputConfig )
118+ if err != nil {
119+ return fmt .Errorf ("librariangen: failed to build protoc command for api %q: %w" , api .Path , err )
120+ }
97121
98- // Create protoc output directories.
99- for _ , dir := range []string {outputConfig .ProtoDir , outputConfig .GRPCDir , outputConfig .GAPICDir } {
100- if err := os .MkdirAll (dir , 0755 ); err != nil {
101- return err
102- }
122+ // Create protoc output directories.
123+ for _ , dir := range []string {outputConfig .ProtoDir , outputConfig .GRPCDir , outputConfig .GAPICDir } {
124+ if err := os .MkdirAll (dir , 0755 ); err != nil {
125+ return err
103126 }
127+ }
104128
105- if err := execvRun (ctx , args , genCtx .OutputDir ); err != nil {
106- return fmt .Errorf ("librariangen: protoc failed for api %q in library %q: %w, execvRun error: %v" , api .Path , generateReq .ID , err , err )
107- }
129+ if err := execvRun (ctx , args , genCtx .OutputDir ); err != nil {
130+ return fmt .Errorf ("librariangen: protoc failed for api %q: %w, execvRun error: %v" , api .Path , err , err )
108131 }
109132 return nil
110133}
@@ -126,23 +149,21 @@ func moveFiles(sourceDir, targetDir string) error {
126149 return nil
127150}
128151
129- func restructureOutput (outputDir , libraryID string ) error {
152+ func restructureOutput (outputDir , libraryID , version string ) error {
130153 slog .Debug ("librariangen: restructuring output directory" , "dir" , outputDir )
131154
132155 // Define source and destination directories.
133- gapicSrcDir := filepath .Join (outputDir , "gapic" , "src" , "main" , "java" )
134- gapicTestDir := filepath .Join (outputDir , "gapic" , "src" , "test" , "java" )
135- protoSrcDir := filepath .Join (outputDir , "proto" )
136- resourceNameSrcDir := filepath .Join (outputDir , "gapic" , "proto" , "src" , "main" , "java" )
137- grpcSrcDir := filepath .Join (outputDir , "grpc" )
138- samplesDir := filepath .Join (outputDir , "gapic" , "samples" , "snippets" )
139-
140- // TODO(meltsufin): currently we assume we have a single API variant v1
156+ gapicSrcDir := filepath .Join (outputDir , version , "gapic" , "src" , "main" , "java" )
157+ gapicTestDir := filepath .Join (outputDir , version , "gapic" , "src" , "test" , "java" )
158+ protoSrcDir := filepath .Join (outputDir , version , "proto" )
159+ resourceNameSrcDir := filepath .Join (outputDir , version , "gapic" , "proto" , "src" , "main" , "java" )
160+ samplesDir := filepath .Join (outputDir , version , "gapic" , "samples" , "snippets" )
161+
141162 gapicDestDir := filepath .Join (outputDir , fmt .Sprintf ("google-cloud-%s" , libraryID ), "src" , "main" , "java" )
142163 gapicTestDestDir := filepath .Join (outputDir , fmt .Sprintf ("google-cloud-%s" , libraryID ), "src" , "test" , "java" )
143- protoDestDir := filepath .Join (outputDir , fmt .Sprintf ("proto-google-cloud-%s-v1 " , libraryID ), "src" , "main" , "java" )
144- resourceNameDestDir := filepath .Join (outputDir , fmt .Sprintf ("proto-google-cloud-%s-v1 " , libraryID ), "src" , "main" , "java" )
145- grpcDestDir := filepath .Join (outputDir , fmt .Sprintf ("grpc-google-cloud-%s-v1 " , libraryID ), "src" , "main" , "java" )
164+ protoDestDir := filepath .Join (outputDir , fmt .Sprintf ("proto-google-cloud-%s-%s " , libraryID , version ), "src" , "main" , "java" )
165+ resourceNameDestDir := filepath .Join (outputDir , fmt .Sprintf ("proto-google-cloud-%s-%s " , libraryID , version ), "src" , "main" , "java" )
166+ grpcDestDir := filepath .Join (outputDir , fmt .Sprintf ("grpc-google-cloud-%s-%s " , libraryID , version ), "src" , "main" , "java" )
146167 samplesDestDir := filepath .Join (outputDir , "samples" , "snippets" )
147168
148169 // Create destination directories.
@@ -161,20 +182,37 @@ func restructureOutput(outputDir, libraryID string) error {
161182 }
162183 }
163184
185+ // Remove the location classes from the proto output to avoid conflicts with
186+ // proto-google-common-protos.
187+ if err := os .RemoveAll (filepath .Join (protoSrcDir , "com" , "google" , "cloud" , "location" )); err != nil {
188+ return err
189+ }
190+ if err := os .Remove (filepath .Join (protoSrcDir , "google" , "cloud" , "CommonResources.java" )); err != nil {
191+ return err
192+ }
193+
164194 // Move files that won't have conflicts.
165195 moves := map [string ]string {
166- gapicSrcDir : gapicDestDir ,
167- gapicTestDir : gapicTestDestDir ,
168- protoSrcDir : protoDestDir ,
169- grpcSrcDir : grpcDestDir ,
170- samplesDir : samplesDestDir ,
196+ filepath .Join (outputDir , version , "proto" ): protoDestDir ,
197+ filepath .Join (outputDir , version , "grpc" ): grpcDestDir ,
171198 }
172199 for src , dest := range moves {
173200 if err := moveFiles (src , dest ); err != nil {
174201 return err
175202 }
176203 }
177204
205+ // Merge the gapic source and test files.
206+ if err := copyAndMerge (gapicSrcDir , gapicDestDir ); err != nil {
207+ return err
208+ }
209+ if err := copyAndMerge (gapicTestDir , gapicTestDestDir ); err != nil {
210+ return err
211+ }
212+ if err := copyAndMerge (samplesDir , samplesDestDir ); err != nil {
213+ return err
214+ }
215+
178216 // Merge the resource name files into the proto destination.
179217 if err := copyAndMerge (resourceNameSrcDir , resourceNameDestDir ); err != nil {
180218 return err
@@ -214,12 +252,7 @@ func copyAndMerge(src, dest string) error {
214252
215253func cleanupIntermediateFiles (outputConfig * protoc.OutputConfig ) error {
216254 slog .Debug ("librariangen: cleaning up intermediate files" )
217- for _ , path := range []string {outputConfig .GAPICDir , outputConfig .GRPCDir , outputConfig .ProtoDir } {
218- if err := os .RemoveAll (path ); err != nil {
219- return fmt .Errorf ("failed to clean up intermediate file at %s: %w" , path , err )
220- }
221- }
222- return nil
255+ return os .RemoveAll (filepath .Dir (outputConfig .GAPICDir ))
223256}
224257
225258func unzip (src , dest string ) error {
0 commit comments