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 }