mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			262 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
 | |
| // license. Its contents can be found at:
 | |
| // http://creativecommons.org/publicdomain/zero/1.0/
 | |
| 
 | |
| package bindata
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"regexp"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 	"unicode"
 | |
| )
 | |
| 
 | |
| // Translate reads assets from an input directory, converts them
 | |
| // to Go code and writes new files to the output specified
 | |
| // in the given configuration.
 | |
| func Translate(c *Config) error {
 | |
| 	var toc []Asset
 | |
| 
 | |
| 	// Ensure our configuration has sane values.
 | |
| 	err := c.validate()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	var knownFuncs = make(map[string]int)
 | |
| 	var visitedPaths = make(map[string]bool)
 | |
| 	// Locate all the assets.
 | |
| 	for _, input := range c.Input {
 | |
| 		err = findFiles(input.Path, c.Prefix, input.Recursive, &toc, c.Ignore, knownFuncs, visitedPaths)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Create output file.
 | |
| 	fd, err := os.Create(c.Output)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	defer fd.Close()
 | |
| 
 | |
| 	// Create a buffered writer for better performance.
 | |
| 	bfd := bufio.NewWriter(fd)
 | |
| 	defer bfd.Flush()
 | |
| 
 | |
| 	// Write the header. This makes e.g. Github ignore diffs in generated files.
 | |
| 	if _, err = fmt.Fprint(bfd, "// Code generated by go-bindata.\n"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if _, err = fmt.Fprint(bfd, "// sources:\n"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	wd, err := os.Getwd()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	for _, asset := range toc {
 | |
| 		relative, _ := filepath.Rel(wd, asset.Path)
 | |
| 		if _, err = fmt.Fprintf(bfd, "// %s\n", filepath.ToSlash(relative)); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	if _, err = fmt.Fprint(bfd, "// DO NOT EDIT!\n\n"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Write build tags, if applicable.
 | |
| 	if len(c.Tags) > 0 {
 | |
| 		if _, err = fmt.Fprintf(bfd, "// +build %s\n\n", c.Tags); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Write package declaration.
 | |
| 	_, err = fmt.Fprintf(bfd, "package %s\n\n", c.Package)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Write assets.
 | |
| 	if c.Debug || c.Dev {
 | |
| 		err = writeDebug(bfd, c, toc)
 | |
| 	} else {
 | |
| 		err = writeRelease(bfd, c, toc)
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Write table of contents
 | |
| 	if err := writeTOC(bfd, toc); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	// Write hierarchical tree of assets
 | |
| 	if err := writeTOCTree(bfd, toc); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Write restore procedure
 | |
| 	return writeRestore(bfd)
 | |
| }
 | |
| 
 | |
| // Implement sort.Interface for []os.FileInfo based on Name()
 | |
| type ByName []os.FileInfo
 | |
| 
 | |
| func (v ByName) Len() int           { return len(v) }
 | |
| func (v ByName) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
 | |
| func (v ByName) Less(i, j int) bool { return v[i].Name() < v[j].Name() }
 | |
| 
 | |
| // findFiles recursively finds all the file paths in the given directory tree.
 | |
| // They are added to the given map as keys. Values will be safe function names
 | |
| // for each file, which will be used when generating the output code.
 | |
| func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regexp.Regexp, knownFuncs map[string]int, visitedPaths map[string]bool) error {
 | |
| 	dirpath := dir
 | |
| 	if len(prefix) > 0 {
 | |
| 		dirpath, _ = filepath.Abs(dirpath)
 | |
| 		prefix, _ = filepath.Abs(prefix)
 | |
| 		prefix = filepath.ToSlash(prefix)
 | |
| 	}
 | |
| 
 | |
| 	fi, err := os.Stat(dirpath)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	var list []os.FileInfo
 | |
| 
 | |
| 	if !fi.IsDir() {
 | |
| 		dirpath = filepath.Dir(dirpath)
 | |
| 		list = []os.FileInfo{fi}
 | |
| 	} else {
 | |
| 		visitedPaths[dirpath] = true
 | |
| 		fd, err := os.Open(dirpath)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		defer fd.Close()
 | |
| 
 | |
| 		list, err = fd.Readdir(0)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		// Sort to make output stable between invocations
 | |
| 		sort.Sort(ByName(list))
 | |
| 	}
 | |
| 
 | |
| 	for _, file := range list {
 | |
| 		var asset Asset
 | |
| 		asset.Path = filepath.Join(dirpath, file.Name())
 | |
| 		asset.Name = filepath.ToSlash(asset.Path)
 | |
| 
 | |
| 		ignoring := false
 | |
| 		for _, re := range ignore {
 | |
| 			if re.MatchString(asset.Path) {
 | |
| 				ignoring = true
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 		if ignoring {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if file.IsDir() {
 | |
| 			if recursive {
 | |
| 				recursivePath := filepath.Join(dir, file.Name())
 | |
| 				visitedPaths[asset.Path] = true
 | |
| 				findFiles(recursivePath, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
 | |
| 			}
 | |
| 			continue
 | |
| 		} else if file.Mode()&os.ModeSymlink == os.ModeSymlink {
 | |
| 			var linkPath string
 | |
| 			if linkPath, err = os.Readlink(asset.Path); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			if !filepath.IsAbs(linkPath) {
 | |
| 				if linkPath, err = filepath.Abs(dirpath + "/" + linkPath); err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 			}
 | |
| 			if _, ok := visitedPaths[linkPath]; !ok {
 | |
| 				visitedPaths[linkPath] = true
 | |
| 				findFiles(asset.Path, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
 | |
| 			}
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if strings.HasPrefix(asset.Name, prefix) {
 | |
| 			asset.Name = asset.Name[len(prefix):]
 | |
| 		} else {
 | |
| 			asset.Name = filepath.Join(dir, file.Name())
 | |
| 		}
 | |
| 
 | |
| 		// If we have a leading slash, get rid of it.
 | |
| 		if len(asset.Name) > 0 && asset.Name[0] == '/' {
 | |
| 			asset.Name = asset.Name[1:]
 | |
| 		}
 | |
| 
 | |
| 		// This shouldn't happen.
 | |
| 		if len(asset.Name) == 0 {
 | |
| 			return fmt.Errorf("Invalid file: %v", asset.Path)
 | |
| 		}
 | |
| 
 | |
| 		asset.Func = safeFunctionName(asset.Name, knownFuncs)
 | |
| 		asset.Path, _ = filepath.Abs(asset.Path)
 | |
| 		*toc = append(*toc, asset)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
 | |
| 
 | |
| // safeFunctionName converts the given name into a name
 | |
| // which qualifies as a valid function identifier. It
 | |
| // also compares against a known list of functions to
 | |
| // prevent conflict based on name translation.
 | |
| func safeFunctionName(name string, knownFuncs map[string]int) string {
 | |
| 	var inBytes, outBytes []byte
 | |
| 	var toUpper bool
 | |
| 
 | |
| 	name = strings.ToLower(name)
 | |
| 	inBytes = []byte(name)
 | |
| 
 | |
| 	for i := 0; i < len(inBytes); i++ {
 | |
| 		if regFuncName.Match([]byte{inBytes[i]}) {
 | |
| 			toUpper = true
 | |
| 		} else if toUpper {
 | |
| 			outBytes = append(outBytes, []byte(strings.ToUpper(string(inBytes[i])))...)
 | |
| 			toUpper = false
 | |
| 		} else {
 | |
| 			outBytes = append(outBytes, inBytes[i])
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	name = string(outBytes)
 | |
| 
 | |
| 	// Identifier can't start with a digit.
 | |
| 	if unicode.IsDigit(rune(name[0])) {
 | |
| 		name = "_" + name
 | |
| 	}
 | |
| 
 | |
| 	if num, ok := knownFuncs[name]; ok {
 | |
| 		knownFuncs[name] = num + 1
 | |
| 		name = fmt.Sprintf("%s%d", name, num)
 | |
| 	} else {
 | |
| 		knownFuncs[name] = 2
 | |
| 	}
 | |
| 
 | |
| 	return name
 | |
| }
 |