github.com/wangyougui/gf/v2@v2.6.5/os/gfile/gfile_source.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gfile 8 9 import ( 10 "os" 11 "runtime" 12 "strings" 13 14 "github.com/wangyougui/gf/v2/text/gregex" 15 "github.com/wangyougui/gf/v2/text/gstr" 16 ) 17 18 var ( 19 // goRootForFilter is used for stack filtering purpose. 20 goRootForFilter = runtime.GOROOT() 21 ) 22 23 func init() { 24 if goRootForFilter != "" { 25 goRootForFilter = strings.ReplaceAll(goRootForFilter, "\\", "/") 26 } 27 } 28 29 // MainPkgPath returns absolute file path of package main, 30 // which contains the entrance function main. 31 // 32 // It's only available in develop environment. 33 // 34 // Note1: Only valid for source development environments, 35 // IE only valid for systems that generate this executable. 36 // 37 // Note2: When the method is called for the first time, if it is in an asynchronous goroutine, 38 // the method may not get the main package path. 39 func MainPkgPath() string { 40 // It is only for source development environments. 41 if goRootForFilter == "" { 42 return "" 43 } 44 path := mainPkgPath.Val() 45 if path != "" { 46 return path 47 } 48 var lastFile string 49 for i := 1; i < 10000; i++ { 50 if pc, file, _, ok := runtime.Caller(i); ok { 51 if goRootForFilter != "" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter { 52 continue 53 } 54 if Ext(file) != ".go" { 55 continue 56 } 57 lastFile = file 58 // Check if it is called in package initialization function, 59 // in which it here cannot retrieve main package path, 60 // it so just returns that can make next check. 61 if fn := runtime.FuncForPC(pc); fn != nil { 62 array := gstr.Split(fn.Name(), ".") 63 if array[0] != "main" { 64 continue 65 } 66 } 67 if gregex.IsMatchString(`package\s+main\s+`, GetContents(file)) { 68 mainPkgPath.Set(Dir(file)) 69 return Dir(file) 70 } 71 } else { 72 break 73 } 74 } 75 // If it still cannot find the path of the package main, 76 // it recursively searches the directory and its parents directory of the last go file. 77 // It's usually necessary for uint testing cases of business project. 78 if lastFile != "" { 79 for path = Dir(lastFile); len(path) > 1 && Exists(path) && path[len(path)-1] != os.PathSeparator; { 80 files, _ := ScanDir(path, "*.go") 81 for _, v := range files { 82 if gregex.IsMatchString(`package\s+main\s+`, GetContents(v)) { 83 mainPkgPath.Set(path) 84 return path 85 } 86 } 87 path = Dir(path) 88 } 89 } 90 return "" 91 }