115 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    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
 | |
| }
 | 
