spec-dirs.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. Copyright © 2021 The CDI Authors
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cdi
  14. import (
  15. "errors"
  16. "io/fs"
  17. "os"
  18. "path/filepath"
  19. )
  20. const (
  21. // DefaultStaticDir is the default directory for static CDI Specs.
  22. DefaultStaticDir = "/etc/cdi"
  23. // DefaultDynamicDir is the default directory for generated CDI Specs
  24. DefaultDynamicDir = "/var/run/cdi"
  25. )
  26. var (
  27. // DefaultSpecDirs is the default Spec directory configuration.
  28. // While altering this variable changes the package defaults,
  29. // the preferred way of overriding the default directories is
  30. // to use a WithSpecDirs options. Otherwise the change is only
  31. // effective if it takes place before creating the Registry or
  32. // other Cache instances.
  33. DefaultSpecDirs = []string{DefaultStaticDir, DefaultDynamicDir}
  34. // ErrStopScan can be returned from a ScanSpecFunc to stop the scan.
  35. ErrStopScan = errors.New("stop Spec scan")
  36. )
  37. // WithSpecDirs returns an option to override the CDI Spec directories.
  38. func WithSpecDirs(dirs ...string) Option {
  39. return func(c *Cache) error {
  40. specDirs := make([]string, len(dirs))
  41. for i, dir := range dirs {
  42. specDirs[i] = filepath.Clean(dir)
  43. }
  44. c.specDirs = specDirs
  45. return nil
  46. }
  47. }
  48. // scanSpecFunc is a function for processing CDI Spec files.
  49. type scanSpecFunc func(string, int, *Spec, error) error
  50. // ScanSpecDirs scans the given directories looking for CDI Spec files,
  51. // which are all files with a '.json' or '.yaml' suffix. For every Spec
  52. // file discovered, ScanSpecDirs loads a Spec from the file then calls
  53. // the scan function passing it the path to the file, the priority (the
  54. // index of the directory in the slice of directories given), the Spec
  55. // itself, and any error encountered while loading the Spec.
  56. //
  57. // Scanning stops once all files have been processed or when the scan
  58. // function returns an error. The result of ScanSpecDirs is the error
  59. // returned by the scan function, if any. The special error ErrStopScan
  60. // can be used to terminate the scan gracefully without ScanSpecDirs
  61. // returning an error. ScanSpecDirs silently skips any subdirectories.
  62. func scanSpecDirs(dirs []string, scanFn scanSpecFunc) error {
  63. var (
  64. spec *Spec
  65. err error
  66. )
  67. for priority, dir := range dirs {
  68. err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
  69. // for initial stat failure Walk calls us with nil info
  70. if info == nil {
  71. if errors.Is(err, fs.ErrNotExist) {
  72. return nil
  73. }
  74. return err
  75. }
  76. // first call from Walk is for dir itself, others we skip
  77. if info.IsDir() {
  78. if path == dir {
  79. return nil
  80. }
  81. return filepath.SkipDir
  82. }
  83. // ignore obviously non-Spec files
  84. if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" {
  85. return nil
  86. }
  87. if err != nil {
  88. return scanFn(path, priority, nil, err)
  89. }
  90. spec, err = ReadSpec(path, priority)
  91. return scanFn(path, priority, spec, err)
  92. })
  93. if err != nil && err != ErrStopScan {
  94. return err
  95. }
  96. }
  97. return nil
  98. }