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 }