// Package addons // @Link https://github.com/bufanyun/hotgo // @Copyright Copyright (c) 2023 HotGo CLI // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE package addons import ( "context" "fmt" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/text/gstr" "hotgo/internal/consts" "hotgo/internal/model" "hotgo/utility/validate" "strconv" "strings" ) type BuildOption struct { Skeleton Skeleton Config *model.BuildAddonConfig Extend []string `json:"extend" dc:"扩展功能"` } // Build 构建新插件 func Build(ctx context.Context, option *BuildOption) (err error) { var ( resourcePath = GetResourcePath(ctx) buildPath = "./" + consts.AddonsDir + "/" + option.Skeleton.Name modulesPath = "./" + consts.AddonsDir + "/modules/" + option.Skeleton.Name + ".go" webApiPath = gstr.Replace(option.Config.WebApiPath, "{$name}", option.Skeleton.Name) webViewsPath = gstr.Replace(option.Config.WebViewsPath, "{$name}", option.Skeleton.Name) replaces = map[string]string{ "@{.label}": option.Skeleton.Label, "@{.name}": option.Skeleton.Name, "@{.group}": strconv.Itoa(option.Skeleton.Group), "@{.brief}": option.Skeleton.Brief, "@{.description}": option.Skeleton.Description, "@{.author}": option.Skeleton.Author, "@{.version}": option.Skeleton.Version, "@{.hgVersion}": consts.VersionApp, // HG 版本 } ) if resourcePath == "" { err = gerror.New("请先设置一个有效的插件资源路径,配置名称:'system.addonsResourcePath'") return } if err = checkBuildDir(buildPath, modulesPath, webApiPath, webViewsPath); err != nil { return } // scans directory recursively list, err := gfile.ScanDirFunc(option.Config.SrcPath, "*", true, func(path string) string { return path }) if err != nil { return } for _, path := range list { if !gfile.IsReadable(path) { err = gerror.Newf("file:%v is unreadable, please check permissions", path) return } if gfile.IsDir(path) { continue } flowFile := gstr.ReplaceByMap(path, map[string]string{ gfile.RealPath(option.Config.SrcPath): "", ".template": "", }) flowFile = buildPath + "/" + flowFile content := gstr.ReplaceByMap(gfile.GetContents(path), replaces) if err = gfile.PutContents(flowFile, content); err != nil { break } } // 隐式注入插件 if err = gfile.PutContents(modulesPath, gstr.ReplaceByMap(importModules, replaces)); err != nil { return } // webApi if err = gfile.PutContents(webApiPath+"/config/index.ts", gstr.ReplaceByMap(webApiLayout, replaces)); err != nil { return } // web插件配置主页面 if err = gfile.PutContents(webViewsPath+"/config/BasicSetting.vue", gstr.ReplaceByMap(webConfigBasicSetting, replaces)); err != nil { return } // web插件基础配置页面 if err = gfile.PutContents(webViewsPath+"/config/system.vue", gstr.ReplaceByMap(webConfigSystem, replaces)); err != nil { return } // 创建静态目录 if validate.InSlice(option.Extend, consts.AddonsExtendResourcePublic) { _, staticPath := StaticPath(option.Skeleton.Name, resourcePath) content := fmt.Sprintf(resourcePublicDefaultFile, option.Skeleton.Label) if err = gfile.PutContents(staticPath+"/default", content); err != nil { return } } // 创建模板目录 if validate.InSlice(option.Extend, consts.AddonsExtendResourceTemplate) { viewPath := ViewPath(option.Skeleton.Name, resourcePath) if err = gfile.PutContents(viewPath+"/home/index.html", resourceTemplateHomeFile); err != nil { return } } return } func checkBuildDir(paths ...string) (err error) { if len(paths) == 0 { return } for _, path := range paths { if gfile.Exists(path) { return gerror.Newf("插件已存在,请换一个插件名称或者经确认无误后依次删除文件夹: [%v] 后重新生成", strings.Join(paths, "、\t")) } } return }