You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-zero/tools/goctl/util/pathx/file.go

315 lines
6.6 KiB
Go

package pathx
import (
"bufio"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
"github.com/gookit/color"
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
)
// NL defines a new line.
const (
NL = "\n"
goctlDir = ".goctl"
gitDir = ".git"
autoCompleteDir = ".auto_complete"
cacheDir = "cache"
)
var goctlHome string
// RegisterGoctlHome register goctl home path.
func RegisterGoctlHome(home string) {
goctlHome = home
}
// CreateIfNotExist creates a file if it is not exists.
func CreateIfNotExist(file string) (*os.File, error) {
_, err := os.Stat(file)
if !os.IsNotExist(err) {
return nil, fmt.Errorf("%s already exist", file)
}
return os.Create(file)
}
// RemoveIfExist deletes the specified file if it is exists.
func RemoveIfExist(filename string) error {
if !FileExists(filename) {
return nil
}
return os.Remove(filename)
}
// RemoveOrQuit deletes the specified file if read a permit command from stdin.
func RemoveOrQuit(filename string) error {
if !FileExists(filename) {
return nil
}
fmt.Printf("%s exists, overwrite it?\nEnter to overwrite or Ctrl-C to cancel...",
color.New(color.BgRed, color.Bold).Render(filename))
bufio.NewReader(os.Stdin).ReadBytes('\n')
return os.Remove(filename)
}
// FileExists returns true if the specified file is exists.
func FileExists(file string) bool {
_, err := os.Stat(file)
return err == nil
}
// FileNameWithoutExt returns a file name without suffix.
func FileNameWithoutExt(file string) string {
return strings.TrimSuffix(file, filepath.Ext(file))
}
// GetGoctlHome returns the path value of the goctl, the default path is ~/.goctl, if the path has
// been set by calling the RegisterGoctlHome method, the user-defined path refers to.
func GetGoctlHome() (home string, err error) {
defer func() {
if err != nil {
return
}
info, err := os.Stat(home)
if err == nil && !info.IsDir() {
os.Rename(home, home+".old")
MkdirIfNotExist(home)
}
}()
if len(goctlHome) != 0 {
home = goctlHome
return
}
home, err = GetDefaultGoctlHome()
return
}
// GetDefaultGoctlHome returns the path value of the goctl home where Join $HOME with .goctl.
func GetDefaultGoctlHome() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, goctlDir), nil
}
// GetGitHome returns the git home of goctl.
func GetGitHome() (string, error) {
goctlH, err := GetGoctlHome()
if err != nil {
return "", err
}
return filepath.Join(goctlH, gitDir), nil
}
// GetAutoCompleteHome returns the auto_complete home of goctl.
func GetAutoCompleteHome() (string, error) {
goctlH, err := GetGoctlHome()
if err != nil {
return "", err
}
return filepath.Join(goctlH, autoCompleteDir), nil
}
// GetCacheDir returns the cache dit of goctl.
func GetCacheDir() (string, error) {
goctlH, err := GetGoctlHome()
if err != nil {
return "", err
}
return filepath.Join(goctlH, cacheDir), nil
}
// GetTemplateDir returns the category path value in GoctlHome where could get it by GetGoctlHome.
func GetTemplateDir(category string) (string, error) {
home, err := GetGoctlHome()
if err != nil {
return "", err
}
if home == goctlHome {
// backward compatible, it will be removed in the feature
// backward compatible start.
beforeTemplateDir := filepath.Join(home, version.GetGoctlVersion(), category)
entries, err := os.ReadDir(beforeTemplateDir)
if err != nil {
return "", err
}
infos := make([]fs.FileInfo, 0, len(entries))
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
return "", err
}
infos = append(infos, info)
}
var hasContent bool
for _, e := range infos {
if e.Size() > 0 {
hasContent = true
}
}
if hasContent {
return beforeTemplateDir, nil
}
// backward compatible end.
return filepath.Join(home, category), nil
}
return filepath.Join(home, version.GetGoctlVersion(), category), nil
}
// InitTemplates creates template files GoctlHome where could get it by GetGoctlHome.
func InitTemplates(category string, templates map[string]string) error {
dir, err := GetTemplateDir(category)
if err != nil {
return err
}
if err := MkdirIfNotExist(dir); err != nil {
return err
}
for k, v := range templates {
if err := createTemplate(filepath.Join(dir, k), v, false); err != nil {
return err
}
}
return nil
}
// CreateTemplate writes template into file even it is exists.
func CreateTemplate(category, name, content string) error {
dir, err := GetTemplateDir(category)
if err != nil {
return err
}
return createTemplate(filepath.Join(dir, name), content, true)
}
// Clean deletes all templates and removes the parent directory.
func Clean(category string) error {
dir, err := GetTemplateDir(category)
if err != nil {
return err
}
return os.RemoveAll(dir)
}
// LoadTemplate gets template content by the specified file.
func LoadTemplate(category, file, builtin string) (string, error) {
dir, err := GetTemplateDir(category)
if err != nil {
return "", err
}
file = filepath.Join(dir, file)
if !FileExists(file) {
return builtin, nil
}
content, err := os.ReadFile(file)
if err != nil {
return "", err
}
return string(content), nil
}
// SameFile compares the between path if the same path,
// it maybe the same path in case case-ignore, such as:
// /Users/go_zero and /Users/Go_zero, as far as we know,
// this case maybe appear on macOS and Windows.
func SameFile(path1, path2 string) (bool, error) {
stat1, err := os.Stat(path1)
if err != nil {
return false, err
}
stat2, err := os.Stat(path2)
if err != nil {
return false, err
}
return os.SameFile(stat1, stat2), nil
}
func createTemplate(file, content string, force bool) error {
if FileExists(file) && !force {
return nil
}
f, err := os.Create(file)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(content)
return err
}
// MustTempDir creates a temporary directory.
func MustTempDir() string {
dir, err := os.MkdirTemp("", "")
if err != nil {
log.Fatalln(err)
}
return dir
}
func Copy(src, dest string) error {
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
dir := filepath.Dir(dest)
err = MkdirIfNotExist(dir)
if err != nil {
return err
}
w, err := os.Create(dest)
if err != nil {
return err
}
w.Chmod(os.ModePerm)
defer w.Close()
_, err = io.Copy(w, f)
return err
}
func Hash(file string) (string, error) {
f, err := os.Open(file)
if err != nil {
return "", err
}
defer func() {
_ = f.Close()
}()
hash := md5.New()
_, err = io.Copy(hash, f)
if err != nil {
return "", err
}
return hex.EncodeToString(hash.Sum(nil)), nil
}