From 9a0066de62dbb233e33a23d7eafc37f3f98b1b05 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 27 Mar 2019 11:48:53 +0800 Subject: [PATCH] add file/folder search support for gcfg/gview in order of envpath/pwdpath/binpath/mainpath; add gfile.Search function --- g/frame/gins/gins.go | 30 +++++---- g/net/ghttp/ghttp_server_config_static.go | 33 ++++------ g/os/gcfg/gcfg.go | 68 ++++++++++++++++++-- g/os/gfile/gfile_search.go | 63 ++++++++++++++++++ g/os/gview/gview.go | 78 ++++++++++++++++++----- 5 files changed, 218 insertions(+), 54 deletions(-) create mode 100644 g/os/gfile/gfile_search.go diff --git a/g/frame/gins/gins.go b/g/frame/gins/gins.go index c77a2da3f..1c4586b24 100644 --- a/g/frame/gins/gins.go +++ b/g/frame/gins/gins.go @@ -75,11 +75,18 @@ func View(name...string) *gview.View { } key := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_VIEW, group) return instances.GetOrSetFuncLock(key, func() interface{} { - path := cmdenv.Get("gf.gview.path", gfile.Pwd()).String() - view := gview.New(path) - // 添加基于源码的搜索目录检索地址,常用于开发环境调试,只添加入口文件目录 - if p := gfile.MainPkgPath(); p != "" && gfile.Exists(p) { - view.AddPath(p) + view := gview.New(gfile.Pwd()) + // 自定义的环境变量/启动参数路径,优先级最高,覆盖默认的工作目录 + if envPath := cmdenv.Get("gf.gview.path").String(); envPath != "" && gfile.Exists(envPath) { + view.SetPath(envPath) + } + // 二进制文件执行目录 + if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) { + view.AddPath(selfPath) + } + // 开发环境源码main包目录 + if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) { + view.AddPath(mainPath) } // 框架内置函数 view.BindFunc("config", funcConfig) @@ -96,21 +103,18 @@ func Config(file...string) *gcfg.Config { } return instances.GetOrSetFuncLock(fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_CONFIG, configFile), func() interface{} { - pwdPath := gfile.Pwd() - envPath := cmdenv.Get("gf.gcfg.path").String() - selfPath := gfile.SelfDir() - mainPath := gfile.MainPkgPath() - config := gcfg.New(pwdPath, configFile) + // 默认当前工作目录 + config := gcfg.New(gfile.Pwd(), configFile) // 自定义的环境变量/启动参数路径,优先级最高,覆盖默认的工作目录 - if envPath != "" && gfile.Exists(envPath) { + if envPath := cmdenv.Get("gf.gcfg.path").String(); envPath != "" && gfile.Exists(envPath) { config.SetPath(envPath) } // 二进制文件执行目录 - if selfPath != "" && gfile.Exists(selfPath) { + if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) { config.AddPath(selfPath) } // 开发环境源码main包目录 - if mainPath != "" && gfile.Exists(mainPath) { + if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) { config.AddPath(mainPath) } return config diff --git a/g/net/ghttp/ghttp_server_config_static.go b/g/net/ghttp/ghttp_server_config_static.go index 87a02158e..4fcda5adb 100644 --- a/g/net/ghttp/ghttp_server_config_static.go +++ b/g/net/ghttp/ghttp_server_config_static.go @@ -57,15 +57,12 @@ func (s *Server)SetServerRoot(root string) { return } // RealPath的作用除了校验地址正确性以外,还转换分隔符号为当前系统正确的文件分隔符号 - path := gfile.RealPath(root) - if path == "" { - path = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + root) + realPath, err := gfile.Search(root) + if err != nil { + glog.Fatal(fmt.Sprintf(`[ghttp] SetServerRoot failed: %s`, err.Error())) } - if path == "" { - glog.Fatal(fmt.Sprintf(`[ghttp] SetServerRoot failed: path "%s" does not exist`, root)) - } - glog.Debug("[ghttp] SetServerRoot path:", path) - s.config.SearchPaths = []string{strings.TrimRight(path, gfile.Separator)} + glog.Debug("[ghttp] SetServerRoot path:", realPath) + s.config.SearchPaths = []string{strings.TrimRight(realPath, gfile.Separator)} s.config.FileServerEnabled = true } @@ -75,13 +72,9 @@ func (s *Server) AddSearchPath(path string) { glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR) return } - // RealPath的作用除了校验地址正确性以外,还转换分隔符号为当前系统正确的文件分隔符号 - realPath := gfile.RealPath(path) - if realPath == "" { - realPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + path) - } - if realPath == "" { - glog.Fatal(fmt.Sprintf(`[ghttp] AddSearchPath failed: path "%s" does not exist`, path)) + realPath, err := gfile.Search(path) + if err != nil { + glog.Fatal(fmt.Sprintf(`[ghttp] AddSearchPath failed: %s`, err.Error())) } s.config.SearchPaths = append(s.config.SearchPaths, realPath) s.config.FileServerEnabled = true @@ -93,13 +86,9 @@ func (s *Server) AddStaticPath(prefix string, path string) { glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR) return } - // RealPath的作用除了校验地址正确性以外,还转换分隔符号为当前系统正确的文件分隔符号 - realPath := gfile.RealPath(path) - if realPath == "" { - realPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + path) - } - if realPath == "" { - glog.Fatal(fmt.Sprintf(`[ghttp] AddStaticPath failed: path "%s" does not exist`, path)) + realPath, err := gfile.Search(path) + if err != nil { + glog.Fatal(fmt.Sprintf(`[ghttp] AddStaticPath failed: %s`, err.Error())) } addItem := staticPathItem { prefix : prefix, diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index 6fb86c8d0..a046ee02e 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -86,10 +86,40 @@ func (c *Config) filePath(file...string) (path string) { // 设置配置管理器的配置文件存放目录绝对路径 func (c *Config) SetPath(path string) error { + // 判断绝对路径(或者工作目录下目录) realPath := gfile.RealPath(path) if realPath == "" { - err := errors.New(fmt.Sprintf(`path "%s" does not exist`, path)) - glog.Error(fmt.Sprintf(`[gcfg] SetPath failed: %s`, err.Error())) + // 判断相对路径 + c.paths.RLockFunc(func(array []string) { + for _, v := range array { + if path, _ := gspath.Search(v, path); path != "" { + realPath = path + break + } + } + }) + } + // 目录不存在错误处理 + if realPath == "" { + buffer := bytes.NewBuffer(nil) + if c.paths.Len() > 0 { + buffer.WriteString(fmt.Sprintf("[gcfg] SetPath failed: cannot find directory \"%s\" in following paths:", path)) + c.paths.RLockFunc(func(array []string) { + for k, v := range array { + buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v)) + } + }) + } else { + buffer.WriteString(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" does not exist`, path)) + } + err := errors.New(buffer.String()) + glog.Error(err) + return err + } + // 路径必须为目录类型 + if !gfile.IsDir(realPath) { + err := errors.New(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" should be directory type`, path)) + glog.Error(err) return err } // 重复判断 @@ -112,10 +142,40 @@ func (c *Config) SetViolenceCheck(check bool) { // 添加配置管理器的配置文件搜索路径 func (c *Config) AddPath(path string) error { + // 判断绝对路径(或者工作目录下目录) realPath := gfile.RealPath(path) if realPath == "" { - err := errors.New(fmt.Sprintf(`path "%s" does not exist`, path)) - glog.Error(fmt.Sprintf(`[gcfg] AddPath failed: %s`, err.Error())) + // 判断相对路径 + c.paths.RLockFunc(func(array []string) { + for _, v := range array { + if path, _ := gspath.Search(v, path); path != "" { + realPath = path + break + } + } + }) + } + // 目录不存在错误处理 + if realPath == "" { + buffer := bytes.NewBuffer(nil) + if c.paths.Len() > 0 { + buffer.WriteString(fmt.Sprintf("[gcfg] AddPath failed: cannot find directory \"%s\" in following paths:", path)) + c.paths.RLockFunc(func(array []string) { + for k, v := range array { + buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v)) + } + }) + } else { + buffer.WriteString(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" does not exist`, path)) + } + err := errors.New(buffer.String()) + glog.Error(err) + return err + } + // 路径必须为目录类型 + if !gfile.IsDir(realPath) { + err := errors.New(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" should be directory type`, path)) + glog.Error(err) return err } // 重复判断 diff --git a/g/os/gfile/gfile_search.go b/g/os/gfile/gfile_search.go new file mode 100644 index 000000000..fbc6e10f0 --- /dev/null +++ b/g/os/gfile/gfile_search.go @@ -0,0 +1,63 @@ +// Copyright 2017-2018 gf Author(https://github.com/gogf/gf). 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 gfile + +import ( + "bytes" + "errors" + "fmt" + "github.com/gogf/gf/g/container/garray" +) + + +// 如果给定绝对路径将会去掉其中的相对路径符号后返回; +// 如果是给定的相对路径,那么将会按照以下路径优先级搜索文件(重复路径会去重): +// prioritySearchPaths、当前工作目录、二进制文件目录、源码main包目录(开发环境下) +func Search(name string, prioritySearchPaths...string) (realPath string, err error) { + // 是否绝对路径 + realPath = RealPath(name) + if realPath != "" { + return + } + // 相对路径搜索 + array := garray.NewStringArray(true) + // 自定义优先路径 + array.Append(prioritySearchPaths...) + // 用户工作目录 + array.Append(Pwd()) + // 二进制所在目录 + array.Append(SelfDir()) + // 源码main包目录 + if path := MainPkgPath(); path != "" { + array.Append(path) + } + // 路径去重 + array.Unique() + // 执行相对路径搜索 + array.RLockFunc(func(array []string) { + path := "" + for _, v := range array { + path = RealPath(v + Separator + name) + if path != "" { + realPath = path + break + } + } + }) + // 目录不存在错误处理 + if realPath == "" { + buffer := bytes.NewBuffer(nil) + buffer.WriteString(fmt.Sprintf("cannot find file/folder \"%s\" in following paths:", name)) + array.RLockFunc(func(array []string) { + for k, v := range array { + buffer.WriteString(fmt.Sprintf("\n%d. %s", k + 1, v)) + } + }) + err = errors.New(buffer.String()) + } + return +} diff --git a/g/os/gview/gview.go b/g/os/gview/gview.go index 2b136fd08..bad53824a 100644 --- a/g/os/gview/gview.go +++ b/g/os/gview/gview.go @@ -24,8 +24,8 @@ import ( "github.com/gogf/gf/g/os/gspath" "github.com/gogf/gf/g/os/gtime" "github.com/gogf/gf/g/os/gview/internal/text/template" - "github.com/gogf/gf/g/util/gconv" "github.com/gogf/gf/g/text/gstr" + "github.com/gogf/gf/g/util/gconv" "strings" "sync" ) @@ -48,16 +48,10 @@ type FuncMap = map[string]interface{} // 默认的视图对象 var viewObj *View -// 初始化默认的视图对象 +// 初始化默认的视图对象, 默认加载包不会初始化,使用包方法才会初始化模板引擎对象。 func checkAndInitDefaultView() { if viewObj == nil { - // gfile.MainPkgPath() 用以判断是否开发环境 - mainPkgPath := gfile.MainPkgPath() - if gfile.MainPkgPath() == "" { - viewObj = New(gfile.Pwd()) - } else { - viewObj = New(mainPkgPath) - } + viewObj = New(gfile.Pwd()) } } @@ -106,13 +100,40 @@ func New(path...string) *View { // 设置模板目录绝对路径 func (view *View) SetPath(path string) error { + // 判断绝对路径(或者工作目录下目录) realPath := gfile.RealPath(path) if realPath == "" { - realPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + path) + // 判断相对路径 + view.paths.RLockFunc(func(array []string) { + for _, v := range array { + if path, _ := gspath.Search(v, path); path != "" { + realPath = path + break + } + } + }) } + // 目录不存在错误处理 if realPath == "" { - err := errors.New(fmt.Sprintf(`path "%s" does not exist`, path)) - glog.Error(fmt.Sprintf(`[gview] SetPath failed: %s`, err.Error())) + buffer := bytes.NewBuffer(nil) + if view.paths.Len() > 0 { + buffer.WriteString(fmt.Sprintf("[gview] SetPath failed: cannot find directory \"%s\" in following paths:", path)) + view.paths.RLockFunc(func(array []string) { + for k, v := range array { + buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v)) + } + }) + } else { + buffer.WriteString(fmt.Sprintf(`[gview] SetPath failed: path "%s" does not exist`, path)) + } + err := errors.New(buffer.String()) + glog.Error(err) + return err + } + // 路径必须为目录类型 + if !gfile.IsDir(realPath) { + err := errors.New(fmt.Sprintf(`[gview] SetPath failed: path "%s" should be directory type`, path)) + glog.Error(err) return err } // 重复判断 @@ -127,13 +148,40 @@ func (view *View) SetPath(path string) error { // 添加模板目录搜索路径 func (view *View) AddPath(path string) error { + // 判断绝对路径(或者工作目录下目录) realPath := gfile.RealPath(path) if realPath == "" { - realPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + path) + // 判断相对路径 + view.paths.RLockFunc(func(array []string) { + for _, v := range array { + if path, _ := gspath.Search(v, path); path != "" { + realPath = path + break + } + } + }) } + // 目录不存在错误处理 if realPath == "" { - err := errors.New(fmt.Sprintf(`path "%s" does not exist`, path)) - glog.Error(fmt.Sprintf(`[gview] AddPath failed: %s`, err.Error())) + buffer := bytes.NewBuffer(nil) + if view.paths.Len() > 0 { + buffer.WriteString(fmt.Sprintf("[gview] AddPath failed: cannot find directory \"%s\" in following paths:", path)) + view.paths.RLockFunc(func(array []string) { + for k, v := range array { + buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v)) + } + }) + } else { + buffer.WriteString(fmt.Sprintf(`[gview] AddPath failed: path "%s" does not exist`, path)) + } + err := errors.New(buffer.String()) + glog.Error(err) + return err + } + // 路径必须为目录类型 + if !gfile.IsDir(realPath) { + err := errors.New(fmt.Sprintf(`[gview] AddPath failed: path "%s" should be directory type`, path)) + glog.Error(err) return err } // 重复判断