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 }