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 }