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
 | 
						|
}
 |