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  }