123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- /*
- 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
- }
|