github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/tools/depsgen/globcmd.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"path/filepath"
    21  	"strings"
    22  
    23  	"github.com/coreos/rkt/tools/common"
    24  	"github.com/coreos/rkt/tools/common/filelist"
    25  )
    26  
    27  const (
    28  	globCmd = "glob"
    29  	// globMakeFunction is a template for generating all files for
    30  	// given set of wildcards. See globMakeWildcard.
    31  	globMakeFunction = `$(strip \
    32          $(eval _DEPS_GEN_FG_ := $(strip !!!WILDCARDS!!!)) \
    33          $(if $(_DEPS_GEN_FG_),$(shell stat --format "%n: %F" $(_DEPS_GEN_FG_) | grep -e 'regular file$$' | cut -f1 -d:)))
    34  `
    35  	// globMakeWildcard is a template for call wildcard function
    36  	// for in a given directory with a given suffix. This wildcard
    37  	// is for normal files.
    38  	globMakeWildcard = "$(wildcard !!!DIR!!!/*!!!SUFFIX!!!)"
    39  	// globMakeHiddenWildcard is a template for call wildcard
    40  	// function for in a given directory with a given suffix. This
    41  	// wildcard is for files beginning with a dot, which are
    42  	// normally not taken into account by wildcard.
    43  	globMakeHiddenWildcard = "$(wildcard !!!DIR!!!/.*!!!SUFFIX!!!)"
    44  )
    45  
    46  type globMode int
    47  
    48  const (
    49  	globNormal globMode = iota
    50  	globDotFiles
    51  	globAll
    52  )
    53  
    54  type globArgs struct {
    55  	target   string
    56  	suffix   string
    57  	mode     globMode
    58  	filelist string
    59  	mapTo    []string
    60  }
    61  
    62  func init() {
    63  	cmds[globCmd] = globDeps
    64  }
    65  
    66  func globDeps(args []string) string {
    67  	parsedArgs := globGetArgs(args)
    68  	files := globGetFiles(parsedArgs)
    69  	makeFunction := globGetMakeFunction(files, parsedArgs.suffix, parsedArgs.mode)
    70  	return GenerateFileDeps(parsedArgs.target, makeFunction, files)
    71  }
    72  
    73  // globGetArgs parses given parameters and returns a target, a suffix
    74  // and a list of files.
    75  func globGetArgs(args []string) globArgs {
    76  	f, target := standardFlags(globCmd)
    77  	suffix := f.String("suffix", "", "File suffix (example: .go)")
    78  	globbingMode := f.String("glob-mode", "all", "Which files to glob (normal, dot-files, all [default])")
    79  	filelist := f.String("filelist", "", "Read all the files from this file")
    80  	var mapTo []string
    81  	mapToWrapper := common.StringSliceWrapper{Slice: &mapTo}
    82  	f.Var(&mapToWrapper, "map-to", "Map contents of filelist to this directory, can be used multiple times")
    83  
    84  	f.Parse(args)
    85  	if *target == "" {
    86  		common.Die("--target parameter must be specified and cannot be empty")
    87  	}
    88  	mode := globModeFromString(*globbingMode)
    89  	if *filelist == "" {
    90  		common.Die("--filelist parameter must be specified and cannot be empty")
    91  	}
    92  	if len(mapTo) < 1 {
    93  		common.Die("--map-to parameter must be specified at least once")
    94  	}
    95  	return globArgs{
    96  		target:   *target,
    97  		suffix:   *suffix,
    98  		mode:     mode,
    99  		filelist: *filelist,
   100  		mapTo:    mapTo,
   101  	}
   102  }
   103  
   104  func globModeFromString(mode string) globMode {
   105  	switch mode {
   106  	case "normal":
   107  		return globNormal
   108  	case "dot-files":
   109  		return globDotFiles
   110  	case "all":
   111  		return globAll
   112  	default:
   113  		common.Die("Unknown glob mode %q", mode)
   114  	}
   115  	panic("Should not happen")
   116  }
   117  
   118  func globGetFiles(args globArgs) []string {
   119  	f, err := globGetFilesFromFilelist(args.filelist)
   120  	if err != nil {
   121  		common.Die("Failed to get files from filelist %q: %v", args.filelist, err)
   122  	}
   123  	return common.MapFilesToDirectories(f, args.mapTo)
   124  }
   125  
   126  func globGetFilesFromFilelist(filename string) ([]string, error) {
   127  	fl, err := os.Open(filename)
   128  	if err != nil {
   129  		return nil, fmt.Errorf("Failed to open filelist %q: %v", filename, err)
   130  	}
   131  	defer fl.Close()
   132  	lists := filelist.Lists{}
   133  	if err := lists.ParseFilelist(fl); err != nil {
   134  		return nil, err
   135  	}
   136  	return lists.Files, nil
   137  }
   138  
   139  // globGetMakeFunction returns a make snippet which calls wildcard
   140  // function in all directories where given files are and with a given
   141  // suffix.
   142  func globGetMakeFunction(files []string, suffix string, mode globMode) string {
   143  	dirs := map[string]struct{}{}
   144  	for _, file := range files {
   145  		dirs[filepath.Dir(file)] = struct{}{}
   146  	}
   147  	makeWildcards := make([]string, 0, len(dirs))
   148  	wildcard := globGetMakeSnippet(mode)
   149  	for dir := range dirs {
   150  		str := replacePlaceholders(wildcard, "SUFFIX", suffix, "DIR", dir)
   151  		makeWildcards = append(makeWildcards, str)
   152  	}
   153  	return replacePlaceholders(globMakeFunction, "WILDCARDS", strings.Join(makeWildcards, " "))
   154  }
   155  
   156  func globGetMakeSnippet(mode globMode) string {
   157  	switch mode {
   158  	case globNormal:
   159  		return globMakeWildcard
   160  	case globDotFiles:
   161  		return globMakeHiddenWildcard
   162  	case globAll:
   163  		return fmt.Sprintf("%s %s", globMakeWildcard, globMakeHiddenWildcard)
   164  	}
   165  	panic("Should not happen")
   166  }