gfile_source.go 2.5 KB

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