@@ -17,16 +17,25 @@ package golang
1717
1818import (
1919 "context"
20+ _ "embed"
2021 "fmt"
2122 "os"
2223 "path/filepath"
2324 "strings"
25+ "text/template"
2426
2527 "github.com/googleapis/librarian/internal/command"
2628 "github.com/googleapis/librarian/internal/config"
2729 "github.com/googleapis/librarian/internal/serviceconfig"
2830)
2931
32+ var (
33+ //go:embed template/_README.md.txt
34+ readmeTmpl string
35+
36+ readmeTmplParsed = template .Must (template .New ("readme" ).Parse (readmeTmpl ))
37+ )
38+
3039// Generate generates a Go client library.
3140func Generate (ctx context.Context , library * config.Library , googleapisDir string ) error {
3241 if len (library .APIs ) == 0 {
@@ -70,6 +79,13 @@ func Generate(ctx context.Context, library *config.Library, googleapisDir string
7079 }
7180
7281 moduleRoot := filepath .Join (outdir , library .Name )
82+ absModuleRoot , err := filepath .Abs (moduleRoot )
83+ if err != nil {
84+ return err
85+ }
86+ if ! strings .HasPrefix (absModuleRoot , outdir + string (filepath .Separator )) && absModuleRoot != outdir {
87+ return fmt .Errorf ("invalid library name: path traversal detected" )
88+ }
7389 if err := generateInternalVersionFile (moduleRoot , library .Version ); err != nil {
7490 return err
7591 }
@@ -78,6 +94,13 @@ func Generate(ctx context.Context, library *config.Library, googleapisDir string
7894 return err
7995 }
8096 }
97+ api , err := serviceconfig .Find (googleapisDir , library .APIs [0 ].Path )
98+ if err != nil {
99+ return err
100+ }
101+ if err := generateREADME (library , api , moduleRoot ); err != nil {
102+ return err
103+ }
81104 return nil
82105}
83106
@@ -293,3 +316,22 @@ func collectProtoFiles(googleapisDir, apiPath string, nestedProtos []string) ([]
293316 }
294317 return files , nil
295318}
319+
320+ func generateREADME (library * config.Library , api * serviceconfig.API , moduleRoot string ) error {
321+ if len (library .APIs ) == 0 {
322+ return fmt .Errorf ("no APIs configured" )
323+ }
324+ f , err := os .Create (filepath .Join (moduleRoot , "README.md" ))
325+ if err != nil {
326+ return err
327+ }
328+ err = readmeTmplParsed .Execute (f , map [string ]string {
329+ "Name" : api .Title ,
330+ "ModulePath" : modulePath (library ),
331+ })
332+ cerr := f .Close ()
333+ if err != nil {
334+ return err
335+ }
336+ return cerr
337+ }
0 commit comments