1*1fa6dee9SAndroid Build Coastguard Worker// Mostly copied from Go's src/cmd/gofmt: 2*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2009 The Go Authors. All rights reserved. 3*1fa6dee9SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style 4*1fa6dee9SAndroid Build Coastguard Worker// license that can be found in the LICENSE file. 5*1fa6dee9SAndroid Build Coastguard Worker 6*1fa6dee9SAndroid Build Coastguard Workerpackage main 7*1fa6dee9SAndroid Build Coastguard Worker 8*1fa6dee9SAndroid Build Coastguard Workerimport ( 9*1fa6dee9SAndroid Build Coastguard Worker "flag" 10*1fa6dee9SAndroid Build Coastguard Worker "fmt" 11*1fa6dee9SAndroid Build Coastguard Worker "io" 12*1fa6dee9SAndroid Build Coastguard Worker "io/ioutil" 13*1fa6dee9SAndroid Build Coastguard Worker "os" 14*1fa6dee9SAndroid Build Coastguard Worker "os/exec" 15*1fa6dee9SAndroid Build Coastguard Worker "path/filepath" 16*1fa6dee9SAndroid Build Coastguard Worker "strings" 17*1fa6dee9SAndroid Build Coastguard Worker "syscall" 18*1fa6dee9SAndroid Build Coastguard Worker "unicode" 19*1fa6dee9SAndroid Build Coastguard Worker 20*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/bpmodify" 21*1fa6dee9SAndroid Build Coastguard Worker) 22*1fa6dee9SAndroid Build Coastguard Worker 23*1fa6dee9SAndroid Build Coastguard Workervar ( 24*1fa6dee9SAndroid Build Coastguard Worker // main operation modes 25*1fa6dee9SAndroid Build Coastguard Worker list = flag.Bool("l", false, "list files that would be modified by bpmodify") 26*1fa6dee9SAndroid Build Coastguard Worker write = flag.Bool("w", false, "write result to (source) file instead of stdout") 27*1fa6dee9SAndroid Build Coastguard Worker doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") 28*1fa6dee9SAndroid Build Coastguard Worker sortLists = flag.Bool("s", false, "sort touched lists, even if they were unsorted") 29*1fa6dee9SAndroid Build Coastguard Worker targetedModules = new(identSet) 30*1fa6dee9SAndroid Build Coastguard Worker targetedProperties = new(identSet) 31*1fa6dee9SAndroid Build Coastguard Worker addIdents = new(identSet) 32*1fa6dee9SAndroid Build Coastguard Worker removeIdents = new(identSet) 33*1fa6dee9SAndroid Build Coastguard Worker removeProperty = flag.Bool("remove-property", false, "remove the property") 34*1fa6dee9SAndroid Build Coastguard Worker moveProperty = flag.Bool("move-property", false, "moves contents of property into newLocation") 35*1fa6dee9SAndroid Build Coastguard Worker newLocation string 36*1fa6dee9SAndroid Build Coastguard Worker setString *string 37*1fa6dee9SAndroid Build Coastguard Worker addLiteral *string 38*1fa6dee9SAndroid Build Coastguard Worker setBool *string 39*1fa6dee9SAndroid Build Coastguard Worker replaceProperty = new(replacements) 40*1fa6dee9SAndroid Build Coastguard Worker) 41*1fa6dee9SAndroid Build Coastguard Worker 42*1fa6dee9SAndroid Build Coastguard Workerfunc init() { 43*1fa6dee9SAndroid Build Coastguard Worker flag.Var(targetedModules, "m", "comma or whitespace separated list of modules on which to operate") 44*1fa6dee9SAndroid Build Coastguard Worker flag.Var(targetedProperties, "parameter", "alias to -property=`name1[,name2[,... […]") 45*1fa6dee9SAndroid Build Coastguard Worker flag.StringVar(&newLocation, "new-location", "", " use with moveProperty to move contents of -property into a property with name -new-location ") 46*1fa6dee9SAndroid Build Coastguard Worker flag.Var(targetedProperties, "property", "comma-separated list of fully qualified `name`s of properties to modify (default \"deps\")") 47*1fa6dee9SAndroid Build Coastguard Worker flag.Var(addIdents, "a", "comma or whitespace separated list of identifiers to add") 48*1fa6dee9SAndroid Build Coastguard Worker flag.Var(stringPtrFlag{&addLiteral}, "add-literal", "a literal to add to a list") 49*1fa6dee9SAndroid Build Coastguard Worker flag.Var(removeIdents, "r", "comma or whitespace separated list of identifiers to remove") 50*1fa6dee9SAndroid Build Coastguard Worker flag.Var(stringPtrFlag{&setString}, "str", "set a string property") 51*1fa6dee9SAndroid Build Coastguard Worker flag.Var(replaceProperty, "replace-property", "property names to be replaced, in the form of oldName1=newName1,oldName2=newName2") 52*1fa6dee9SAndroid Build Coastguard Worker flag.Var(stringPtrFlag{&setBool}, "set-bool", "a boolean value to set a property with (not a list)") 53*1fa6dee9SAndroid Build Coastguard Worker flag.Usage = usage 54*1fa6dee9SAndroid Build Coastguard Worker} 55*1fa6dee9SAndroid Build Coastguard Worker 56*1fa6dee9SAndroid Build Coastguard Workervar ( 57*1fa6dee9SAndroid Build Coastguard Worker exitCode = 0 58*1fa6dee9SAndroid Build Coastguard Worker) 59*1fa6dee9SAndroid Build Coastguard Worker 60*1fa6dee9SAndroid Build Coastguard Workerfunc report(err error) { 61*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err) 62*1fa6dee9SAndroid Build Coastguard Worker exitCode = 2 63*1fa6dee9SAndroid Build Coastguard Worker} 64*1fa6dee9SAndroid Build Coastguard Worker 65*1fa6dee9SAndroid Build Coastguard Workerfunc usage() { 66*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [flags] [path ...]\n", os.Args[0]) 67*1fa6dee9SAndroid Build Coastguard Worker flag.PrintDefaults() 68*1fa6dee9SAndroid Build Coastguard Worker} 69*1fa6dee9SAndroid Build Coastguard Worker 70*1fa6dee9SAndroid Build Coastguard Workerfunc processBp(bp *bpmodify.Blueprint) error { 71*1fa6dee9SAndroid Build Coastguard Worker var modules *bpmodify.ModuleSet 72*1fa6dee9SAndroid Build Coastguard Worker if targetedModules.all { 73*1fa6dee9SAndroid Build Coastguard Worker modules = bp.AllModules() 74*1fa6dee9SAndroid Build Coastguard Worker } else { 75*1fa6dee9SAndroid Build Coastguard Worker modules = bp.ModulesByName(targetedModules.idents...) 76*1fa6dee9SAndroid Build Coastguard Worker } 77*1fa6dee9SAndroid Build Coastguard Worker 78*1fa6dee9SAndroid Build Coastguard Worker if *removeProperty { 79*1fa6dee9SAndroid Build Coastguard Worker // remove-property is used solely, so return here. 80*1fa6dee9SAndroid Build Coastguard Worker return modules.RemoveProperty(targetedProperties.idents...) 81*1fa6dee9SAndroid Build Coastguard Worker } else if *moveProperty { 82*1fa6dee9SAndroid Build Coastguard Worker return modules.MoveProperty(newLocation, targetedProperties.idents...) 83*1fa6dee9SAndroid Build Coastguard Worker } else if len(addIdents.idents) > 0 { 84*1fa6dee9SAndroid Build Coastguard Worker props, err := modules.GetOrCreateProperty(bpmodify.List, targetedProperties.idents...) 85*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 86*1fa6dee9SAndroid Build Coastguard Worker return err 87*1fa6dee9SAndroid Build Coastguard Worker } 88*1fa6dee9SAndroid Build Coastguard Worker return props.AddStringToList(addIdents.idents...) 89*1fa6dee9SAndroid Build Coastguard Worker } else if addLiteral != nil { 90*1fa6dee9SAndroid Build Coastguard Worker props, err := modules.GetOrCreateProperty(bpmodify.List, targetedProperties.idents...) 91*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 92*1fa6dee9SAndroid Build Coastguard Worker return err 93*1fa6dee9SAndroid Build Coastguard Worker } 94*1fa6dee9SAndroid Build Coastguard Worker return props.AddLiteral(*addLiteral) 95*1fa6dee9SAndroid Build Coastguard Worker } else if setString != nil { 96*1fa6dee9SAndroid Build Coastguard Worker props, err := modules.GetOrCreateProperty(bpmodify.String, targetedProperties.idents...) 97*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 98*1fa6dee9SAndroid Build Coastguard Worker return err 99*1fa6dee9SAndroid Build Coastguard Worker } 100*1fa6dee9SAndroid Build Coastguard Worker return props.SetString(*setString) 101*1fa6dee9SAndroid Build Coastguard Worker } else if setBool != nil { 102*1fa6dee9SAndroid Build Coastguard Worker props, err := modules.GetOrCreateProperty(bpmodify.Bool, targetedProperties.idents...) 103*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 104*1fa6dee9SAndroid Build Coastguard Worker return err 105*1fa6dee9SAndroid Build Coastguard Worker } 106*1fa6dee9SAndroid Build Coastguard Worker var value bool 107*1fa6dee9SAndroid Build Coastguard Worker if *setBool == "true" { 108*1fa6dee9SAndroid Build Coastguard Worker value = true 109*1fa6dee9SAndroid Build Coastguard Worker } else if *setBool == "false" { 110*1fa6dee9SAndroid Build Coastguard Worker value = false 111*1fa6dee9SAndroid Build Coastguard Worker } else { 112*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("expected parameter to be true or false, found %s", *setBool) 113*1fa6dee9SAndroid Build Coastguard Worker } 114*1fa6dee9SAndroid Build Coastguard Worker return props.SetBool(value) 115*1fa6dee9SAndroid Build Coastguard Worker } else { 116*1fa6dee9SAndroid Build Coastguard Worker props, err := modules.GetProperty(targetedProperties.idents...) 117*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 118*1fa6dee9SAndroid Build Coastguard Worker return err 119*1fa6dee9SAndroid Build Coastguard Worker } 120*1fa6dee9SAndroid Build Coastguard Worker if len(removeIdents.idents) > 0 { 121*1fa6dee9SAndroid Build Coastguard Worker return props.RemoveStringFromList(removeIdents.idents...) 122*1fa6dee9SAndroid Build Coastguard Worker } else if replaceProperty.size() != 0 { 123*1fa6dee9SAndroid Build Coastguard Worker return props.ReplaceStrings(replaceProperty.oldNameToNewName) 124*1fa6dee9SAndroid Build Coastguard Worker } 125*1fa6dee9SAndroid Build Coastguard Worker } 126*1fa6dee9SAndroid Build Coastguard Worker 127*1fa6dee9SAndroid Build Coastguard Worker return nil 128*1fa6dee9SAndroid Build Coastguard Worker} 129*1fa6dee9SAndroid Build Coastguard Worker 130*1fa6dee9SAndroid Build Coastguard Worker// If in == nil, the source is the contents of the file with the given filename. 131*1fa6dee9SAndroid Build Coastguard Workerfunc processFile(filename string, in io.Reader, out io.Writer) error { 132*1fa6dee9SAndroid Build Coastguard Worker if in == nil { 133*1fa6dee9SAndroid Build Coastguard Worker f, err := os.Open(filename) 134*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 135*1fa6dee9SAndroid Build Coastguard Worker return err 136*1fa6dee9SAndroid Build Coastguard Worker } 137*1fa6dee9SAndroid Build Coastguard Worker defer f.Close() 138*1fa6dee9SAndroid Build Coastguard Worker if *write { 139*1fa6dee9SAndroid Build Coastguard Worker syscall.Flock(int(f.Fd()), syscall.LOCK_EX) 140*1fa6dee9SAndroid Build Coastguard Worker } 141*1fa6dee9SAndroid Build Coastguard Worker in = f 142*1fa6dee9SAndroid Build Coastguard Worker } 143*1fa6dee9SAndroid Build Coastguard Worker 144*1fa6dee9SAndroid Build Coastguard Worker src, err := io.ReadAll(in) 145*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 146*1fa6dee9SAndroid Build Coastguard Worker return err 147*1fa6dee9SAndroid Build Coastguard Worker } 148*1fa6dee9SAndroid Build Coastguard Worker 149*1fa6dee9SAndroid Build Coastguard Worker bp, err := bpmodify.NewBlueprint(filename, src) 150*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 151*1fa6dee9SAndroid Build Coastguard Worker return err 152*1fa6dee9SAndroid Build Coastguard Worker } 153*1fa6dee9SAndroid Build Coastguard Worker 154*1fa6dee9SAndroid Build Coastguard Worker err = processBp(bp) 155*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 156*1fa6dee9SAndroid Build Coastguard Worker return err 157*1fa6dee9SAndroid Build Coastguard Worker } 158*1fa6dee9SAndroid Build Coastguard Worker 159*1fa6dee9SAndroid Build Coastguard Worker res, err := bp.Bytes() 160*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 161*1fa6dee9SAndroid Build Coastguard Worker return err 162*1fa6dee9SAndroid Build Coastguard Worker } 163*1fa6dee9SAndroid Build Coastguard Worker if *list { 164*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(out, filename) 165*1fa6dee9SAndroid Build Coastguard Worker } 166*1fa6dee9SAndroid Build Coastguard Worker if *write { 167*1fa6dee9SAndroid Build Coastguard Worker err = os.WriteFile(filename, res, 0644) 168*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 169*1fa6dee9SAndroid Build Coastguard Worker return err 170*1fa6dee9SAndroid Build Coastguard Worker } 171*1fa6dee9SAndroid Build Coastguard Worker } 172*1fa6dee9SAndroid Build Coastguard Worker if *doDiff { 173*1fa6dee9SAndroid Build Coastguard Worker data, err := diff(src, res) 174*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 175*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("computing diff: %s", err) 176*1fa6dee9SAndroid Build Coastguard Worker } 177*1fa6dee9SAndroid Build Coastguard Worker fmt.Printf("diff %s bpfmt/%s\n", filename, filename) 178*1fa6dee9SAndroid Build Coastguard Worker out.Write(data) 179*1fa6dee9SAndroid Build Coastguard Worker } 180*1fa6dee9SAndroid Build Coastguard Worker if !*list && !*write && !*doDiff { 181*1fa6dee9SAndroid Build Coastguard Worker _, err = out.Write(res) 182*1fa6dee9SAndroid Build Coastguard Worker } 183*1fa6dee9SAndroid Build Coastguard Worker 184*1fa6dee9SAndroid Build Coastguard Worker return err 185*1fa6dee9SAndroid Build Coastguard Worker} 186*1fa6dee9SAndroid Build Coastguard Worker 187*1fa6dee9SAndroid Build Coastguard Workerfunc visitFile(path string, f os.FileInfo, err error) error { 188*1fa6dee9SAndroid Build Coastguard Worker //TODO(dacek): figure out a better way to target intended .bp files without parsing errors 189*1fa6dee9SAndroid Build Coastguard Worker if err == nil && (f.Name() == "Blueprints" || strings.HasSuffix(f.Name(), ".bp")) { 190*1fa6dee9SAndroid Build Coastguard Worker err = processFile(path, nil, os.Stdout) 191*1fa6dee9SAndroid Build Coastguard Worker } 192*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 193*1fa6dee9SAndroid Build Coastguard Worker report(err) 194*1fa6dee9SAndroid Build Coastguard Worker } 195*1fa6dee9SAndroid Build Coastguard Worker return nil 196*1fa6dee9SAndroid Build Coastguard Worker} 197*1fa6dee9SAndroid Build Coastguard Worker 198*1fa6dee9SAndroid Build Coastguard Workerfunc walkDir(path string) { 199*1fa6dee9SAndroid Build Coastguard Worker filepath.Walk(path, visitFile) 200*1fa6dee9SAndroid Build Coastguard Worker} 201*1fa6dee9SAndroid Build Coastguard Worker 202*1fa6dee9SAndroid Build Coastguard Workerfunc main() { 203*1fa6dee9SAndroid Build Coastguard Worker defer func() { 204*1fa6dee9SAndroid Build Coastguard Worker if err := recover(); err != nil { 205*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("error: %s", err)) 206*1fa6dee9SAndroid Build Coastguard Worker } 207*1fa6dee9SAndroid Build Coastguard Worker os.Exit(exitCode) 208*1fa6dee9SAndroid Build Coastguard Worker }() 209*1fa6dee9SAndroid Build Coastguard Worker flag.Parse() 210*1fa6dee9SAndroid Build Coastguard Worker 211*1fa6dee9SAndroid Build Coastguard Worker if len(targetedProperties.idents) == 0 && *moveProperty { 212*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("-move-property must specify property")) 213*1fa6dee9SAndroid Build Coastguard Worker return 214*1fa6dee9SAndroid Build Coastguard Worker } 215*1fa6dee9SAndroid Build Coastguard Worker 216*1fa6dee9SAndroid Build Coastguard Worker if len(targetedProperties.idents) == 0 { 217*1fa6dee9SAndroid Build Coastguard Worker targetedProperties.Set("deps") 218*1fa6dee9SAndroid Build Coastguard Worker } 219*1fa6dee9SAndroid Build Coastguard Worker if flag.NArg() == 0 { 220*1fa6dee9SAndroid Build Coastguard Worker if *write { 221*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("error: cannot use -w with standard input")) 222*1fa6dee9SAndroid Build Coastguard Worker return 223*1fa6dee9SAndroid Build Coastguard Worker } 224*1fa6dee9SAndroid Build Coastguard Worker if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil { 225*1fa6dee9SAndroid Build Coastguard Worker report(err) 226*1fa6dee9SAndroid Build Coastguard Worker } 227*1fa6dee9SAndroid Build Coastguard Worker return 228*1fa6dee9SAndroid Build Coastguard Worker } 229*1fa6dee9SAndroid Build Coastguard Worker if len(targetedModules.idents) == 0 { 230*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("-m parameter is required")) 231*1fa6dee9SAndroid Build Coastguard Worker return 232*1fa6dee9SAndroid Build Coastguard Worker } 233*1fa6dee9SAndroid Build Coastguard Worker 234*1fa6dee9SAndroid Build Coastguard Worker if len(addIdents.idents) == 0 && len(removeIdents.idents) == 0 && setString == nil && addLiteral == nil && !*removeProperty && !*moveProperty && (*replaceProperty).size() == 0 && setBool == nil { 235*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("-a, -add-literal, -r, -remove-property, -move-property, replace-property or -str parameter is required")) 236*1fa6dee9SAndroid Build Coastguard Worker return 237*1fa6dee9SAndroid Build Coastguard Worker } 238*1fa6dee9SAndroid Build Coastguard Worker if *removeProperty && (len(addIdents.idents) > 0 || len(removeIdents.idents) > 0 || setString != nil || addLiteral != nil || (*replaceProperty).size() > 0) { 239*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("-remove-property cannot be used with other parameter(s)")) 240*1fa6dee9SAndroid Build Coastguard Worker return 241*1fa6dee9SAndroid Build Coastguard Worker } 242*1fa6dee9SAndroid Build Coastguard Worker if *moveProperty && (len(addIdents.idents) > 0 || len(removeIdents.idents) > 0 || setString != nil || addLiteral != nil || (*replaceProperty).size() > 0) { 243*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("-move-property cannot be used with other parameter(s)")) 244*1fa6dee9SAndroid Build Coastguard Worker return 245*1fa6dee9SAndroid Build Coastguard Worker } 246*1fa6dee9SAndroid Build Coastguard Worker if *moveProperty && newLocation == "" { 247*1fa6dee9SAndroid Build Coastguard Worker report(fmt.Errorf("-move-property must specify -new-location")) 248*1fa6dee9SAndroid Build Coastguard Worker return 249*1fa6dee9SAndroid Build Coastguard Worker } 250*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < flag.NArg(); i++ { 251*1fa6dee9SAndroid Build Coastguard Worker path := flag.Arg(i) 252*1fa6dee9SAndroid Build Coastguard Worker switch dir, err := os.Stat(path); { 253*1fa6dee9SAndroid Build Coastguard Worker case err != nil: 254*1fa6dee9SAndroid Build Coastguard Worker report(err) 255*1fa6dee9SAndroid Build Coastguard Worker case dir.IsDir(): 256*1fa6dee9SAndroid Build Coastguard Worker walkDir(path) 257*1fa6dee9SAndroid Build Coastguard Worker default: 258*1fa6dee9SAndroid Build Coastguard Worker if err := processFile(path, nil, os.Stdout); err != nil { 259*1fa6dee9SAndroid Build Coastguard Worker report(err) 260*1fa6dee9SAndroid Build Coastguard Worker } 261*1fa6dee9SAndroid Build Coastguard Worker } 262*1fa6dee9SAndroid Build Coastguard Worker } 263*1fa6dee9SAndroid Build Coastguard Worker} 264*1fa6dee9SAndroid Build Coastguard Worker 265*1fa6dee9SAndroid Build Coastguard Workerfunc diff(b1, b2 []byte) (data []byte, err error) { 266*1fa6dee9SAndroid Build Coastguard Worker f1, err := ioutil.TempFile("", "bpfmt") 267*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 268*1fa6dee9SAndroid Build Coastguard Worker return 269*1fa6dee9SAndroid Build Coastguard Worker } 270*1fa6dee9SAndroid Build Coastguard Worker defer os.Remove(f1.Name()) 271*1fa6dee9SAndroid Build Coastguard Worker defer f1.Close() 272*1fa6dee9SAndroid Build Coastguard Worker f2, err := ioutil.TempFile("", "bpfmt") 273*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 274*1fa6dee9SAndroid Build Coastguard Worker return 275*1fa6dee9SAndroid Build Coastguard Worker } 276*1fa6dee9SAndroid Build Coastguard Worker defer os.Remove(f2.Name()) 277*1fa6dee9SAndroid Build Coastguard Worker defer f2.Close() 278*1fa6dee9SAndroid Build Coastguard Worker f1.Write(b1) 279*1fa6dee9SAndroid Build Coastguard Worker f2.Write(b2) 280*1fa6dee9SAndroid Build Coastguard Worker data, err = exec.Command("diff", "-uw", f1.Name(), f2.Name()).CombinedOutput() 281*1fa6dee9SAndroid Build Coastguard Worker if len(data) > 0 { 282*1fa6dee9SAndroid Build Coastguard Worker // diff exits with a non-zero status when the files don't match. 283*1fa6dee9SAndroid Build Coastguard Worker // Ignore that failure as long as we get output. 284*1fa6dee9SAndroid Build Coastguard Worker err = nil 285*1fa6dee9SAndroid Build Coastguard Worker } 286*1fa6dee9SAndroid Build Coastguard Worker return 287*1fa6dee9SAndroid Build Coastguard Worker} 288*1fa6dee9SAndroid Build Coastguard Worker 289*1fa6dee9SAndroid Build Coastguard Workertype stringPtrFlag struct { 290*1fa6dee9SAndroid Build Coastguard Worker s **string 291*1fa6dee9SAndroid Build Coastguard Worker} 292*1fa6dee9SAndroid Build Coastguard Worker 293*1fa6dee9SAndroid Build Coastguard Workerfunc (f stringPtrFlag) Set(s string) error { 294*1fa6dee9SAndroid Build Coastguard Worker *f.s = &s 295*1fa6dee9SAndroid Build Coastguard Worker return nil 296*1fa6dee9SAndroid Build Coastguard Worker} 297*1fa6dee9SAndroid Build Coastguard Workerfunc (f stringPtrFlag) String() string { 298*1fa6dee9SAndroid Build Coastguard Worker if f.s == nil || *f.s == nil { 299*1fa6dee9SAndroid Build Coastguard Worker return "" 300*1fa6dee9SAndroid Build Coastguard Worker } 301*1fa6dee9SAndroid Build Coastguard Worker return **f.s 302*1fa6dee9SAndroid Build Coastguard Worker} 303*1fa6dee9SAndroid Build Coastguard Worker 304*1fa6dee9SAndroid Build Coastguard Workertype replacements struct { 305*1fa6dee9SAndroid Build Coastguard Worker oldNameToNewName map[string]string 306*1fa6dee9SAndroid Build Coastguard Worker} 307*1fa6dee9SAndroid Build Coastguard Worker 308*1fa6dee9SAndroid Build Coastguard Workerfunc (m *replacements) String() string { 309*1fa6dee9SAndroid Build Coastguard Worker ret := "" 310*1fa6dee9SAndroid Build Coastguard Worker sep := "" 311*1fa6dee9SAndroid Build Coastguard Worker for k, v := range m.oldNameToNewName { 312*1fa6dee9SAndroid Build Coastguard Worker ret += sep 313*1fa6dee9SAndroid Build Coastguard Worker ret += k 314*1fa6dee9SAndroid Build Coastguard Worker ret += ":" 315*1fa6dee9SAndroid Build Coastguard Worker ret += v 316*1fa6dee9SAndroid Build Coastguard Worker sep = "," 317*1fa6dee9SAndroid Build Coastguard Worker } 318*1fa6dee9SAndroid Build Coastguard Worker return ret 319*1fa6dee9SAndroid Build Coastguard Worker} 320*1fa6dee9SAndroid Build Coastguard Worker 321*1fa6dee9SAndroid Build Coastguard Workerfunc (m *replacements) Set(s string) error { 322*1fa6dee9SAndroid Build Coastguard Worker usedNames := make(map[string]struct{}) 323*1fa6dee9SAndroid Build Coastguard Worker 324*1fa6dee9SAndroid Build Coastguard Worker pairs := strings.Split(s, ",") 325*1fa6dee9SAndroid Build Coastguard Worker length := len(pairs) 326*1fa6dee9SAndroid Build Coastguard Worker m.oldNameToNewName = make(map[string]string) 327*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < length; i++ { 328*1fa6dee9SAndroid Build Coastguard Worker 329*1fa6dee9SAndroid Build Coastguard Worker pair := strings.SplitN(pairs[i], "=", 2) 330*1fa6dee9SAndroid Build Coastguard Worker if len(pair) != 2 { 331*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("Invalid replacement pair %s", pairs[i]) 332*1fa6dee9SAndroid Build Coastguard Worker } 333*1fa6dee9SAndroid Build Coastguard Worker oldName := pair[0] 334*1fa6dee9SAndroid Build Coastguard Worker newName := pair[1] 335*1fa6dee9SAndroid Build Coastguard Worker if _, seen := usedNames[oldName]; seen { 336*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("Duplicated replacement name %s", oldName) 337*1fa6dee9SAndroid Build Coastguard Worker } 338*1fa6dee9SAndroid Build Coastguard Worker if _, seen := usedNames[newName]; seen { 339*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("Duplicated replacement name %s", newName) 340*1fa6dee9SAndroid Build Coastguard Worker } 341*1fa6dee9SAndroid Build Coastguard Worker usedNames[oldName] = struct{}{} 342*1fa6dee9SAndroid Build Coastguard Worker usedNames[newName] = struct{}{} 343*1fa6dee9SAndroid Build Coastguard Worker m.oldNameToNewName[oldName] = newName 344*1fa6dee9SAndroid Build Coastguard Worker } 345*1fa6dee9SAndroid Build Coastguard Worker return nil 346*1fa6dee9SAndroid Build Coastguard Worker} 347*1fa6dee9SAndroid Build Coastguard Worker 348*1fa6dee9SAndroid Build Coastguard Workerfunc (m *replacements) Get() interface{} { 349*1fa6dee9SAndroid Build Coastguard Worker //TODO(dacek): Remove Get() method from interface as it seems unused. 350*1fa6dee9SAndroid Build Coastguard Worker return m.oldNameToNewName 351*1fa6dee9SAndroid Build Coastguard Worker} 352*1fa6dee9SAndroid Build Coastguard Worker 353*1fa6dee9SAndroid Build Coastguard Workerfunc (m *replacements) size() (length int) { 354*1fa6dee9SAndroid Build Coastguard Worker return len(m.oldNameToNewName) 355*1fa6dee9SAndroid Build Coastguard Worker} 356*1fa6dee9SAndroid Build Coastguard Worker 357*1fa6dee9SAndroid Build Coastguard Workertype identSet struct { 358*1fa6dee9SAndroid Build Coastguard Worker idents []string 359*1fa6dee9SAndroid Build Coastguard Worker all bool 360*1fa6dee9SAndroid Build Coastguard Worker} 361*1fa6dee9SAndroid Build Coastguard Worker 362*1fa6dee9SAndroid Build Coastguard Workerfunc (m *identSet) String() string { 363*1fa6dee9SAndroid Build Coastguard Worker return strings.Join(m.idents, ",") 364*1fa6dee9SAndroid Build Coastguard Worker} 365*1fa6dee9SAndroid Build Coastguard Workerfunc (m *identSet) Set(s string) error { 366*1fa6dee9SAndroid Build Coastguard Worker m.idents = strings.FieldsFunc(s, func(c rune) bool { 367*1fa6dee9SAndroid Build Coastguard Worker return unicode.IsSpace(c) || c == ',' 368*1fa6dee9SAndroid Build Coastguard Worker }) 369*1fa6dee9SAndroid Build Coastguard Worker if len(m.idents) == 1 && m.idents[0] == "*" { 370*1fa6dee9SAndroid Build Coastguard Worker m.all = true 371*1fa6dee9SAndroid Build Coastguard Worker } 372*1fa6dee9SAndroid Build Coastguard Worker return nil 373*1fa6dee9SAndroid Build Coastguard Worker} 374*1fa6dee9SAndroid Build Coastguard Workerfunc (m *identSet) Get() interface{} { 375*1fa6dee9SAndroid Build Coastguard Worker return m.idents 376*1fa6dee9SAndroid Build Coastguard Worker} 377*1fa6dee9SAndroid Build Coastguard Worker 378*1fa6dee9SAndroid Build Coastguard Workertype qualifiedProperties struct { 379*1fa6dee9SAndroid Build Coastguard Worker properties []qualifiedProperty 380*1fa6dee9SAndroid Build Coastguard Worker} 381*1fa6dee9SAndroid Build Coastguard Worker 382*1fa6dee9SAndroid Build Coastguard Workertype qualifiedProperty struct { 383*1fa6dee9SAndroid Build Coastguard Worker parts []string 384*1fa6dee9SAndroid Build Coastguard Worker} 385*1fa6dee9SAndroid Build Coastguard Worker 386*1fa6dee9SAndroid Build Coastguard Workervar _ flag.Getter = (*qualifiedProperties)(nil) 387*1fa6dee9SAndroid Build Coastguard Worker 388*1fa6dee9SAndroid Build Coastguard Workerfunc (p *qualifiedProperty) name() string { 389*1fa6dee9SAndroid Build Coastguard Worker return p.parts[len(p.parts)-1] 390*1fa6dee9SAndroid Build Coastguard Worker} 391*1fa6dee9SAndroid Build Coastguard Workerfunc (p *qualifiedProperty) prefixes() []string { 392*1fa6dee9SAndroid Build Coastguard Worker return p.parts[:len(p.parts)-1] 393*1fa6dee9SAndroid Build Coastguard Worker} 394*1fa6dee9SAndroid Build Coastguard Workerfunc (p *qualifiedProperty) String() string { 395*1fa6dee9SAndroid Build Coastguard Worker return strings.Join(p.parts, ".") 396*1fa6dee9SAndroid Build Coastguard Worker} 397*1fa6dee9SAndroid Build Coastguard Worker 398*1fa6dee9SAndroid Build Coastguard Workerfunc parseQualifiedProperty(s string) (*qualifiedProperty, error) { 399*1fa6dee9SAndroid Build Coastguard Worker parts := strings.Split(s, ".") 400*1fa6dee9SAndroid Build Coastguard Worker if len(parts) == 0 { 401*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("%q is not a valid property name", s) 402*1fa6dee9SAndroid Build Coastguard Worker } 403*1fa6dee9SAndroid Build Coastguard Worker for _, part := range parts { 404*1fa6dee9SAndroid Build Coastguard Worker if part == "" { 405*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("%q is not a valid property name", s) 406*1fa6dee9SAndroid Build Coastguard Worker } 407*1fa6dee9SAndroid Build Coastguard Worker } 408*1fa6dee9SAndroid Build Coastguard Worker prop := qualifiedProperty{parts} 409*1fa6dee9SAndroid Build Coastguard Worker return &prop, nil 410*1fa6dee9SAndroid Build Coastguard Worker 411*1fa6dee9SAndroid Build Coastguard Worker} 412*1fa6dee9SAndroid Build Coastguard Worker 413*1fa6dee9SAndroid Build Coastguard Workerfunc (p *qualifiedProperties) Set(s string) error { 414*1fa6dee9SAndroid Build Coastguard Worker properties := strings.Split(s, ",") 415*1fa6dee9SAndroid Build Coastguard Worker if len(properties) == 0 { 416*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("%q is not a valid property name", s) 417*1fa6dee9SAndroid Build Coastguard Worker } 418*1fa6dee9SAndroid Build Coastguard Worker 419*1fa6dee9SAndroid Build Coastguard Worker p.properties = make([]qualifiedProperty, len(properties)) 420*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < len(properties); i++ { 421*1fa6dee9SAndroid Build Coastguard Worker tmp, err := parseQualifiedProperty(properties[i]) 422*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 423*1fa6dee9SAndroid Build Coastguard Worker return err 424*1fa6dee9SAndroid Build Coastguard Worker } 425*1fa6dee9SAndroid Build Coastguard Worker p.properties[i] = *tmp 426*1fa6dee9SAndroid Build Coastguard Worker } 427*1fa6dee9SAndroid Build Coastguard Worker return nil 428*1fa6dee9SAndroid Build Coastguard Worker} 429*1fa6dee9SAndroid Build Coastguard Worker 430*1fa6dee9SAndroid Build Coastguard Workerfunc (p *qualifiedProperties) String() string { 431*1fa6dee9SAndroid Build Coastguard Worker arrayLength := len(p.properties) 432*1fa6dee9SAndroid Build Coastguard Worker props := make([]string, arrayLength) 433*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < len(p.properties); i++ { 434*1fa6dee9SAndroid Build Coastguard Worker props[i] = p.properties[i].String() 435*1fa6dee9SAndroid Build Coastguard Worker } 436*1fa6dee9SAndroid Build Coastguard Worker return strings.Join(props, ",") 437*1fa6dee9SAndroid Build Coastguard Worker} 438*1fa6dee9SAndroid Build Coastguard Workerfunc (p *qualifiedProperties) Get() interface{} { 439*1fa6dee9SAndroid Build Coastguard Worker return p.properties 440*1fa6dee9SAndroid Build Coastguard Worker} 441