From 27d0046e3e8e1e015d17df8cc83b49c9a1459a57 Mon Sep 17 00:00:00 2001 From: Randy Fay Date: Thu, 23 Jan 2020 19:30:49 -0700 Subject: [PATCH] Add disable_settings_management as config option, fixes #2024, fixes #1806 (#2036) --- cmd/ddev/cmd/config.go | 6 +++ docs/users/extend/config_yaml.md | 1 + pkg/ddevapp/apptypes.go | 5 ++ pkg/ddevapp/ddevapp.go | 83 +++++++++++++++---------------- pkg/ddevapp/ddevapp_test.go | 84 ++++++++++++++++++++++++++++++++ pkg/ddevapp/drupal.go | 40 +++++++-------- pkg/ddevapp/templates.go | 5 ++ 7 files changed, 164 insertions(+), 60 deletions(-) diff --git a/cmd/ddev/cmd/config.go b/cmd/ddev/cmd/config.go index b6f68729a4e..61fc40b10d4 100644 --- a/cmd/ddev/cmd/config.go +++ b/cmd/ddev/cmd/config.go @@ -293,6 +293,8 @@ func init() { ConfigCommand.Flags().String("timezone", "", "Specify timezone for containers and php, like Europe/London or America/Denver or GMT or UTC") + ConfigCommand.Flags().Bool("disable-settings-management", false, "Prevent ddev from creating or updating CMS settings files") + RootCmd.AddCommand(ConfigCommand) } @@ -512,6 +514,10 @@ func handleMainConfigArgs(cmd *cobra.Command, args []string, app *ddevapp.DdevAp } } + if cmd.Flag("disable-settings-management").Changed { + app.DisableSettingsManagement, _ = cmd.Flags().GetBool("disable-settings-management") + } + if uploadDirArg != "" { app.UploadDir = uploadDirArg } diff --git a/docs/users/extend/config_yaml.md b/docs/users/extend/config_yaml.md index 6ea99bd9e91..cc5929118e5 100644 --- a/docs/users/extend/config_yaml.md +++ b/docs/users/extend/config_yaml.md @@ -39,6 +39,7 @@ the .ddev/config.yaml is the primary configuration for the project. | use_dns_when_possible | defaults to true (using DNS instead of editing /etc/hosts) | If set to false, ddev will always update the /etc/hosts file with the project hostname instead of using DNS for name resolution | | project_tld | defaults to "ddev.site" so project urls become "someproject.ddev.site" | This can be changed to anything that works for you; to keep things the way they were before ddev v1.9, use "ddev.local" | | ngrok_args | Extra flags for ngrok when using the `ddev share` command | For example, `--subdomain mysite --auth user:pass`. See [ngrok docs on http flags](https://ngrok.com/docs#http) | +| disable_settings_management | defaults to false | If true, ddev will not create or update CMS-specific settings files | | | provider| hosting provider for `ddev pull` | "pantheon" or "drud-aws" or "default" | | hooks | | See [Extending Commands](../extending-commands.md) for more information. | diff --git a/pkg/ddevapp/apptypes.go b/pkg/ddevapp/apptypes.go index 7763891f81b..295d08e25ff 100644 --- a/pkg/ddevapp/apptypes.go +++ b/pkg/ddevapp/apptypes.go @@ -103,6 +103,11 @@ func (app *DdevApp) CreateSettingsFile() (string, error) { app.SetApptypeSettingsPaths() + if app.DisableSettingsManagement { + util.Warning("Not creating CMA settings files because disable_settings_management=true") + return "", nil + } + // 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. diff --git a/pkg/ddevapp/ddevapp.go b/pkg/ddevapp/ddevapp.go index 285fad47f3a..0c4341b5f17 100644 --- a/pkg/ddevapp/ddevapp.go +++ b/pkg/ddevapp/ddevapp.go @@ -63,47 +63,48 @@ const DdevFileSignature = "#ddev-generated" // DdevApp is the struct that represents a ddev app, mostly its config // from config.yaml. type DdevApp struct { - APIVersion string `yaml:"APIVersion"` - Name string `yaml:"name"` - Type string `yaml:"type"` - Docroot string `yaml:"docroot"` - PHPVersion string `yaml:"php_version"` - WebserverType string `yaml:"webserver_type"` - WebImage string `yaml:"webimage,omitempty"` - DBImage string `yaml:"dbimage,omitempty"` - DBAImage string `yaml:"dbaimage,omitempty"` - RouterHTTPPort string `yaml:"router_http_port"` - RouterHTTPSPort string `yaml:"router_https_port"` - XdebugEnabled bool `yaml:"xdebug_enabled"` - AdditionalHostnames []string `yaml:"additional_hostnames"` - AdditionalFQDNs []string `yaml:"additional_fqdns"` - MariaDBVersion string `yaml:"mariadb_version,omitempty"` - MySQLVersion string `yaml:"mysql_version,omitempty"` - NFSMountEnabled bool `yaml:"nfs_mount_enabled"` - ConfigPath string `yaml:"-"` - AppRoot string `yaml:"-"` - Platform string `yaml:"-"` - Provider string `yaml:"provider,omitempty"` - DataDir string `yaml:"-"` - SiteSettingsPath string `yaml:"-"` - SiteDdevSettingsFile string `yaml:"-"` - providerInstance Provider `yaml:"-"` - Hooks map[string][]YAMLTask `yaml:"hooks,omitempty"` - UploadDir string `yaml:"upload_dir,omitempty"` - WorkingDir map[string]string `yaml:"working_dir,omitempty"` - OmitContainers []string `yaml:"omit_containers,omitempty,flow"` - HostDBPort string `yaml:"host_db_port,omitempty"` - HostWebserverPort string `yaml:"host_webserver_port,omitempty"` - HostHTTPSPort string `yaml:"host_https_port,omitempty"` - MailhogPort string `yaml:"mailhog_port,omitempty"` - PHPMyAdminPort string `yaml:"phpmyadmin_port,omitempty"` - WebImageExtraPackages []string `yaml:"webimage_extra_packages,omitempty,flow"` - DBImageExtraPackages []string `yaml:"dbimage_extra_packages,omitempty,flow"` - ProjectTLD string `yaml:"project_tld,omitempty"` - UseDNSWhenPossible bool `yaml:"use_dns_when_possible"` - MkcertEnabled bool `yaml:"-"` - NgrokArgs string `yaml:"ngrok_args,omitempty"` - Timezone string `yaml:"timezone"` + APIVersion string `yaml:"APIVersion"` + Name string `yaml:"name"` + Type string `yaml:"type"` + Docroot string `yaml:"docroot"` + PHPVersion string `yaml:"php_version"` + WebserverType string `yaml:"webserver_type"` + WebImage string `yaml:"webimage,omitempty"` + DBImage string `yaml:"dbimage,omitempty"` + DBAImage string `yaml:"dbaimage,omitempty"` + RouterHTTPPort string `yaml:"router_http_port"` + RouterHTTPSPort string `yaml:"router_https_port"` + XdebugEnabled bool `yaml:"xdebug_enabled"` + AdditionalHostnames []string `yaml:"additional_hostnames"` + AdditionalFQDNs []string `yaml:"additional_fqdns"` + MariaDBVersion string `yaml:"mariadb_version,omitempty"` + MySQLVersion string `yaml:"mysql_version,omitempty"` + NFSMountEnabled bool `yaml:"nfs_mount_enabled"` + ConfigPath string `yaml:"-"` + AppRoot string `yaml:"-"` + Platform string `yaml:"-"` + Provider string `yaml:"provider,omitempty"` + DataDir string `yaml:"-"` + SiteSettingsPath string `yaml:"-"` + SiteDdevSettingsFile string `yaml:"-"` + providerInstance Provider `yaml:"-"` + Hooks map[string][]YAMLTask `yaml:"hooks,omitempty"` + UploadDir string `yaml:"upload_dir,omitempty"` + WorkingDir map[string]string `yaml:"working_dir,omitempty"` + OmitContainers []string `yaml:"omit_containers,omitempty,flow"` + HostDBPort string `yaml:"host_db_port,omitempty"` + HostWebserverPort string `yaml:"host_webserver_port,omitempty"` + HostHTTPSPort string `yaml:"host_https_port,omitempty"` + MailhogPort string `yaml:"mailhog_port,omitempty"` + PHPMyAdminPort string `yaml:"phpmyadmin_port,omitempty"` + WebImageExtraPackages []string `yaml:"webimage_extra_packages,omitempty,flow"` + DBImageExtraPackages []string `yaml:"dbimage_extra_packages,omitempty,flow"` + ProjectTLD string `yaml:"project_tld,omitempty"` + UseDNSWhenPossible bool `yaml:"use_dns_when_possible"` + MkcertEnabled bool `yaml:"-"` + NgrokArgs string `yaml:"ngrok_args,omitempty"` + Timezone string `yaml:"timezone"` + DisableSettingsManagement bool `yaml:"disable_settings_management,omitempty"` } // GetType returns the application type as a (lowercase) string diff --git a/pkg/ddevapp/ddevapp_test.go b/pkg/ddevapp/ddevapp_test.go index cd0dcc0ef8e..1a42dcf5d1a 100644 --- a/pkg/ddevapp/ddevapp_test.go +++ b/pkg/ddevapp/ddevapp_test.go @@ -462,6 +462,90 @@ func TestDdevStartMultipleHostnames(t *testing.T) { } } +// TestDdevStartUnmanagedSettings start and config with disable_settings_management +func TestDdevStartUnmanagedSettings(t *testing.T) { + assert := asrt.New(t) + app := &ddevapp.DdevApp{} + + // Make sure this leaves us in the original test directory + testDir, _ := os.Getwd() + //nolint: errcheck + defer os.Chdir(testDir) + + // Use Drupal8 only, mostly for the composer example + site := FullTestSites[1] + // If running this with GOTEST_SHORT we have to create the directory, tarball etc. + if site.Dir == "" || !fileutil.FileExists(site.Dir) { + app := &ddevapp.DdevApp{Name: site.Name} + _ = app.Stop(true, false) + _ = globalconfig.RemoveProjectInfo(site.Name) + + err := site.Prepare() + require.NoError(t, err) + // nolint: errcheck + defer os.RemoveAll(site.Dir) + } + switchDir := site.Chdir() + defer switchDir() + + runTime := util.TimeTrack(time.Now(), fmt.Sprintf("%s DdevStart", site.Name)) + defer runTime() + + err := app.Init(site.Dir) + assert.NoError(err) + + // Previous tests may have left settings files + _ = os.Remove(app.SiteSettingsPath) + _ = os.Remove(app.SiteDdevSettingsFile) + + // On initial init, settings files should not exist + assert.False(fileutil.FileExists(app.SiteSettingsPath)) + assert.False(fileutil.FileExists(app.SiteDdevSettingsFile)) + + app.DisableSettingsManagement = true + err = app.WriteConfig() + assert.NoError(err) + + // After config, they should still not exist, because we had DisableSettingsManagement + assert.False(fileutil.FileExists(app.SiteSettingsPath)) + assert.False(fileutil.FileExists(app.SiteDdevSettingsFile)) + + err = app.Start() + assert.NoError(err) + //nolint: errcheck + defer app.Stop(true, false) + + // After start, they should still not exist, because we had DisableSettingsManagement + assert.False(fileutil.FileExists(app.SiteSettingsPath)) + assert.False(fileutil.FileExists(app.SiteDdevSettingsFile)) + + app.DisableSettingsManagement = false + err = app.WriteConfig() + assert.NoError(err) + _, err = app.CreateSettingsFile() + assert.NoError(err) + + // Now with DisableSettingsManagement=false, both should exist after config/settings creation + assert.FileExists(app.SiteSettingsPath) + assert.FileExists(app.SiteDdevSettingsFile) + + _ = os.Remove(filepath.Join(app.SiteSettingsPath)) + _ = os.Remove(filepath.Join(app.SiteDdevSettingsFile)) + + assert.False(fileutil.FileExists(app.SiteSettingsPath)) + assert.False(fileutil.FileExists(app.SiteDdevSettingsFile)) + + err = app.Start() + assert.NoError(err) + //nolint: errcheck + defer app.Stop(true, false) + + // Now with DisableSettingsManagement=false, start should have created both + assert.FileExists(app.SiteSettingsPath) + assert.FileExists(app.SiteDdevSettingsFile) + +} + // TestDdevXdebugEnabled tests running with xdebug_enabled = true, etc. func TestDdevXdebugEnabled(t *testing.T) { assert := asrt.New(t) diff --git a/pkg/ddevapp/drupal.go b/pkg/ddevapp/drupal.go index 993a769564e..8f306e5d6ce 100755 --- a/pkg/ddevapp/drupal.go +++ b/pkg/ddevapp/drupal.go @@ -673,29 +673,31 @@ func drupal7ConfigOverrideAction(app *DdevApp) error { // drupal8PostStartAction handles default post-start actions for D8 apps, like ensuring // useful permissions settings on sites/default. func drupal8PostStartAction(app *DdevApp) error { - if err := createDrupal8SyncDir(app); err != nil { - return err - } + if !app.DisableSettingsManagement { + if err := createDrupal8SyncDir(app); err != nil { + return err + } - if err := drupalEnsureWritePerms(app); err != nil { - return err - } + if err := drupalEnsureWritePerms(app); err != nil { + return err + } - // Write both drush.yml and drushrc.php for Drupal 8, because we can't know - // what version of drush may be in use. drush8 is happy with drushrc.php - // drush9 wants drush.yml - err := WriteDrushYML(app, filepath.Join(app.AppRoot, "drush", "drush.yml")) - if err != nil { - util.Warning("Failed to WriteDrushYML: %v", err) - } + // Write both drush.yml and drushrc.php for Drupal 8, because we can't know + // what version of drush may be in use. drush8 is happy with drushrc.php + // drush9 wants drush.yml + err := WriteDrushYML(app, filepath.Join(app.AppRoot, "drush", "drush.yml")) + if err != nil { + util.Warning("Failed to WriteDrushYML: %v", err) + } - err = WriteDrushrc(app, filepath.Join(filepath.Dir(app.SiteSettingsPath), "drushrc.php")) - if err != nil { - util.Warning("Failed to WriteDrushrc: %v", err) - } + err = WriteDrushrc(app, filepath.Join(filepath.Dir(app.SiteSettingsPath), "drushrc.php")) + if err != nil { + util.Warning("Failed to WriteDrushrc: %v", err) + } - if _, err = app.CreateSettingsFile(); err != nil { - return fmt.Errorf("failed to write settings file %s: %v", app.SiteDdevSettingsFile, err) + if _, err = app.CreateSettingsFile(); err != nil { + return fmt.Errorf("failed to write settings file %s: %v", app.SiteDdevSettingsFile, err) + } } return nil } diff --git a/pkg/ddevapp/templates.go b/pkg/ddevapp/templates.go index f08b757507b..b00ae57b4f1 100644 --- a/pkg/ddevapp/templates.go +++ b/pkg/ddevapp/templates.go @@ -302,6 +302,11 @@ const ConfigInstructions = ` # Provide extra flags to the "ngrok http" command, see # https://ngrok.com/docs#http or run "ngrok http -h" +# disable_settings_management: false +# If true, ddev will not create CMS-specific settings files like +# Drupal's settings.php/settings.ddev.php or TYPO3's AdditionalSettings.php +# In this case the user must provide all such settings. + # provider: default # Currently either "default" or "pantheon" # # Many ddev commands can be extended to run tasks before or after the