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