github.com/getgauge/gauge@v1.6.9/template/template.go (about) 1 /*---------------------------------------------------------------- 2 * Copyright (c) ThoughtWorks, Inc. 3 * Licensed under the Apache License, Version 2.0 4 * See LICENSE in the project root for license information. 5 *----------------------------------------------------------------*/ 6 7 package template 8 9 import ( 10 "fmt" 11 "net/url" 12 "path/filepath" 13 "sort" 14 "strings" 15 16 "github.com/getgauge/common" 17 "github.com/getgauge/gauge/config" 18 19 "github.com/schollz/closestmatch" 20 ) 21 22 const templateProperties = "template.properties" 23 24 type templates struct { 25 t map[string]*config.Property 26 names []string 27 } 28 29 func (t *templates) String() (string, error) { 30 var buffer strings.Builder 31 for _, k := range t.names { 32 v := t.t[k] 33 _, err := buffer.WriteString(fmt.Sprintf("\n# %s\n%s = %s\n", v.Description, v.Key, v.Value)) 34 if err != nil { 35 return "", err 36 } 37 } 38 return buffer.String(), nil 39 } 40 41 func (t *templates) update(k, v string, validate bool) error { 42 if validate { 43 if _, err := url.ParseRequestURI(v); err != nil { 44 return fmt.Errorf("Failed to add template '%s'. The template location must be a valid (https) URI", k) 45 } 46 } 47 if _, ok := t.t[k]; ok { 48 t.t[k].Value = v 49 } else { 50 t.t[k] = config.NewProperty(k, v, fmt.Sprintf("Template download information for gauge %s projects", k)) 51 t.names = append(t.names, k) 52 } 53 sort.Strings(t.names) 54 return nil 55 } 56 57 func (t *templates) get(k string) (string, error) { 58 if _, ok := t.t[k]; ok { 59 return t.t[k].Value, nil 60 } 61 matches := t.closestMatch(k) 62 if len(matches) > 0 { 63 return "", fmt.Errorf("Cannot find Gauge template '%s'.\nThe most similar template names are\n\n\t%s", k, strings.Join(matches, "\n\t")) 64 } 65 return "", fmt.Errorf("Cannot find Gauge template '%s'", k) 66 } 67 68 func (t *templates) closestMatch(k string) []string { 69 matches := []string{} 70 cm := closestmatch.New(t.names, []int{2}) 71 for _, m := range cm.ClosestN(k, 5) { 72 if m != "" { 73 matches = append(matches, m) 74 } 75 } 76 sort.Strings(matches) 77 return matches 78 } 79 80 func (t *templates) write() error { 81 s, err := t.String() 82 if err != nil { 83 return err 84 } 85 return config.Write(s, templateProperties) 86 } 87 88 func Update(name, value string) error { 89 t, err := getTemplates() 90 if err != nil { 91 return err 92 } 93 if err := t.update(name, value, true); err != nil { 94 return err 95 } 96 return t.write() 97 } 98 99 func Generate() error { 100 cd, err := common.GetConfigurationDir() 101 if err != nil { 102 return err 103 } 104 if !common.FileExists(filepath.Join(cd, templateProperties)) { 105 return defaults().write() 106 } 107 return nil 108 } 109 110 func Get(name string) (string, error) { 111 mp, err := getTemplates() 112 if err != nil { 113 return "", err 114 } 115 return mp.get(name) 116 } 117 118 func All() (string, error) { 119 t, err := getTemplates() 120 if err != nil { 121 return "", err 122 } 123 return strings.Join(t.names, "\n"), nil 124 } 125 126 func List(machineReadable bool) (string, error) { 127 var f config.Formatter 128 f = config.TextFormatter{Headers: []string{"Template Name", "Location"}} 129 if machineReadable { 130 f = config.JsonFormatter{} 131 } 132 t, err := getTemplates() 133 if err != nil { 134 return "", err 135 } 136 var all []config.Property 137 for _, v := range t.t { 138 all = append(all, *v) 139 } 140 return f.Format(all) 141 } 142 143 func defaults() *templates { 144 prop := map[string]*config.Property{ 145 "dotnet": getProperty("template-dotnet", "dotnet"), 146 "java": getProperty("template-java", "java"), 147 "java_gradle": getProperty("template-java-gradle", "java_gradle"), 148 "java_maven": getProperty("template-java-maven", "java_maven"), 149 "java_maven_selenium": getProperty("template-java-maven-selenium", "java_maven_selenium"), 150 "js": getProperty("template-js", "js"), 151 "js_simple": getProperty("template-js-simple", "js_simple"), 152 "python": getProperty("template-python", "python"), 153 "python_selenium": getProperty("template-python-selenium", "python_selenium"), 154 "ruby": getProperty("template-ruby", "ruby"), 155 "ruby_selenium": getProperty("template-ruby-selenium", "ruby_selenium"), 156 "ts": getProperty("template-ts", "ts"), 157 } 158 return &templates{t: prop, names: getKeys(prop)} 159 } 160 161 func getKeys(prop map[string]*config.Property) []string { 162 var keys []string 163 for k := range prop { 164 keys = append(keys, k) 165 } 166 sort.Strings(keys) 167 return keys 168 } 169 170 func getTemplates() (*templates, error) { 171 prop, err := common.GetGaugeConfigurationFor(templateProperties) 172 if err != nil { 173 return nil, err 174 } 175 t := &templates{t: make(map[string]*config.Property), names: []string{}} 176 for k, v := range prop { 177 if err := t.update(k, v, false); err != nil { 178 return nil, err 179 } 180 } 181 return t, nil 182 } 183 184 func getProperty(repoName, templateName string) *config.Property { 185 f := "https://github.com/getgauge/%s/releases/latest/download/%s.zip" 186 templateURL := fmt.Sprintf(f, repoName, templateName) 187 desc := fmt.Sprintf("Template for gauge %s projects", templateName) 188 return config.NewProperty(templateName, templateURL, desc) 189 }