github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/command/expansion.go (about) 1 package command 2 3 import ( 4 "io/ioutil" 5 "regexp" 6 "strings" 7 8 "github.com/pkg/errors" 9 yaml "gopkg.in/yaml.v2" 10 ) 11 12 var ( 13 expansionRegex = regexp.MustCompile(`\$\{.*?\}`) 14 ) 15 16 // Wrapper for an expansions map, with some utility functions. 17 type Expansions map[string]string 18 19 // Return a new Expansions object with all of the specified expansions present. 20 func NewExpansions(initMap map[string]string) *Expansions { 21 exp := Expansions(map[string]string{}) 22 exp.Update(initMap) 23 return &exp 24 } 25 26 // Update all of the specified keys in the expansions to point to the specified 27 // values. 28 func (self *Expansions) Update(newItems map[string]string) { 29 for k, v := range newItems { 30 self.Put(k, v) 31 } 32 } 33 34 // Read a map of keys/values from the given file, and update the expansions 35 // to include them (overwriting any duplicates with the new value). 36 func (self *Expansions) UpdateFromYaml(filename string) error { 37 filedata, err := ioutil.ReadFile(filename) 38 if err != nil { 39 return err 40 } 41 newExpansions := make(map[string]string) 42 err = yaml.Unmarshal(filedata, newExpansions) 43 if err != nil { 44 return err 45 } 46 self.Update(newExpansions) 47 return nil 48 } 49 50 // Set a single value in the expansions. 51 func (self *Expansions) Put(expansion string, value string) { 52 (*self)[expansion] = value 53 } 54 55 // Get a single value from the expansions. 56 // Return the value, or the empty string if the value is not present. 57 func (self *Expansions) Get(expansion string) string { 58 if self.Exists(expansion) { 59 return (*self)[expansion] 60 } 61 return "" 62 } 63 64 // Check if a value is present in the expansions. 65 func (self *Expansions) Exists(expansion string) bool { 66 _, ok := (*self)[expansion] 67 return ok 68 } 69 70 // Apply the expansions to a single string. 71 // Return the expanded string, or an error if the input string is malformed. 72 func (self *Expansions) ExpandString(toExpand string) (string, error) { 73 // replace all expandable parts of the string 74 malformedFound := false 75 expanded := string(expansionRegex.ReplaceAllFunc([]byte(toExpand), 76 func(matchByte []byte) []byte { 77 78 match := string(matchByte) 79 // trim off ${ and } 80 match = match[2 : len(match)-1] 81 82 // if there is a ${ within the match, then it is malformed (we 83 // caught an unmatched ${) 84 if strings.Contains(match, "${") { 85 malformedFound = true 86 } 87 88 // parse into the name and default value 89 var defaultVal string 90 if idx := strings.Index(match, "|"); idx != -1 { 91 defaultVal = match[idx+1:] 92 match = match[0:idx] 93 } 94 95 // return the specified expansion, if it is present. 96 if self.Exists(match) { 97 return []byte(self.Get(match)) 98 } 99 100 return []byte(defaultVal) 101 })) 102 103 if malformedFound || strings.Contains(expanded, "${") { 104 return expanded, errors.Errorf("'%s' contains an unclosed expansion", expanded) 105 } 106 107 return expanded, nil 108 }