dir.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * Rufs - Remote Union File System
  3. *
  4. * Copyright 2017 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. /*
  11. Package rumble contains Rumble functions which interface with Rufs.
  12. */
  13. package rumble
  14. import (
  15. "fmt"
  16. "os"
  17. "regexp"
  18. "devt.de/krotik/common/defs/rumble"
  19. "devt.de/krotik/common/stringutil"
  20. "devt.de/krotik/rufs/api"
  21. )
  22. // Function: dir
  23. // =============
  24. /*
  25. DirFunc queries a directory in a tree.
  26. */
  27. type DirFunc struct {
  28. }
  29. /*
  30. Name returns the name of the function.
  31. */
  32. func (f *DirFunc) Name() string {
  33. return "fs.dir"
  34. }
  35. /*
  36. Validate is called for parameter validation and to reset the function state.
  37. */
  38. func (f *DirFunc) Validate(argsNum int, rt rumble.Runtime) rumble.RuntimeError {
  39. var err rumble.RuntimeError
  40. if argsNum != 3 && argsNum != 4 {
  41. err = rt.NewRuntimeError(rumble.ErrInvalidConstruct,
  42. "Function dir requires 3 or 4 parameters: tree, a path, a glob expression and optionally a recursive flag")
  43. }
  44. return err
  45. }
  46. /*
  47. Execute executes the rumble function.
  48. */
  49. func (f *DirFunc) Execute(argsVal []interface{}, vars rumble.Variables,
  50. rt rumble.Runtime) (interface{}, rumble.RuntimeError) {
  51. var res interface{}
  52. var paths []string
  53. var fiList [][]os.FileInfo
  54. treeName := fmt.Sprint(argsVal[0])
  55. path := fmt.Sprint(argsVal[1])
  56. pattern := fmt.Sprint(argsVal[2])
  57. recursive := argsVal[3] == true
  58. conv := func(re *regexp.Regexp, fis []os.FileInfo) []interface{} {
  59. r := make([]interface{}, 0, len(fis))
  60. for _, fi := range fis {
  61. if !fi.IsDir() && !re.MatchString(fi.Name()) {
  62. continue
  63. }
  64. r = append(r, map[interface{}]interface{}{
  65. "name": fi.Name(),
  66. "mode": fmt.Sprint(fi.Mode()),
  67. "modtime": fmt.Sprint(fi.ModTime()),
  68. "isdir": fi.IsDir(),
  69. "size": fi.Size(),
  70. })
  71. }
  72. return r
  73. }
  74. tree, ok, err := api.GetTree(treeName)
  75. if !ok {
  76. if err == nil {
  77. err = fmt.Errorf("Unknown tree: %v", treeName)
  78. }
  79. }
  80. if err == nil {
  81. var globPattern string
  82. // Create regex for files
  83. if globPattern, err = stringutil.GlobToRegex(pattern); err == nil {
  84. var re *regexp.Regexp
  85. if re, err = regexp.Compile(globPattern); err == nil {
  86. // Query the file system
  87. paths, fiList, err = tree.Dir(path, "", recursive, false)
  88. pathData := make([]interface{}, 0, len(paths))
  89. fisData := make([]interface{}, 0, len(paths))
  90. // Convert the result into a Rumble data structure
  91. for i := range paths {
  92. fis := conv(re, fiList[i])
  93. // If we have a regex then only include directories which have files
  94. pathData = append(pathData, paths[i])
  95. fisData = append(fisData, fis)
  96. }
  97. res = []interface{}{pathData, fisData}
  98. }
  99. }
  100. }
  101. if err != nil {
  102. // Wrap error message in RuntimeError
  103. err = rt.NewRuntimeError(rumble.ErrInvalidState,
  104. fmt.Sprintf("Cannot list files: %v", err.Error()))
  105. }
  106. return res, err
  107. }