github.com/replicatedhq/ship@v0.55.0/pkg/specs/patch.go (about)

     1  package specs
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/go-kit/kit/log"
     7  	"github.com/go-kit/kit/log/level"
     8  	"github.com/replicatedhq/ship/pkg/api"
     9  	"github.com/replicatedhq/ship/pkg/templates"
    10  )
    11  
    12  func NewIDPatcher(logger log.Logger) *IDPatcher {
    13  	return &IDPatcher{
    14  		Logger: log.With(logger, "struct", "idpatcher"),
    15  	}
    16  }
    17  
    18  type IDPatcher struct {
    19  	Logger log.Logger
    20  }
    21  
    22  type idSet map[string]interface{}
    23  
    24  func (s idSet) contains(id string) bool {
    25  	_, ok := s[id]
    26  	return ok
    27  
    28  }
    29  
    30  func (s idSet) add(id string) {
    31  	s[id] = true
    32  }
    33  
    34  func (p *IDPatcher) EnsureAllStepsHaveUniqueIDs(lc api.Lifecycle) api.Lifecycle {
    35  
    36  	newLc := api.Lifecycle{V1: []api.Step{}}
    37  	seenIds := make(idSet)
    38  	for _, step := range lc.V1 {
    39  		id := step.Shared().ID
    40  		if id != "" && !seenIds.contains(id) {
    41  			// the id is unique, add it to the ones we've seen, and append this step to the new lifecycle
    42  			seenIds.add(id)
    43  			newLc.V1 = append(newLc.V1, step)
    44  			continue
    45  		}
    46  
    47  		// the current step's id is missing or a duplicate, so generate a new one
    48  		newID := p.generateID(seenIds, step)
    49  		level.Debug(p.Logger).Log("event", "id.generate", "id", newID)
    50  		seenIds.add(newID)
    51  		step.Shared().ID = newID
    52  		newLc.V1 = append(newLc.V1, step)
    53  	}
    54  	return newLc
    55  }
    56  
    57  func (p *IDPatcher) generateID(seenIds idSet, step api.Step) string {
    58  	// try with the $shortname
    59  	candidateID := step.ShortName()
    60  	if !seenIds.contains(candidateID) {
    61  		return candidateID
    62  	}
    63  
    64  	// try ${shortname}-2 ${shortname}-3 up to 99
    65  	i := 2
    66  	for i < 100 {
    67  		candidateID := fmt.Sprintf("%s-%d", step.ShortName(), i)
    68  		if !seenIds.contains(candidateID) {
    69  			return candidateID
    70  		}
    71  		i++
    72  	}
    73  
    74  	// hack, just get a random one
    75  	return fmt.Sprintf(
    76  		"%s-%s",
    77  		step.ShortName(),
    78  		(&templates.StaticCtx{Logger: p.Logger}).RandomString(12),
    79  	)
    80  }