Skip to content

Commit

Permalink
WIP common models
Browse files Browse the repository at this point in the history
  • Loading branch information
manicminer committed Jul 13, 2023
1 parent 1534f87 commit 38712ff
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 26 deletions.
99 changes: 99 additions & 0 deletions tools/generator-go-sdk/generator/common_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package generator

import (
"fmt"
"log"
"os"
"path/filepath"
"strings"

"github.com/hashicorp/pandora/tools/sdk/resourcemanager"
"github.com/hashicorp/pandora/tools/sdk/services"
)

type CommonTypesGenerator struct{}

func NewCommonTypesGenerator() CommonTypesGenerator {
return CommonTypesGenerator{}
}

type SDKInput struct {
CommonPackageName string
CommonPackagePath string
CommonTypes *services.ResourceManagerCommonTypes
OutputDirectory string
VersionName string
}

func (s *CommonTypesGenerator) GenerateForSDK(input SDKInput) error {
input.VersionName = strings.ToLower(input.VersionName)
commonTypesDirectory := filepath.Join(input.OutputDirectory, input.CommonPackagePath)

if err := cleanAndRecreateWorkingDirectory(commonTypesDirectory); err != nil {
return fmt.Errorf("cleaning/recreating working directory %q: %+v", commonTypesDirectory, err)
}

stages := map[string]func(SDKInput, string) error{
"commonTypes": s.commonTypes,
}
for name, stage := range stages {
log.Printf("[DEBUG] Running Stage %q..", name)
if err := stage(input, commonTypesDirectory); err != nil {
return fmt.Errorf("generating %s: %+v", name, err)
}
}

runGoFmt(commonTypesDirectory)
runGoImports(commonTypesDirectory)
return nil
}

func (s *CommonTypesGenerator) commonTypes(input SDKInput, outputDirectory string) error {
data := ServiceGeneratorData{
apiVersion: input.VersionName,
constants: input.CommonTypes.Constants,
models: input.CommonTypes.Models,
packageName: "models",
source: resourcemanager.ApiDefinitionsSourceMicrosoftGraphMetadata,
}

gen := constantsTemplater{
constantTemplateFunc: templateForConstant,
}
if err := s.writeToPath(outputDirectory, "constants.go", gen, data); err != nil {
return fmt.Errorf("templating constants: %+v", err)
}

for modelName, model := range input.CommonTypes.Models {
fileName := fmt.Sprintf("model_%s.go", strings.ToLower(modelName))
gen := modelsTemplater{
name: modelName,
model: model,
}
if err := s.writeToPath(outputDirectory, fileName, gen, data); err != nil {
return fmt.Errorf("templating model for %q: %+v", modelName, err)
}
}

return nil
}

func (s *CommonTypesGenerator) writeToPath(directory, filePath string, templater templaterForResource, data ServiceGeneratorData) error {
fileContents, err := templater.template(data)
if err != nil {
return fmt.Errorf("templating: %+v", err)
}

fullFilePath := filepath.Join(directory, filePath)

// remove any existing file if it exists
_ = os.Remove(fullFilePath)
file, err := os.Create(fullFilePath)
defer file.Close()
if err != nil {
return fmt.Errorf("opening %q: %+v", fullFilePath, err)
}

_, _ = file.WriteString(*fileContents)
return nil
}
8 changes: 5 additions & 3 deletions tools/generator-go-sdk/generator/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ type ServiceGeneratorData struct {

baseClientMethod string
baseClientPackage string
commonPackagePath string
}

func (i ServiceGeneratorInput) generatorData(settings Settings) ServiceGeneratorData {
servicePackageName := golangPackageName(i.ServiceName)
versionPackageName := golangPackageName(i.VersionName)
servicePackageName := GolangPackageName(i.ServiceName)
versionPackageName := GolangPackageName(i.VersionName)
// TODO: it'd be nice to make these snake_case but that's a problem for another day
resourcePackageName := golangPackageName(i.ResourceName)
resourcePackageName := GolangPackageName(i.ResourceName)
versionOutputPath := filepath.Join(i.OutputDirectory, servicePackageName, versionPackageName)
resourceOutputPath := filepath.Join(versionOutputPath, resourcePackageName)
idsPath := filepath.Join(versionOutputPath, "ids")
Expand All @@ -75,6 +76,7 @@ func (i ServiceGeneratorInput) generatorData(settings Settings) ServiceGenerator
apiVersion: i.VersionName,
baseClientMethod: i.BaseClientMethod,
baseClientPackage: i.BaseClientPackage,
commonPackagePath: i.CommonPackagePath,
constants: i.ResourceDetails.Schema.Constants,
idsOutputPath: idsPath,
models: i.ResourceDetails.Schema.Models,
Expand Down
4 changes: 2 additions & 2 deletions tools/generator-go-sdk/generator/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,14 @@ func golangTypeNameForConstantType(input resourcemanager.ConstantType) (*string,
return &segmentType, nil
}

func golangPackageName(input string) (output string) {
func GolangPackageName(input string) (output string) {
output = input
output = regexp.MustCompile("[^0-9A-z-]").ReplaceAllString(output, "_")
output = strings.ToLower(output)
return
}

func golangPackageNameForVersion(input string) (output string) {
func GolangPackageNameForVersion(input string) (output string) {
output = input
output = regexp.MustCompile("[^0-9A-z]").ReplaceAllString(output, "_")
output = strings.ToLower(output)
Expand Down
3 changes: 2 additions & 1 deletion tools/generator-go-sdk/generator/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type ServiceGeneratorInput struct {
ResourceDetails services.Resource
BaseClientMethod string
BaseClientPackage string
CommonPackagePath string
OutputDirectory string
Source resourcemanager.ApiDefinitionsSource
}
Expand Down Expand Up @@ -84,7 +85,7 @@ type VersionInput struct {
func (s *ServiceGenerator) GenerateForVersion(input VersionInput) error {
input.ServiceName = strings.ToLower(input.ServiceName)
input.VersionName = strings.ToLower(input.VersionName)
versionDirectory := filepath.Join(input.OutputDirectory, golangPackageName(input.ServiceName), golangPackageName(input.VersionName))
versionDirectory := filepath.Join(input.OutputDirectory, GolangPackageName(input.ServiceName), GolangPackageName(input.VersionName))

stages := map[string]func(data VersionInput, versionDirectory string) error{
"metaClient": s.metaClient,
Expand Down
4 changes: 2 additions & 2 deletions tools/generator-go-sdk/generator/templater_meta_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (m metaClientTemplater) template() (*string, error) {
for _, resourceName := range resourceNames {
variableName := fmt.Sprintf("%s%sClient", strings.ToLower(string(resourceName[0])), resourceName[1:])

imports = append(imports, fmt.Sprintf(`"github.com/hashicorp/go-azure-sdk/%s/%s/%s/%s"`, m.sdkPackage, golangPackageName(m.serviceName), golangPackageName(m.apiVersion), golangPackageName(resourceName)))
imports = append(imports, fmt.Sprintf(`"github.com/hashicorp/go-azure-sdk/%s/%s/%s/%s"`, m.sdkPackage, GolangPackageName(m.serviceName), GolangPackageName(m.apiVersion), GolangPackageName(resourceName)))
fields = append(fields, fmt.Sprintf("%[1]s *%[2]s.%[1]sClient", resourceName, strings.ToLower(resourceName)))
clientInitializationTemplate := fmt.Sprintf(`%[1]s, err := %[2]s.New%[3]sClientWithBaseURI(api)
if err != nil {
Expand All @@ -54,7 +54,7 @@ configureFunc(%[1]s.Client)
sort.Strings(fields)
sort.Strings(imports)

packageName := golangPackageNameForVersion(m.apiVersion)
packageName := GolangPackageNameForVersion(m.apiVersion)

out := fmt.Sprintf(`package %[1]s
Expand Down
3 changes: 2 additions & 1 deletion tools/generator-go-sdk/generator/templater_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ import (
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
"github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
"github.com/hashicorp/go-azure-sdk/%[4]s"
)
%[2]s
%[3]s
`, data.packageName, *copyrightLines, *methods)
`, data.packageName, *copyrightLines, *methods, data.commonPackagePath)
return &template, nil
}

Expand Down
68 changes: 54 additions & 14 deletions tools/generator-go-sdk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,24 @@ type GeneratorInput struct {
}

type SDK struct {
baseClientMethod string
baseClientPackage string
clients []func(string) resourcemanager.Client
outputSubDirectory string
versionMapper func(string) (*string, error)
baseClientMethod string
baseClientPackage string
clients map[string]func(string) resourcemanager.Client
commonModelsPackageFromVersion func(string) (*string, error)
outputSubDirectory string
versionMapper func(string) (*string, error)
}

var availableSDKs = map[string]SDK{
"resource-manager": {
baseClientMethod: "NewResourceManagerClient",
baseClientPackage: "resourcemanager",
clients: []func(string) resourcemanager.Client{
resourcemanager.NewResourceManagerClient,
clients: map[string]func(string) resourcemanager.Client{
"resource-manager": resourcemanager.NewResourceManagerClient,
},
commonModelsPackageFromVersion: func(in string) (*string, error) {
path := "common/models"
return &path, nil
},
outputSubDirectory: "resource-manager",
versionMapper: func(in string) (*string, error) { return &in, nil },
Expand All @@ -45,9 +50,13 @@ var availableSDKs = map[string]SDK{
"microsoft-graph": {
baseClientMethod: "NewMsGraphClient",
baseClientPackage: "msgraph",
clients: []func(string) resourcemanager.Client{
resourcemanager.NewMicrosoftGraphStableV1Client,
resourcemanager.NewMicrosoftGraphBetaClient,
clients: map[string]func(string) resourcemanager.Client{
"v1.0": resourcemanager.NewMicrosoftGraphStableV1Client,
"beta": resourcemanager.NewMicrosoftGraphBetaClient,
},
commonModelsPackageFromVersion: func(in string) (*string, error) {
path := fmt.Sprintf("common/%s/models", fmt.Sprintf(generator.GolangPackageNameForVersion(in)))
return &path, nil
},
outputSubDirectory: "microsoft-graph",
versionMapper: func(in string) (*string, error) {
Expand Down Expand Up @@ -200,9 +209,13 @@ func run(input GeneratorInput) error {

input.outputDirectory = path.Join(input.outputDirectory, sdk.outputSubDirectory)

for _, apiClient := range sdk.clients {
for clientName, apiClient := range sdk.clients {
client := apiClient(input.apiServerEndpoint)

commonTypes, err := services.GetResourceManagerCommonTypes(client)
if err != nil {
return fmt.Errorf("retrieving resource manager common types: %+v", err)
}
var loadedServices services.ResourceManagerServices
if len(input.services) > 0 {
log.Printf("[DEBUG] Loading the Services from the Data API %q..", strings.Join(input.services, " / "))
Expand Down Expand Up @@ -231,6 +244,30 @@ func run(input GeneratorInput) error {
}
}

wg.Add(1)
go func(input GeneratorInput) {
defer wg.Done()
log.Printf("[DEBUG] Common Types for %q..", clientName)
commonPackagePath, err := sdk.commonModelsPackageFromVersion(clientName)
if err != nil {
addErr(fmt.Errorf("generating Common Types for %q: %+v", clientName, err))
return
}
generatorTypes := generator.NewCommonTypesGenerator()
generatorData := generator.SDKInput{
CommonTypes: commonTypes,
OutputDirectory: input.outputDirectory,
CommonPackagePath: *commonPackagePath,
VersionName: clientName,
}
log.Printf("[DEBUG] Generating Common Types..")
if err := generatorTypes.GenerateForSDK(generatorData); err != nil {
addErr(fmt.Errorf("generating common types: %+v", err))
return
}
log.Printf("[DEBUG] Generated Common Types..")
}(input)

generatorService := generator.NewServiceGenerator(input.settings)
for serviceName, service := range loadedServices.Services {
log.Printf("[DEBUG] Service %q..", serviceName)
Expand All @@ -245,22 +282,25 @@ func run(input GeneratorInput) error {
log.Printf("[DEBUG] Service %q", serviceName)
for versionNumber, versionDetails := range service.Versions {
log.Printf("[DEBUG] Version %q", versionNumber)
versionName, err := sdk.versionMapper(versionNumber)

commonPackagePath, err := sdk.commonModelsPackageFromVersion(clientName)
if err != nil {
addErr(fmt.Errorf("generating Service %q / Version %q: %+v", serviceName, versionNumber, err))
return
}

for resourceName, resourceDetails := range versionDetails.Resources {
log.Printf("[DEBUG] Resource %q..", resourceName)
generatorData := generator.ServiceGeneratorInput{
ServiceName: serviceName,
ServiceDetails: service,
VersionName: *versionName,
VersionName: clientName,
VersionDetails: versionDetails,
ResourceName: resourceName,
ResourceDetails: resourceDetails,
BaseClientMethod: sdk.baseClientMethod,
BaseClientPackage: sdk.baseClientPackage,
CommonPackagePath: *commonPackagePath,
OutputDirectory: input.outputDirectory,
Source: versionDetails.Details.Source,
}
Expand All @@ -276,7 +316,7 @@ func run(input GeneratorInput) error {
generatorData := generator.VersionInput{
OutputDirectory: input.outputDirectory,
ServiceName: serviceName,
VersionName: *versionName,
VersionName: clientName,
BaseClientPackage: sdk.baseClientPackage,
SdkPackage: sdk.outputSubDirectory,
Resources: versionDetails.Resources,
Expand Down
6 changes: 6 additions & 0 deletions tools/sdk/resourcemanager/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func (c Client) ApiSchema() ApiSchemaClient {
}
}

func (c Client) CommonTypes() CommonTypesClient {
return CommonTypesClient{
Client: c,
}
}

func (c Client) ServiceDetails() ServiceDetailsClient {
return ServiceDetailsClient{
Client: c,
Expand Down
37 changes: 37 additions & 0 deletions tools/sdk/resourcemanager/common_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package resourcemanager

import (
"encoding/json"
"fmt"
)

type CommonTypesClient struct {
Client
}

func (c CommonTypesClient) Get() (*CommonTypesDetails, error) {
endpoint := fmt.Sprintf("%s%s/commonTypes", c.endpoint, c.apiEndpoint)
resp, err := c.client.Get(endpoint)
if err != nil {
return nil, err
}

// TODO: handle this being a 404 etc

var response CommonTypesDetails
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, err
}

return &response, nil
}

type CommonTypesDetails struct {
// Constants is a map of key (Constant Name) to value (ConstantDetails) describing
// each common Constant supported by this API
Constants map[string]ConstantDetails `json:"constants"`

// Models is a map of key (Model Name) to value (ModelDetails) describing
// each common Model supported by this API
Models map[string]ModelDetails `json:"models"`
}
5 changes: 5 additions & 0 deletions tools/sdk/resourcemanager/service_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ const (
// that this set of API Definitions is based on data within the Azure
// Rest API Specs repository.
ApiDefinitionsSourceResourceManagerRestApiSpecs ApiDefinitionsSource = "ResourceManagerRestApiSpecs"

// ApiDefinitionsSourceMicrosoftGraphMetadata is used to signify that
// this set of API Definitions is based on data within the
// Microsoft-Graph/MSGraph-Metadata repository.
ApiDefinitionsSourceMicrosoftGraphMetadata ApiDefinitionsSource = "MicrosoftGraphMetadata"
)
Loading

0 comments on commit 38712ff

Please sign in to comment.