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  }