Skip to content

Commit 2ad875c

Browse files
committed
Pull templates from store when not present
Implements a user-experience changes: faas-cli new - when the templates folder is not present the language will be looked up in the template store using the default URL or an overriden one. faas-cli publish - when no template folder is available then a pull will be carried out if a configuration section is present with a template given within in Filtering - whilst there is no way to avoid pulling all the templates wihtin a repository, only the requested/needed ones are expanded by commands like faas-cli new. Tested mainly with existing-unit tests, faas-cli new / publish with and without a templates folder. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <[email protected]>
1 parent b368a1c commit 2ad875c

File tree

10 files changed

+132
-104
lines changed

10 files changed

+132
-104
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@ Find templates with: `faas-cli template store list`
216216

217217
> Note: You can set your own custom store location with `--url` flag or set `OPENFAAS_TEMPLATE_STORE_URL` environmental variable
218218
219-
To pull templates from the store just write the name of the template you want `faas-cli template store pull go` or the repository and name `faas-cli template store pull openfaas/go`
219+
To pull templates from the store just write the name of the template you want `faas-cli template store pull golang-middleware` or the repository and name `faas-cli template store pull openfaas/golang-middleware`
220220

221-
To get more detail on a template just use the `template store describe` command and pick a template of your choice, example with `go` would look like this `faas-cli template store describe go`
221+
To get more detail on a template just use the `template store describe` command and pick a template of your choice, example with `go` would look like this `faas-cli template store describe golang-middleware`
222222

223223
> Note: This feature is still in experimental stage and in the future the CLI verbs might be changed
224224

commands/build.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package commands
55

66
import (
77
"fmt"
8-
"log"
98
"os"
109
"strings"
1110
"sync"
@@ -155,6 +154,8 @@ func parseBuildArgs(args []string) (map[string]string, error) {
155154

156155
func runBuild(cmd *cobra.Command, args []string) error {
157156

157+
templateName := "" // templateName may not be known at this point
158+
158159
var services stack.Services
159160
if len(yamlFile) > 0 {
160161
parsedServices, err := stack.ParseYAMLFile(yamlFile, regex, filter, envsubst)
@@ -178,7 +179,7 @@ func runBuild(cmd *cobra.Command, args []string) error {
178179
}
179180
} else {
180181
templateAddress := getTemplateURL("", os.Getenv(templateURLEnvironment), DefaultTemplateRepository)
181-
if pullErr := pullTemplates(templateAddress); pullErr != nil {
182+
if pullErr := pullTemplates(templateAddress, templateName); pullErr != nil {
182183
return fmt.Errorf("could not pull templates for OpenFaaS: %v", pullErr)
183184
}
184185
}
@@ -304,20 +305,19 @@ func build(services *stack.Services, queueDepth int, shrinkwrap, quietBuild bool
304305
}
305306

306307
// pullTemplates pulls templates from specified git remote. templateURL may be a pinned repository.
307-
func pullTemplates(templateURL string) error {
308-
var err error
309-
exists, err := os.Stat("./template")
310-
if err != nil || exists == nil {
311-
log.Println("No templates found in current directory.")
308+
func pullTemplates(templateURL, templateName string) error {
309+
310+
if _, err := os.Stat("./template"); err != nil && os.IsNotExist(err) {
311+
312+
fmt.Printf("No templates found in current directory.\n")
312313

313314
templateURL, refName := versioncontrol.ParsePinnedRemote(templateURL)
314-
err = fetchTemplates(templateURL, refName, false)
315-
if err != nil {
316-
log.Println("Unable to download templates from Github.")
315+
if err := fetchTemplates(templateURL, refName, templateName, false); err != nil {
317316
return err
318317
}
319318
}
320-
return err
319+
320+
return nil
321321
}
322322

323323
func combineBuildOpts(YAMLBuildOpts []string, buildFlagBuildOpts []string) []string {

commands/fetch_templates.go

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package commands
55

66
import (
77
"fmt"
8-
"io/ioutil"
98
"log"
109
"os"
1110
"path/filepath"
@@ -20,21 +19,22 @@ const DefaultTemplateRepository = "https://github.com/openfaas/templates.git"
2019
const templateDirectory = "./template/"
2120

2221
// fetchTemplates fetch code templates using git clone.
23-
func fetchTemplates(templateURL string, refName string, overwrite bool) error {
22+
func fetchTemplates(templateURL, refName, templateName string, overwrite bool) error {
2423
if len(templateURL) == 0 {
2524
return fmt.Errorf("pass valid templateURL")
2625
}
2726

2827
dir, err := os.MkdirTemp("", "openfaas-templates-*")
2928
if err != nil {
30-
log.Fatal(err)
29+
return err
3130
}
31+
3232
if !pullDebug {
33-
defer os.RemoveAll(dir) // clean up
33+
defer os.RemoveAll(dir)
3434
}
3535

36-
log.Printf("Attempting to expand templates from %s\n", templateURL)
3736
pullDebugPrint(fmt.Sprintf("Temp files in %s", dir))
37+
3838
args := map[string]string{"dir": dir, "repo": templateURL}
3939
cmd := versioncontrol.GitCloneDefault
4040

@@ -47,7 +47,7 @@ func fetchTemplates(templateURL string, refName string, overwrite bool) error {
4747
return err
4848
}
4949

50-
preExistingLanguages, fetchedLanguages, err := moveTemplates(dir, overwrite)
50+
preExistingLanguages, fetchedLanguages, err := moveTemplates(dir, templateName, overwrite)
5151
if err != nil {
5252
return err
5353
}
@@ -56,7 +56,7 @@ func fetchTemplates(templateURL string, refName string, overwrite bool) error {
5656
log.Printf("Cannot overwrite the following %d template(s): %v\n", len(preExistingLanguages), preExistingLanguages)
5757
}
5858

59-
log.Printf("Fetched %d template(s) : %v from %s\n", len(fetchedLanguages), fetchedLanguages, templateURL)
59+
fmt.Printf("Wrote %d template(s) : %v from %s\n", len(fetchedLanguages), fetchedLanguages, templateURL)
6060

6161
return err
6262
}
@@ -87,7 +87,7 @@ func templateFolderExists(language string, overwrite bool) bool {
8787
return true
8888
}
8989

90-
func moveTemplates(repoPath string, overwrite bool) ([]string, []string, error) {
90+
func moveTemplates(repoPath, templateName string, overwrite bool) ([]string, []string, error) {
9191
var (
9292
existingLanguages []string
9393
fetchedLanguages []string
@@ -97,7 +97,7 @@ func moveTemplates(repoPath string, overwrite bool) ([]string, []string, error)
9797
availableLanguages := make(map[string]bool)
9898

9999
templateDir := filepath.Join(repoPath, templateDirectory)
100-
templates, err := ioutil.ReadDir(templateDir)
100+
templates, err := os.ReadDir(templateDir)
101101
if err != nil {
102102
return nil, nil, fmt.Errorf("can't find templates in: %s", repoPath)
103103
}
@@ -108,23 +108,35 @@ func moveTemplates(repoPath string, overwrite bool) ([]string, []string, error)
108108
}
109109
language := file.Name()
110110

111-
canWrite := canWriteLanguage(availableLanguages, language, overwrite)
112-
if canWrite {
113-
fetchedLanguages = append(fetchedLanguages, language)
114-
// Do cp here
115-
languageSrc := filepath.Join(templateDir, language)
116-
languageDest := filepath.Join(templateDirectory, language)
117-
builder.CopyFiles(languageSrc, languageDest)
118-
} else {
119-
existingLanguages = append(existingLanguages, language)
120-
continue
111+
if len(templateName) == 0 {
112+
113+
canWrite := canWriteLanguage(availableLanguages, language, overwrite)
114+
if canWrite {
115+
fetchedLanguages = append(fetchedLanguages, language)
116+
// Do cp here
117+
languageSrc := filepath.Join(templateDir, language)
118+
languageDest := filepath.Join(templateDirectory, language)
119+
builder.CopyFiles(languageSrc, languageDest)
120+
} else {
121+
existingLanguages = append(existingLanguages, language)
122+
continue
123+
}
124+
} else if language == templateName {
125+
126+
if canWriteLanguage(availableLanguages, language, overwrite) {
127+
fetchedLanguages = append(fetchedLanguages, language)
128+
// Do cp here
129+
languageSrc := filepath.Join(templateDir, language)
130+
languageDest := filepath.Join(templateDirectory, language)
131+
builder.CopyFiles(languageSrc, languageDest)
132+
}
121133
}
122134
}
123135

124136
return existingLanguages, fetchedLanguages, nil
125137
}
126138

127-
func pullTemplate(repository string) error {
139+
func pullTemplate(repository, templateName string) error {
128140
if _, err := os.Stat(repository); err != nil {
129141
if !versioncontrol.IsGitRemote(repository) && !versioncontrol.IsPinnedGitRemote(repository) {
130142
return fmt.Errorf("the repository URL must be a valid git repo uri")
@@ -143,8 +155,12 @@ func pullTemplate(repository string) error {
143155
}
144156
}
145157

146-
fmt.Printf("Fetch templates from repository: %s at %s\n", repository, refName)
147-
if err := fetchTemplates(repository, refName, overwrite); err != nil {
158+
refStr := ""
159+
if len(refName) > 0 {
160+
refStr = fmt.Sprintf(" @ %s", refName)
161+
}
162+
fmt.Printf("Fetch templates from repository: %s%s\n", repository, refStr)
163+
if err := fetchTemplates(repository, refName, templateName, overwrite); err != nil {
148164
return fmt.Errorf("error while fetching templates: %s", err)
149165
}
150166

commands/fetch_templates_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@ func Test_PullTemplates(t *testing.T) {
2121
defer os.RemoveAll(localTemplateRepository)
2222
defer tearDownFetchTemplates(t)
2323

24+
templateName := ""
2425
t.Run("pullTemplates", func(t *testing.T) {
2526
defer tearDownFetchTemplates(t)
26-
if err := pullTemplates(localTemplateRepository); err != nil {
27-
t.Fatal(err)
27+
if err := pullTemplates(localTemplateRepository, templateName); err != nil {
28+
t.Fatalf("Trying to pull %s, error: %s", localTemplateRepository, err)
2829
}
2930
})
3031

3132
t.Run("fetchTemplates with master ref", func(t *testing.T) {
3233
defer tearDownFetchTemplates(t)
3334

34-
if err := fetchTemplates(localTemplateRepository, "master", false); err != nil {
35+
if err := fetchTemplates(localTemplateRepository, "master", templateName, false); err != nil {
3536
t.Fatal(err)
3637
}
3738

@@ -40,8 +41,8 @@ func Test_PullTemplates(t *testing.T) {
4041
t.Run("fetchTemplates with default ref", func(t *testing.T) {
4142
defer tearDownFetchTemplates(t)
4243

43-
err := fetchTemplates(localTemplateRepository, "", false)
44-
if err != nil {
44+
templateName := ""
45+
if err := fetchTemplates(localTemplateRepository, "", templateName, false); err != nil {
4546
t.Error(err)
4647
}
4748

commands/new_function.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package commands
55

66
import (
77
"fmt"
8-
"io/ioutil"
98
"os"
109
"path/filepath"
1110
"regexp"
@@ -74,7 +73,7 @@ func validateFunctionName(functionName string) error {
7473

7574
// preRunNewFunction validates args & flags
7675
func preRunNewFunction(cmd *cobra.Command, args []string) error {
77-
if list == true {
76+
if list {
7877
return nil
7978
}
8079

@@ -102,16 +101,18 @@ func preRunNewFunction(cmd *cobra.Command, args []string) error {
102101
}
103102

104103
func runNewFunction(cmd *cobra.Command, args []string) error {
105-
if list == true {
104+
if list {
106105
var availableTemplates []string
107106

108-
templateFolders, err := ioutil.ReadDir(templateDirectory)
107+
templateFolders, err := os.ReadDir(templateDirectory)
109108
if err != nil {
110109
return fmt.Errorf(`no language templates were found.
111110
112111
Download templates:
113-
faas-cli template pull download the default templates
114-
faas-cli template store list view the community template store`)
112+
faas-cli template pull download the default templates
113+
faas-cli template store list view the template store
114+
faas-cli template store pull NAME download the default templates
115+
faas-cli new --lang NAME Attempt to download NAME from the template store`)
115116
}
116117

117118
for _, file := range templateFolders {
@@ -125,11 +126,34 @@ Download templates:
125126
return nil
126127
}
127128

128-
templateAddress := getTemplateURL("", os.Getenv(templateURLEnvironment), DefaultTemplateRepository)
129-
pullTemplates(templateAddress)
130-
131129
if !stack.IsValidTemplate(language) {
132-
return fmt.Errorf("template: \"%s\" was not found in the templates directory", language)
130+
131+
envTemplateRepoStore := os.Getenv(templateStoreURLEnvironment)
132+
storeURL := getTemplateStoreURL(templateStoreURL, envTemplateRepoStore, DefaultTemplatesStore)
133+
134+
templatesInfo, err := getTemplateInfo(storeURL)
135+
if err != nil {
136+
return fmt.Errorf("error while getting templates info: %s", err)
137+
}
138+
139+
var templateInfo *TemplateInfo
140+
for _, info := range templatesInfo {
141+
if info.TemplateName == language {
142+
templateInfo = &info
143+
break
144+
}
145+
}
146+
147+
if templateInfo == nil {
148+
return fmt.Errorf("template: \"%s\" was not found in the templates folder or in the store", language)
149+
}
150+
151+
templateName := templateInfo.TemplateName
152+
153+
if err := pullTemplate(templateInfo.Repository, templateName); err != nil {
154+
return fmt.Errorf("error while pulling template: %s", err)
155+
}
156+
133157
}
134158

135159
var fileName, outputMsg string

commands/new_function_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ const (
2727
- dockerfile
2828
- ruby`
2929

30-
LangNotExistsOutput = `(template: \"([0-9A-Za-z-])*\" was not found in the templates directory)`
30+
LangNotExistsOutput = `(template: \"([0-9A-Za-z-])*\" was not found in the templates folder or in the store)`
3131
FunctionExistsOutput = `(Function (.+)? already exists in (.+)? file)`
3232
NoTemplates = `no language templates were found.
3333
3434
Download templates:
35-
faas-cli template pull download the default templates
36-
faas-cli template store list view the community template store`
35+
faas-cli template pull download the default templates
36+
faas-cli template store list view the template store
37+
faas-cli template store pull NAME download the default templates
38+
faas-cli new --lang NAME Attempt to download NAME from the template store`
3739
InvalidFileSuffix = "when appending to a stack the suffix should be .yml or .yaml"
3840
)
3941

commands/publish.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,35 @@ func runPublish(cmd *cobra.Command, args []string) error {
139139
}
140140
}
141141

142-
templateAddress := getTemplateURL("", os.Getenv(templateURLEnvironment), DefaultTemplateRepository)
143-
if pullErr := pullTemplates(templateAddress); pullErr != nil {
144-
return fmt.Errorf("could not pull templates for OpenFaaS: %v", pullErr)
142+
needTemplates := false
143+
for _, function := range services.Functions {
144+
if len(function.Language) > 0 {
145+
needTemplates = true
146+
break
147+
}
148+
}
149+
150+
templatesFound := false
151+
if stat, err := os.Stat("./template"); err == nil && stat.IsDir() {
152+
templatesFound = true
153+
}
154+
155+
// if no templates are configured, but they exist in the configuration section,
156+
// attempt to pull them first
157+
if !templatesFound && needTemplates {
158+
if len(services.StackConfiguration.TemplateConfigs) > 0 {
159+
if err := pullStackTemplates(services.StackConfiguration.TemplateConfigs, cmd); err != nil {
160+
return err
161+
}
162+
163+
}
164+
}
165+
166+
if needTemplates {
167+
if _, err := os.Stat("./template"); os.IsNotExist(err) {
168+
169+
return fmt.Errorf(`the "template" directory is missing but required by at least one function`)
170+
}
145171
}
146172

147173
if resetQemu {

commands/template_pull.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ func runTemplatePull(cmd *cobra.Command, args []string) error {
4343
if len(args) > 0 {
4444
repository = args[0]
4545
}
46+
47+
templateName := "" // templateName may not be known at this point
48+
4649
repository = getTemplateURL(repository, os.Getenv(templateURLEnvironment), DefaultTemplateRepository)
47-
return pullTemplate(repository)
50+
return pullTemplate(repository, templateName)
4851
}
4952

5053
func pullDebugPrint(message string) {

0 commit comments

Comments
 (0)