github.com/tiagovtristao/plz@v13.4.0+incompatible/src/hashes/rewrite_hashes.go (about) 1 // +build !bootstrap 2 3 package hashes 4 5 import ( 6 "bytes" 7 "encoding/hex" 8 "fmt" 9 "io/ioutil" 10 "runtime" 11 "strings" 12 13 "gopkg.in/op/go-logging.v1" 14 15 "github.com/thought-machine/please/src/build" 16 "github.com/thought-machine/please/src/core" 17 "github.com/thought-machine/please/src/parse/asp" 18 ) 19 20 var log = logging.MustGetLogger("hashes") 21 22 // RewriteHashes rewrites the hashes in a BUILD file. 23 func RewriteHashes(state *core.BuildState, labels []core.BuildLabel) { 24 // Collect the targets per-package so we only rewrite each file once. 25 m := map[*core.Package]map[string]string{} 26 for _, l := range labels { 27 pkg := state.Graph.PackageOrDie(l) 28 for _, target := range pkg.AllChildren(state.Graph.TargetOrDie(l)) { 29 // Ignore targets with no hash specified. 30 if len(target.Hashes) == 0 { 31 continue 32 } 33 h, err := build.OutputHash(state, target) 34 if err != nil { 35 log.Fatalf("%s\n", err) 36 } 37 // Interior targets won't appear in the BUILD file directly, look for their parent instead. 38 l := target.Label.Parent() 39 hashStr := hex.EncodeToString(h) 40 if m2, present := m[pkg]; present { 41 m2[l.Name] = hashStr 42 } else { 43 m[pkg] = map[string]string{l.Name: hashStr} 44 } 45 } 46 } 47 for pkg, hashes := range m { 48 if err := rewriteHashes(state, pkg.Filename, runtime.GOOS+"_"+runtime.GOARCH, hashes); err != nil { 49 log.Fatalf("%s\n", err) 50 } 51 } 52 } 53 54 // rewriteHashes rewrites hashes in a single file. 55 func rewriteHashes(state *core.BuildState, filename, platform string, hashes map[string]string) error { 56 log.Notice("Rewriting hashes in %s...", filename) 57 p := asp.NewParser(nil) 58 stmts, err := p.ParseFileOnly(filename) 59 if err != nil { 60 return err 61 } 62 b, err := ioutil.ReadFile(filename) 63 if err != nil { 64 return err 65 } 66 lines := bytes.Split(b, []byte{'\n'}) 67 for k, v := range hashes { 68 if err := rewriteHash(lines, stmts, platform, k, v); err != nil { 69 return err 70 } 71 } 72 return ioutil.WriteFile(filename, bytes.Join(lines, []byte{'\n'}), 0664) 73 } 74 75 // rewriteHash rewrites a single hash on a statement. 76 func rewriteHash(lines [][]byte, stmts []*asp.Statement, platform, name, hash string) error { 77 stmt := asp.FindTarget(stmts, name) 78 if stmt == nil { 79 return fmt.Errorf("Can't find target %s to rewrite", name) 80 } else if arg := asp.FindArgument(stmt, "hash", "hashes"); arg != nil { 81 if arg.Value.Val != nil && arg.Value.Val.List != nil { 82 for _, h := range arg.Value.Val.List.Values { 83 if line, ok := rewriteLine(lines[h.Pos.Line-1], h.Pos.Column, platform, h.Val.String, hash); ok { 84 lines[h.Pos.Line-1] = line 85 return nil 86 } 87 } 88 } else if arg.Value.Val != nil && arg.Value.Val.String != "" { 89 h := arg.Value 90 if line, ok := rewriteLine(lines[h.Pos.Line-1], h.Pos.Column, platform, h.Val.String, hash); ok { 91 lines[h.Pos.Line-1] = line 92 return nil 93 } 94 } 95 } 96 if platform != "" { 97 return rewriteHash(lines, stmts, "", name, hash) 98 } 99 return fmt.Errorf("Can't find hash or hashes argument on %s", name) 100 } 101 102 // rewriteLine implements the rewriting logic within a single line. 103 // It returns the new line and true if it should be replaced, or false if not. 104 func rewriteLine(line []byte, start int, platform, current, new string) ([]byte, bool) { 105 current = strings.Trim(current, `"`) // asp string literals are surrounded by quotes 106 if strings.HasPrefix(current, platform) { 107 if platform != "" { 108 new = platform + ": " + new 109 } 110 return bytes.Join([][]byte{line[:start], []byte(new), line[start+len(current):]}, nil), true 111 } 112 return nil, false 113 }