glob.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // Copyright 2019 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package main
  15. import (
  16. "errors"
  17. "path/filepath"
  18. "strings"
  19. )
  20. // Match returns true if name matches pattern using the same rules as filepath.Match, but supporting
  21. // recursive globs (**).
  22. func Match(pattern, name string) (bool, error) {
  23. if filepath.Base(pattern) == "**" {
  24. return false, errors.New("pattern has '**' as last path element")
  25. }
  26. patternDir := pattern[len(pattern)-1] == '/'
  27. nameDir := name[len(name)-1] == '/'
  28. if patternDir != nameDir {
  29. return false, nil
  30. }
  31. if nameDir {
  32. name = name[:len(name)-1]
  33. pattern = pattern[:len(pattern)-1]
  34. }
  35. for {
  36. var patternFile, nameFile string
  37. pattern, patternFile = filepath.Dir(pattern), filepath.Base(pattern)
  38. if patternFile == "**" {
  39. if strings.Contains(pattern, "**") {
  40. return false, errors.New("pattern contains multiple '**'")
  41. }
  42. // Test if the any prefix of name matches the part of the pattern before **
  43. for {
  44. if name == "." || name == "/" {
  45. return name == pattern, nil
  46. }
  47. if match, err := filepath.Match(pattern, name); err != nil {
  48. return false, err
  49. } else if match {
  50. return true, nil
  51. }
  52. name = filepath.Dir(name)
  53. }
  54. } else if strings.Contains(patternFile, "**") {
  55. return false, errors.New("pattern contains other characters between '**' and path separator")
  56. }
  57. name, nameFile = filepath.Dir(name), filepath.Base(name)
  58. if nameFile == "." && patternFile == "." {
  59. return true, nil
  60. } else if nameFile == "/" && patternFile == "/" {
  61. return true, nil
  62. } else if nameFile == "." || patternFile == "." || nameFile == "/" || patternFile == "/" {
  63. return false, nil
  64. }
  65. match, err := filepath.Match(patternFile, nameFile)
  66. if err != nil || !match {
  67. return match, err
  68. }
  69. }
  70. }