@ -20,26 +20,40 @@ import (
const buildIDSeparator = "/"
// splitActionID returns the action ID half of a build ID, the first component .
// splitActionID returns the action ID half of a build ID, the first hash .
func splitActionID ( buildID string ) string {
return buildID [ : strings . Index ( buildID , buildIDSeparator ) ]
}
// splitContentID returns the content ID half of a build ID, the last component .
// splitContentID returns the content ID half of a build ID, the last hash .
func splitContentID ( buildID string ) string {
return buildID [ strings . LastIndex ( buildID , buildIDSeparator ) + 1 : ]
}
// decodeHash is the opposite of hashToString, with a panic for error handling
// since it should never happen.
func decodeHash ( str string ) [ ] byte {
// buildIDHashLength is the number of bytes each build ID hash takes,
// such as an action ID or a content ID.
const buildIDHashLength = 15
// decodeBuildIDHash decodes a build ID hash in base64, just like cmd/go does.
func decodeBuildIDHash ( str string ) [ ] byte {
h , err := base64 . RawURLEncoding . DecodeString ( str )
if err != nil {
panic ( fmt . Sprintf ( "invalid hash %q: %v" , str , err ) )
}
if len ( h ) != buildIDHashLength {
panic ( fmt . Sprintf ( "decodeHash expects to result in a hash of length %d, got %d" , buildIDHashLength , len ( h ) ) )
}
return h
}
// encodeBuildIDHash encodes a build ID hash in base64, just like cmd/go does.
func encodeBuildIDHash ( h [ ] byte ) string {
if len ( h ) != buildIDHashLength {
panic ( fmt . Sprintf ( "hashToString expects a hash of length %d, got %d" , buildIDHashLength , len ( h ) ) )
}
return base64 . RawURLEncoding . EncodeToString ( h )
}
func alterToolVersion ( tool string , args [ ] string ) error {
cmd := exec . Command ( args [ 0 ] , args [ 1 : ] ... )
out , err := cmd . Output ( )
@ -57,7 +71,7 @@ func alterToolVersion(tool string, args []string) error {
var toolID [ ] byte
if f [ 2 ] == "devel" {
// On the development branch, use the content ID part of the build ID.
toolID = decode Hash( splitContentID ( f [ len ( f ) - 1 ] ) )
toolID = decode BuildID Hash( splitContentID ( f [ len ( f ) - 1 ] ) )
} else {
// For a release, the output is like: "compile version go1.9.1 X:framepointer".
// Use the whole line, as we can assume it's unique.
@ -70,9 +84,9 @@ func alterToolVersion(tool string, args []string) error {
// the action (build) or not. Since cmd/go parses the last word in the
// output as "buildID=...", we simply add "+garble buildID=_/_/_/${hash}".
// The slashes let us imitate a full binary build ID, but we assume that
// the other component s such as the action ID are not necessary, since the
// the other hashe s such as the action ID are not necessary, since the
// only reader here is cmd/go and it only consumes the content ID.
fmt . Printf ( "%s +garble buildID=_/_/_/%s\n" , line , hashToString ( contentID ) )
fmt . Printf ( "%s +garble buildID=_/_/_/%s\n" , line , encodeBuildIDHash ( contentID ) )
return nil
}
@ -106,7 +120,7 @@ func addGarbleToHash(inputHash []byte) []byte {
// addGarbleToHash returns the sum buffer, so we need a new copy.
// Otherwise the next use of the global sumBuffer would conflict.
sumBuffer := make ( [ ] byte , 0 , sha256 . Size )
return hasher . Sum ( sumBuffer ) [ : buildID Component Length]
return hasher . Sum ( sumBuffer ) [ : buildID Hash Length]
}
// appendFlags writes garble's own flags to w in string form.
@ -151,16 +165,6 @@ func appendFlags(w io.Writer, forBuildHash bool) {
}
}
// buildIDComponentLength is the number of bytes each build ID component takes,
// such as an action ID or a content ID.
const buildIDComponentLength = 15
// hashToString encodes the first 120 bits of a sha256 sum in base64, the same
// format used for components in a build ID.
func hashToString ( h [ ] byte ) string {
return base64 . RawURLEncoding . EncodeToString ( h [ : buildIDComponentLength ] )
}
func buildidOf ( path string ) ( string , error ) {
cmd := exec . Command ( "go" , "tool" , "buildid" , path )
out , err := cmd . Output ( )