Repository: go-swagger/go-swagger
Pull request #2082 (2019-10-15 20:59:49)

Add flag to allow overwriting protected templates
Gives option to the user willing to take the risk to overwrite templates
protected by go-swagger by passing --allow-template-override flag.

Related to #1606


Patch:
diff --git a/cmd/swagger/commands/generate/server.go b/cmd/swagger/commands/generate/server.go
index 6cf39aed..a8c4e5a0 100644
--- a/cmd/swagger/commands/generate/server.go
+++ b/cmd/swagger/commands/generate/server.go
@@ -83,6 +83,7 @@ func (s *Server) getOpts() (*generator.GenOpts, error) {
 		FlagStrategy:               s.FlagStrategy,
 		CompatibilityMode:          s.CompatibilityMode,
 		ExistingModels:             s.ExistingModels,
+		AllowTemplateOverride:      s.AllowTemplateOverride,
 	}, nil
 }
 
diff --git a/cmd/swagger/commands/generate/shared.go b/cmd/swagger/commands/generate/shared.go
index 8e0142f8..90bd3513 100644
--- a/cmd/swagger/commands/generate/shared.go
+++ b/cmd/swagger/commands/generate/shared.go
@@ -81,6 +81,7 @@ type shared struct {
 	CopyrightFile         flags.Filename `long:"copyright-file" short:"r" description:"copyright file used to add copyright header"`
 	ExistingModels        string         `long:"existing-models" description:"use pre-generated models e.g. github.com/foobar/model"`
 	AdditionalInitialisms []string       `long:"additional-initialism" description:"consecutive capitals that should be considered intialisms"`
+	AllowTemplateOverride bool           `long:"allow-template-override" description:"allows overriding protected templates"`
 	FlattenCmdOptions
 }
 
diff --git a/docs/generate/client.md b/docs/generate/client.md
index 3fb923d2..d8fdbb28 100644
--- a/docs/generate/client.md
+++ b/docs/generate/client.md
@@ -26,6 +26,7 @@ Help Options:
       -t, --target=                                                               the base directory for generating the files (default: ./)
           --template=[stratoscale]                                                Load contributed templates
       -T, --template-dir=                                                         alternative template override directory
+          --allow-template-override                                               allows overriding protected templates
       -C, --config-file=                                                          configuration file to use for overriding template options
       -r, --copyright-file=                                                       copyright file used to add copyright header
           --existing-models=                                                      use pre-generated models e.g. github.com/foobar/model
diff --git a/docs/generate/model.md b/docs/generate/model.md
index ff10f243..23df4b52 100644
--- a/docs/generate/model.md
+++ b/docs/generate/model.md
@@ -23,6 +23,7 @@ Help Options:
       -t, --target=                                                               the base directory for generating the files (default: ./)
           --template=[stratoscale]                                                Load contributed templates
       -T, --template-dir=                                                         alternative template override directory
+          --allow-template-override                                               allows overriding protected templates
       -C, --config-file=                                                          configuration file to use for overriding template options
       -r, --copyright-file=                                                       copyright file used to add copyright header
           --existing-models=                                                      use pre-generated models e.g. github.com/foobar/model
diff --git a/docs/generate/server.md b/docs/generate/server.md
index c2da04f6..8ae1eee1 100644
--- a/docs/generate/server.md
+++ b/docs/generate/server.md
@@ -35,6 +35,7 @@ Help Options:
       -t, --target=                                                               the base directory for generating the files (default: ./)
           --template=[stratoscale]                                                Load contributed templates
       -T, --template-dir=                                                         alternative template override directory
+          --allow-template-override                                               allows overriding protected templates
       -C, --config-file=                                                          configuration file to use for overriding template options
       -r, --copyright-file=                                                       copyright file used to add copyright header
           --existing-models=                                                      use pre-generated models e.g. github.com/foobar/model
@@ -226,12 +227,12 @@ type or to override an existing mapping, call the corresponding API functions in
 ```go
 func configureAPI(api *operations.ToDoListAPI) http.Handler {
 	// other setup code here...
-	
+
 	api.RegisterConsumer("application/pkcs10", myCustomConsumer)
 	api.RegisterProducer("application/pkcs10", myCustomProducer)
 }
 
-``` 
+```
 
 The next thing that happens in the configureAPI method is setting up the authentication with a stub handler in this case. This particular swagger specification supports token based authentication and as such it wants you to configure a token auth handler.  Any error for an authentication handler is assumed to be an invalid authentication and will return the 401 status code.
 
diff --git a/generator/client.go b/generator/client.go
index d701d5dd..7eda6c39 100644
--- a/generator/client.go
+++ b/generator/client.go
@@ -41,6 +41,8 @@ func GenerateClient(name string, modelNames, operationIDs []string, opts *GenOpt
 		}
 	}
 
+	templates.SetAllowOverride(opts.AllowTemplateOverride)
+
 	if opts.TemplateDir != "" {
 		if err := templates.LoadDir(opts.TemplateDir); err != nil {
 			return err
diff --git a/generator/model.go b/generator/model.go
index 1ff1855e..9b6bd198 100644
--- a/generator/model.go
+++ b/generator/model.go
@@ -55,6 +55,8 @@ func GenerateDefinition(modelNames []string, opts *GenOpts) error {
 		return errors.New("gen opts are required")
 	}
 
+	templates.SetAllowOverride(opts.AllowTemplateOverride)
+
 	if opts.TemplateDir != "" {
 		if err := templates.LoadDir(opts.TemplateDir); err != nil {
 			return err
diff --git a/generator/operation.go b/generator/operation.go
index 44d878fe..48a3c6ef 100644
--- a/generator/operation.go
+++ b/generator/operation.go
@@ -63,6 +63,9 @@ func GenerateServerOperation(operationNames []string, opts *GenOpts) error {
 		return errors.New("gen opts are required")
 	}
 	templates.LoadDefaults()
+
+	templates.SetAllowOverride(opts.AllowTemplateOverride)
+
 	if opts.TemplateDir != "" {
 		if err := templates.LoadDir(opts.TemplateDir); err != nil {
 			return err
diff --git a/generator/shared.go b/generator/shared.go
index ea93a238..fcbc45d1 100644
--- a/generator/shared.go
+++ b/generator/shared.go
@@ -557,6 +557,7 @@ type GenOpts struct {
 	defaultsEnsured            bool
 	PropertiesSpecOrder        bool
 	StrictAdditionalProperties bool
+	AllowTemplateOverride      bool
 
 	Spec                   string
 	APIPackage             string
diff --git a/generator/support.go b/generator/support.go
index 742f0bdd..9e41175b 100644
--- a/generator/support.go
+++ b/generator/support.go
@@ -70,6 +70,9 @@ func newAppGenerator(name string, modelNames, operationIDs []string, opts *GenOp
 			return nil, err
 		}
 	}
+
+	templates.SetAllowOverride(opts.AllowTemplateOverride)
+
 	if opts.TemplateDir != "" {
 		if err := templates.LoadDir(opts.TemplateDir); err != nil {
 			return nil, err
diff --git a/generator/template_repo.go b/generator/template_repo.go
index 463e10ee..ec3a4f65 100644
--- a/generator/template_repo.go
+++ b/generator/template_repo.go
@@ -249,9 +249,10 @@ func NewRepository(funcs template.FuncMap) *Repository {
 
 // Repository is the repository for the generator templates
 type Repository struct {
-	files     map[string]string
-	templates map[string]*template.Template
-	funcs     template.FuncMap
+	files         map[string]string
+	templates     map[string]*template.Template
+	funcs         template.FuncMap
+	allowOverride bool
 }
 
 // LoadDefaults will load the embedded templates
@@ -329,7 +330,7 @@ func (t *Repository) addFile(name, data string, allowOverride bool) error {
 	}
 
 	// check if any protected templates are defined
-	if !allowOverride {
+	if !allowOverride && !t.allowOverride {
 		for _, template := range templ.Templates() {
 			if protectedTemplates[template.Name()] {
 				return fmt.Errorf("cannot overwrite protected template %s", template.Name())
@@ -366,6 +367,11 @@ func (t *Repository) AddFile(name, data string) error {
 	return t.addFile(name, data, false)
 }
 
+// SetAllowOverride allows setting allowOverride after the Repository was initialized
+func (t *Repository) SetAllowOverride(value bool) {
+	t.allowOverride = value
+}
+
 func findDependencies(n parse.Node) []string {
 
 	var deps []string


Test patch:
diff --git a/generator/template_repo_test.go b/generator/template_repo_test.go
index 4589b2de..1f7a8c68 100644
--- a/generator/template_repo_test.go
+++ b/generator/template_repo_test.go
@@ -479,6 +479,21 @@ func TestTemplates_LoadDir(t *testing.T) {
 	assert.NoError(t, err)
 }
 
+// Test LoadDir
+func TestTemplates_SetAllowOverride(t *testing.T) {
+	log.SetOutput(os.Stdout)
+
+	// adding protected file with allowOverride set to false fails
+	templates.SetAllowOverride(false)
+	err := templates.AddFile("schemabody", "some data")
+	assert.Contains(t, err.Error(), "cannot overwrite protected template schemabody")
+
+	// adding protected file with allowOverride set to true should not fail
+	templates.SetAllowOverride(true)
+	err = templates.AddFile("schemabody", "some data")
+	assert.NoError(t, err)
+}
+
 // Test LoadContrib
 func TestTemplates_LoadContrib(t *testing.T) {
 	tests := []struct {