File utilities and wrappers that may be useful for some projects.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
3.0KB

  1. // Configuration file helpers.
  2. package fileutils
  3. import (
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. )
  8. // DefaultConfig is the default package-level configuration which FindConfig
  9. // will attempt to locate. You should change this to whatever your default
  10. // configuration file is named by setting `fileutils.DefaultConfig = "value"`.
  11. var DefaultConfig = "config.yaml"
  12. // FindConfig locates a configuration file (default: "config.yaml") and returns
  13. // the absolute path of its location.
  14. //
  15. // This routine starts by examining the following locations, in order of
  16. // precedence:
  17. //
  18. // 1) The current directory.
  19. // 2) (Linux) $XDG_CONFIG_HOME is searched, followed by each directory listed in
  20. // $XDG_CONFIG_DIRS. If none of these values is set, the user's
  21. // ~/.config/`base` directory is examined.
  22. // 3) (Windows) The directory %APPDATA%/`base` is searched for the specific
  23. // configuration, if applicable.
  24. // 4) (Linux) Failing the contents of the user directories and the current
  25. // working directory, the last place this will look is in /etc/`base`
  26. //
  27. // (where the string `base`, above, is replaced with the value of FindConfig's
  28. // second argument.)
  29. //
  30. // If the file cannot be located, the empty string will be returned.
  31. //
  32. // For the Windows implementation, see util_windows.go.
  33. func FindConfig(name, base string) string {
  34. var path string
  35. var err error
  36. if name == "" {
  37. name = DefaultConfig
  38. }
  39. if name[0] == '/' || (len(name) >= 2 && name[0] == '.' && name[1] == '/') {
  40. // If the path contains symlinks, we'll get the "correct" path instead.
  41. path, err = filepath.Abs(name)
  42. if err != nil {
  43. path = name
  44. }
  45. if stat, err := os.Stat(path); !os.IsNotExist(err) {
  46. if stat != nil && !stat.IsDir() {
  47. return path
  48. }
  49. }
  50. }
  51. etc := filepath.Join("/etc", base)
  52. xdgHome := os.ExpandEnv(filepath.Join("${HOME}/.config", base))
  53. // Check current directory.
  54. cwd, err := os.Getwd()
  55. if err == nil {
  56. if stat, err := os.Stat(filepath.Join(cwd, name)); !os.IsNotExist(err) {
  57. if stat != nil && !stat.IsDir() {
  58. return filepath.Join(cwd, name)
  59. }
  60. }
  61. }
  62. if env, exists := os.LookupEnv("XDG_CONFIG_HOME"); exists {
  63. path = AbsPath(os.ExpandEnv(env))
  64. if stat, err := os.Stat(filepath.Join(path, name)); !os.IsNotExist(err) {
  65. if stat != nil && !stat.IsDir() {
  66. return filepath.Join(env, name)
  67. }
  68. }
  69. }
  70. if env, exists := os.LookupEnv("XDG_CONFIG_DIRS"); exists {
  71. env = os.ExpandEnv(env)
  72. for _, path := range strings.Split(env, ":") {
  73. path = AbsPath(path)
  74. if stat, err := os.Stat(filepath.Join(path, name)); !os.IsNotExist(err) {
  75. if stat != nil && !stat.IsDir() {
  76. return filepath.Join(path, name)
  77. }
  78. }
  79. }
  80. }
  81. if stat, err := os.Stat(filepath.Join(xdgHome, name)); !os.IsNotExist(err) {
  82. if stat != nil && !stat.IsDir() {
  83. return filepath.Join(xdgHome, name)
  84. }
  85. }
  86. if stat, err := os.Stat(filepath.Join(etc, name)); !os.IsNotExist(err) {
  87. if stat != nil && !stat.IsDir() {
  88. return filepath.Join(etc, name)
  89. }
  90. }
  91. // If we cannot find the file, we'll return the empty string.
  92. return ""
  93. }