diff --git a/cmd/gf/gfcmd/gfcmd.go b/cmd/gf/gfcmd/gfcmd.go index d899927ec..6d7126031 100644 --- a/cmd/gf/gfcmd/gfcmd.go +++ b/cmd/gf/gfcmd/gfcmd.go @@ -26,6 +26,7 @@ const ( ) // Command manages the CLI command of `gf`. +// This struct can be globally accessible and extended with custom struct. type Command struct { *gcmd.Command } diff --git a/cmd/gf/go.mod b/cmd/gf/go.mod index f9e58e23f..d4f1fe4ad 100644 --- a/cmd/gf/go.mod +++ b/cmd/gf/go.mod @@ -3,13 +3,13 @@ module github.com/gogf/gf/cmd/gf/v2 go 1.18 require ( - github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.4.2 - github.com/gogf/gf/contrib/drivers/mssql/v2 v2.4.2 - github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.2 - github.com/gogf/gf/contrib/drivers/oracle/v2 v2.4.2 - github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.4.2 - github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.4.2 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.4.3 + github.com/gogf/gf/contrib/drivers/mssql/v2 v2.4.3 + github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.3 + github.com/gogf/gf/contrib/drivers/oracle/v2 v2.4.3 + github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.4.3 + github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.4.3 + github.com/gogf/gf/v2 v2.4.3 github.com/minio/selfupdate v0.6.0 github.com/olekukonko/tablewriter v0.0.5 golang.org/x/tools v0.7.0 diff --git a/cmd/gf/internal/cmd/cmd_gen.go b/cmd/gf/internal/cmd/cmd_gen.go index bf60e639e..10f03dac5 100644 --- a/cmd/gf/internal/cmd/cmd_gen.go +++ b/cmd/gf/internal/cmd/cmd_gen.go @@ -19,6 +19,7 @@ type cGen struct { g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"` cGenDao cGenEnums + cGenCtrl cGenPb cGenPbEntity cGenService diff --git a/cmd/gf/internal/cmd/cmd_gen_ctrl.go b/cmd/gf/internal/cmd/cmd_gen_ctrl.go new file mode 100644 index 000000000..1fcc9eddf --- /dev/null +++ b/cmd/gf/internal/cmd/cmd_gen_ctrl.go @@ -0,0 +1,15 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package cmd + +import ( + "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl" +) + +type ( + cGenCtrl = genctrl.CGenCtrl +) diff --git a/cmd/gf/internal/cmd/genctrl/genctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl.go new file mode 100644 index 000000000..b29ba84fe --- /dev/null +++ b/cmd/gf/internal/cmd/genctrl/genctrl.go @@ -0,0 +1,197 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package genctrl + +import ( + "context" + + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gtag" + + "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" +) + +const ( + CGenCtrlConfig = `gfcli.gen.ctrl` + CGenCtrlUsage = `gf gen ctrl [OPTION]` + CGenCtrlBrief = `parse api definitions to generate controller/sdk go files` + CGenCtrlEg = ` +gf gen ctrl +` + CGenCtrlBriefSrcFolder = `source folder path to be parsed. default: api` + CGenCtrlBriefDstFolder = `destination folder path storing automatically generated go files. default: internal/controller` + CGenCtrlBriefWatchFile = `used in file watcher, it re-generates go files only if given file is under srcFolder` + CGenCtrlBriefSdkPath = `also generate SDK go files for api definitions to specified directory` + CGenCtrlBriefSdkStdVersion = `use standard version prefix for generated sdk request path` + CGenCtrlBriefSdkNoV1 = `do not add version suffix for interface module name if version is v1` +) + +const ( + PatternApiDefinition = `type\s+(\w+)Req\s+struct\s+{` + PatternCtrlDefinition = `func\s+\(.+?\)\s+\w+\(.+?\*(\w+)\.(\w+)Req\)\s+\(.+?\*(\w+)\.(\w+)Res,\s+\w+\s+error\)\s+{` +) + +const ( + genCtrlFileLockSeconds = 10 +) + +func init() { + gtag.Sets(g.MapStrStr{ + `CGenCtrlConfig`: CGenCtrlConfig, + `CGenCtrlUsage`: CGenCtrlUsage, + `CGenCtrlBrief`: CGenCtrlBrief, + `CGenCtrlEg`: CGenCtrlEg, + `CGenCtrlBriefSrcFolder`: CGenCtrlBriefSrcFolder, + `CGenCtrlBriefDstFolder`: CGenCtrlBriefDstFolder, + `CGenCtrlBriefWatchFile`: CGenCtrlBriefWatchFile, + `CGenCtrlBriefSdkPath`: CGenCtrlBriefSdkPath, + `CGenCtrlBriefSdkStdVersion`: CGenCtrlBriefSdkStdVersion, + `CGenCtrlBriefSdkNoV1`: CGenCtrlBriefSdkNoV1, + }) +} + +type ( + CGenCtrl struct{} + CGenCtrlInput struct { + g.Meta `name:"ctrl" config:"{CGenCtrlConfig}" usage:"{CGenCtrlUsage}" brief:"{CGenCtrlBrief}" eg:"{CGenCtrlEg}"` + SrcFolder string `short:"s" name:"srcFolder" brief:"{CGenCtrlBriefSrcFolder}" d:"api"` + DstFolder string `short:"d" name:"dstFolder" brief:"{CGenCtrlBriefDstFolder}" d:"internal/controller"` + WatchFile string `short:"w" name:"watchFile" brief:"{CGenCtrlBriefWatchFile}"` + SdkPath string `short:"k" name:"sdkPath" brief:"{CGenCtrlBriefSdkPath}"` + SdkStdVersion bool `short:"v" name:"sdkStdVersion" brief:"{CGenCtrlBriefSdkStdVersion}" orphan:"true"` + SdkNoV1 bool `short:"n" name:"sdkNoV1" brief:"{CGenCtrlBriefSdkNoV1}" orphan:"true"` + } + CGenCtrlOutput struct{} +) + +func (c CGenCtrl) Ctrl(ctx context.Context, in CGenCtrlInput) (out *CGenCtrlOutput, err error) { + if in.WatchFile != "" { + err = c.generateByWatchFile(in.WatchFile, in.SdkPath, in.SdkStdVersion, in.SdkNoV1) + return + } + + if !gfile.Exists(in.SrcFolder) { + mlog.Fatalf(`source folder path "%s" does not exist`, in.SrcFolder) + } + // retrieve all api modules. + apiModuleFolderPaths, err := gfile.ScanDir(in.SrcFolder, "*", false) + if err != nil { + return nil, err + } + for _, apiModuleFolderPath := range apiModuleFolderPaths { + if !gfile.IsDir(apiModuleFolderPath) { + continue + } + // generate go files by api module. + var ( + module = gfile.Basename(apiModuleFolderPath) + dstModuleFolderPath = gfile.Join(in.DstFolder, module) + ) + err = c.generateByModule(apiModuleFolderPath, dstModuleFolderPath, in.SdkPath, in.SdkStdVersion, in.SdkNoV1) + if err != nil { + return nil, err + } + } + + mlog.Print(`done!`) + return +} + +func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, sdkNoV1 bool) (err error) { + // File lock to avoid multiple processes. + var ( + flockFilePath = gfile.Temp("gf.cli.gen.service.lock") + flockContent = gfile.GetContents(flockFilePath) + ) + if flockContent != "" { + if gtime.Timestamp()-gconv.Int64(flockContent) < genCtrlFileLockSeconds { + // If another generating process is running, it just exits. + mlog.Debug(`another "gen service" process is running, exit`) + return + } + } + defer gfile.Remove(flockFilePath) + _ = gfile.PutContents(flockFilePath, gtime.TimestampStr()) + + // check this updated file is an api file. + // watch file should be in standard goframe project structure. + var ( + apiVersionPath = gfile.Dir(watchFile) + apiModuleFolderPath = gfile.Dir(apiVersionPath) + shouldBeNameOfAPi = gfile.Basename(gfile.Dir(apiModuleFolderPath)) + ) + if shouldBeNameOfAPi != "api" { + return nil + } + // watch file should have api definitions. + if !gregex.IsMatchString(PatternApiDefinition, gfile.GetContents(watchFile)) { + return nil + } + var ( + projectRootPath = gfile.Dir(gfile.Dir(apiModuleFolderPath)) + module = gfile.Basename(apiModuleFolderPath) + dstModuleFolderPath = gfile.Join(projectRootPath, "internal", "controller", module) + ) + return c.generateByModule(apiModuleFolderPath, dstModuleFolderPath, sdkPath, sdkStdVersion, sdkNoV1) +} + +// parseApiModule parses certain api and generate associated go files by certain module, not all api modules. +func (c CGenCtrl) generateByModule( + apiModuleFolderPath, dstModuleFolderPath, sdkPath string, sdkStdVersion, sdkNoV1 bool, +) (err error) { + // parse src and dst folder go files. + apiItemsInSrc, err := c.getApiItemsInSrc(apiModuleFolderPath) + if err != nil { + return err + } + apiItemsInDst, err := c.getApiItemsInDst(dstModuleFolderPath) + if err != nil { + return err + } + + // api filtering for already implemented api controllers. + var ( + alreadyImplementedCtrlSet = gset.NewStrSet() + toBeImplementedApiItems = make([]apiItem, 0) + ) + for _, item := range apiItemsInDst { + alreadyImplementedCtrlSet.Add(item.String()) + } + for _, item := range apiItemsInSrc { + if alreadyImplementedCtrlSet.Contains(item.String()) { + continue + } + toBeImplementedApiItems = append(toBeImplementedApiItems, item) + } + + // generate api interface go files. + if err = newApiInterfaceGenerator().Generate(apiModuleFolderPath, apiItemsInSrc); err != nil { + return + } + + // generate controller go files. + if len(toBeImplementedApiItems) > 0 { + err = newControllerGenerator().Generate(dstModuleFolderPath, toBeImplementedApiItems) + if err != nil { + return + } + } + + // generate sdk go files. + if sdkPath != "" { + if err = newApiSdkGenerator().Generate(apiItemsInSrc, sdkPath, sdkStdVersion, sdkNoV1); err != nil { + return + } + } + + return +} diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_api_item.go b/cmd/gf/internal/cmd/genctrl/genctrl_api_item.go new file mode 100644 index 000000000..997c38a5f --- /dev/null +++ b/cmd/gf/internal/cmd/genctrl/genctrl_api_item.go @@ -0,0 +1,22 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package genctrl + +import "github.com/gogf/gf/v2/text/gstr" + +type apiItem struct { + Import string `eg:"demo.com/api/user/v1"` + Module string `eg:"user"` + Version string `eg:"v1"` + MethodName string `eg:"GetList"` +} + +func (a apiItem) String() string { + return gstr.Join([]string{ + a.Import, a.Module, a.Version, a.MethodName, + }, ",") +} diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go new file mode 100644 index 000000000..f1fe252aa --- /dev/null +++ b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go @@ -0,0 +1,136 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package genctrl + +import ( + "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" +) + +func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, err error) { + var ( + fileContent string + importPath string + ) + // The second level folders: versions. + apiVersionFolderPaths, err := gfile.ScanDir(apiModuleFolderPath, "*", false) + if err != nil { + return nil, err + } + for _, apiVersionFolderPath := range apiVersionFolderPaths { + if !gfile.IsDir(apiVersionFolderPath) { + continue + } + // The second level folders: versions. + apiFileFolderPaths, err := gfile.ScanDir(apiVersionFolderPath, "*.go", false) + if err != nil { + return nil, err + } + importPath = utils.GetImportPath(apiVersionFolderPath) + for _, apiFileFolderPath := range apiFileFolderPaths { + if gfile.IsDir(apiFileFolderPath) { + continue + } + fileContent = gfile.GetContents(apiFileFolderPath) + matches, err := gregex.MatchAllString(PatternApiDefinition, fileContent) + if err != nil { + return nil, err + } + for _, match := range matches { + item := apiItem{ + Import: gstr.Trim(importPath, `"`), + Module: gfile.Basename(apiModuleFolderPath), + Version: gfile.Basename(apiVersionFolderPath), + MethodName: match[1], + } + items = append(items, item) + } + } + } + return +} + +func (c CGenCtrl) getApiItemsInDst(dstFolder string) (items []apiItem, err error) { + if !gfile.Exists(dstFolder) { + return nil, nil + } + type importItem struct { + Path string + Alias string + } + var fileContent string + filePaths, err := gfile.ScanDir(dstFolder, "*.go", true) + if err != nil { + return nil, err + } + for _, filePath := range filePaths { + fileContent = gfile.GetContents(filePath) + match, err := gregex.MatchString(`import\s+\(([\s\S]+?)\)`, fileContent) + if err != nil { + return nil, err + } + if len(match) < 2 { + continue + } + var ( + array []string + importItems []importItem + importLines = gstr.SplitAndTrim(match[1], "\n") + module = gfile.Basename(gfile.Dir(filePath)) + ) + // retrieve all imports. + for _, importLine := range importLines { + array = gstr.SplitAndTrim(importLine, " ") + if len(array) == 2 { + importItems = append(importItems, importItem{ + Path: gstr.Trim(array[1], `"`), + Alias: array[0], + }) + } else { + importItems = append(importItems, importItem{ + Path: gstr.Trim(array[0], `"`), + }) + } + } + // retrieve all api usages. + matches, err := gregex.MatchAllString(PatternCtrlDefinition, fileContent) + if err != nil { + return nil, err + } + for _, match = range matches { + // try to find the import path of the api. + var ( + importPath string + version = match[1] + methodName = match[2] // not the function name, but the method name in api definition. + ) + for _, item := range importItems { + if item.Alias != "" { + if item.Alias == version { + importPath = item.Path + break + } + continue + } + if gfile.Basename(item.Path) == version { + importPath = item.Path + break + } + } + item := apiItem{ + Import: gstr.Trim(importPath, `"`), + Module: module, + Version: gfile.Basename(importPath), + MethodName: methodName, + } + items = append(items, item) + } + } + return +} diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl.go new file mode 100644 index 000000000..5388a4adb --- /dev/null +++ b/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl.go @@ -0,0 +1,135 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package genctrl + +import ( + "fmt" + + "github.com/gogf/gf/cmd/gf/v2/internal/consts" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/text/gstr" +) + +type controllerGenerator struct{} + +func newControllerGenerator() *controllerGenerator { + return &controllerGenerator{} +} + +func (c *controllerGenerator) Generate(dstModuleFolderPath string, apiModuleApiItems []apiItem) (err error) { + var ( + doneApiItemSet = gset.NewStrSet() + ) + for _, item := range apiModuleApiItems { + if doneApiItemSet.Contains(item.String()) { + continue + } + // retrieve all api items of the same module. + subItems := c.getSubItemsByModuleAndVersion(apiModuleApiItems, item.Module, item.Version) + if err = c.doGenerateCtrlNewByModuleAndVersion( + dstModuleFolderPath, item.Module, item.Version, gfile.Dir(item.Import), + ); err != nil { + return + } + for _, subItem := range subItems { + if err = c.doGenerateCtrlItem(dstModuleFolderPath, subItem); err != nil { + return + } + doneApiItemSet.Add(subItem.String()) + } + } + return +} + +func (c *controllerGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) { + for _, item := range items { + if item.Module == module && item.Version == version { + subItems = append(subItems, item) + } + } + return +} + +func (c *controllerGenerator) doGenerateCtrlNewByModuleAndVersion( + dstModuleFolderPath, module, version, importPath string, +) (err error) { + var ( + moduleFilePath = gfile.Join(dstModuleFolderPath, module+".go") + moduleFilePathNew = gfile.Join(dstModuleFolderPath, module+"_new.go") + ctrlName = fmt.Sprintf(`Controller%s`, gstr.UcFirst(version)) + interfaceName = fmt.Sprintf(`%s.I%s%s`, module, gstr.CaseCamel(module), gstr.UcFirst(version)) + newFuncName = fmt.Sprintf(`New%s`, gstr.UcFirst(version)) + newFuncNameDefinition = fmt.Sprintf(`func %s()`, newFuncName) + alreadyCreated bool + ) + if !gfile.Exists(moduleFilePath) { + content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerEmpty, g.MapStrStr{ + "{Module}": module, + }) + if err = gfile.PutContents(moduleFilePath, gstr.TrimLeft(content)); err != nil { + return err + } + mlog.Printf(`generated: %s`, moduleFilePath) + } + if !gfile.Exists(moduleFilePathNew) { + content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerNewEmpty, g.MapStrStr{ + "{Module}": module, + "{ImportPath}": fmt.Sprintf(`"%s"`, importPath), + }) + if err = gfile.PutContents(moduleFilePathNew, gstr.TrimLeft(content)); err != nil { + return err + } + mlog.Printf(`generated: %s`, moduleFilePathNew) + } + filePaths, err := gfile.ScanDir(dstModuleFolderPath, "*.go", false) + if err != nil { + return err + } + for _, filePath := range filePaths { + if gstr.Contains(gfile.GetContents(filePath), newFuncNameDefinition) { + alreadyCreated = true + break + } + } + if !alreadyCreated { + content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerNewFunc, g.MapStrStr{ + "{CtrlName}": ctrlName, + "{NewFuncName}": newFuncName, + "{InterfaceName}": interfaceName, + }) + err = gfile.PutContentsAppend(moduleFilePathNew, gstr.TrimLeft(content)) + if err != nil { + return err + } + } + return +} + +func (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, item apiItem) (err error) { + var ( + methodNameSnake = gstr.CaseSnake(item.MethodName) + ctrlName = fmt.Sprintf(`Controller%s`, gstr.UcFirst(item.Version)) + methodFilePath = gfile.Join(dstModuleFolderPath, fmt.Sprintf( + `%s_%s_%s.go`, item.Module, item.Version, methodNameSnake, + )) + ) + content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFunc, g.MapStrStr{ + "{Module}": item.Module, + "{ImportPath}": item.Import, + "{CtrlName}": ctrlName, + "{Version}": item.Version, + "{MethodName}": item.MethodName, + }) + if err = gfile.PutContents(methodFilePath, gstr.TrimLeft(content)); err != nil { + return err + } + mlog.Printf(`generated: %s`, methodFilePath) + return +} diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_generate_interface.go b/cmd/gf/internal/cmd/genctrl/genctrl_generate_interface.go new file mode 100644 index 000000000..3d641a077 --- /dev/null +++ b/cmd/gf/internal/cmd/genctrl/genctrl_generate_interface.go @@ -0,0 +1,111 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package genctrl + +import ( + "fmt" + + "github.com/gogf/gf/cmd/gf/v2/internal/consts" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" +) + +type apiInterfaceGenerator struct{} + +func newApiInterfaceGenerator() *apiInterfaceGenerator { + return &apiInterfaceGenerator{} +} + +func (c *apiInterfaceGenerator) Generate(apiModuleFolderPath string, apiModuleApiItems []apiItem) (err error) { + if len(apiModuleApiItems) == 0 { + return nil + } + var firstApiItem = apiModuleApiItems[0] + if err = c.doGenerate(apiModuleFolderPath, firstApiItem.Module, apiModuleApiItems); err != nil { + return + } + return +} + +func (c *apiInterfaceGenerator) doGenerate(apiModuleFolderPath string, module string, items []apiItem) (err error) { + var ( + moduleFilePath = gfile.Join(apiModuleFolderPath, fmt.Sprintf(`%s.go`, module)) + importPathMap = gmap.NewListMap() + importPaths []string + ) + // all import paths. + importPathMap.Set("\t"+`"context"`, 1) + importPathMap.Set("\t"+``, 1) + for _, item := range items { + importPathMap.Set(fmt.Sprintf("\t"+`"%s"`, item.Import), 1) + } + importPaths = gconv.Strings(importPathMap.Keys()) + // interface definitions. + var ( + doneApiItemSet = gset.NewStrSet() + interfaceDefinition string + interfaceContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlApiInterface, g.MapStrStr{ + "{Module}": module, + "{ImportPaths}": gstr.Join(importPaths, "\n"), + })) + ) + for _, item := range items { + if doneApiItemSet.Contains(item.String()) { + continue + } + // retrieve all api items of the same module. + subItems := c.getSubItemsByModuleAndVersion(items, item.Module, item.Version) + var ( + method string + methods = make([]string, 0) + interfaceName = fmt.Sprintf(`I%s%s`, gstr.CaseCamel(item.Module), gstr.UcFirst(item.Version)) + ) + for _, subItem := range subItems { + method = fmt.Sprintf( + "\t%s(ctx context.Context, req *%s.%sReq) (res *%s.%sRes, err error)", + subItem.MethodName, subItem.Version, subItem.MethodName, subItem.Version, subItem.MethodName, + ) + methods = append(methods, method) + doneApiItemSet.Add(subItem.String()) + } + interfaceDefinition += fmt.Sprintf("type %s interface {", interfaceName) + interfaceDefinition += "\n" + interfaceDefinition += gstr.Join(methods, "\n") + interfaceDefinition += "\n" + interfaceDefinition += fmt.Sprintf("}") + interfaceDefinition += "\n\n" + } + interfaceContent = gstr.TrimLeft(gstr.ReplaceByMap(interfaceContent, g.MapStrStr{ + "{Interfaces}": interfaceDefinition, + })) + err = gfile.PutContents(moduleFilePath, interfaceContent) + mlog.Printf(`generated: %s`, moduleFilePath) + return +} + +func (c *apiInterfaceGenerator) getSubItemsByModule(items []apiItem, module string) (subItems []apiItem) { + for _, item := range items { + if item.Module == module { + subItems = append(subItems, item) + } + } + return +} + +func (c *apiInterfaceGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) { + for _, item := range items { + if item.Module == module && item.Version == version { + subItems = append(subItems, item) + } + } + return +} diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_generate_sdk.go b/cmd/gf/internal/cmd/genctrl/genctrl_generate_sdk.go new file mode 100644 index 000000000..d51c48a28 --- /dev/null +++ b/cmd/gf/internal/cmd/genctrl/genctrl_generate_sdk.go @@ -0,0 +1,194 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package genctrl + +import ( + "fmt" + + "github.com/gogf/gf/cmd/gf/v2/internal/consts" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" +) + +type apiSdkGenerator struct{} + +func newApiSdkGenerator() *apiSdkGenerator { + return &apiSdkGenerator{} +} + +func (c *apiSdkGenerator) Generate(apiModuleApiItems []apiItem, sdkFolderPath string, sdkStdVersion, sdkNoV1 bool) (err error) { + if err = c.doGenerateSdkPkgFile(sdkFolderPath); err != nil { + return + } + + var doneApiItemSet = gset.NewStrSet() + for _, item := range apiModuleApiItems { + if doneApiItemSet.Contains(item.String()) { + continue + } + // retrieve all api items of the same module. + subItems := c.getSubItemsByModuleAndVersion(apiModuleApiItems, item.Module, item.Version) + if err = c.doGenerateSdkIClient(sdkFolderPath, item.Import, item.Module, item.Version, sdkNoV1); err != nil { + return + } + if err = c.doGenerateSdkImplementer( + subItems, sdkFolderPath, item.Import, item.Module, item.Version, sdkStdVersion, sdkNoV1, + ); err != nil { + return + } + for _, subItem := range subItems { + doneApiItemSet.Add(subItem.String()) + } + } + return +} + +func (c *apiSdkGenerator) doGenerateSdkPkgFile(sdkFolderPath string) (err error) { + var ( + pkgName = gfile.Basename(sdkFolderPath) + pkgFilePath = gfile.Join(sdkFolderPath, fmt.Sprintf(`%s.go`, pkgName)) + fileContent string + ) + if gfile.Exists(pkgFilePath) { + return nil + } + fileContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkPkgNew, g.MapStrStr{ + "{PkgName}": pkgName, + })) + err = gfile.PutContents(pkgFilePath, fileContent) + mlog.Printf(`generated: %s`, pkgFilePath) + return +} + +func (c *apiSdkGenerator) doGenerateSdkIClient( + sdkFolderPath, versionImportPath, module, version string, sdkNoV1 bool, +) (err error) { + var ( + fileContent string + isDirty bool + isExist bool + pkgName = gfile.Basename(sdkFolderPath) + funcName = gstr.CaseCamel(module) + gstr.UcFirst(version) + interfaceName = fmt.Sprintf(`I%s`, funcName) + moduleImportPath = fmt.Sprintf(`"%s"`, gfile.Dir(versionImportPath)) + iClientFilePath = gfile.Join(sdkFolderPath, fmt.Sprintf(`%s.iclient.go`, pkgName)) + interfaceFuncDefinition = fmt.Sprintf( + `%s() %s.%s`, + gstr.CaseCamel(module)+gstr.UcFirst(version), module, interfaceName, + ) + ) + if sdkNoV1 && version == "v1" { + interfaceFuncDefinition = fmt.Sprintf( + `%s() %s.%s`, + gstr.CaseCamel(module), module, interfaceName, + ) + } + if isExist = gfile.Exists(iClientFilePath); isExist { + fileContent = gfile.GetContents(iClientFilePath) + } else { + fileContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkIClient, g.MapStrStr{ + "{PkgName}": pkgName, + })) + } + + // append the import path to current import paths. + if !gstr.Contains(fileContent, moduleImportPath) { + isDirty = true + fileContent, err = gregex.ReplaceString( + `(import \([\s\S]*?)\)`, + fmt.Sprintf("$1\t%s\n)", moduleImportPath), + fileContent, + ) + if err != nil { + return + } + } + + // append the function definition to interface definition. + if !gstr.Contains(fileContent, interfaceFuncDefinition) { + isDirty = true + fileContent, err = gregex.ReplaceString( + `(type iClient interface {[\s\S]*?)}`, + fmt.Sprintf("$1\t%s\n}", interfaceFuncDefinition), + fileContent, + ) + if err != nil { + return + } + } + if isDirty { + err = gfile.PutContents(iClientFilePath, fileContent) + if isExist { + mlog.Printf(`updated: %s`, iClientFilePath) + } else { + mlog.Printf(`generated: %s`, iClientFilePath) + } + } + return +} + +func (c *apiSdkGenerator) doGenerateSdkImplementer( + items []apiItem, sdkFolderPath, versionImportPath, module, version string, sdkStdVersion, sdkNoV1 bool, +) (err error) { + var ( + pkgName = gfile.Basename(sdkFolderPath) + moduleNameCamel = gstr.CaseCamel(module) + moduleNameSnake = gstr.CaseSnake(module) + moduleImportPath = gfile.Dir(versionImportPath) + versionPrefix = "" + implementerName = moduleNameCamel + gstr.UcFirst(version) + implementerFilePath = gfile.Join(sdkFolderPath, fmt.Sprintf( + `%s_%s_%s.go`, pkgName, moduleNameSnake, version, + )) + ) + if sdkNoV1 && version == "v1" { + implementerName = moduleNameCamel + } + // implementer file template. + var importPaths = make([]string, 0) + importPaths = append(importPaths, fmt.Sprintf("\t\"%s\"", moduleImportPath)) + importPaths = append(importPaths, fmt.Sprintf("\t\"%s\"", versionImportPath)) + implementerFileContent := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementer, g.MapStrStr{ + "{PkgName}": pkgName, + "{ImportPaths}": gstr.Join(importPaths, "\n"), + "{ImplementerName}": implementerName, + })) + // implementer new function definition. + if sdkStdVersion { + versionPrefix = fmt.Sprintf(`/api/%s`, version) + } + implementerFileContent += gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementerNew, g.MapStrStr{ + "{Module}": module, + "{VersionPrefix}": versionPrefix, + "{ImplementerName}": implementerName, + })) + // implementer functions definitions. + for _, item := range items { + implementerFileContent += gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementerFunc, g.MapStrStr{ + "{Version}": item.Version, + "{MethodName}": item.MethodName, + "{ImplementerName}": implementerName, + })) + implementerFileContent += "\n" + } + err = gfile.PutContents(implementerFilePath, implementerFileContent) + mlog.Printf(`generated: %s`, implementerFilePath) + return +} + +func (c *apiSdkGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) { + for _, item := range items { + if item.Module == module && item.Version == version { + subItems = append(subItems, item) + } + } + return +} diff --git a/cmd/gf/internal/cmd/gendao/gendao_dao.go b/cmd/gf/internal/cmd/gendao/gendao_dao.go index a76126ac7..c25a7bfaf 100644 --- a/cmd/gf/internal/cmd/gendao/gendao_dao.go +++ b/cmd/gf/internal/cmd/gendao/gendao_dao.go @@ -17,7 +17,6 @@ import ( "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gfile" - "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/cmd/gf/v2/internal/consts" @@ -60,23 +59,13 @@ func generateDaoSingle(ctx context.Context, in generateDaoSingleInput) { mlog.Fatalf(`fetching tables fields failed for table "%s": %+v`, in.TableName, err) } var ( - dirRealPath = gfile.RealPath(in.Path) tableNameCamelCase = gstr.CaseCamel(in.NewTableName) tableNameCamelLowerCase = gstr.CaseCamelLower(in.NewTableName) tableNameSnakeCase = gstr.CaseSnake(in.NewTableName) importPrefix = in.ImportPrefix ) if importPrefix == "" { - if dirRealPath == "" { - dirRealPath = in.Path - importPrefix = dirRealPath - importPrefix = gstr.Trim(dirRealPath, "./") - } else { - importPrefix = gstr.Replace(dirRealPath, gfile.Pwd(), "") - } - importPrefix = gstr.Replace(importPrefix, gfile.Separator, "/") - importPrefix = gstr.Join(g.SliceStr{in.ModName, importPrefix, in.DaoPath}, "/") - importPrefix, _ = gregex.ReplaceString(`\/{2,}`, `/`, gstr.Trim(importPrefix, "/")) + importPrefix = utils.GetImportPath(in.DaoPath) } else { importPrefix = gstr.Join(g.SliceStr{importPrefix, in.DaoPath}, "/") } diff --git a/cmd/gf/internal/cmd/genservice/genservice.go b/cmd/gf/internal/cmd/genservice/genservice.go index 26ac93332..f66562205 100644 --- a/cmd/gf/internal/cmd/genservice/genservice.go +++ b/cmd/gf/internal/cmd/genservice/genservice.go @@ -145,16 +145,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe } if in.ImportPrefix == "" { - if !gfile.Exists("go.mod") { - mlog.Fatal("ImportPrefix is empty and go.mod does not exist in current working directory") - } - var ( - goModContent = gfile.GetContents("go.mod") - match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent) - ) - if len(match) > 1 { - in.ImportPrefix = fmt.Sprintf(`%s/%s`, gstr.Trim(match[1]), gstr.Replace(in.SrcFolder, `\`, `/`)) - } + in.ImportPrefix = utils.GetImportPath(in.SrcFolder) } var ( @@ -205,7 +196,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe return nil, err } // Calculate functions and interfaces for service generating. - err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap, dstPackageName) + err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap) if err != nil { return nil, err } diff --git a/cmd/gf/internal/cmd/genservice/genservice_calculate.go b/cmd/gf/internal/cmd/genservice/genservice_calculate.go index dea843a82..3b48230c9 100644 --- a/cmd/gf/internal/cmd/genservice/genservice_calculate.go +++ b/cmd/gf/internal/cmd/genservice/genservice_calculate.go @@ -37,7 +37,7 @@ func (c CGenService) calculateImportedPackages(fileContent string, srcImportedPa } func (c CGenService) calculateInterfaceFunctions( - in CGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string, + in CGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray, ) (err error) { var ( ok bool diff --git a/cmd/gf/internal/cmd/genservice/genservice_generate.go b/cmd/gf/internal/cmd/genservice/genservice_generate.go index a592f6e7f..4249ec7fa 100644 --- a/cmd/gf/internal/cmd/genservice/genservice_generate.go +++ b/cmd/gf/internal/cmd/genservice/genservice_generate.go @@ -151,6 +151,7 @@ func (c CGenService) isToGenerateServiceGoFile(dstPackageName, filePath string, return false } +// generateInitializationFile generates `logic.go`. func (c CGenService) generateInitializationFile(in CGenServiceInput, importSrcPackages []string) (err error) { var ( srcPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder)) diff --git a/cmd/gf/internal/consts/consts_gen_ctrl_template.go b/cmd/gf/internal/consts/consts_gen_ctrl_template.go new file mode 100644 index 000000000..de01e04fb --- /dev/null +++ b/cmd/gf/internal/consts/consts_gen_ctrl_template.go @@ -0,0 +1,65 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package consts + +const TemplateGenCtrlControllerEmpty = ` +package {Module} + +` + +const TemplateGenCtrlControllerNewEmpty = ` +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package {Module} + +import ( + {ImportPath} +) + +` + +const TemplateGenCtrlControllerNewFunc = ` +type {CtrlName} struct{} + +func {NewFuncName}() {InterfaceName} { + return &{CtrlName}{} +} + +` + +const TemplateGenCtrlControllerMethodFunc = ` +package {Module} + +import ( + "context" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + + "{ImportPath}" +) + +func (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) { + return nil, gerror.NewCode(gcode.CodeNotImplemented) +} +` + +const TemplateGenCtrlApiInterface = ` +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package {Module} + +import ( +{ImportPaths} +) + +{Interfaces} +` diff --git a/cmd/gf/internal/consts/consts_gen_ctrl_template_sdk.go b/cmd/gf/internal/consts/consts_gen_ctrl_template_sdk.go new file mode 100644 index 000000000..bd778be53 --- /dev/null +++ b/cmd/gf/internal/consts/consts_gen_ctrl_template_sdk.go @@ -0,0 +1,93 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package consts + +const TemplateGenCtrlSdkPkgNew = ` +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= +package {PkgName} + +import ( + "fmt" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/contrib/sdk/httpclient/v2" +) + +type implementer struct { + config httpclient.Config +} + +func New(config httpclient.Config) iClient { + if !gstr.HasPrefix(config.URL, "http") { + config.URL = fmt.Sprintf("http://%s", config.URL) + } + if config.Logger == nil { + config.Logger = g.Log() + } + return &implementer{ + config: config, + } +} + +` + +const TemplateGenCtrlSdkIClient = ` +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package {PkgName} + +import ( +) + +type iClient interface { +} +` + +const TemplateGenCtrlSdkImplementer = ` +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package {PkgName} + +import ( + "context" + + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/contrib/sdk/httpclient/v2" + +{ImportPaths} +) + +type implementer{ImplementerName} struct { + *httpclient.Client +} + +` + +const TemplateGenCtrlSdkImplementerNew = ` +func (i *implementer) {ImplementerName}() {Module}.I{ImplementerName} { + var ( + client = httpclient.New(i.config) + prefix = gstr.TrimRight(i.config.URL, "/") + "{VersionPrefix}" + ) + client.Client = client.Prefix(prefix) + return &implementer{ImplementerName}{client} +} +` + +const TemplateGenCtrlSdkImplementerFunc = ` +func (i *implementer{ImplementerName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) { + err = i.Request(ctx, req, &res) + return +} +` diff --git a/cmd/gf/internal/consts/consts_gen_dao_template_dao.go b/cmd/gf/internal/consts/consts_gen_dao_template_dao.go index a9b7ee2e5..bcf23736a 100644 --- a/cmd/gf/internal/consts/consts_gen_dao_template_dao.go +++ b/cmd/gf/internal/consts/consts_gen_dao_template_dao.go @@ -39,7 +39,7 @@ var ( const TemplateGenDaoInternalContent = ` // ========================================================================== -// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr} +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr} // ========================================================================== package internal diff --git a/cmd/gf/internal/consts/consts_gen_dao_template_do.go b/cmd/gf/internal/consts/consts_gen_dao_template_do.go index 4880b4056..11914b010 100644 --- a/cmd/gf/internal/consts/consts_gen_dao_template_do.go +++ b/cmd/gf/internal/consts/consts_gen_dao_template_do.go @@ -8,7 +8,7 @@ package consts const TemplateGenDaoDoContent = ` // ================================================================================= -// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr} +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr} // ================================================================================= package do diff --git a/cmd/gf/internal/consts/consts_gen_dao_template_entity.go b/cmd/gf/internal/consts/consts_gen_dao_template_entity.go index afe15ea17..44af06aa3 100644 --- a/cmd/gf/internal/consts/consts_gen_dao_template_entity.go +++ b/cmd/gf/internal/consts/consts_gen_dao_template_entity.go @@ -8,7 +8,7 @@ package consts const TemplateGenDaoEntityContent = ` // ================================================================================= -// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr} +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr} // ================================================================================= package entity diff --git a/cmd/gf/internal/consts/consts_gen_enums_template.go b/cmd/gf/internal/consts/consts_gen_enums_template.go index e97f40de4..947778709 100644 --- a/cmd/gf/internal/consts/consts_gen_enums_template.go +++ b/cmd/gf/internal/consts/consts_gen_enums_template.go @@ -8,7 +8,7 @@ package consts const TemplateGenEnums = ` // ================================================================================ -// Code generated by GoFrame CLI tool. DO NOT EDIT. +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. // ================================================================================ package {PackageName} diff --git a/cmd/gf/internal/consts/consts_gen_pbentity_template.go b/cmd/gf/internal/consts/consts_gen_pbentity_template.go index ad9218ab1..73b693ed9 100644 --- a/cmd/gf/internal/consts/consts_gen_pbentity_template.go +++ b/cmd/gf/internal/consts/consts_gen_pbentity_template.go @@ -8,7 +8,7 @@ package consts const TemplatePbEntityMessageContent = ` // ========================================================================== -// Code generated by GoFrame CLI tool. DO NOT EDIT. +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. // ========================================================================== syntax = "proto3"; diff --git a/cmd/gf/internal/consts/consts_gen_service_template.go b/cmd/gf/internal/consts/consts_gen_service_template.go index b7d6e52a0..f5c4f5a84 100644 --- a/cmd/gf/internal/consts/consts_gen_service_template.go +++ b/cmd/gf/internal/consts/consts_gen_service_template.go @@ -8,7 +8,7 @@ package consts const TemplateGenServiceContentHead = ` // ================================================================================ -// Code generated by GoFrame CLI tool. DO NOT EDIT. +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. // You can delete these comments if you wish manually maintain this interface file. // ================================================================================ diff --git a/cmd/gf/internal/consts/consts_gen_service_template_logic.go b/cmd/gf/internal/consts/consts_gen_service_template_logic.go index 8a32d6992..eb43a0346 100644 --- a/cmd/gf/internal/consts/consts_gen_service_template_logic.go +++ b/cmd/gf/internal/consts/consts_gen_service_template_logic.go @@ -8,7 +8,7 @@ package consts const TemplateGenServiceLogicContent = ` // ========================================================================== -// Code generated by GoFrame CLI tool. DO NOT EDIT. +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. // ========================================================================== package {PackageName} diff --git a/cmd/gf/internal/packed/template-mono.go b/cmd/gf/internal/packed/template-mono.go index dbed154a8..d08011d1f 100644 --- a/cmd/gf/internal/packed/template-mono.go +++ b/cmd/gf/internal/packed/template-mono.go @@ -3,7 +3,7 @@ package packed import "github.com/gogf/gf/v2/os/gres" func init() { - if err := gres.Add("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"); err != nil { + if err := gres.Add("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"); err != nil { panic("add binary content to resource manager failed: " + err.Error()) } } diff --git a/cmd/gf/internal/packed/template-single.go b/cmd/gf/internal/packed/template-single.go index 30c8b1452..ee2019315 100644 --- a/cmd/gf/internal/packed/template-single.go +++ b/cmd/gf/internal/packed/template-single.go @@ -3,7 +3,7 @@ package packed import "github.com/gogf/gf/v2/os/gres" func init() { - if err := gres.Add("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"); err != nil { + if err := gres.Add("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"); err != nil { panic("add binary content to resource manager failed: " + err.Error()) } } diff --git a/cmd/gf/internal/utility/utils/utils.go b/cmd/gf/internal/utility/utils/utils.go index e8ea446a8..6e4678a1f 100644 --- a/cmd/gf/internal/utility/utils/utils.go +++ b/cmd/gf/internal/utility/utils/utils.go @@ -15,6 +15,7 @@ import ( "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/os/gproc" + "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" ) @@ -72,3 +73,33 @@ func ReplaceGeneratedContentGFV2(folderPath string) (err error) { return content }, folderPath, "*.go", true) } + +// GetImportPath calculates and returns the golang import path for given `filePath`. +// Note that it needs a `go.mod` in current working directory or parent directories to detect the path. +func GetImportPath(filePath string) string { + var ( + newDir = gfile.Dir(filePath) + oldDir string + suffix string + goModName = "go.mod" + goModPath string + importPath string + ) + if gfile.IsDir(filePath) { + suffix = gfile.Basename(filePath) + } + for { + goModPath = gfile.Join(newDir, goModName) + if gfile.Exists(goModPath) { + match, _ := gregex.MatchString(`^module\s+(.+)\s*`, gfile.GetContents(goModPath)) + importPath = gstr.Trim(match[1]) + "/" + suffix + return gstr.Replace(importPath, `\`, `/`) + } + oldDir = newDir + newDir = gfile.Dir(oldDir) + if newDir == oldDir { + return "" + } + suffix = gfile.Basename(oldDir) + "/" + suffix + } +} diff --git a/contrib/config/apollo/go.mod b/contrib/config/apollo/go.mod index 28109c03a..add6046f7 100644 --- a/contrib/config/apollo/go.mod +++ b/contrib/config/apollo/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/apolloconfig/agollo/v4 v4.1.1 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 ) replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/config/kubecm/go.mod b/contrib/config/kubecm/go.mod index 9b2683133..ac4a2af18 100644 --- a/contrib/config/kubecm/go.mod +++ b/contrib/config/kubecm/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/kubecm/v2 go 1.18 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 k8s.io/api v0.25.2 k8s.io/apimachinery v0.25.2 k8s.io/client-go v0.25.2 diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod index 2c9c5d85f..1bc6c7b49 100644 --- a/contrib/config/nacos/go.mod +++ b/contrib/config/nacos/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/nacos/v2 go 1.15 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 github.com/nacos-group/nacos-sdk-go v1.1.2 ) diff --git a/contrib/config/polaris/go.mod b/contrib/config/polaris/go.mod index df2cfcdb1..040aabda7 100644 --- a/contrib/config/polaris/go.mod +++ b/contrib/config/polaris/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/polaris/v2 go 1.15 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 github.com/polarismesh/polaris-go v1.4.3 ) diff --git a/contrib/drivers/clickhouse/go.mod b/contrib/drivers/clickhouse/go.mod index 36640df02..53dd685d6 100644 --- a/contrib/drivers/clickhouse/go.mod +++ b/contrib/drivers/clickhouse/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/ClickHouse/clickhouse-go/v2 v2.0.15 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 github.com/google/uuid v1.3.0 github.com/shopspring/decimal v1.3.1 ) diff --git a/contrib/drivers/dm/go.mod b/contrib/drivers/dm/go.mod index c36cf60d6..3de6d0e8f 100644 --- a/contrib/drivers/dm/go.mod +++ b/contrib/drivers/dm/go.mod @@ -6,5 +6,5 @@ replace github.com/gogf/gf/v2 => ../../../ require ( gitee.com/chunanyong/dm v1.8.10 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 ) diff --git a/contrib/drivers/mssql/go.mod b/contrib/drivers/mssql/go.mod index d959c03ed..2a850652c 100644 --- a/contrib/drivers/mssql/go.mod +++ b/contrib/drivers/mssql/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/denisenkom/go-mssqldb v0.11.0 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 ) replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/drivers/mysql/go.mod b/contrib/drivers/mysql/go.mod index 2b202738c..a4ba86cdf 100644 --- a/contrib/drivers/mysql/go.mod +++ b/contrib/drivers/mysql/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/go-sql-driver/mysql v1.6.0 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 ) replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/drivers/oracle/go.mod b/contrib/drivers/oracle/go.mod index b139d5ccb..6765f07f2 100644 --- a/contrib/drivers/oracle/go.mod +++ b/contrib/drivers/oracle/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/oracle/v2 go 1.17 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 github.com/sijms/go-ora/v2 v2.4.20 ) diff --git a/contrib/drivers/pgsql/go.mod b/contrib/drivers/pgsql/go.mod index b9bce5061..be16ac9a5 100644 --- a/contrib/drivers/pgsql/go.mod +++ b/contrib/drivers/pgsql/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/pgsql/v2 go 1.15 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 github.com/lib/pq v1.10.4 ) diff --git a/contrib/drivers/sqlite/go.mod b/contrib/drivers/sqlite/go.mod index 41eecd54c..7101af1db 100644 --- a/contrib/drivers/sqlite/go.mod +++ b/contrib/drivers/sqlite/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/glebarez/go-sqlite v1.17.3 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 ) replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/nosql/redis/go.mod b/contrib/nosql/redis/go.mod index c15336096..3c3d34892 100644 --- a/contrib/nosql/redis/go.mod +++ b/contrib/nosql/redis/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/go-redis/redis/v8 v8.11.5 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 go.opentelemetry.io/otel v1.7.0 go.opentelemetry.io/otel/trace v1.7.0 ) diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod index b055410b5..3560a4661 100644 --- a/contrib/registry/etcd/go.mod +++ b/contrib/registry/etcd/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/etcd/v2 go 1.15 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 go.etcd.io/etcd/client/v3 v3.5.4 ) diff --git a/contrib/registry/file/go.mod b/contrib/registry/file/go.mod index 34e470479..4dca61245 100644 --- a/contrib/registry/file/go.mod +++ b/contrib/registry/file/go.mod @@ -2,6 +2,6 @@ module github.com/gogf/gf/contrib/registry/file/v2 go 1.15 -require github.com/gogf/gf/v2 v2.4.2 +require github.com/gogf/gf/v2 v2.4.3 replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod index 71bc5b947..9135d9257 100644 --- a/contrib/registry/polaris/go.mod +++ b/contrib/registry/polaris/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/polaris/v2 go 1.15 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 github.com/polarismesh/polaris-go v1.4.3 ) diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod index 5819ce7bc..e3a655029 100644 --- a/contrib/registry/zookeeper/go.mod +++ b/contrib/registry/zookeeper/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/go-zookeeper/zk v1.0.3 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 golang.org/x/sync v0.1.0 ) diff --git a/contrib/rpc/grpcx/go.mod b/contrib/rpc/grpcx/go.mod index 929b58491..768c6a5cf 100644 --- a/contrib/rpc/grpcx/go.mod +++ b/contrib/rpc/grpcx/go.mod @@ -3,8 +3,8 @@ module github.com/gogf/gf/contrib/rpc/grpcx/v2 go 1.15 require ( - github.com/gogf/gf/contrib/registry/file/v2 v2.4.2 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/contrib/registry/file/v2 v2.4.3 + github.com/gogf/gf/v2 v2.4.3 go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/trace v1.10.0 golang.org/x/net v0.0.0-20220919232410-f2f64ebce3c1 // indirect diff --git a/contrib/sdk/httpclient/go.mod b/contrib/sdk/httpclient/go.mod new file mode 100644 index 000000000..140850767 --- /dev/null +++ b/contrib/sdk/httpclient/go.mod @@ -0,0 +1,7 @@ +module github.com/gogf/gf/contrib/sdk/httpclient/v2 + +go 1.15 + +require github.com/gogf/gf/v2 v2.4.3 + +replace github.com/gogf/gf/v2 => ../../../ diff --git a/contrib/sdk/httpclient/go.sum b/contrib/sdk/httpclient/go.sum new file mode 100644 index 000000000..ea20ffef8 --- /dev/null +++ b/contrib/sdk/httpclient/go.sum @@ -0,0 +1,83 @@ +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= +github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/sdk/httpclient/httpclient.go b/contrib/sdk/httpclient/httpclient.go new file mode 100644 index 000000000..39c722c10 --- /dev/null +++ b/contrib/sdk/httpclient/httpclient.go @@ -0,0 +1,109 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +// Package httpclient provides http client used for SDK. +package httpclient + +import ( + "context" + "encoding/json" + "net/http" + + "github.com/gogf/gf/v2/encoding/gurl" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/net/gclient" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gmeta" + "github.com/gogf/gf/v2/util/gtag" +) + +// Client is a http client for SDK. +type Client struct { + *gclient.Client + config Config +} + +// New creates and returns a http client for SDK. +func New(config Config) *Client { + return &Client{ + Client: config.Client, + config: config, + } +} + +func (c *Client) handleResponse(ctx context.Context, res *gclient.Response, out interface{}) error { + if c.config.RawDump { + c.config.Logger.Debugf(ctx, "raw request&response:\n%s", res.Raw()) + } + + var ( + responseBytes = res.ReadAll() + result = ghttp.DefaultHandlerResponse{ + Data: out, + } + ) + if !json.Valid(responseBytes) { + return gerror.Newf(`invalid response content: %s`, responseBytes) + } + if err := json.Unmarshal(responseBytes, &result); err != nil { + return gerror.Wrapf(err, `json.Unmarshal failed with content:%s`, responseBytes) + } + if result.Code != gcode.CodeOK.Code() { + return gerror.NewCode( + gcode.New(result.Code, result.Message, nil), + result.Message, + ) + } + return nil +} + +// Request sends request to service by struct object `req`, and receives response to struct object `res`. +func (c *Client) Request(ctx context.Context, req, res interface{}) error { + var ( + method = gmeta.Get(req, gtag.Method).String() + path = gmeta.Get(req, gtag.Path).String() + ) + switch gstr.ToUpper(method) { + case http.MethodGet: + return c.Get(ctx, path, req, res) + + default: + result, err := c.ContentJson().DoRequest(ctx, method, c.handlePath(path, req), req) + if err != nil { + return err + } + return c.handleResponse(ctx, result, res) + } +} + +// Get sends a request using GET method. +func (c *Client) Get(ctx context.Context, path string, in, out interface{}) error { + if urlParams := ghttp.BuildParams(in); urlParams != "" { + path += "?" + ghttp.BuildParams(in) + } + res, err := c.ContentJson().Get(ctx, c.handlePath(path, in)) + if err != nil { + return gerror.Wrap(err, `http request failed`) + } + return c.handleResponse(ctx, res, out) +} + +func (c *Client) handlePath(path string, in interface{}) string { + if gstr.Contains(path, "{") { + data := gconv.MapStrStr(in) + path, _ = gregex.ReplaceStringFuncMatch(`\{(\w+)\}`, path, func(match []string) string { + if v, ok := data[match[1]]; ok { + return gurl.Encode(v) + } + return match[1] + }) + } + return path +} diff --git a/contrib/sdk/httpclient/httpclient_config.go b/contrib/sdk/httpclient/httpclient_config.go new file mode 100644 index 000000000..7a9c0feb7 --- /dev/null +++ b/contrib/sdk/httpclient/httpclient_config.go @@ -0,0 +1,20 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package httpclient + +import ( + "github.com/gogf/gf/v2/net/gclient" + "github.com/gogf/gf/v2/os/glog" +) + +// Config is the configuration struct for SDK client. +type Config struct { + URL string `v:"required"` // Service address. Eg: user.svc.local, http://user.svc.local + Client *gclient.Client // Custom underlying client. + Logger *glog.Logger // Custom logger. + RawDump bool // Whether auto dump request&response in stdout. +} diff --git a/contrib/trace/jaeger/go.mod b/contrib/trace/jaeger/go.mod index c90d51f51..f566fa23b 100644 --- a/contrib/trace/jaeger/go.mod +++ b/contrib/trace/jaeger/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/jaeger/v2 go 1.15 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 go.opentelemetry.io/otel v1.7.0 go.opentelemetry.io/otel/exporters/jaeger v1.7.0 go.opentelemetry.io/otel/sdk v1.7.0 diff --git a/contrib/trace/otlpgrpc/go.mod b/contrib/trace/otlpgrpc/go.mod index dc2e25825..39a430aae 100644 --- a/contrib/trace/otlpgrpc/go.mod +++ b/contrib/trace/otlpgrpc/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/otlpgrpc/v2 go 1.20 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 diff --git a/contrib/trace/otlphttp/go.mod b/contrib/trace/otlphttp/go.mod index 9040fc6d6..af69be9cb 100644 --- a/contrib/trace/otlphttp/go.mod +++ b/contrib/trace/otlphttp/go.mod @@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/otlphttp/v2 go 1.20 require ( - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/v2 v2.4.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 diff --git a/database/gredis/gredis.go b/database/gredis/gredis.go index 82bf15e6d..3f8f5dc24 100644 --- a/database/gredis/gredis.go +++ b/database/gredis/gredis.go @@ -57,7 +57,7 @@ func New(config ...*Config) (*Redis, error) { ) } redis := &Redis{ - config: config[0], + config: usedConfig, localAdapter: usedAdapter, } return redis.initGroup(), nil diff --git a/example/go.mod b/example/go.mod index 167ab0838..488ad6c94 100644 --- a/example/go.mod +++ b/example/go.mod @@ -3,20 +3,20 @@ module github.com/gogf/gf/example go 1.15 require ( - github.com/gogf/gf/contrib/config/apollo/v2 v2.4.2 - github.com/gogf/gf/contrib/config/kubecm/v2 v2.4.2 - github.com/gogf/gf/contrib/config/nacos/v2 v2.4.2 - github.com/gogf/gf/contrib/config/polaris/v2 v2.4.2 - github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.2 - github.com/gogf/gf/contrib/nosql/redis/v2 v2.4.2 - github.com/gogf/gf/contrib/registry/etcd/v2 v2.4.2 - github.com/gogf/gf/contrib/registry/file/v2 v2.4.2 - github.com/gogf/gf/contrib/registry/polaris/v2 v2.4.2 - github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.4.2 - github.com/gogf/gf/contrib/trace/jaeger/v2 v2.4.2 - github.com/gogf/gf/contrib/trace/otlpgrpc/v2 v2.4.2 - github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.4.2 - github.com/gogf/gf/v2 v2.4.2 + github.com/gogf/gf/contrib/config/apollo/v2 v2.4.3 + github.com/gogf/gf/contrib/config/kubecm/v2 v2.4.3 + github.com/gogf/gf/contrib/config/nacos/v2 v2.4.3 + github.com/gogf/gf/contrib/config/polaris/v2 v2.4.3 + github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.3 + github.com/gogf/gf/contrib/nosql/redis/v2 v2.4.3 + github.com/gogf/gf/contrib/registry/etcd/v2 v2.4.3 + github.com/gogf/gf/contrib/registry/file/v2 v2.4.3 + github.com/gogf/gf/contrib/registry/polaris/v2 v2.4.3 + github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.4.3 + github.com/gogf/gf/contrib/trace/jaeger/v2 v2.4.3 + github.com/gogf/gf/contrib/trace/otlpgrpc/v2 v2.4.3 + github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.4.3 + github.com/gogf/gf/v2 v2.4.3 github.com/nacos-group/nacos-sdk-go v1.1.2 github.com/polarismesh/polaris-go v1.4.3 google.golang.org/grpc v1.55.0 diff --git a/version.go b/version.go index 9fb1de78f..9b8c8bf32 100644 --- a/version.go +++ b/version.go @@ -2,5 +2,5 @@ package gf const ( // VERSION is the current GoFrame version. - VERSION = "v2.4.2" + VERSION = "v2.4.3" )