Skip to content

Commit

Permalink
Allow multiple directives including OSType and ProjectType in custom …
Browse files Browse the repository at this point in the history
…command, fixes #2209 (#2452)


* Allow multiple directives including OSType and ProjectType in custom command, fixes #2209
* Add drush, sequelpro, sequelace, typo3 and typo3cms, artisan and magento commands

Co-authored-by: Joe Chellman <joe@shooflydesign.org>
  • Loading branch information
rfay and chellman committed Aug 14, 2020
1 parent 8efab22 commit c34907d
Show file tree
Hide file tree
Showing 16 changed files with 257 additions and 214 deletions.
62 changes: 48 additions & 14 deletions cmd/ddev/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,44 @@ func addCustomCommands(rootCmd *cobra.Command) error {
util.Warning("command '%s' contains CRLF, please convert to Linux-style linefeeds with dos2unix or another tool, skipping %s", commandName, onHostFullPath)
continue
}
description := findDirectiveInScript(onHostFullPath, "## Description")
if description == "" {
description = commandName
directives := findDirectivesInScriptCommand(onHostFullPath)
var description, usage, example, projectTypes, osTypes, hostBinaryExists string

description = commandName
if val, ok := directives["Description"]; ok {
description = val
}

if val, ok := directives["Usage"]; ok {
usage = val
}
usage := findDirectiveInScript(onHostFullPath, "## Usage")
if usage == "" {
usage = commandName + " [flags] [args]"
if val, ok := directives["Example"]; ok {
example = val
}
example := findDirectiveInScript(onHostFullPath, "## Example")
if val, ok := directives["ProjectTypes"]; ok {
projectTypes = val
}
// If ProjectTypes is specified and we aren't of that type, skip
if projectTypes != "" && !strings.Contains(projectTypes, app.Type) {
continue
}

if val, ok := directives["OSTypes"]; ok {
osTypes = val
}
// If OSTypes is specified and we aren't this isn't a specified OS, skip
if osTypes != "" && !strings.Contains(osTypes, runtime.GOOS) {
continue
}

if val, ok := directives["HostBinaryExists"]; ok {
hostBinaryExists = val
}
// If hostBinaryExists is specified it doesn't exist here, skip
if hostBinaryExists != "" && !fileutil.FileExists(hostBinaryExists) {
continue
}

descSuffix := " (shell " + service + " container command)"
if serviceDirOnHost[0:1] == "." {
descSuffix = " (global shell " + service + " container command)"
Expand Down Expand Up @@ -203,8 +232,9 @@ func makeContainerCmd(app *ddevapp.DdevApp, fullPath, name string, service strin
}
}

// findDirectiveInScript() looks for the named directive and returns the string following colon and spaces
func findDirectiveInScript(script string, directive string) string {
// findDirectivesInScriptCommand() Returns a map of directives and their contents
// found in the named script
func findDirectivesInScriptCommand(script string) map[string]string {
f, err := os.Open(script)
if err != nil {
util.Failed("Failed to open %s: %v", script, err)
Expand All @@ -213,22 +243,26 @@ func findDirectiveInScript(script string, directive string) string {
// nolint errcheck
defer f.Close()

var directives = make(map[string]string)

// Splits on newlines by default.
scanner := bufio.NewScanner(f)

for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, directive) && strings.Contains(line, ":") {
parts := strings.Split(line, ":")
return strings.Trim(parts[1], " ")
if strings.HasPrefix(line, "## ") && strings.Contains(line, ":") {
line = strings.Replace(line, "## ", "", 1)
parts := strings.SplitN(line, ":", 2)
parts[1] = strings.Trim(parts[1], " ")
directives[parts[0]] = parts[1]
}
}

if err := scanner.Err(); err != nil {
return ""
return nil
}

return ""
return directives
}

// populateExamplesCommandsHomeadditions grabs packr2 assets
Expand Down
34 changes: 29 additions & 5 deletions cmd/ddev/cmd/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ func TestCustomCommands(t *testing.T) {
site := TestSites[0]
switchDir := TestSites[0].Chdir()
app, _ := ddevapp.NewApp(TestSites[0].Dir, false, "")
defer func() {
t.Cleanup(func() {
_ = os.RemoveAll(tmpHome)
_ = os.Setenv("HOME", origHome)
_ = os.Setenv("DDEV_DEBUG", origDebug)
_ = fileutil.PurgeDirectory(filepath.Join(site.Dir, ".ddev", "commands"))
_ = fileutil.PurgeDirectory(filepath.Join(site.Dir, ".ddev", ".global_commands"))
switchDir()
}()
})

// We can't use the standard getGlobalDDevDir here because *our* global hasn't changed.
// It's changed via $HOME for the ddev subprocess
Expand Down Expand Up @@ -101,13 +101,37 @@ func TestCustomCommands(t *testing.T) {
}

// Make sure that all the official ddev-provided custom commands are usable by just checking help
for _, c := range []string{"mysql", "launch", "live", "xdebug"} {
for _, c := range []string{"launch", "live", "mysql", "xdebug"} {
_, err = exec.RunCommand(DdevBin, []string{c, "-h"})
assert.NoError(err, "Failed to run ddev %s -h", c)
}

// Make sure that all the non-command stuff we installed is there
for _, f := range []string{"db/mysqldump.example", "db/README.txt", "web/drush.example", "web/README.txt", "host/README.txt", "host/phpstorm.example"} {
// The TYPO3 and Drupal commands should not be available here (currently WordPress)
for _, c := range []string{"typo3", "typo3cms", "drush", "artisan", "magento"} {
_, err = exec.RunCommand(DdevBin, []string{c, "-h"})
assert.Error(err)
}

// TYPO3 commands should only be available for type typo3
app.Type = nodeps.AppTypeTYPO3
_ = app.WriteConfig()
_, _ = exec.RunCommand(DdevBin, nil)
for _, c := range []string{"typo3", "typo3cms"} {
_, err = exec.RunCommand(DdevBin, []string{c, "-h"})
assert.NoError(err)
}

// Drupal types should only be available for type drupal*
app.Type = nodeps.AppTypeDrupal9
_ = app.WriteConfig()
_, _ = exec.RunCommand(DdevBin, nil)
for _, c := range []string{"drush"} {
_, err = exec.RunCommand(DdevBin, []string{c, "-h"})
assert.NoError(err)
}

// Make sure that the non-command stuff we installed is there
for _, f := range []string{"db/mysqldump.example", "db/README.txt", "web/README.txt", "host/README.txt", "host/phpstorm.example"} {
assert.FileExists(filepath.Join(projectCommandsDir, f))
assert.FileExists(filepath.Join(globalCommandsDir, f))
}
Expand Down
14 changes: 14 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/host/sequelace
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

#ddev-generated
## Description: Run sequelace with current project database
## Usage: sequelace
## Example: "ddev sequelace"
## OSTypes: darwin
## HostBinaryExists: /Applications/Sequel ace.app

set -x
query="mysql://root:root@127.0.0.1:${DDEV_HOST_DB_PORT}/db"

open "$query" -a "/Applications/Sequel Ace.app/Contents/MacOS/Sequel Ace"

77 changes: 77 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/host/sequelpro
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash

#ddev-generated
## Description: Run sequelpro with current project database
## Usage: sequelpro
## Example: "ddev sequelpro"
## OSTypes: darwin
## HostBinaryExists: /Applications/Sequel Pro.app

tmpdir=$(mktemp -d -t sequelpro-XXXXXXXXXX)
templatepath="$tmpdir/sequelpro.spf"

cat >$templatepath <<END
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ContentFilters</key>
<dict/>
<key>auto_connect</key>
<true/>
<key>data</key>
<dict>
<key>connection</key>
<dict>
<key>database</key>
<string>db</string>
<key>host</key>
<string>127.0.0.1</string>
<key>name</key>
<string>${DDEV_SITENAME}</string>
<key>password</key>
<string>root</string>
<key>port</key>
<integer>$DDEV_HOST_DB_PORT</integer>
<key>rdbms_type</key>
<string>mysql</string>
<key>sslCACertFileLocation</key>
<string></string>
<key>sslCACertFileLocationEnabled</key>
<integer>0</integer>
<key>sslCertificateFileLocation</key>
<string></string>
<key>sslCertificateFileLocationEnabled</key>
<integer>0</integer>
<key>sslKeyFileLocation</key>
<string></string>
<key>sslKeyFileLocationEnabled</key>
<integer>0</integer>
<key>type</key>
<string>SPTCPIPConnection</string>
<key>useSSL</key>
<integer>0</integer>
<key>user</key>
<string>root</string>
</dict>
</dict>
<key>encrypted</key>
<false/>
<key>format</key>
<string>connection</string>
<key>queryFavorites</key>
<array/>
<key>queryHistory</key>
<array/>
<key>rdbms_type</key>
<string>mysql</string>
<key>rdbms_version</key>
<string>5.5.44</string>
<key>version</key>
<integer>1</integer>
</dict>
</plist>
END

open "${templatepath}"

10 changes: 10 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/web/artisan
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

#ddev-generated
## Description: Run artisan CLI inside the web container
## Usage: artisan [flags] [args]
## Example: "ddev artisan list" or "ddev artisan cache:clear"
## ProjectTypes: laravel

./artisan "$@"

9 changes: 9 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/web/drush
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

#ddev-generated
## Description: Run drush CLI inside the web container
## Usage: drush [flags] [args]
## Example: "ddev drush uli" or "ddev drush sql-cli" or "ddev drush --version"
## ProjectTypes: drupal7,drupal8,drupal9,backdrop

drush "$@"
10 changes: 10 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/web/magento
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

#ddev-generated
## Description: Run magento CLI inside the web container
## Usage: magento [flags] [args]
## Example: "ddev magento list" or "ddev magento maintenance:enable" or "ddev magento sampledata:reset"
## ProjectTypes: magento2

bin/magento "$@"

12 changes: 12 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/web/typo3
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

#ddev-generated
# This assumes that the typo3cms command will be in the $PATH; if in vendor/bin/typo3cms it will be

## Description: Run typo3 console (typo3cms) command inside the web container
## Usage: typo3cms [args]
## Example: "ddev typo3cms cache:flush" or "ddev typo3cms database:export"
## ProjectTypes: typo3

typo3 "$@"

12 changes: 12 additions & 0 deletions cmd/ddev/cmd/global_dotddev_assets/commands/web/typo3cms
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

#ddev-generated
# This assumes that the typo3 command will be in the $PATH; if in vendor/bin/typo3 it will be

## Description: Run typo3 command inside the web container
## Usage: typo3 [args]
## Example: "ddev typo3 site:list" or "ddev typo3 list" or "ddev typo3 extension:list"
## ProjectTypes: typo3

typo3 "$@"

Loading

0 comments on commit c34907d

Please sign in to comment.