github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/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  	"github.com/hashicorp/errwrap"
    26  )
    27  
    28  const (
    29  	globCmd = "glob"
    30  	// globMakeFunction is a template for generating all files for
    31  	// given set of wildcards. See globMakeWildcard.
    32  	globMakeFunction = `$(strip \
    33          $(eval _DEPS_GEN_FG_ := $(strip !!!WILDCARDS!!!)) \
    34          $(if $(_DEPS_GEN_FG_),$(shell stat --format "%n: %F" $(_DEPS_GEN_FG_) | grep -e 'regular file$$' | cut -f1 -d:)))
    35  `
    36  	// globMakeWildcard is a template for call wildcard function
    37  	// for in a given directory with a given suffix. This wildcard
    38  	// is for normal files.
    39  	globMakeWildcard = "$(wildcard !!!DIR!!!/*!!!SUFFIX!!!)"
    40  	// globMakeHiddenWildcard is a template for call wildcard
    41  	// function for in a given directory with a given suffix. This
    42  	// wildcard is for files beginning with a dot, which are
    43  	// normally not taken into account by wildcard.
    44  	globMakeHiddenWildcard = "$(wildcard !!!DIR!!!/.*!!!SUFFIX!!!)"
    45  )
    46  
    47  type globMode int
    48  
    49  const (
    50  	globNormal globMode = iota
    51  	globDotFiles
    52  	globAll
    53  )
    54  
    55  type globArgs struct {
    56  	target   string
    57  	suffix   string
    58  	mode     globMode
    59  	filelist string
    60  	mapTo    []string
    61  }
    62  
    63  func init() {
    64  	cmds[globCmd] = globDeps
    65  }
    66  
    67  func globDeps(args []string) string {
    68  	parsedArgs := globGetArgs(args)
    69  	files := globGetFiles(parsedArgs)
    70  	makeFunction := globGetMakeFunction(files, parsedArgs.suffix, parsedArgs.mode)
    71  	return GenerateFileDeps(parsedArgs.target, makeFunction, files)
    72  }
    73  
    74  // globGetArgs parses given parameters and returns a target, a suffix
    75  // and a list of files.
    76  func globGetArgs(args []string) globArgs {
    77  	f, target := standardFlags(globCmd)
    78  	suffix := f.String("suffix", "", "File suffix (example: .go)")
    79  	globbingMode := f.String("glob-mode", "all", "Which files to glob (normal, dot-files, all [default])")
    80  	filelist := f.String("filelist", "", "Read all the files from this file")
    81  	var mapTo []string
    82  	mapToWrapper := common.StringSliceWrapper{Slice: &mapTo}
    83  	f.Var(&mapToWrapper, "map-to", "Map contents of filelist to this directory, can be used multiple times")
    84  
    85  	f.Parse(args)
    86  	if *target == "" {
    87  		common.Die("--target parameter must be specified and cannot be empty")
    88  	}
    89  	mode := globModeFromString(*globbingMode)
    90  	if *filelist == "" {
    91  		common.Die("--filelist parameter must be specified and cannot be empty")
    92  	}
    93  	if len(mapTo) < 1 {
    94  		common.Die("--map-to parameter must be specified at least once")
    95  	}
    96  	return globArgs{
    97  		target:   *target,
    98  		suffix:   *suffix,
    99  		mode:     mode,
   100  		filelist: *filelist,
   101  		mapTo:    mapTo,
   102  	}
   103  }
   104  
   105  func globModeFromString(mode string) globMode {
   106  	switch mode {
   107  	case "normal":
   108  		return globNormal
   109  	case "dot-files":
   110  		return globDotFiles
   111  	case "all":
   112  		return globAll
   113  	default:
   114  		common.Die("Unknown glob mode %q", mode)
   115  	}
   116  	panic("Should not happen")
   117  }
   118  
   119  func globGetFiles(args globArgs) []string {
   120  	f, err := globGetFilesFromFilelist(args.filelist)
   121  	if err != nil {
   122  		common.Die("Failed to get files from filelist %q: %v", args.filelist, err)
   123  	}
   124  	return common.MapFilesToDirectories(f, args.mapTo)
   125  }
   126  
   127  func globGetFilesFromFilelist(filename string) ([]string, error) {
   128  	fl, err := os.Open(filename)
   129  	if err != nil {
   130  		return nil, errwrap.Wrap(fmt.Errorf("failed to open filelist %q", filename), err)
   131  	}
   132  	defer fl.Close()
   133  	lists := filelist.Lists{}
   134  	if err := lists.ParseFilelist(fl); err != nil {
   135  		return nil, err
   136  	}
   137  	return lists.Files, nil
   138  }
   139  
   140  // globGetMakeFunction returns a make snippet which calls wildcard
   141  // function in all directories where given files are and with a given
   142  // suffix.
   143  func globGetMakeFunction(files []string, suffix string, mode globMode) string {
   144  	dirs := map[string]struct{}{}
   145  	for _, file := range files {
   146  		dirs[filepath.Dir(file)] = struct{}{}
   147  	}
   148  	makeWildcards := make([]string, 0, len(dirs))
   149  	wildcard := globGetMakeSnippet(mode)
   150  	for dir := range dirs {
   151  		str := replacePlaceholders(wildcard, "SUFFIX", suffix, "DIR", dir)
   152  		makeWildcards = append(makeWildcards, str)
   153  	}
   154  	return replacePlaceholders(globMakeFunction, "WILDCARDS", strings.Join(makeWildcards, " "))
   155  }
   156  
   157  func globGetMakeSnippet(mode globMode) string {
   158  	switch mode {
   159  	case globNormal:
   160  		return globMakeWildcard
   161  	case globDotFiles:
   162  		return globMakeHiddenWildcard
   163  	case globAll:
   164  		return fmt.Sprintf("%s %s", globMakeWildcard, globMakeHiddenWildcard)
   165  	}
   166  	panic("Should not happen")
   167  }