1// Copyright 2017 The Wuffs 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// https://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// wuffs is a tool for managing Wuffs source code. 16package main 17 18import ( 19 "bytes" 20 "flag" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "sort" 26 "strings" 27 28 "github.com/google/wuffs/lang/wuffsroot" 29) 30 31var commands = []struct { 32 name string 33 do func(wuffsRoot string, args []string) error 34}{ 35 {"bench", doBench}, 36 {"gen", doGen}, 37 {"genlib", doGenlib}, 38 {"test", doTest}, 39} 40 41func usage() { 42 fmt.Fprintf(os.Stderr, `Wuffs is a tool for managing Wuffs source code. 43 44Usage: 45 46 wuffs command [arguments] 47 48The commands are: 49 50 bench benchmark packages 51 gen generate code for packages and dependencies 52 genlib generate software libraries 53 test test packages 54`) 55} 56 57func main() { 58 if err := main1(); err != nil { 59 os.Stderr.WriteString(err.Error() + "\n") 60 os.Exit(1) 61 } 62} 63 64func main1() error { 65 flag.Usage = usage 66 flag.Parse() 67 68 wuffsRoot, err := wuffsroot.Value() 69 if err != nil { 70 return err 71 } 72 if args := flag.Args(); len(args) > 0 { 73 for _, c := range commands { 74 if args[0] == c.name { 75 return c.do(wuffsRoot, args[1:]) 76 } 77 } 78 } 79 usage() 80 os.Exit(1) 81 return nil 82} 83 84func findFiles(qualDirname string, suffix string) (filenames []string, err error) { 85 filenames, err = findFiles1(nil, qualDirname, suffix) 86 if err != nil { 87 return nil, err 88 } 89 sort.Strings(filenames) 90 return filenames, nil 91} 92 93func findFiles1(dstQF []string, qualDirname string, suffix string) (qualFilenames []string, err error) { 94 dstQF, relDirnames, err := appendDir(dstQF, qualDirname, suffix, true) 95 if err != nil { 96 return nil, err 97 } 98 for _, d := range relDirnames { 99 dstQF, err = findFiles1(dstQF, filepath.Join(qualDirname, d), suffix) 100 if err != nil { 101 return nil, err 102 } 103 } 104 return dstQF, nil 105} 106 107func listDir(qualDirname string, suffix string, returnSubdirs bool) (qualFilenames []string, relDirnames []string, err error) { 108 qualFilenames, relDirnames, err = appendDir(nil, qualDirname, suffix, returnSubdirs) 109 if err != nil { 110 return nil, nil, err 111 } 112 sort.Strings(qualFilenames) 113 sort.Strings(relDirnames) 114 return qualFilenames, relDirnames, nil 115} 116 117func appendDir(dstQF []string, qualDirname string, suffix string, returnSubdirs bool) (qualFilenames []string, relDirnames []string, err error) { 118 f, err := os.Open(qualDirname) 119 if err != nil { 120 return nil, nil, err 121 } 122 defer f.Close() 123 124 infos, err := f.Readdir(-1) 125 if err != nil { 126 return nil, nil, err 127 } 128 for _, o := range infos { 129 name := o.Name() 130 if o.IsDir() { 131 if returnSubdirs { 132 relDirnames = append(relDirnames, name) 133 } 134 } else if strings.HasSuffix(name, suffix) { 135 dstQF = append(dstQF, filepath.Join(qualDirname, name)) 136 } 137 } 138 139 return dstQF, relDirnames, nil 140} 141 142func writeFile(filename string, contents []byte) error { 143 if existing, err := ioutil.ReadFile(filename); err == nil && bytes.Equal(existing, contents) { 144 fmt.Println("gen unchanged: ", filename) 145 return nil 146 } 147 if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil { 148 return err 149 } 150 if err := ioutil.WriteFile(filename, contents, 0644); err != nil { 151 return err 152 } 153 fmt.Println("gen wrote: ", filename) 154 return nil 155} 156 157const ( 158 langsDefault = "c" 159 langsUsage = `comma-separated list of target languages (file extensions), e.g. "c,go,rs"` 160 161 skipgenDefault = false 162 skipgenUsage = `whether to skip automatically generating code when testing` 163 164 skipgendepsDefault = false 165 skipgendepsUsage = `whether to skip automatically generating packages' dependencies` 166) 167 168func parseLangs(commaSeparated string) ([]string, error) { 169 ret := []string(nil) 170 for _, s := range strings.Split(commaSeparated, ",") { 171 if !validName(s) { 172 return nil, fmt.Errorf(`invalid lang %q, not in [a-z0-9]+`, s) 173 } 174 ret = append(ret, s) 175 } 176 return ret, nil 177} 178 179func validName(s string) bool { 180 if len(s) == 0 { 181 return false 182 } 183 for _, c := range s { 184 if (c < '0' || '9' < c) && (c < 'a' || 'z' < c) { 185 return false 186 } 187 } 188 return true 189} 190