1// Copyright 2018 Google Inc. All rights reserved. 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 15package main 16 17import ( 18 "bytes" 19 "fmt" 20 "io" 21 "strings" 22 23 "android/soong/androidmk/parser" 24) 25 26type Deps struct { 27 Output string 28 Inputs []string 29} 30 31func Parse(filename string, r io.Reader) (*Deps, error) { 32 p := parser.NewParser(filename, r) 33 nodes, errs := p.Parse() 34 35 if len(errs) == 1 { 36 return nil, errs[0] 37 } else if len(errs) > 1 { 38 return nil, fmt.Errorf("many errors: %v", errs) 39 } 40 41 pos := func(node parser.Node) string { 42 return p.Unpack(node.Pos()).String() + ": " 43 } 44 45 ret := &Deps{} 46 47 for _, node := range nodes { 48 switch x := node.(type) { 49 case *parser.Comment: 50 // Do nothing 51 case *parser.Rule: 52 if x.Recipe != "" { 53 return nil, fmt.Errorf("%sunexpected recipe in rule: %v", pos(node), x) 54 } 55 56 if !x.Target.Const() { 57 return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Target.Dump()) 58 } 59 outputs := x.Target.Words() 60 if len(outputs) == 0 { 61 return nil, fmt.Errorf("%smissing output: %v", pos(node), x) 62 } 63 ret.Output = outputs[0].Value(nil) 64 65 if !x.Prerequisites.Const() { 66 return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Prerequisites.Dump()) 67 } 68 for _, input := range x.Prerequisites.Words() { 69 ret.Inputs = append(ret.Inputs, input.Value(nil)) 70 } 71 default: 72 return nil, fmt.Errorf("%sunexpected line: %#v", pos(node), node) 73 } 74 } 75 76 return ret, nil 77} 78 79func (d *Deps) Print() []byte { 80 // We don't really have to escape every \, but it's simpler, 81 // and ninja will handle it. 82 replacer := strings.NewReplacer(" ", "\\ ", 83 ":", "\\:", 84 "#", "\\#", 85 "$", "$$", 86 "\\", "\\\\") 87 88 b := &bytes.Buffer{} 89 fmt.Fprintf(b, "%s:", replacer.Replace(d.Output)) 90 for _, input := range d.Inputs { 91 fmt.Fprintf(b, " %s", replacer.Replace(input)) 92 } 93 fmt.Fprintln(b) 94 return b.Bytes() 95} 96