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  }