github.com/metux/go-metabuild@v0.0.0-20240118143255-d9ed5ab697f9/util/jobs/runner.go (about)

     1  package jobs
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	// "sync"
     7  )
     8  
     9  type Runner struct {
    10  	Jobs map[JobId]*RunnerJob
    11  }
    12  
    13  func NewRunner() Runner {
    14  	r := Runner{}
    15  	r.Jobs = make(map[JobId]*RunnerJob)
    16  	return r
    17  }
    18  
    19  func (r Runner) AddJob(id JobId, job Job) error {
    20  	j, err := NewJob(id, job)
    21  	if err != nil {
    22  		log.Println("AddJob: error creating job runner: ", err)
    23  		return err
    24  	}
    25  
    26  	r.Jobs[id] = j
    27  
    28  	for _, walk := range j.Sub {
    29  		r.AddJob(walk.JobId(), walk)
    30  	}
    31  
    32  	return err
    33  }
    34  
    35  // resolve dependencies
    36  func (r Runner) Resolve() error {
    37  	for id, walk := range r.Jobs {
    38  		for _, dwalk := range walk.Job.JobDepends() {
    39  			if d1, ok := r.Jobs[dwalk]; ok {
    40  				walk.Depends = append(walk.Depends, d1)
    41  			} else {
    42  				err := fmt.Errorf("missing dep %s for %s", dwalk, id)
    43  				return err
    44  			}
    45  		}
    46  		for _, subWalk := range walk.Sub {
    47  			subId := subWalk.JobId()
    48  			if d1, ok := r.Jobs[subId]; ok {
    49  				walk.Depends = append(walk.Depends, d1)
    50  			} else {
    51  				err := fmt.Errorf("missing sub dep %s for %s", subId, id)
    52  				return err
    53  			}
    54  		}
    55  	}
    56  	return nil
    57  }
    58  
    59  func (r Runner) Scan() (RunnerJobList, RunnerJobList, RunnerJobList) {
    60  	doneList := RunnerJobList{}
    61  	runnableList := RunnerJobList{}
    62  	waitList := RunnerJobList{}
    63  
    64  	for _, walk := range r.Jobs {
    65  		if walk.Done {
    66  			doneList = append(doneList, walk)
    67  		} else if walk.Runnable() {
    68  			runnableList = append(runnableList, walk)
    69  		} else {
    70  			waitList = append(waitList, walk)
    71  		}
    72  	}
    73  	return doneList, runnableList, waitList
    74  }
    75  
    76  // FIXME: parallel runs
    77  func (r Runner) Run() error {
    78  	if err := r.Resolve(); err != nil {
    79  		return err
    80  	}
    81  
    82  	for true {
    83  		done, runnable, waiting := r.Scan()
    84  		log.Printf("done: %d runnable: %d waiting: %d\n", len(done), len(runnable), len(waiting))
    85  
    86  		if len(runnable) == 0 {
    87  			log.Println("no more waiting. finished")
    88  			if len(waiting) != 0 {
    89  				return fmt.Errorf("some jobs cant run: %d", len(waiting))
    90  			}
    91  			return nil
    92  		}
    93  
    94  		for _, b := range runnable {
    95  			log.Println("Running job", b.Id)
    96  			if err := b.Job.JobRun(); err != nil {
    97  				return err
    98  			}
    99  			b.Done = true
   100  			log.Println("Done job", b.Id)
   101  		}
   102  	}
   103  	return nil
   104  }