package byg import ( "context" "log" "sync" "golang.org/x/sync/errgroup" ) type buildStep struct { name string tasks []StepExecuteFunc } type Builder struct { steps []*buildStep addmu sync.RWMutex } func New() *Builder { return &Builder{ steps: make([]*buildStep, 0), } } type Context struct{} type StepExecuteFunc func(ctx Context) error type Step struct { Execute StepExecuteFunc } func (bb *Builder) Step(name string, steps ...Step) *Builder { bb.addmu.Lock() defer bb.addmu.Unlock() bs := &buildStep{ name: name, tasks: make([]StepExecuteFunc, 0), } for _, st := range steps { bs.tasks = append(bs.tasks, st.Execute) } bb.steps = append(bb.steps, bs) return bb } func (bb *Builder) Execute(ctx context.Context) error { bb.addmu.Lock() defer bb.addmu.Unlock() for _, step := range bb.steps { log.Printf("executing step: %s", step.name) errgroup, _ := errgroup.WithContext(ctx) for _, task := range step.tasks { func(task StepExecuteFunc) { errgroup.Go(func() error { return task(Context{}) }) }(task) } if err := errgroup.Wait(); err != nil { return err } } return nil }