2019-02-02 16:18:25 +08:00
|
|
|
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2017-12-29 16:03:30 +08:00
|
|
|
//
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2017-12-29 16:03:30 +08:00
|
|
|
|
2019-01-15 23:27:47 +08:00
|
|
|
// Package gfile provides easy-to-use operations for file system.
|
2017-11-23 10:21:28 +08:00
|
|
|
package gfile
|
|
|
|
|
|
|
|
import (
|
2019-04-22 22:33:11 +08:00
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"github.com/gogf/gf/g/container/gtype"
|
|
|
|
"github.com/gogf/gf/g/text/gregex"
|
2019-05-16 23:41:09 +08:00
|
|
|
"github.com/gogf/gf/g/text/gstr"
|
2019-04-22 22:33:11 +08:00
|
|
|
"github.com/gogf/gf/g/util/gconv"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"os/user"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2017-11-23 10:21:28 +08:00
|
|
|
)
|
|
|
|
|
2018-04-19 14:58:25 +08:00
|
|
|
const (
|
2019-06-19 09:06:52 +08:00
|
|
|
// Separator for file system.
|
|
|
|
Separator = string(filepath.Separator)
|
|
|
|
// Default perm for file opening.
|
|
|
|
gDEFAULT_PERM = 0666
|
2018-04-19 14:58:25 +08:00
|
|
|
)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
2018-08-21 21:18:56 +08:00
|
|
|
var (
|
2019-06-19 09:06:52 +08:00
|
|
|
// The absolute file path for main package.
|
|
|
|
// It can be only checked and set once.
|
|
|
|
mainPkgPath = gtype.NewString()
|
2018-08-21 21:18:56 +08:00
|
|
|
)
|
2018-05-03 16:12:01 +08:00
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Mkdir creates directories recursively with given <path>.
|
|
|
|
// The parameter <path> is suggested to be absolute path.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Mkdir(path string) error {
|
2019-06-19 09:06:52 +08:00
|
|
|
err := os.MkdirAll(path, os.ModePerm)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Create creates file with given <path> recursively.
|
|
|
|
// The parameter <path> is suggested to be absolute path.
|
2019-02-15 21:30:35 +08:00
|
|
|
func Create(path string) (*os.File, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
dir := Dir(path)
|
|
|
|
if !Exists(dir) {
|
|
|
|
Mkdir(dir)
|
|
|
|
}
|
|
|
|
return os.Create(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Open opens file/directory readonly.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Open(path string) (*os.File, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.Open(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// OpenFile opens file/directory with given <flag> and <perm>.
|
2019-02-15 21:30:35 +08:00
|
|
|
func OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.OpenFile(path, flag, perm)
|
2019-02-15 21:30:35 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// OpenWithFlag opens file/directory with default perm and given <flag>.
|
2017-11-23 10:21:28 +08:00
|
|
|
func OpenWithFlag(path string, flag int) (*os.File, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
f, err := os.OpenFile(path, flag, gDEFAULT_PERM)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return f, nil
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// OpenWithFlagPerm opens file/directory with given <flag> and <perm>.
|
2018-10-22 18:58:11 +08:00
|
|
|
func OpenWithFlagPerm(path string, flag int, perm int) (*os.File, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
f, err := os.OpenFile(path, flag, os.FileMode(perm))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return f, nil
|
2018-10-22 18:58:11 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Exists checks whether given <path> exist.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Exists(path string) bool {
|
2019-06-19 09:06:52 +08:00
|
|
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// IsDir checks whether given <path> a directory.
|
2017-11-23 10:21:28 +08:00
|
|
|
func IsDir(path string) bool {
|
2019-06-19 09:06:52 +08:00
|
|
|
s, err := os.Stat(path)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return s.IsDir()
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Pwd returns absolute path of current working directory.
|
2018-08-14 19:53:31 +08:00
|
|
|
func Pwd() string {
|
2019-06-19 09:06:52 +08:00
|
|
|
path, _ := os.Getwd()
|
|
|
|
return path
|
2018-08-14 19:53:31 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// IsFile checks whether given <path> a file, which means it's not a directory.
|
2017-11-23 10:21:28 +08:00
|
|
|
func IsFile(path string) bool {
|
2019-06-19 09:06:52 +08:00
|
|
|
s, err := os.Stat(path)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return !s.IsDir()
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Alias of Stat.
|
2019-03-12 00:24:31 +08:00
|
|
|
// See Stat.
|
|
|
|
func Info(path string) (os.FileInfo, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
return Stat(path)
|
2019-03-12 00:24:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stat returns a FileInfo describing the named file.
|
2019-02-15 21:30:35 +08:00
|
|
|
// If there is an error, it will be of type *PathError.
|
2019-03-12 00:24:31 +08:00
|
|
|
func Stat(path string) (os.FileInfo, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.Stat(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Move renames (moves) <src> to <dst> path.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Move(src string, dst string) error {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.Rename(src, dst)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Alias of Move.
|
|
|
|
// See Move.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Rename(src string, dst string) error {
|
2019-06-19 09:06:52 +08:00
|
|
|
return Move(src, dst)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Copy file from <src> to <dst>.
|
2019-02-15 21:30:35 +08:00
|
|
|
//
|
2019-05-23 21:58:04 +08:00
|
|
|
// @TODO directory copy support.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Copy(src string, dst string) error {
|
2019-06-19 09:06:52 +08:00
|
|
|
srcFile, err := Open(src)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer srcFile.Close()
|
|
|
|
dstFile, err := Create(dst)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer dstFile.Close()
|
|
|
|
_, err = io.Copy(dstFile, srcFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = dstFile.Sync()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// DirNames returns sub-file names of given directory <path>.
|
2018-09-18 18:57:34 +08:00
|
|
|
func DirNames(path string) ([]string, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
list, err := f.Readdirnames(-1)
|
|
|
|
f.Close()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return list, nil
|
2018-09-18 18:57:34 +08:00
|
|
|
}
|
|
|
|
|
2019-02-15 21:30:35 +08:00
|
|
|
// Glob returns the names of all files matching pattern or nil
|
|
|
|
// if there is no matching file. The syntax of patterns is the same
|
|
|
|
// as in Match. The pattern may describe hierarchical names such as
|
|
|
|
// /usr/*/bin/ed (assuming the Separator is '/').
|
|
|
|
//
|
|
|
|
// Glob ignores file system errors such as I/O errors reading directories.
|
|
|
|
// The only possible returned error is ErrBadPattern, when pattern
|
|
|
|
// is malformed.
|
2019-06-19 09:06:52 +08:00
|
|
|
func Glob(pattern string, onlyNames ...bool) ([]string, error) {
|
|
|
|
if list, err := filepath.Glob(pattern); err == nil {
|
|
|
|
if len(onlyNames) > 0 && onlyNames[0] && len(list) > 0 {
|
|
|
|
array := make([]string, len(list))
|
|
|
|
for k, v := range list {
|
|
|
|
array[k] = Basename(v)
|
|
|
|
}
|
|
|
|
return array, nil
|
|
|
|
}
|
|
|
|
return list, nil
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-06-19 15:17:58 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Remove deletes all file/directory with <path> parameter.
|
|
|
|
// If parameter <path> is directory, it deletes it recursively.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Remove(path string) error {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.RemoveAll(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// IsReadable checks whether given <path> is readable.
|
2017-11-23 10:21:28 +08:00
|
|
|
func IsReadable(path string) bool {
|
2019-06-19 09:06:52 +08:00
|
|
|
result := true
|
|
|
|
file, err := os.OpenFile(path, os.O_RDONLY, gDEFAULT_PERM)
|
|
|
|
if err != nil {
|
|
|
|
result = false
|
|
|
|
}
|
|
|
|
file.Close()
|
|
|
|
return result
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// IsWritable checks whether given <path> is writable.
|
2019-02-15 21:30:35 +08:00
|
|
|
//
|
2019-05-23 21:58:04 +08:00
|
|
|
// @TODO improve performance; use golang.org/x/sys to cross-plat-form
|
2017-11-23 10:21:28 +08:00
|
|
|
func IsWritable(path string) bool {
|
2019-06-19 09:06:52 +08:00
|
|
|
result := true
|
|
|
|
if IsDir(path) {
|
|
|
|
// If it's a directory, create a temporary file to test whether it's writable.
|
|
|
|
tmpFile := strings.TrimRight(path, Separator) + Separator + gconv.String(time.Now().UnixNano())
|
|
|
|
if f, err := Create(tmpFile); err != nil || !Exists(tmpFile) {
|
|
|
|
result = false
|
|
|
|
} else {
|
|
|
|
f.Close()
|
|
|
|
Remove(tmpFile)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// 如果是文件,那么判断文件是否可打开
|
|
|
|
file, err := os.OpenFile(path, os.O_WRONLY, gDEFAULT_PERM)
|
|
|
|
if err != nil {
|
|
|
|
result = false
|
|
|
|
}
|
|
|
|
file.Close()
|
|
|
|
}
|
|
|
|
return result
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-02-15 21:30:35 +08:00
|
|
|
// See os.Chmod.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Chmod(path string, mode os.FileMode) error {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.Chmod(path, mode)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// ScanDir returns all sub-files with absolute paths of given <path>,
|
|
|
|
// It scans directory recursively if given parameter <recursive> is true.
|
2019-06-19 09:06:52 +08:00
|
|
|
func ScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
|
|
|
|
list, err := doScanDir(path, pattern, recursive...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(list) > 0 {
|
|
|
|
sort.Strings(list)
|
|
|
|
}
|
|
|
|
return list, nil
|
2018-09-13 18:40:04 +08:00
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// doScanDir is an internal method which scans directory
|
|
|
|
// and returns the absolute path list of files that are not sorted.
|
|
|
|
//
|
|
|
|
// The pattern parameter <pattern> supports multiple file name patterns,
|
|
|
|
// using the ',' symbol to separate multiple patterns.
|
|
|
|
//
|
|
|
|
// It scans directory recursively if given parameter <recursive> is true.
|
2019-06-19 09:06:52 +08:00
|
|
|
func doScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
|
|
|
|
list := ([]string)(nil)
|
|
|
|
file, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
names, err := file.Readdirnames(-1)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, name := range names {
|
|
|
|
path := fmt.Sprintf("%s%s%s", path, Separator, name)
|
|
|
|
if IsDir(path) && len(recursive) > 0 && recursive[0] {
|
|
|
|
array, _ := doScanDir(path, pattern, true)
|
|
|
|
if len(array) > 0 {
|
|
|
|
list = append(list, array...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If it meets pattern, then add it to the result list.
|
|
|
|
for _, p := range strings.Split(pattern, ",") {
|
|
|
|
if match, err := filepath.Match(strings.TrimSpace(p), name); err == nil && match {
|
|
|
|
list = append(list, path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return list, nil
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// RealPath converts the given <path> to its absolute path
|
|
|
|
// and checks if the file path exists.
|
|
|
|
// If the file does not exist, return an empty string.
|
2017-11-23 10:21:28 +08:00
|
|
|
func RealPath(path string) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
p, err := filepath.Abs(path)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if !Exists(p) {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return p
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// SelfPath returns absolute file path of current running process(binary).
|
2017-11-23 10:21:28 +08:00
|
|
|
func SelfPath() string {
|
2019-06-19 09:06:52 +08:00
|
|
|
p, _ := filepath.Abs(os.Args[0])
|
|
|
|
return p
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// SelfDir returns absolute directory path of current running process(binary).
|
2017-11-23 10:21:28 +08:00
|
|
|
func SelfDir() string {
|
2019-06-19 09:06:52 +08:00
|
|
|
return filepath.Dir(SelfPath())
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Basename returns the last element of path.
|
|
|
|
// Trailing path separators are removed before extracting the last element.
|
|
|
|
// If the path is empty, Base returns ".".
|
|
|
|
// If the path consists entirely of separators, Base returns a single separator.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Basename(path string) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
return filepath.Base(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Dir returns all but the last element of path, typically the path's directory.
|
|
|
|
// After dropping the final element, Dir calls Clean on the path and trailing
|
|
|
|
// slashes are removed.
|
|
|
|
// If the path is empty, Dir returns ".".
|
|
|
|
// If the path consists entirely of separators, Dir returns a single separator.
|
|
|
|
// The returned path does not end in a separator unless it is the root directory.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Dir(path string) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
return filepath.Dir(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Ext returns the file name extension used by path.
|
|
|
|
// The extension is the suffix beginning at the final dot
|
|
|
|
// in the final element of path; it is empty if there is
|
|
|
|
// no dot.
|
2019-02-15 21:30:35 +08:00
|
|
|
//
|
2019-05-23 21:58:04 +08:00
|
|
|
// Note: the result contains symbol '.'.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Ext(path string) string {
|
2019-06-19 09:06:52 +08:00
|
|
|
return filepath.Ext(path)
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// Home returns absolute path of current user's home directory.
|
2017-11-23 10:21:28 +08:00
|
|
|
func Home() (string, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
u, err := user.Current()
|
|
|
|
if nil == err {
|
|
|
|
return u.HomeDir, nil
|
|
|
|
}
|
|
|
|
if "windows" == runtime.GOOS {
|
|
|
|
return homeWindows()
|
|
|
|
}
|
|
|
|
return homeUnix()
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func homeUnix() (string, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if home := os.Getenv("HOME"); home != "" {
|
|
|
|
return home, nil
|
|
|
|
}
|
|
|
|
var stdout bytes.Buffer
|
|
|
|
cmd := exec.Command("sh", "-c", "eval echo ~$USER")
|
|
|
|
cmd.Stdout = &stdout
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
result := strings.TrimSpace(stdout.String())
|
|
|
|
if result == "" {
|
|
|
|
return "", errors.New("blank output when reading home directory")
|
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
return result, nil
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func homeWindows() (string, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
drive := os.Getenv("HOMEDRIVE")
|
|
|
|
path := os.Getenv("HOMEPATH")
|
|
|
|
home := drive + path
|
|
|
|
if drive == "" || path == "" {
|
|
|
|
home = os.Getenv("USERPROFILE")
|
|
|
|
}
|
|
|
|
if home == "" {
|
|
|
|
return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
|
|
|
|
}
|
2017-11-23 10:21:28 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
return home, nil
|
2017-11-23 10:21:28 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:58:04 +08:00
|
|
|
// MainPkgPath returns absolute file path of package main,
|
|
|
|
// which contains the entrance function main.
|
|
|
|
//
|
|
|
|
// It's only available in develop environment.
|
2019-02-15 21:30:35 +08:00
|
|
|
//
|
2019-05-23 21:58:04 +08:00
|
|
|
// Note1: Only valid for source development environments,
|
|
|
|
// IE only valid for systems that generate this executable.
|
|
|
|
// Note2: When the method is called for the first time, if it is in an asynchronous goroutine,
|
|
|
|
// the method may not get the main package path.
|
2018-05-03 16:12:01 +08:00
|
|
|
func MainPkgPath() string {
|
2019-06-19 09:06:52 +08:00
|
|
|
path := mainPkgPath.Val()
|
|
|
|
if path != "" {
|
|
|
|
if path == "-" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
for i := 1; i < 10000; i++ {
|
|
|
|
if _, file, _, ok := runtime.Caller(i); ok {
|
|
|
|
// <file> is separated by '/'
|
|
|
|
if gstr.Contains(file, "/gf/g/") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if Ext(file) != ".go" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// separator of <file> '/' will be converted to Separator.
|
|
|
|
for path = Dir(file); len(path) > 1 && Exists(path) && path[len(path)-1] != os.PathSeparator; {
|
|
|
|
files, _ := ScanDir(path, "*.go")
|
|
|
|
for _, v := range files {
|
|
|
|
if gregex.IsMatchString(`package\s+main`, GetContents(v)) {
|
|
|
|
mainPkgPath.Set(path)
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path = Dir(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If it fails finding the path, then mark it as "-",
|
|
|
|
// which means it will never do this search again.
|
2019-04-25 22:14:20 +08:00
|
|
|
mainPkgPath.Set("-")
|
2019-06-19 09:06:52 +08:00
|
|
|
return ""
|
2018-05-29 13:40:36 +08:00
|
|
|
}
|
|
|
|
|
2019-02-15 21:30:35 +08:00
|
|
|
// See os.TempDir().
|
2018-05-06 22:35:08 +08:00
|
|
|
func TempDir() string {
|
2019-06-19 09:06:52 +08:00
|
|
|
return os.TempDir()
|
2019-01-30 21:27:03 +08:00
|
|
|
}
|