github.com/qiniu/go-sdk/v7@v7.27.0/internal/api-generator/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/dave/jennifer/jen"
     9  	"github.com/iancoleman/strcase"
    10  	goflags "github.com/jessevdk/go-flags"
    11  	"gopkg.in/yaml.v3"
    12  )
    13  
    14  const (
    15  	PackageNameHTTPClient  = "github.com/qiniu/go-sdk/v7/storagev2/http_client"
    16  	PackageNameAuth        = "github.com/qiniu/go-sdk/v7/auth"
    17  	PackageNameCredentials = "github.com/qiniu/go-sdk/v7/storagev2/credentials"
    18  	PackageNameRegion      = "github.com/qiniu/go-sdk/v7/storagev2/region"
    19  	PackageNameUpToken     = "github.com/qiniu/go-sdk/v7/storagev2/uptoken"
    20  	PackageNameErrors      = "github.com/qiniu/go-sdk/v7/storagev2/errors"
    21  	PackageNameUtils       = "github.com/qiniu/go-sdk/v7/storagev2/internal/utils"
    22  	PackageNameUplog       = "github.com/qiniu/go-sdk/v7/internal/uplog"
    23  	PackageNameInternalIo  = "github.com/qiniu/go-sdk/v7/internal/io"
    24  )
    25  
    26  var flags struct {
    27  	ApiSpecsPaths  []string `long:"api-specs" required:"true"`
    28  	OutputDirPath  string   `long:"output" required:"true"`
    29  	ApiPackagePath string   `long:"api-package" required:"true"`
    30  	StructName     string   `long:"struct-name" required:"true"`
    31  }
    32  
    33  func main() {
    34  	_, err := goflags.ParseArgs(&flags, os.Args[2:])
    35  	if err != nil {
    36  		fmt.Fprintf(os.Stderr, "%s\n", err)
    37  		os.Exit(1)
    38  	}
    39  	os.RemoveAll(flags.OutputDirPath)
    40  	for _, apiSpecsPath := range flags.ApiSpecsPaths {
    41  		entries, err := os.ReadDir(apiSpecsPath)
    42  		if err != nil {
    43  			fmt.Fprintf(os.Stderr, "Failed to read directory %s: %s\n", apiSpecsPath, err)
    44  			os.Exit(1)
    45  		}
    46  
    47  		for _, entry := range entries {
    48  			apiSpecName := extractApiSpecName(entry.Name())
    49  			generatedApiDirPath := filepath.Join(flags.OutputDirPath, apiSpecName)
    50  			if err = os.MkdirAll(generatedApiDirPath, 0755); err != nil {
    51  				fmt.Fprintf(os.Stderr, "Failed to create directory %s: %s\n", generatedApiDirPath, err)
    52  				os.Exit(1)
    53  			}
    54  			if err = writeGolangPackages(apiSpecName, filepath.Join(apiSpecsPath, entry.Name()), flags.OutputDirPath); err != nil {
    55  				fmt.Fprintf(os.Stderr, "Failed to write go package %s: %s\n", apiSpecName, err)
    56  				os.Exit(1)
    57  			}
    58  		}
    59  	}
    60  	if err = writeApiClient(flags.OutputDirPath); err != nil {
    61  		fmt.Fprintf(os.Stderr, "Failed to write api client: %s\n", err)
    62  		os.Exit(1)
    63  	}
    64  }
    65  
    66  func writeGolangPackages(apiSpecName, apiSpecPath, generatedDirPath string) (err error) {
    67  	generatedApiDirPath := filepath.Join(generatedDirPath, apiSpecName)
    68  	apiSpecFile, err := os.Open(apiSpecPath)
    69  	if err != nil {
    70  		return
    71  	}
    72  	defer apiSpecFile.Close()
    73  
    74  	var apiSpec ApiDetailedDescription
    75  	decoder := yaml.NewDecoder(apiSpecFile)
    76  	decoder.KnownFields(true)
    77  	if err = decoder.Decode(&apiSpec); err != nil {
    78  		return
    79  	}
    80  	if err = apiSpecFile.Close(); err != nil {
    81  		return
    82  	}
    83  
    84  	if err = writeSubPackage(apiSpecName, generatedApiDirPath, &apiSpec); err != nil {
    85  		return
    86  	}
    87  	return writeApiPackage(apiSpecName, generatedDirPath, &apiSpec)
    88  }
    89  
    90  func writeSubPackage(apiSpecName, generatedDirPath string, apiSpec *ApiDetailedDescription) error {
    91  	packageFile := jen.NewFile(apiSpecName)
    92  	packageFile.HeaderComment("THIS FILE IS GENERATED BY api-generator, DO NOT EDIT DIRECTLY!")
    93  	packageFile.PackageComment(apiSpec.Documentation)
    94  	if err := apiSpec.generateSubPackages(packageFile.Group, CodeGeneratorOptions{
    95  		Name:          apiSpecName,
    96  		CamelCaseName: apiSpec.CamelCaseName,
    97  		SnakeCaseName: apiSpec.SnakeCaseName,
    98  		Documentation: apiSpec.Documentation,
    99  	}); err != nil {
   100  		return err
   101  	}
   102  	return packageFile.Save(filepath.Join(generatedDirPath, "api.go"))
   103  }
   104  
   105  func writeApiPackage(apiSpecName, generatedDirPath string, apiSpec *ApiDetailedDescription) error {
   106  	apisPackageFile := jen.NewFile("apis")
   107  	apisPackageFile.HeaderComment("THIS FILE IS GENERATED BY api-generator, DO NOT EDIT DIRECTLY!")
   108  	if err := apiSpec.generatePackage(apisPackageFile.Group, CodeGeneratorOptions{
   109  		Name:          apiSpecName,
   110  		CamelCaseName: apiSpec.CamelCaseName,
   111  		SnakeCaseName: apiSpec.SnakeCaseName,
   112  		Documentation: apiSpec.Documentation,
   113  	}); err != nil {
   114  		return err
   115  	}
   116  	return apisPackageFile.Save(filepath.Join(generatedDirPath, "api_"+apiSpecName+".go"))
   117  }
   118  
   119  func writeApiClient(generatedDirPath string) error {
   120  	apiPackageFile := jen.NewFile("apis")
   121  	apiPackageFile.HeaderComment("THIS FILE IS GENERATED BY api-generator, DO NOT EDIT DIRECTLY!")
   122  	generateApiClient(apiPackageFile.Group)
   123  	return apiPackageFile.Save(filepath.Join(generatedDirPath, "apis.go"))
   124  }
   125  
   126  func generateApiClient(group *jen.Group) {
   127  	structName := strcase.ToCamel(flags.StructName)
   128  	group.Add(jen.Comment("API 客户端"))
   129  	group.Add(
   130  		jen.Type().Id(structName).StructFunc(func(group *jen.Group) {
   131  			group.Add(jen.Id("client").Op("*").Qual(PackageNameHTTPClient, "Client"))
   132  		}),
   133  	)
   134  	group.Add(jen.Comment("创建 API 客户端"))
   135  	group.Add(
   136  		jen.Func().
   137  			Id("New" + structName).
   138  			Params(jen.Id("options").Op("*").Qual(PackageNameHTTPClient, "Options")).
   139  			Params(jen.Op("*").Id(structName)).
   140  			BlockFunc(func(group *jen.Group) {
   141  				group.Return(jen.Op("&").Id(structName).ValuesFunc(func(group *jen.Group) {
   142  					group.Add(jen.Id("client").Op(":").Qual(PackageNameHTTPClient, "NewClient").Call(jen.Id("options")))
   143  				}))
   144  			}),
   145  	)
   146  
   147  	group.Add(jen.Comment("API 客户端选项"))
   148  	group.Add(
   149  		jen.Type().Id("Options").StructFunc(func(group *jen.Group) {
   150  			group.Add(jen.Id("OverwrittenBucketHosts").Qual(PackageNameRegion, "EndpointsProvider"))
   151  			group.Add(jen.Id("OverwrittenBucketName").String())
   152  			group.Add(jen.Id("OverwrittenEndpoints").Qual(PackageNameRegion, "EndpointsProvider"))
   153  			group.Add(jen.Id("OverwrittenRegion").Qual(PackageNameRegion, "RegionsProvider"))
   154  			group.Add(jen.Id("OnRequestProgress").Func().Params(
   155  				jen.Uint64(),
   156  				jen.Uint64(),
   157  			))
   158  		}),
   159  	)
   160  }
   161  
   162  func isStorageAPIs() bool {
   163  	structName := strcase.ToCamel(flags.StructName)
   164  	return structName == "Storage"
   165  }