github.com/benchkram/bob@v0.0.0-20240314204020-b7a57f2f9be9/bob/playbook/sync_artifacts.go (about)

     1  package playbook
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/benchkram/bob/bobtask"
     9  	"github.com/benchkram/bob/bobtask/hash"
    10  	"github.com/benchkram/bob/pkg/boblog"
    11  	"github.com/benchkram/bob/pkg/store"
    12  	"github.com/benchkram/bob/pkg/usererror"
    13  	"github.com/logrusorgru/aurora"
    14  )
    15  
    16  // TaskKey is key for context values passed to client for upload/download output formatting
    17  type TaskKey string
    18  
    19  func (p *Playbook) pullArtifact(ctx context.Context, a hash.In, task *bobtask.Task, ignoreLocal bool) error {
    20  	if !(p.enablePull && p.enableCaching && p.remoteStore != nil && p.localStore != nil) {
    21  		return nil
    22  	}
    23  
    24  	description := fmt.Sprintf("%-*s\t  %s", p.namePad, task.ColoredName(), aurora.Faint("pulling artifact "+a.String()))
    25  	ctx = context.WithValue(ctx, TaskKey("description"), description)
    26  	return pull(ctx, p.remoteStore, p.localStore, a, p.namePad, task, ignoreLocal)
    27  }
    28  
    29  func (p *Playbook) pushArtifact(ctx context.Context, a hash.In, taskName string) error {
    30  	if !(p.enableCaching && p.remoteStore != nil && p.localStore != nil) {
    31  		return nil
    32  	}
    33  
    34  	description := fmt.Sprintf("  %-*s\t%s", p.namePad, taskName, aurora.Faint("pushing artifact "+a.String()))
    35  	ctx = context.WithValue(ctx, TaskKey("description"), description)
    36  	return push(ctx, p.localStore, p.remoteStore, a, taskName, p.namePad)
    37  }
    38  
    39  // pull syncs the artifact from the remote store to the local store.
    40  // if ignoreAlreadyExists is true it will ignore local artifact and perform a fresh download
    41  func pull(ctx context.Context, remote store.Store, local store.Store, a hash.In, namePad int, task *bobtask.Task, ignoreAlreadyExists bool) error {
    42  	err := store.Sync(ctx, remote, local, a.String(), ignoreAlreadyExists)
    43  	if errors.Is(err, store.ErrArtifactAlreadyExists) {
    44  		boblog.Log.V(5).Info(fmt.Sprintf("artifact already exists locally [artifactId: %s]. skipping...", a.String()))
    45  	} else if errors.Is(err, store.ErrArtifactNotFoundinSrc) {
    46  		boblog.Log.V(5).Info(fmt.Sprintf("failed to pull [artifactId: %s]", a.String()))
    47  	} else if errors.Is(err, context.Canceled) {
    48  		return usererror.Wrap(err)
    49  	} else if err != nil {
    50  		fmt.Printf("%-*s\t%s\n",
    51  			namePad,
    52  			task.ColoredName(),
    53  			aurora.Red(fmt.Errorf("failed pull [artifactId: %s]: %w", a.String(), err)),
    54  		)
    55  	}
    56  
    57  	boblog.Log.V(5).Info(fmt.Sprintf("pull succeeded [artifactId: %s]", a.String()))
    58  	return nil
    59  }
    60  
    61  // push syncs the artifact from the local store to the remote store.
    62  func push(ctx context.Context, local store.Store, remote store.Store, a hash.In, taskName string, namePad int) error {
    63  	err := store.Sync(ctx, local, remote, a.String(), false)
    64  	if errors.Is(err, store.ErrArtifactAlreadyExists) {
    65  		boblog.Log.V(5).Info(fmt.Sprintf("artifact already exists on the remote [artifactId: %s]. skipping...", a.String()))
    66  		return nil
    67  	} else if errors.Is(err, context.Canceled) {
    68  		return nil // cancel err is handled after remote.Done()
    69  	} else if err != nil {
    70  		return fmt.Errorf("  %-*s\tfailed push [artifactId: %s]: %w", namePad, taskName, a.String(), err)
    71  	}
    72  
    73  	// wait for the remote store to finish uploading this artifact. can be moved outside the for loop, but then
    74  	// we don't know which artifacts failed to upload.
    75  	err = remote.Done()
    76  	if err != nil {
    77  		return fmt.Errorf("  %-*s\tfailed push [artifactId: %s]: cancelled", namePad, taskName, a.String())
    78  	}
    79  	boblog.Log.V(5).Info(fmt.Sprintf("push succeeded [artifactId: %s]", a.String()))
    80  	return nil
    81  }