Skip to content

Commit a092883

Browse files
authored
feat(create): add default argument logic and match specs and adds entry to librarian.yaml (#3244)
1) Refactor arguments to match [rust spec]([go/sdk-librarian-cli](http://goto.google.com/sdk-librarian-cli)) This includes: a) making library name an argument instead of a flag b) setting default values for output, spec source - this is following generate format that contains default logic per language 2) Added functionality to add entry to Librarian yaml file. 3) moved language agnostic logic outside of rust switch For #3072
1 parent 0980271 commit a092883

File tree

2 files changed

+325
-85
lines changed

2 files changed

+325
-85
lines changed

internal/librarian/create.go

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,30 @@ import (
1818
"context"
1919
"errors"
2020
"fmt"
21-
"log/slog"
21+
"os"
22+
"path"
23+
"strconv"
24+
"strings"
25+
"time"
2226

2327
"github.com/googleapis/librarian/internal/config"
24-
"github.com/googleapis/librarian/internal/librarian/internal/rust"
2528
"github.com/googleapis/librarian/internal/yaml"
2629
"github.com/urfave/cli/v3"
2730
)
2831

2932
var (
30-
errUnsupportedLanguage = errors.New("library creation is not supported for the specified language")
31-
errOutputFlagRequired = errors.New("output flag is required when default.output is not set in librarian.yaml")
32-
errServiceConfigOrSpecRequired = errors.New("both service-config and specification-source flags are required for creating a new library")
33-
errMissingNameFlag = errors.New("name flag is required to create a new library")
34-
errNoYaml = errors.New("unable to read librarian.yaml")
33+
errUnsupportedLanguage = errors.New("library creation is not supported for the specified language")
34+
errOutputFlagRequired = errors.New("output flag is required when default.output is not set in librarian.yaml")
35+
errMissingLibraryName = errors.New("must provide library name as argument to create a new library")
36+
errNoYaml = errors.New("unable to read librarian.yaml")
3537
)
3638

3739
func createCommand() *cli.Command {
3840
return &cli.Command{
3941
Name: "create",
4042
Usage: "create a new client library",
41-
UsageText: "librarian create --name <name> --specification-source <path> --service-config <path>",
43+
UsageText: "librarian create [library] --specification-source [path] --service-config [path]",
4244
Flags: []cli.Flag{
43-
&cli.StringFlag{
44-
Name: "name",
45-
Usage: "library name",
46-
},
4745
&cli.StringFlag{
4846
Name: "specification-source",
4947
Usage: "path to the specification source (e.g., google/cloud/secretmanager/v1)",
@@ -63,15 +61,15 @@ func createCommand() *cli.Command {
6361
},
6462
},
6563
Action: func(ctx context.Context, c *cli.Command) error {
66-
name := c.String("name")
64+
libraryName := c.Args().First()
65+
if libraryName == "" {
66+
return errMissingLibraryName
67+
}
6768
specSource := c.String("specification-source")
6869
serviceConfig := c.String("service-config")
6970
output := c.String("output")
7071
specFormat := c.String("specification-format")
71-
if name == "" {
72-
return errMissingNameFlag
73-
}
74-
return runCreate(ctx, name, specSource, serviceConfig, output, specFormat)
72+
return runCreate(ctx, libraryName, specSource, serviceConfig, output, specFormat)
7573
},
7674
}
7775
}
@@ -80,36 +78,90 @@ func runCreate(ctx context.Context, name, specSource, serviceConfig, output, spe
8078
return runCreateWithGenerator(ctx, name, specSource, serviceConfig, output, specFormat, &Generate{})
8179
}
8280

83-
func runCreateWithGenerator(ctx context.Context, name, specSource, serviceConfig, output, specFormat string, gen Generator) error {
81+
func runCreateWithGenerator(ctx context.Context, libraryName, specSource, serviceConfig, output, specFormat string, gen Generator) error {
8482
cfg, err := yaml.Read[config.Config](librarianConfigPath)
8583
if err != nil {
8684
return fmt.Errorf("%w: %v", errNoYaml, err)
8785
}
86+
// check for existing libraries, if it exists just run generate
87+
for _, lib := range cfg.Libraries {
88+
if lib.Name == libraryName {
89+
return gen.Run(ctx, false, libraryName)
90+
}
91+
}
92+
specSource = deriveSpecSource(specSource, serviceConfig, cfg.Language)
93+
if output, err = deriveOutput(output, cfg, libraryName, specSource, cfg.Language); err != nil {
94+
return err
95+
}
96+
if err := addLibraryToLibrarianConfig(cfg, libraryName, output, specSource, serviceConfig, specFormat); err != nil {
97+
return err
98+
}
8899
switch cfg.Language {
89100
case "rust":
90-
for _, lib := range cfg.Libraries {
91-
if lib.Name == name {
92-
return gen.Run(ctx, false, name)
93-
}
94-
}
101+
//TODO: add create logic
102+
return gen.Run(ctx, false, libraryName)
103+
default:
104+
return errUnsupportedLanguage
105+
}
106+
}
95107

96-
// if we add support for creating veneers this check should be ignored
97-
if serviceConfig == "" && specSource == "" {
98-
return errServiceConfigOrSpecRequired
108+
func deriveSpecSource(specSource string, serviceConfig string, language string) string {
109+
switch language {
110+
case "rust":
111+
if specSource == "" && serviceConfig != "" {
112+
return path.Dir(serviceConfig)
99113
}
114+
}
115+
return specSource
116+
}
100117

118+
func deriveOutput(output string, cfg *config.Config, libraryName string, specSource string, language string) (string, error) {
119+
if output == "" && (cfg.Default == nil || cfg.Default.Output == "") {
120+
return "", errOutputFlagRequired
121+
}
122+
switch language {
123+
case "rust":
101124
if output == "" {
102125
if cfg.Default == nil || cfg.Default.Output == "" {
103-
return errOutputFlagRequired
126+
return "", errOutputFlagRequired
127+
}
128+
if specSource != "" {
129+
return defaultOutput(language, specSource, cfg.Default.Output), nil
104130
}
105-
output = rust.DefaultOutput(specSource, cfg.Default.Output)
131+
libOutputDir := strings.ReplaceAll(libraryName, "-", "/")
132+
return defaultOutput(language, libOutputDir, cfg.Default.Output), nil
106133
}
107-
108-
// TODO: port over sidekick rustGenerate logic to create a new librarian
109-
slog.InfoContext(ctx, "Creating new Rust library", "name", name, "specSource", specSource, "serviceConfig", serviceConfig, "output", output, "specFormat", specFormat)
110-
return nil
111134
default:
112-
return errUnsupportedLanguage
135+
return defaultOutput(language, specSource, cfg.Default.Output), nil
136+
}
137+
138+
return output, nil
139+
}
140+
141+
func addLibraryToLibrarianConfig(rootConfig *config.Config, name, output, specificationSource, serviceConfig, specificationFormat string) error {
142+
lib := &config.Library{
143+
Name: name,
144+
Output: output,
145+
Version: "0.1.0",
146+
SpecificationFormat: specificationFormat,
147+
CopyrightYear: strconv.Itoa(time.Now().Year()),
148+
}
149+
if serviceConfig != "" || specificationSource != "" {
150+
lib.Channels = []*config.Channel{
151+
{
152+
Path: specificationSource,
153+
ServiceConfig: serviceConfig,
154+
},
155+
}
156+
}
157+
rootConfig.Libraries = append(rootConfig.Libraries, lib)
158+
data, err := yaml.Marshal(rootConfig)
159+
if err != nil {
160+
return fmt.Errorf("error marshaling librarian config: %w", err)
113161
}
114162

163+
if err := os.WriteFile(librarianConfigPath, data, 0o644); err != nil {
164+
return fmt.Errorf("error writing librarian.yaml: %w", err)
165+
}
166+
return nil
115167
}

0 commit comments

Comments
 (0)