file.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package pathx
  2. import (
  3. "bufio"
  4. "crypto/md5"
  5. "encoding/hex"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "log"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. "github.com/logrusorgru/aurora"
  14. "github.com/zeromicro/go-zero/tools/goctl/internal/version"
  15. )
  16. // NL defines a new line.
  17. const (
  18. NL = "\n"
  19. goctlDir = ".goctl"
  20. gitDir = ".git"
  21. autoCompleteDir = ".auto_complete"
  22. cacheDir = "cache"
  23. )
  24. var goctlHome string
  25. // RegisterGoctlHome register goctl home path.
  26. func RegisterGoctlHome(home string) {
  27. goctlHome = home
  28. }
  29. // CreateIfNotExist creates a file if it is not exists.
  30. func CreateIfNotExist(file string) (*os.File, error) {
  31. _, err := os.Stat(file)
  32. if !os.IsNotExist(err) {
  33. return nil, fmt.Errorf("%s already exist", file)
  34. }
  35. return os.Create(file)
  36. }
  37. // RemoveIfExist deletes the specified file if it is exists.
  38. func RemoveIfExist(filename string) error {
  39. if !FileExists(filename) {
  40. return nil
  41. }
  42. return os.Remove(filename)
  43. }
  44. // RemoveOrQuit deletes the specified file if read a permit command from stdin.
  45. func RemoveOrQuit(filename string) error {
  46. if !FileExists(filename) {
  47. return nil
  48. }
  49. fmt.Printf("%s exists, overwrite it?\nEnter to overwrite or Ctrl-C to cancel...",
  50. aurora.BgRed(aurora.Bold(filename)))
  51. bufio.NewReader(os.Stdin).ReadBytes('\n')
  52. return os.Remove(filename)
  53. }
  54. // FileExists returns true if the specified file is exists.
  55. func FileExists(file string) bool {
  56. _, err := os.Stat(file)
  57. return err == nil
  58. }
  59. // FileNameWithoutExt returns a file name without suffix.
  60. func FileNameWithoutExt(file string) string {
  61. return strings.TrimSuffix(file, filepath.Ext(file))
  62. }
  63. // GetGoctlHome returns the path value of the goctl, the default path is ~/.goctl, if the path has
  64. // been set by calling the RegisterGoctlHome method, the user-defined path refers to.
  65. func GetGoctlHome() (home string, err error) {
  66. defer func() {
  67. if err != nil {
  68. return
  69. }
  70. info, err := os.Stat(home)
  71. if err == nil && !info.IsDir() {
  72. os.Rename(home, home+".old")
  73. MkdirIfNotExist(home)
  74. }
  75. }()
  76. if len(goctlHome) != 0 {
  77. home = goctlHome
  78. return
  79. }
  80. home, err = GetDefaultGoctlHome()
  81. return
  82. }
  83. // GetDefaultGoctlHome returns the path value of the goctl home where Join $HOME with .goctl.
  84. func GetDefaultGoctlHome() (string, error) {
  85. home, err := os.UserHomeDir()
  86. if err != nil {
  87. return "", err
  88. }
  89. return filepath.Join(home, goctlDir), nil
  90. }
  91. // GetGitHome returns the git home of goctl.
  92. func GetGitHome() (string, error) {
  93. goctlH, err := GetGoctlHome()
  94. if err != nil {
  95. return "", err
  96. }
  97. return filepath.Join(goctlH, gitDir), nil
  98. }
  99. // GetAutoCompleteHome returns the auto_complete home of goctl.
  100. func GetAutoCompleteHome() (string, error) {
  101. goctlH, err := GetGoctlHome()
  102. if err != nil {
  103. return "", err
  104. }
  105. return filepath.Join(goctlH, autoCompleteDir), nil
  106. }
  107. // GetCacheDir returns the cache dit of goctl.
  108. func GetCacheDir() (string, error) {
  109. goctlH, err := GetGoctlHome()
  110. if err != nil {
  111. return "", err
  112. }
  113. return filepath.Join(goctlH, cacheDir), nil
  114. }
  115. // GetTemplateDir returns the category path value in GoctlHome where could get it by GetGoctlHome.
  116. func GetTemplateDir(category string) (string, error) {
  117. home, err := GetGoctlHome()
  118. if err != nil {
  119. return "", err
  120. }
  121. if home == goctlHome {
  122. // backward compatible, it will be removed in the feature
  123. // backward compatible start.
  124. beforeTemplateDir := filepath.Join(home, version.GetGoctlVersion(), category)
  125. fs, _ := ioutil.ReadDir(beforeTemplateDir)
  126. var hasContent bool
  127. for _, e := range fs {
  128. if e.Size() > 0 {
  129. hasContent = true
  130. }
  131. }
  132. if hasContent {
  133. return beforeTemplateDir, nil
  134. }
  135. // backward compatible end.
  136. return filepath.Join(home, category), nil
  137. }
  138. return filepath.Join(home, version.GetGoctlVersion(), category), nil
  139. }
  140. // InitTemplates creates template files GoctlHome where could get it by GetGoctlHome.
  141. func InitTemplates(category string, templates map[string]string) error {
  142. dir, err := GetTemplateDir(category)
  143. if err != nil {
  144. return err
  145. }
  146. if err := MkdirIfNotExist(dir); err != nil {
  147. return err
  148. }
  149. for k, v := range templates {
  150. if err := createTemplate(filepath.Join(dir, k), v, false); err != nil {
  151. return err
  152. }
  153. }
  154. return nil
  155. }
  156. // CreateTemplate writes template into file even it is exists.
  157. func CreateTemplate(category, name, content string) error {
  158. dir, err := GetTemplateDir(category)
  159. if err != nil {
  160. return err
  161. }
  162. return createTemplate(filepath.Join(dir, name), content, true)
  163. }
  164. // Clean deletes all templates and removes the parent directory.
  165. func Clean(category string) error {
  166. dir, err := GetTemplateDir(category)
  167. if err != nil {
  168. return err
  169. }
  170. return os.RemoveAll(dir)
  171. }
  172. // LoadTemplate gets template content by the specified file.
  173. func LoadTemplate(category, file, builtin string) (string, error) {
  174. dir, err := GetTemplateDir(category)
  175. if err != nil {
  176. return "", err
  177. }
  178. file = filepath.Join(dir, file)
  179. if !FileExists(file) {
  180. return builtin, nil
  181. }
  182. content, err := os.ReadFile(file)
  183. if err != nil {
  184. return "", err
  185. }
  186. return string(content), nil
  187. }
  188. // SameFile compares the between path if the same path,
  189. // it maybe the same path in case case-ignore, such as:
  190. // /Users/go_zero and /Users/Go_zero, as far as we know,
  191. // this case maybe appear on macOS and Windows.
  192. func SameFile(path1, path2 string) (bool, error) {
  193. stat1, err := os.Stat(path1)
  194. if err != nil {
  195. return false, err
  196. }
  197. stat2, err := os.Stat(path2)
  198. if err != nil {
  199. return false, err
  200. }
  201. return os.SameFile(stat1, stat2), nil
  202. }
  203. func createTemplate(file, content string, force bool) error {
  204. if FileExists(file) && !force {
  205. return nil
  206. }
  207. f, err := os.Create(file)
  208. if err != nil {
  209. return err
  210. }
  211. defer f.Close()
  212. _, err = f.WriteString(content)
  213. return err
  214. }
  215. // MustTempDir creates a temporary directory.
  216. func MustTempDir() string {
  217. dir, err := ioutil.TempDir("", "")
  218. if err != nil {
  219. log.Fatalln(err)
  220. }
  221. return dir
  222. }
  223. func Copy(src, dest string) error {
  224. f, err := os.Open(src)
  225. if err != nil {
  226. return err
  227. }
  228. defer f.Close()
  229. dir := filepath.Dir(dest)
  230. err = MkdirIfNotExist(dir)
  231. if err != nil {
  232. return err
  233. }
  234. w, err := os.Create(dest)
  235. if err != nil {
  236. return err
  237. }
  238. w.Chmod(os.ModePerm)
  239. defer w.Close()
  240. _, err = io.Copy(w, f)
  241. return err
  242. }
  243. func Hash(file string) (string, error) {
  244. f, err := os.Open(file)
  245. if err != nil {
  246. return "", err
  247. }
  248. defer func() {
  249. _ = f.Close()
  250. }()
  251. hash := md5.New()
  252. _, err = io.Copy(hash, f)
  253. if err != nil {
  254. return "", err
  255. }
  256. return hex.EncodeToString(hash.Sum(nil)), nil
  257. }