-
-
Notifications
You must be signed in to change notification settings - Fork 579
/
apptypes.go
235 lines (198 loc) · 8.99 KB
/
apptypes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
package ddevapp
import (
"fmt"
"os"
"path/filepath"
"github.com/drud/ddev/pkg/util"
)
type settingsCreator func(*DdevApp) (string, error)
type uploadDir func(*DdevApp) string
// hookDefaultComments should probably change its arg from string to app when
// config refactor is done.
type hookDefaultComments func() []byte
type apptypeSettingsPaths func(app *DdevApp)
// appTypeDetect returns true if the app is of the specified type
type appTypeDetect func(app *DdevApp) bool
// postImportDBAction can take actions after import (like warning user about
// required actions on Wordpress.
type postImportDBAction func(app *DdevApp) error
// configOverrideAction allows a particular apptype to override elements
// of the config for that apptype. Key example is drupal6 needing php56
type configOverrideAction func(app *DdevApp) error
// postConfigAction allows actions to take place at the end of ddev config
type postConfigAction func(app *DdevApp) error
// postStartAction allows actions to take place at the end of ddev start
type postStartAction func(app *DdevApp) error
// importFilesAction
type importFilesAction func(app *DdevApp, importPath, extPath string) error
// AppTypeFuncs struct defines the functions that can be called (if populated)
// for a given appType.
type AppTypeFuncs struct {
settingsCreator
uploadDir
hookDefaultComments
apptypeSettingsPaths
appTypeDetect
postImportDBAction
configOverrideAction
postConfigAction
postStartAction
importFilesAction
}
// appTypeMatrix is a static map that defines the various functions to be called
// for each apptype (CMS).
// Example: appTypeMatrix["drupal"]["7"] == { settingsCreator etc }
var appTypeMatrix map[string]AppTypeFuncs
func init() {
appTypeMatrix = map[string]AppTypeFuncs{
"php": {},
"drupal6": {
settingsCreator: createDrupal6SettingsFile, uploadDir: getDrupalUploadDir, hookDefaultComments: getDrupal6Hooks, apptypeSettingsPaths: setDrupalSiteSettingsPaths, appTypeDetect: isDrupal6App, postImportDBAction: nil, configOverrideAction: drupal6ConfigOverrideAction, postConfigAction: nil, postStartAction: drupal6PostStartAction, importFilesAction: drupalImportFilesAction,
},
"drupal7": {
settingsCreator: createDrupal7SettingsFile, uploadDir: getDrupalUploadDir, hookDefaultComments: getDrupal7Hooks, apptypeSettingsPaths: setDrupalSiteSettingsPaths, appTypeDetect: isDrupal7App, postImportDBAction: nil, configOverrideAction: drupal7ConfigOverrideAction, postConfigAction: nil, postStartAction: drupal7PostStartAction, importFilesAction: drupalImportFilesAction,
},
"drupal8": {
settingsCreator: createDrupal8SettingsFile, uploadDir: getDrupalUploadDir, hookDefaultComments: getDrupal8Hooks, apptypeSettingsPaths: setDrupalSiteSettingsPaths, appTypeDetect: isDrupal8App, postImportDBAction: nil, configOverrideAction: nil, postConfigAction: nil, postStartAction: drupal8PostStartAction, importFilesAction: drupalImportFilesAction,
},
"wordpress": {
settingsCreator: createWordpressSettingsFile, uploadDir: getWordpressUploadDir, hookDefaultComments: getWordpressHooks, apptypeSettingsPaths: setWordpressSiteSettingsPaths, appTypeDetect: isWordpressApp, postImportDBAction: nil, configOverrideAction: nil, postConfigAction: nil, postStartAction: nil, importFilesAction: wordpressImportFilesAction,
},
"typo3": {
settingsCreator: createTypo3SettingsFile, uploadDir: getTypo3UploadDir, hookDefaultComments: getTypo3Hooks, apptypeSettingsPaths: setTypo3SiteSettingsPaths, appTypeDetect: isTypo3App, postImportDBAction: nil, configOverrideAction: typo3ConfigOverrideAction, postConfigAction: nil, postStartAction: nil, importFilesAction: typo3ImportFilesAction,
},
"backdrop": {
settingsCreator: createBackdropSettingsFile, uploadDir: getBackdropUploadDir, hookDefaultComments: getBackdropHooks, apptypeSettingsPaths: setBackdropSiteSettingsPaths, appTypeDetect: isBackdropApp, postImportDBAction: backdropPostImportDBAction, configOverrideAction: nil, postConfigAction: nil, postStartAction: backdropPostStartAction, importFilesAction: backdropImportFilesAction,
},
}
}
// GetValidAppTypes returns the valid apptype keys from the appTypeMatrix
func GetValidAppTypes() []string {
keys := make([]string, 0, len(appTypeMatrix))
for k := range appTypeMatrix {
keys = append(keys, k)
}
return keys
}
// IsValidAppType checks to see if the given apptype string is a valid configured
// apptype.
func IsValidAppType(apptype string) bool {
if _, ok := appTypeMatrix[apptype]; ok {
return true
}
return false
}
// CreateSettingsFile creates the settings file (like settings.php) for the
// provided app is the apptype has a settingsCreator function.
func (app *DdevApp) CreateSettingsFile() (string, error) {
app.SetApptypeSettingsPaths()
// If neither settings file options are set, then don't continue. Return
// a nil error because this should not halt execution if the apptype
// does not have a settings definition.
if app.SiteLocalSettingsPath == "" && app.SiteSettingsPath == "" {
util.Warning("Project type has no settings paths configured, so not creating settings file.")
return "", nil
}
// Drupal and WordPress love to change settings files to be unwriteable.
// Chmod them to something we can work with in the event that they already
// exist.
chmodTargets := []string{filepath.Dir(app.SiteSettingsPath), app.SiteLocalSettingsPath}
for _, fp := range chmodTargets {
if fileInfo, err := os.Stat(fp); !os.IsNotExist(err) {
perms := 0644
if fileInfo.IsDir() {
perms = 0755
}
err = os.Chmod(fp, os.FileMode(perms))
if err != nil {
return "", fmt.Errorf("could not change permissions on file %s to make it writeable: %v", fp, err)
}
}
}
// If we have a function to do the settings creation, do it, otherwise
// just ignore.
if appFuncs, ok := appTypeMatrix[app.GetType()]; ok && appFuncs.settingsCreator != nil {
settingsPath, err := appFuncs.settingsCreator(app)
if err != nil {
util.Warning("Unable to create settings file: %v", err)
}
if err := CreateGitIgnore(filepath.Dir(app.SiteSettingsPath), filepath.Base(app.SiteLocalSettingsPath), "ddev_drush_settings.php"); err != nil {
util.Warning("Failed to write .gitignore in %s: %v", filepath.Dir(app.SiteLocalSettingsPath), err)
}
return settingsPath, nil
}
return "", nil
}
// GetUploadDir returns the upload (public files) directory for the given app
func (app *DdevApp) GetUploadDir() string {
if appFuncs, ok := appTypeMatrix[app.GetType()]; ok && appFuncs.uploadDir != nil {
uploadDir := appFuncs.uploadDir(app)
return uploadDir
}
return ""
}
// GetHookDefaultComments gets the actual text of the config.yaml hook suggestions
// for a given apptype
func (app *DdevApp) GetHookDefaultComments() []byte {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.hookDefaultComments != nil {
suggestions := appFuncs.hookDefaultComments()
return suggestions
}
return []byte("")
}
// SetApptypeSettingsPaths chooses and sets the settings.php/settings.local.php
// and related paths for a given app.
func (app *DdevApp) SetApptypeSettingsPaths() {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.apptypeSettingsPaths != nil {
appFuncs.apptypeSettingsPaths(app)
}
}
// DetectAppType calls each apptype's detector until it finds a match,
// or returns 'php' as a last resort.
func (app *DdevApp) DetectAppType() string {
for appName, appFuncs := range appTypeMatrix {
if appFuncs.appTypeDetect != nil && appFuncs.appTypeDetect(app) {
return appName
}
}
return "php"
}
// PostImportDBAction calls each apptype's detector until it finds a match,
// or returns 'php' as a last resort.
func (app *DdevApp) PostImportDBAction() error {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.postImportDBAction != nil {
return appFuncs.postImportDBAction(app)
}
return nil
}
// ConfigFileOverrideAction gives a chance for an apptype to override any element
// of config.yaml that it needs to (on initial creation, but not after that)
func (app *DdevApp) ConfigFileOverrideAction() error {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.configOverrideAction != nil && !app.ConfigExists() {
return appFuncs.configOverrideAction(app)
}
return nil
}
// PostConfigAction gives a chance for an apptype to override do something at
// the end of ddev config.
func (app *DdevApp) PostConfigAction() error {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.postConfigAction != nil {
return appFuncs.postConfigAction(app)
}
return nil
}
// PostStartAction gives a chance for an apptype to do something after the app
// has been started.
func (app *DdevApp) PostStartAction() error {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.postStartAction != nil {
return appFuncs.postStartAction(app)
}
return nil
}
// ImportFilesAction executes the relevant import files workflow for each app type.
func (app *DdevApp) ImportFilesAction(importPath, extPath string) error {
if appFuncs, ok := appTypeMatrix[app.Type]; ok && appFuncs.importFilesAction != nil {
return appFuncs.importFilesAction(app, importPath, extPath)
}
return nil
}