github.com/bilus/oya@v0.0.3-0.20190301162104-da4acbd394c6/pkg/mvs/mvs.go (about)

     1  package mvs
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/bilus/oya/pkg/mvs/internal"
     8  	"github.com/bilus/oya/pkg/pack"
     9  	"github.com/bilus/oya/pkg/types"
    10  )
    11  
    12  type Reqs interface {
    13  	Reqs(pack pack.Pack) ([]pack.Pack, error)
    14  }
    15  
    16  func max(p1, p2 pack.Pack) pack.Pack {
    17  	if p1.Version().LessThan(p2.Version()) {
    18  		return p2
    19  	} else {
    20  		return p1
    21  	}
    22  }
    23  
    24  func Hash(pack pack.Pack) string {
    25  	return fmt.Sprintf("%v@%v", pack.ImportPath(), pack.Version())
    26  }
    27  
    28  type Job struct {
    29  	pack.Pack
    30  }
    31  
    32  func (j Job) Payload() interface{} {
    33  	return j.Pack
    34  }
    35  
    36  func (j Job) ID() interface{} {
    37  	return Hash(j.Pack)
    38  }
    39  
    40  // List creates a list of requirements based on initial list of required packs, taking inter-pack requirements into account.
    41  func List(required []pack.Pack, reqs Reqs) ([]pack.Pack, error) {
    42  	mtx := sync.Mutex{}
    43  	latest := make(map[types.ImportPath]pack.Pack)
    44  	queue := internal.Work{}
    45  	for _, r := range required {
    46  		queue.Add(Job{r})
    47  	}
    48  	var firstErr error
    49  	queue.Do(10,
    50  		func(job internal.Job) {
    51  			if firstErr != nil {
    52  				return
    53  			}
    54  			mtx.Lock()
    55  			crnt, ok := job.Payload().(pack.Pack)
    56  			if !ok {
    57  				mtx.Unlock()
    58  				panic("Internal error: expected pack.Pack passed to work queue")
    59  			}
    60  			if l, ok := latest[crnt.ImportPath()]; !ok || Hash(max(l, crnt)) != Hash(l) {
    61  				latest[crnt.ImportPath()] = crnt
    62  			}
    63  			mtx.Unlock()
    64  
    65  			reqs, err := reqs.Reqs(crnt)
    66  			if err != nil {
    67  				firstErr = err
    68  				return
    69  			}
    70  
    71  			for _, req := range reqs {
    72  				queue.Add(Job{req})
    73  			}
    74  		})
    75  
    76  	if firstErr != nil {
    77  		return nil, firstErr
    78  	}
    79  
    80  	packs := make([]pack.Pack, 0)
    81  	for _, pack := range latest {
    82  		packs = append(packs, pack)
    83  	}
    84  	return packs, nil
    85  }