github.com/oNaiPs/go-generate-fast@v0.3.0/src/plugins/go-bindata/main.go (about)

     1  // from https://github.com/go-bindata/go-bindata/blob/master/go-bindata/main.go
     2  package plugin_go_bindata
     3  
     4  import (
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  	"sort"
    11  	"strings"
    12  	"unicode"
    13  
    14  	"github.com/go-bindata/go-bindata"
    15  )
    16  
    17  // parseArgs create s a new, filled configuration instance
    18  // by reading and parsing command line options.
    19  //
    20  // This function exits the program with an error, if
    21  // any of the command line options are incorrect.
    22  func parseArgs(args []string) *bindata.Config {
    23  	flag := flag.NewFlagSet("Gobindata", flag.ContinueOnError)
    24  
    25  	var version bool
    26  
    27  	c := bindata.NewConfig()
    28  
    29  	flag.Usage = func() {
    30  		fmt.Printf("Usage: %s [options] <input directories>\n\n", os.Args[0])
    31  		flag.PrintDefaults()
    32  	}
    33  
    34  	flag.BoolVar(&c.Debug, "debug", c.Debug, "Do not embed the assets, but provide the embedding API. Contents will still be loaded from disk.")
    35  	flag.BoolVar(&c.Dev, "dev", c.Dev, "Similar to debug, but does not emit absolute paths. Expects a rootDir variable to already exist in the generated code's package.")
    36  	flag.StringVar(&c.Tags, "tags", c.Tags, "Optional set of build tags to include.")
    37  	flag.StringVar(&c.Prefix, "prefix", c.Prefix, "Optional path prefix to strip off asset names.")
    38  	flag.StringVar(&c.Package, "pkg", c.Package, "Package name to use in the generated code.")
    39  	flag.BoolVar(&c.NoMemCopy, "nomemcopy", c.NoMemCopy, "Use a .rodata hack to get rid of unnecessary memcopies. Refer to the documentation to see what implications this carries.")
    40  	flag.BoolVar(&c.NoCompress, "nocompress", c.NoCompress, "Assets will *not* be GZIP compressed when this flag is specified.")
    41  	flag.BoolVar(&c.NoMetadata, "nometadata", c.NoMetadata, "Assets will not preserve size, mode, and modtime info.")
    42  	flag.BoolVar(&c.HttpFileSystem, "fs", c.HttpFileSystem, "Whether generate instance http.FileSystem interface code.")
    43  	flag.UintVar(&c.Mode, "mode", c.Mode, "Optional file mode override for all files.")
    44  	flag.Int64Var(&c.ModTime, "modtime", c.ModTime, "Optional modification unix timestamp override for all files.")
    45  	flag.StringVar(&c.Output, "o", c.Output, "Optional name of the output file to be generated.")
    46  	flag.BoolVar(&version, "version", false, "Displays version information.")
    47  
    48  	ignore := make([]string, 0)
    49  	flag.Var((*AppendSliceValue)(&ignore), "ignore", "Regex pattern to ignore")
    50  
    51  	err := flag.Parse(args)
    52  	if err != nil {
    53  		return nil
    54  	}
    55  
    56  	patterns := make([]*regexp.Regexp, 0)
    57  	for _, pattern := range ignore {
    58  		patterns = append(patterns, regexp.MustCompile(pattern))
    59  	}
    60  	c.Ignore = patterns
    61  
    62  	if version {
    63  		return nil
    64  	}
    65  
    66  	// Make sure we have input paths.
    67  	if flag.NArg() == 0 {
    68  		return nil
    69  	}
    70  
    71  	// Create input configurations.
    72  	c.Input = make([]bindata.InputConfig, flag.NArg())
    73  	for i := range c.Input {
    74  		c.Input[i] = parseInput(flag.Arg(i))
    75  	}
    76  
    77  	return c
    78  }
    79  
    80  // parseRecursive determines whether the given path has a recursive indicator and
    81  // returns a new path with the recursive indicator chopped off if it does.
    82  //
    83  //	ex:
    84  //	    /path/to/foo/...    -> (/path/to/foo, true)
    85  //	    /path/to/bar        -> (/path/to/bar, false)
    86  func parseInput(path string) bindata.InputConfig {
    87  	if strings.HasSuffix(path, "/...") {
    88  		return bindata.InputConfig{
    89  			Path:      filepath.Clean(path[:len(path)-4]),
    90  			Recursive: true,
    91  		}
    92  	} else {
    93  		return bindata.InputConfig{
    94  			Path:      filepath.Clean(path),
    95  			Recursive: false,
    96  		}
    97  	}
    98  }
    99  
   100  // ByName implements sort.Interface for []os.FileInfo based on Name()
   101  type ByName []os.FileInfo
   102  
   103  func (v ByName) Len() int           { return len(v) }
   104  func (v ByName) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
   105  func (v ByName) Less(i, j int) bool { return v[i].Name() < v[j].Name() }
   106  
   107  // findFiles recursively finds all the file paths in the given directory tree.
   108  // They are added to the given map as keys. Values will be safe function names
   109  // for each file, which will be used when generating the output code.
   110  func findFiles(dir, prefix string, recursive bool, toc *[]bindata.Asset, ignore []*regexp.Regexp, knownFuncs map[string]int, visitedPaths map[string]bool) error {
   111  	dirpath := dir
   112  	if len(prefix) > 0 {
   113  		dirpath, _ = filepath.Abs(dirpath)
   114  		prefix, _ = filepath.Abs(prefix)
   115  		prefix = filepath.ToSlash(prefix)
   116  	}
   117  
   118  	fi, err := os.Stat(dirpath)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	var list []os.FileInfo
   124  
   125  	if !fi.IsDir() {
   126  		dirpath = filepath.Dir(dirpath)
   127  		list = []os.FileInfo{fi}
   128  	} else {
   129  		visitedPaths[dirpath] = true
   130  		fd, err := os.Open(dirpath)
   131  		if err != nil {
   132  			return err
   133  		}
   134  
   135  		defer fd.Close()
   136  
   137  		list, err = fd.Readdir(0)
   138  		if err != nil {
   139  			return err
   140  		}
   141  
   142  		// Sort to make output stable between invocations
   143  		sort.Sort(ByName(list))
   144  	}
   145  
   146  	for _, file := range list {
   147  		var asset bindata.Asset
   148  		asset.Path = filepath.Join(dirpath, file.Name())
   149  		asset.Name = filepath.ToSlash(asset.Path)
   150  
   151  		ignoring := false
   152  		for _, re := range ignore {
   153  			if re.MatchString(asset.Path) {
   154  				ignoring = true
   155  				break
   156  			}
   157  		}
   158  		if ignoring {
   159  			continue
   160  		}
   161  
   162  		if file.IsDir() {
   163  			if recursive {
   164  				recursivePath := filepath.Join(dir, file.Name())
   165  				visitedPaths[asset.Path] = true
   166  				_ = findFiles(recursivePath, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
   167  			}
   168  			continue
   169  		} else if file.Mode()&os.ModeSymlink == os.ModeSymlink {
   170  			var linkPath string
   171  			if linkPath, err = os.Readlink(asset.Path); err != nil {
   172  				return err
   173  			}
   174  			if !filepath.IsAbs(linkPath) {
   175  				if linkPath, err = filepath.Abs(dirpath + "/" + linkPath); err != nil {
   176  					return err
   177  				}
   178  			}
   179  			if _, ok := visitedPaths[linkPath]; !ok {
   180  				visitedPaths[linkPath] = true
   181  				_ = findFiles(asset.Path, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
   182  			}
   183  			continue
   184  		}
   185  
   186  		if strings.HasPrefix(asset.Name, prefix) {
   187  			asset.Name = asset.Name[len(prefix):]
   188  		} else {
   189  			asset.Name = filepath.Join(dir, file.Name())
   190  		}
   191  
   192  		// If we have a leading slash, get rid of it.
   193  		if len(asset.Name) > 0 && asset.Name[0] == '/' {
   194  			asset.Name = asset.Name[1:]
   195  		}
   196  
   197  		// This shouldn't happen.
   198  		if len(asset.Name) == 0 {
   199  			return fmt.Errorf("invalid file: %v", asset.Path)
   200  		}
   201  
   202  		asset.Func = safeFunctionName(asset.Name, knownFuncs)
   203  		asset.Path, _ = filepath.Abs(asset.Path)
   204  		*toc = append(*toc, asset)
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
   211  
   212  // safeFunctionName converts the given name into a name
   213  // which qualifies as a valid function identifier. It
   214  // also compares against a known list of functions to
   215  // prevent conflict based on name translation.
   216  func safeFunctionName(name string, knownFuncs map[string]int) string {
   217  	var inBytes, outBytes []byte
   218  	var toUpper bool
   219  
   220  	name = strings.ToLower(name)
   221  	inBytes = []byte(name)
   222  
   223  	for i := 0; i < len(inBytes); i++ {
   224  		if regFuncName.Match([]byte{inBytes[i]}) {
   225  			toUpper = true
   226  		} else if toUpper {
   227  			outBytes = append(outBytes, []byte(strings.ToUpper(string(inBytes[i])))...)
   228  			toUpper = false
   229  		} else {
   230  			outBytes = append(outBytes, inBytes[i])
   231  		}
   232  	}
   233  
   234  	name = string(outBytes)
   235  
   236  	// Identifier can't start with a digit.
   237  	if unicode.IsDigit(rune(name[0])) {
   238  		name = "_" + name
   239  	}
   240  
   241  	if num, ok := knownFuncs[name]; ok {
   242  		knownFuncs[name] = num + 1
   243  		name = fmt.Sprintf("%s%d", name, num)
   244  	} else {
   245  		knownFuncs[name] = 2
   246  	}
   247  
   248  	return name
   249  }