github.com/Benchkram/bob@v0.0.0-20220321080157-7c8f3876e225/bobtask/hash_in.go (about)

     1  package bobtask
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"sort"
    10  	"strings"
    11  
    12  	"github.com/Benchkram/bob/bobtask/hash"
    13  	"github.com/Benchkram/bob/pkg/filehash"
    14  	"gopkg.in/yaml.v2"
    15  )
    16  
    17  // HashIn computes a hash containing inputs, environment and the task description.
    18  func (t *Task) HashIn() (taskHash hash.In, _ error) {
    19  	if t.hashIn != nil {
    20  		return *t.hashIn, nil
    21  	}
    22  
    23  	aggregatedHashes := bytes.NewBuffer([]byte{})
    24  
    25  	// Hash input files
    26  	for _, f := range t.inputs {
    27  		h, err := filehash.Hash(f)
    28  		if err != nil {
    29  			if errors.Is(err, os.ErrPermission) {
    30  				t.addToSkippedInputs(f)
    31  				continue
    32  			} else {
    33  				return taskHash, fmt.Errorf("failed to hash file %q: %w", f, err)
    34  			}
    35  		}
    36  
    37  		_, err = aggregatedHashes.Write(h)
    38  		if err != nil {
    39  			return taskHash, fmt.Errorf("failed to write file hash to aggregated hash %q: %w", f, err)
    40  		}
    41  	}
    42  
    43  	// Hash the public task description
    44  	description, err := yaml.Marshal(t)
    45  	if err != nil {
    46  		return taskHash, fmt.Errorf("failed to marshal task: %w", err)
    47  	}
    48  	descriptionHash, err := filehash.HashBytes(bytes.NewBuffer(description))
    49  	if err != nil {
    50  		return taskHash, fmt.Errorf("failed to write description hash: %w", err)
    51  	}
    52  	_, err = aggregatedHashes.Write(descriptionHash)
    53  	if err != nil {
    54  		return taskHash, fmt.Errorf("failed to write task description to aggregated hash: %w", err)
    55  	}
    56  
    57  	// Hash the environment
    58  	sort.Strings(t.env)
    59  	environment := strings.Join(t.env, ",")
    60  	environmentHash, err := filehash.HashBytes(bytes.NewBufferString(environment))
    61  	if err != nil {
    62  		return taskHash, fmt.Errorf("failed to write description hash: %w", err)
    63  	}
    64  	_, err = aggregatedHashes.Write(environmentHash)
    65  	if err != nil {
    66  		return taskHash, fmt.Errorf("failed to write task environment to aggregated hash: %w", err)
    67  	}
    68  
    69  	// Summarize
    70  	h, err := filehash.HashBytes(aggregatedHashes)
    71  	if err != nil {
    72  		return taskHash, fmt.Errorf("failed to write aggregated hash: %w", err)
    73  	}
    74  
    75  	hashIn := hash.In(hex.EncodeToString(h))
    76  
    77  	// store hash for reuse
    78  	t.hashIn = &hashIn
    79  
    80  	return hashIn, nil
    81  }