Documentation ¶
Index ¶
Constants ¶
const ( FtBool = "bool" FtBoolSlice = "boolSlice" FtBytesHex = "bytesHex" FtBytesBase64 = "bytesBase64" FtCount = "count" FtDuration = "duration" FtDurationSlice = "durationSlice" FtFloat32 = "float32" FtFloat32Slice = "float32Slice" FtFloat64 = "float64" FtFloat64Slice = "float64Slice" FtInt = "int" FtIntSlice = "intSlice" FtInt8 = "int8" FtInt16 = "int16" FtInt32 = "int32" FtInt32Slice = "int32Slice" FtInt64 = "int64" FtInt64Slice = "int64Slice" FtIP = "ip" FtIPSlice = "ipSlice" FtIPMask = "ipMask" FtIPNet = "ipNet" FtString = "string" FtStringArray = "stringArray" FtStringSlice = "stringSlice" FtStringToInt = "stringToInt" FtStringToInt64 = "stringToInt64" FtStringToString = "stringToString" FtUint = "uint" FtUintSlice = "uintSlice" FtUint8 = "uint8" FtUint16 = "uint16" FtUint32 = "uint32" FtUint64 = "uint64" )
Defines the constants for the valid types which always should used in the source code.
Variables ¶
var AuthCmd = &cobra.Command{ Use: "auth [command]", Short: "A collection of authentication commands", Example: `ddev auth ssh`, Run: func(cmd *cobra.Command, args []string) { err := cmd.Usage() util.CheckErr(err) }, }
AuthCmd is the top-level "ddev auth" command
var AuthSSHCommand = &cobra.Command{ Use: "ssh", Short: "Add ssh key authentication to the ddev-ssh-auth container", Long: `Use this command to provide the password to your ssh key to the ddev-ssh-agent container, where it can be used by other containers. Normal usage is just "ddev auth ssh", or if your key is not in ~/.ssh, ddev auth ssh --ssh-key-path=/some/path/.ssh"`, Example: `ddev auth ssh`, Run: func(cmd *cobra.Command, args []string) { var err error if len(args) > 0 { util.Failed("This command takes no arguments.") } uidStr, _, _ := util.GetContainerUIDGid() if sshKeyPath == "" { homeDir, err := os.UserHomeDir() if err != nil { util.Failed("Unable to determine home directory: %v", err) } sshKeyPath = filepath.Join(homeDir, ".ssh") } if !filepath.IsAbs(sshKeyPath) { sshKeyPath, err = filepath.Abs(sshKeyPath) if err != nil { util.Failed("Failed to derive absolute path for ssh key path %s: %v", sshKeyPath, err) } } fi, err := os.Stat(sshKeyPath) if os.IsNotExist(err) { util.Failed("The ssh key directory %s was not found", sshKeyPath) } if err != nil { util.Failed("Failed to check status of ssh key directory %s: %v", sshKeyPath, err) } if !fi.IsDir() { util.Failed("The ssh key directory (%s) must be a directory", sshKeyPath) } app, err := ddevapp.GetActiveApp("") if err != nil || app == nil { app = &ddevapp.DdevApp{OmitContainersGlobal: globalconfig.DdevGlobalConfig.OmitContainersGlobal} } omitted := app.GetOmittedContainers() if nodeps.ArrayContainsString(omitted, nodeps.DdevSSHAgentContainer) { util.Failed("ddev-ssh-agent is omitted in your configuration so ssh auth cannot be used") } err = app.EnsureSSHAgentContainer() if err != nil { util.Failed("Failed to start ddev-ssh-agent container: %v", err) } sshKeyPath = dockerutil.MassageWindowsHostMountpoint(sshKeyPath) dockerCmd := []string{"run", "-it", "--rm", "--volumes-from=" + ddevapp.SSHAuthName, "--user=" + uidStr, "--entrypoint=", "--mount=type=bind,src=" + sshKeyPath + ",dst=/tmp/sshtmp", versionconstants.SSHAuthImage + ":" + versionconstants.SSHAuthTag + "-built", "bash", "-c", `cp -r /tmp/sshtmp ~/.ssh && chmod -R go-rwx ~/.ssh && cd ~/.ssh && ssh-add $(file * | awk -F: "/private key/ { print \$1 }")`} err = exec.RunInteractiveCommand("docker", dockerCmd) if err != nil { util.Failed("Docker command 'docker %v' failed: %v", dockerCmd, err) } }, }
AuthSSHCommand implements the "ddev auth ssh" command
var CleanCmd = &cobra.Command{ Use: "clean [projectname ...]", Short: "Removes items ddev has created", Long: `Stops all running projects and then removes downloads and snapshots for the selected projects. Then clean will remove "drud/ddev-*" images. Warning - This command will permanently delete your snapshots for the named project[s]. Additional commands that can help clean up resources: ddev delete --omit-snapshot docker rmi -f $(docker images -q) docker system prune --volumes `, Example: `ddev clean ddev clean project1 project2 ddev clean --all`, Run: func(cmd *cobra.Command, args []string) { cleanAll, _ := cmd.Flags().GetBool("all") if len(args) == 0 && !cleanAll { util.Failed("No project provided. See ddev clean --help for usage") } projects, err := getRequestedProjects(args, cleanAll) if err != nil { util.Failed("Failed to get project(s) '%v': %v", args, err) } util.Warning("Warning - Snapshots for the following project[s] will be permanently deleted") for _, project := range projects { snapshots, err := project.ListSnapshots() if err != nil { util.Failed("Failed to get project %s snapshots: %v", project.Name, err) } if len(snapshots) > 0 { output.UserOut.Printf("%v Snapshots for project %s will be deleted", len(snapshots), project.Name) } else { output.UserOut.Printf("No snapshots found for project %s", project.Name) } } dryRun, _ := cmd.Flags().GetBool("dry-run") if dryRun { util.Warning("Dry run terminated without removing items") return } confirm := util.Prompt("Are you sure you want to continue? y/n", "n") if strings.ToLower(confirm) != "y" { return } util.Success("Powering off ddev to avoid conflicts.") ddevapp.PowerOff() globalDdevDir := globalconfig.GetGlobalDdevDir() _ = os.RemoveAll(filepath.Join(globalDdevDir, "testcache")) _ = os.RemoveAll(filepath.Join(globalDdevDir, "bin")) output.UserOut.Print("Deleting snapshots and downloads for selected projects...") for _, project := range projects { err = os.RemoveAll(project.GetConfigPath(".downloads")) if err != nil { util.Warning("There was an error removing .downloads for project %v", project) } err = os.RemoveAll(project.GetConfigPath("db_snapshots")) if err != nil { util.Warning("There was an error removing db_snapshots for project %v", project) } } output.UserOut.Print("Deleting Docker images that ddev created...") err = deleteDdevImages(true) if err != nil { util.Failed("Failed to delete image tag", err) } util.Success("Finished cleaning ddev projects") }, }
var ComposerCmd = &cobra.Command{ DisableFlagParsing: true, Use: "composer [command]", Short: "Executes a composer command within the web container", Long: `Executes a composer command at the composer root in the web container. Generally, any composer command can be forwarded to the container context by prepending the command with 'ddev'.`, Example: `ddev composer install ddev composer require <package> ddev composer outdated --minor-only ddev composer create drupal/recommended-project`, Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed(err.Error()) } status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { if err = app.Start(); err != nil { util.Failed("Failed to start %s: %v", app.Name, err) } } stdout, stderr, err := app.Composer(args) if err != nil { util.Failed("composer %v failed, %v. stderr=%v", args, err, stderr) } _, _ = fmt.Fprint(os.Stderr, stderr) _, _ = fmt.Fprint(os.Stdout, stdout) }, }
ComposerCmd handles ddev composer
var ComposerCreateCmd = &cobra.Command{ Use: "create [args] [flags]", FParseErrWhitelist: cobra.FParseErrWhitelist{ UnknownFlags: true, }, Short: "Executes 'composer create-project' within the web container with the arguments and flags provided", Long: `Directs basic invocations of 'composer create-project' within the context of the web container. Projects will be installed to a temporary directory and moved to the composer root directory after install. Any existing files in the composer root will be deleted when creating a project.`, Example: `ddev composer create drupal/recommended-project ddev composer create -y drupal/recommended-project ddev composer create "typo3/cms-base-distribution:^10" ddev composer create drupal/recommended-project --no-install ddev composer create --repository=https://repo.magento.com/ magento/project-community-edition ddev composer create --prefer-dist --no-interaction --no-dev psr/log `, Run: func(cmd *cobra.Command, args []string) { osargs := []string{} if len(os.Args) > 3 { osargs = os.Args[3:] osargs = nodeps.RemoveItemFromSlice(osargs, "--yes") osargs = nodeps.RemoveItemFromSlice(osargs, "-y") } app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed(err.Error()) } status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { err = app.Start() if err != nil { util.Failed("Failed to start app %s to run create-project: %v", app.Name, err) } } composerRoot := app.GetComposerRoot(false, false) util.Warning("Warning: MOST EXISTING CONTENT in the composer root (%s) will be deleted by the composer create-project operation. Only .ddev, .git and .tarballs will be preserved.", composerRoot) if !composerCreateYesFlag { if !util.Confirm("Would you like to continue?") { util.Failed("create-project cancelled") } } util.Warning("Removing any existing files in composer root") objs, err := fileutil.ListFilesInDir(composerRoot) if err != nil { util.Failed("Failed to create project: %v", err) } for _, o := range objs { if o == ".ddev" || o == ".git" || o == ".tarballs" { continue } if err = os.RemoveAll(filepath.Join(composerRoot, o)); err != nil { util.Failed("Failed to create project: %v", err) } } err = app.MutagenSyncFlush() if err != nil { util.Failed("Failed to sync mutagen contents: %v", err) } tmpDir := util.RandString(6) containerInstallPath := path.Join("/tmp", tmpDir) noInstallPresent := nodeps.ArrayContainsString(osargs, "--no-install") if !noInstallPresent { osargs = append(osargs, "--no-install") } composerCmd := []string{ "composer", "create-project", } composerCmd = append(composerCmd, osargs...) composerCmd = append(composerCmd, containerInstallPath) output.UserOut.Printf("Executing composer command: %v\n", composerCmd) stdout, stderr, err := app.Exec(&ddevapp.ExecOpts{ Service: "web", RawCmd: composerCmd, Dir: "/var/www/html", Tty: isatty.IsTerminal(os.Stdin.Fd()), }) if err != nil { util.Failed("Failed to create project:%v, stderr=%v", err, stderr) } if len(stdout) > 0 { fmt.Println(strings.TrimSpace(stdout)) } output.UserOut.Printf("Moving install to composer root") rsyncArgs := "-rltgopD" if runtime.GOOS == "windows" { rsyncArgs = "-rlD" } _, _, err = app.Exec(&ddevapp.ExecOpts{ Service: "web", Cmd: fmt.Sprintf(`rsync %s "%s/" "%s/"`, rsyncArgs, containerInstallPath, app.GetComposerRoot(true, false)), Dir: "/var/www/html", }) if err != nil { util.Failed("Failed to create project: %v", err) } if !noInstallPresent { composerCmd = []string{ "composer", "install", } supportedArgs := []string{ "--prefer-source", "--prefer-dist", "--prefer-install", "--no-dev", "--no-progress", "--ignore-platform-req", "--ignore-platform-reqs", "-q", "--quiet", "--ansi", "--no-ansi", "-n", "--no-interaction", "--profile", "--no-plugins", "--no-scripts", "-d", "--working-dir", "--no-cache", "-v", "-vv", "-vvv", "--verbose", } for _, osarg := range osargs { for _, supportedArg := range supportedArgs { if strings.HasPrefix(osarg, supportedArg) { composerCmd = append(composerCmd, osarg) } } } output.UserOut.Printf("Executing composer command: %v\n", composerCmd) stdout, stderr, err := app.Exec(&ddevapp.ExecOpts{ Service: "web", RawCmd: composerCmd, Dir: "/var/www/html", Tty: isatty.IsTerminal(os.Stdin.Fd()), }) if err != nil { util.Failed("Failed to install project:%v, stderr=%v", err, stderr) } if len(stdout) > 0 { fmt.Println(strings.TrimSpace(stdout)) } } err = app.Restart() if err != nil { util.Warning("Failed to restart project after composer create: %v", err) } if runtime.GOOS == "windows" { fileutil.ReplaceSimulatedLinks(app.AppRoot) } }, }
ComposerCreateCmd handles ddev composer create
var ComposerCreateProjectCmd = &cobra.Command{ Use: "create-project", Short: "Unsupported, use `ddev composer create` instead", DisableFlagParsing: true, Run: func(cmd *cobra.Command, args []string) { util.Failed(`'ddev composer create-project' is unsupported. Please use 'ddev composer create' for basic project creation or 'ddev ssh' into the web container and execute 'composer create-project' directly.`) }, }
ComposerCreateProjectCmd just sends people to the right thing when they try ddev composer create-project
var ConfigCommand = &cobra.Command{ Use: "config [provider or 'global']", Short: "Create or modify a ddev project configuration in the current directory", Example: `"ddev config" or "ddev config --docroot=web --project-type=drupal8"`, Args: cobra.ExactArgs(0), Run: handleConfigRun, }
ConfigCommand represents the `ddev config` command
var DdevExecCmd = &cobra.Command{ Use: "exec <command>", Aliases: []string{"."}, Short: "Execute a shell command in the container for a service. Uses the web service by default.", Long: `Execute a shell command in the container for a service. Uses the web service by default. To run your command in the container for another service, run "ddev exec --service <service> <cmd>". If you want to use raw, uninterpreted command inside container use --raw as in example.`, Example: `ddev exec ls /var/www/html ddev exec --service db\nddev exec -s db ddev exec -s solr (assuming an add-on service named 'solr') ddev exec --raw -- ls -lR`, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { err := cmd.Usage() util.CheckErr(err) os.Exit(1) } app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Failed to exec command: %v", err) } status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { util.Failed("Project is not currently running. Try 'ddev start'.") } app.DockerEnv() opts := &ddevapp.ExecOpts{ Service: serviceType, Dir: execDirArg, Cmd: strings.Join(args, " "), Tty: true, } if cmd.Flag("raw").Changed { if useRaw, _ := cmd.Flags().GetBool("raw"); useRaw { opts.RawCmd = args } } _, _, err = app.Exec(opts) if err != nil { util.Failed("Failed to execute command %s: %v", strings.Join(args, " "), err) } }, }
DdevExecCmd allows users to execute arbitrary sh commands within a container.
var DdevLogsCmd = &cobra.Command{ Use: "logs [projectname]", Short: "Get the logs from your running services.", Long: `Uses 'docker logs' to display stdout from the running services.`, Example: `ddev logs ddev logs -f ddev logs -s db ddev logs -s db [projectname]`, Run: func(cmd *cobra.Command, args []string) { if len(args) > 1 { util.Failed("Too many arguments provided. Please use 'ddev logs' or 'ddev logs [projectname]'") } projects, err := getRequestedProjects(args, false) if err != nil { util.Failed("GetRequestedProjects() failed: %v", err) } project := projects[0] err = project.Logs(serviceType, follow, timestamp, tail) if err != nil { util.Failed("Failed to retrieve logs for %s: %v", project.GetName(), err) } }, }
DdevLogsCmd contains the "ddev logs" command
var DdevPauseCommand = &cobra.Command{ Use: "pause [projectname ...]", Short: "uses 'docker stop' to pause/stop the containers belonging to a project.", Long: `Uses "docker-compose stop" to pause/stop the containers belonging to a project. This leaves the containers instantiated instead of removing them like ddev stop does. You can run 'ddev pause' from a project directory to stop the containers of that project, or you can stop running projects in any directory by running 'ddev pause projectname [projectname ...]' or pause all with 'ddev pause --all'`, Aliases: []string{"sc", "stop-containers"}, Run: func(cmd *cobra.Command, args []string) { projects, err := getRequestedProjects(args, pauseAllProjects) if err != nil { util.Failed("Unable to get project(s): %v", err) } if len(projects) > 0 { instrumentationApp = projects[0] } for _, project := range projects { if err := ddevapp.CheckForMissingProjectFiles(project); err != nil { util.Failed("Failed to pause/stop-containers %s: %v", project.GetName(), err) } if err := project.Pause(); err != nil { util.Failed("Failed to pause/stop-containers %s: %v", project.GetName(), err) } util.Success("Project %s has been paused.", project.GetName()) } }, }
DdevPauseCommand represents the stop command
var DdevRestoreSnapshotCommand = &cobra.Command{ Hidden: true, Use: "restore-snapshot [snapshot_name]", Short: "Restore a project's database to the provided snapshot version.", Long: "Please use \"snapshot restore\" command", Run: func(cmd *cobra.Command, args []string) { util.Failed("Please use \"ddev snapshot restore\".") os.Exit(1) }, }
DdevRestoreSnapshotCommand provides the ability to revert to a database snapshot
var DdevSSHCmd = &cobra.Command{ Use: "ssh [projectname]", Short: "Starts a shell session in the container for a service. Uses web service by default.", Long: `Starts a shell session in the container for a service. Uses web service by default. To start a shell session for another service, run "ddev ssh --service <service>`, Example: `ddev ssh ddev ssh -s sb ddev ssh <projectname> ddev ssh -d /var/www/html`, Args: cobra.MaximumNArgs(1), Run: func(cmd *cobra.Command, args []string) { projects, err := getRequestedProjects(args, false) if err != nil || len(projects) == 0 { util.Failed("Failed to ddev ssh: %v", err) } app := projects[0] instrumentationApp = app status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { util.Failed("Project is not currently running. Try 'ddev start'.") } app.DockerEnv() shell := "bash" if !nodeps.ArrayContainsString([]string{"web", "db", "dba", "solr"}, serviceType) { shell = "sh" } err = app.ExecWithTty(&ddevapp.ExecOpts{ Service: serviceType, Cmd: shell + " -l", Dir: sshDirArg, }) if err != nil { util.Failed("Failed to ddev ssh %s: %v", serviceType, err) } }, }
DdevSSHCmd represents the ssh command.
cobra.Command, args []string) { if len(args) > 1 { util.Failed("Too many arguments provided. Please use 'ddev share' or 'ddev share [projectname]'") } apps, err := getRequestedProjects(args, false) if err != nil { util.Failed("Failed to describe project(s): %v", err) } app := apps[0] status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { util.Failed("Project is not yet running. Use 'ddev start' first.") } ngrokLoc, err := exec.LookPath("ngrok") if ngrokLoc == "" || err != nil { util.Failed("ngrok not found in path, please install it, see https://ngrok.com/download") } urls := []string{app.GetWebContainerDirectHTTPURL()} var ngrokErr error for _, url := range urls { ngrokArgs := []string{"http"} ngrokArgs = append(ngrokArgs, url) if app.NgrokArgs != "" { ngrokArgs = append(ngrokArgs, strings.Split(app.NgrokArgs, " ")...) } if cmd.Flags().Changed("subdomain") { sub, err := cmd.Flags().GetString("subdomain") if err != nil { util.Failed("unable to get --subdomain flag: %v", err) } ngrokArgs = append(ngrokArgs, "--subdomain="+sub) } ngrokCmd := exec.Command(ngrokLoc, ngrokArgs...) ngrokCmd.Stdout = os.Stdout ngrokCmd.Stderr = os.Stderr err = ngrokCmd.Start() if err != nil { util.Failed("Failed to run %s %s: %v", ngrokLoc, strings.Join(ngrokArgs, " "), err) } util.Success("Running %s %s", ngrokLoc, strings.Join(ngrokArgs, " ")) ngrokErr = ngrokCmd.Wait() if ngrokErr == nil { break } exitErr, ok := ngrokErr.(*exec.ExitError) if !ok { util.Error("ngrok exited: %v", ngrokErr) break } exitCode := exitErr.ExitCode() if exitCode != 1 { util.Error("ngrok exited: %v", exitErr) break } } os.Exit(0) }, }Use: "share [project]", Short: "Share project on the internet via ngrok.", Long: `Use "ddev share" or add on extra ngrok commands, like "ddev share --basic-auth username:pass1234". Although a few ngrok commands are supported directly, any ngrok flag can be added in the ngrok_args section of .ddev/config.yaml. Requires a free or paid account on ngrok.com; use the "ngrok authtoken" command to set up ngrok.`, Example: `ddev share ddev share --basic-auth username:pass1234 ddev share myproject`, Run: func(cmd *
DdevShareCommand contains the "ddev share" command
var DdevSnapshotCommand = &cobra.Command{ Use: "snapshot [projectname projectname...]", Short: "Create a database snapshot for one or more projects.", Long: `Uses mariabackup or xtrabackup command to create a database snapshot in the .ddev/db_snapshots folder. These are compatible with server backups using the same tools and can be restored with "ddev snapshot restore".`, Example: `ddev snapshot ddev snapshot --name some_descriptive_name ddev snapshot --cleanup ddev snapshot --cleanup -y ddev snapshot --list ddev snapshot --all`, Run: func(cmd *cobra.Command, args []string) { apps, err := getRequestedProjects(args, snapshotAll) if err != nil { util.Failed("Unable to get project(s) %v: %v", args, err) } if len(apps) > 0 { instrumentationApp = apps[0] } for _, app := range apps { if app.Database.Type == nodeps.Postgres && app.Database.Version == nodeps.Postgres9 { util.Failed("Snapshots are not supported for postgres:9") } switch { case snapshotList: listAppSnapshots(app) case snapshotCleanup: deleteAppSnapshot(app) default: createAppSnapshot(app) } } }, }
DdevSnapshotCommand provides the snapshot command
var DdevSnapshotRestoreCommand = &cobra.Command{ Use: "restore [snapshot_name]", Short: "Restore a project's database to the provided snapshot version.", Long: `Uses mariabackup command to restore a project database to a particular snapshot from the .ddev/db_snapshots folder. Example: "ddev snapshot restore d8git_20180717203845"`, Run: func(cmd *cobra.Command, args []string) { var snapshotName string app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Failed to find active project: %v", err) } if app.Database.Type == nodeps.Postgres && app.Database.Version == nodeps.Postgres9 { util.Failed("Snapshots are not supported for postgres:9") } if snapshotRestoreLatest { if snapshotName, err = app.GetLatestSnapshot(); err != nil { util.Failed("Failed to get latest snapshot of project %s: %v", app.GetName(), err) } } else { if len(args) != 1 { snapshots, err := app.ListSnapshots() if err != nil { util.Failed("Cannot list snapshots of project %s: %v", app.GetName(), err) } if len(snapshots) == 0 { util.Failed("No snapshots found for project %s", app.GetName()) } templates := &promptui.SelectTemplates{ Label: "{{ . | cyan }}:", } prompt := promptui.Select{ Label: "Snapshot", Items: snapshots, Templates: templates, } _, snapshotName, err = prompt.Run() if err != nil { util.Failed("Prompt failed %v", err) } } else { snapshotName = args[0] } } if err := app.RestoreSnapshot(snapshotName); err != nil { util.Failed("Failed to restore snapshot %s for project %s: %v", snapshotName, app.GetName(), err) } }, }
DdevSnapshotRestoreCommand handles ddev snapshot restore
var DdevStopCmd = &cobra.Command{ Use: "stop [projectname ...]", Aliases: []string{"rm", "remove"}, Short: "Stop and remove the containers of a project. Does not lose or harm anything unless you add --remove-data.", Long: `Stop and remove the containers of a project. You can run 'ddev stop' from a project directory to stop/remove that project, or you can stop/remove projects in any directory by running 'ddev stop projectname [projectname ...]' or 'ddev stop -a'. By default, stop is a non-destructive operation and will leave database contents intact. It never touches your code or files directories. To remove database contents and global listing, use "ddev delete" or "ddev stop --remove-data". To snapshot the database on stop, use "ddev stop --snapshot"; A snapshot is automatically created on "ddev stop --remove-data" unless you use "ddev stop --remove-data --omit-snapshot". `, Example: `ddev stop ddev stop proj1 proj2 proj3 ddev stop --all ddev stop --all --stop-ssh-agent ddev stop --remove-data`, Run: func(cmd *cobra.Command, args []string) { if createSnapshot && omitSnapshot { util.Failed("Illegal option combination: --snapshot and --omit-snapshot:") } selectFlag, err := cmd.Flags().GetBool("select") if err != nil { util.Failed(err.Error()) } if selectFlag { activeProjects := ddevapp.GetActiveProjects() if len(activeProjects) == 0 { util.Warning("No project is currently running") os.Exit(0) } activeProjectNames := ddevapp.ExtractProjectNames(activeProjects) prompt := promptui.Select{ Label: "Running projects", Items: activeProjectNames, Templates: &promptui.SelectTemplates{ Label: "{{ . | cyan }}:", }, } _, projectName, err := prompt.Run() if err != nil { util.Failed(err.Error()) } args = append(args, projectName) } projects, err := getRequestedProjects(args, stopAll) if err != nil { util.Failed("Failed to get project(s): %v", err) } if len(projects) > 0 { instrumentationApp = projects[0] } for _, project := range projects { status, _ := project.SiteStatus() if status == ddevapp.SiteStopped { util.Success("Project %s is already stopped.", project.GetName()) } doSnapshot := (createSnapshot || removeData) && !omitSnapshot if err := project.Stop(removeData, doSnapshot); err != nil { util.Failed("Failed to stop project %s: \n%v", project.GetName(), err) } if unlist { project.RemoveGlobalProjectInfo() err = ddevapp.TerminateMutagenSync(project) if err != nil { util.Warning("Unable to terminate mutagen sync for project %s", project.Name) } } util.Success("Project %s has been stopped.", project.GetName()) } if stopSSHAgent { if err := ddevapp.RemoveSSHAgentContainer(); err != nil { util.Error("Failed to remove ddev-ssh-agent: %v", err) } } }, }
DdevStopCmd represents the remove command
var DebugCapabilitiesCmd = &cobra.Command{ Use: "capabilities", Short: "Show capabilities of this version of ddev", Run: func(cmd *cobra.Command, args []string) { capabilities := []string{ "multiple-dockerfiles", "interactive-project-selection", "ddev-get-yaml-interpolation", "config-star-yaml-merging", "pre-dockerfile-insertion", "user-env-var", "npm-yarn-caching", "exposed-ports-configuration", "daemon-run-configuration", "get-volume-db-version", "migrate-database", } output.UserOut.WithField("raw", capabilities).Print(strings.Join(capabilities, "\n")) }, }
DebugCapabilitiesCmd implements the ddev debug capabilities command
var DebugCheckDBMatch = &cobra.Command{ Use: "check-db-match", Short: "Verify that the database in the ddev-db server matches the configured type/version", Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Can't find active project: %v", err) } dbType, err := app.GetExistingDBType() if err != nil { util.Failed("Failed to check existing DB type: %v", err) } expected := app.Database.Type + ":" + app.Database.Version if expected != dbType { util.Failed("configured database type=%s but database type in volume is %s", expected, dbType) } util.Success("database in volume matches configured database: %s", expected) }, }
DebugCheckDBMatch verified that the DB Type/Version in container matches configured
var DebugCmd = &cobra.Command{ Use: "debug [command]", Short: "A collection of debugging commands", Aliases: []string{"d", "dbg"}, Example: `ddev debug ddev debug mutagen sync list ddev d mutagen sync list ddev d capabilities`, Run: func(cmd *cobra.Command, args []string) { err := cmd.Usage() util.CheckErr(err) }, }
DebugCmd is the top-level "ddev debug" command
var DebugComposeConfigCmd = &cobra.Command{ Use: "compose-config [project]", Short: "Prints the docker-compose configuration of the current project", Run: func(cmd *cobra.Command, args []string) { projectName := "" if len(args) > 1 { util.Failed("This command only takes one optional argument: project name") } if len(args) == 1 { projectName = args[0] } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get compose-config: %v", err) } app.DockerEnv() if err = app.WriteDockerComposeYAML(); err != nil { util.Failed("Failed to get compose-config: %v", err) } out, err := fileutil.ReadFileIntoString(app.DockerComposeFullRenderedYAMLPath()) if err != nil { util.Failed("unable to read rendered file %s: %v", app.DockerComposeFullRenderedYAMLPath(), err) } output.UserOut.Print(strings.TrimSpace(out)) }, }
DebugComposeConfigCmd implements the ddev debug compose-config command
var DebugConfigYamlCmd = &cobra.Command{ Use: "configyaml [project]", Short: "Prints the project config.*.yaml usage", Example: "ddev debug configyaml, ddev debug configyaml <projectname>", Run: func(cmd *cobra.Command, args []string) { projectName := "" if len(args) > 1 { util.Failed("This command only takes one optional argument: project-name") } if len(args) == 1 { projectName = args[0] } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get active project: %v", err) } configFiles, err := app.ReadConfig(true) if err != nil { util.Error("failed reading config for project %s: %v", app.Name, err) } output.UserOut.Printf("These config files were loaded for project %s: %v", app.Name, configFiles) fields := reflect.TypeOf(*app) values := reflect.ValueOf(*app) num := fields.NumField() for i := 0; i < num; i++ { field := fields.Field(i) v := values.Field(i) yaml := field.Tag.Get("yaml") key := strings.Split(yaml, ",") if v.CanInterface() && key[0] != "-" && !isZero(v) { output.UserOut.Printf("%s: %v", key[0], v) } } }, }
DebugConfigYamlCmd implements the ddev debug configyaml command
var DebugDockercheckCmd = &cobra.Command{ Use: "dockercheck", Short: "Diagnose DDEV docker/colima setup", Example: "ddev debug dockercheck", Run: func(cmd *cobra.Command, args []string) { if len(args) != 0 { util.Failed("This command takes no additional arguments") } versionInfo := version.GetVersionInfo() util.Success("Docker platform: %v", versionInfo["docker-platform"]) switch versionInfo["docker-platform"] { case "colima": p, err := exec.LookPath("colima") if err == nil { bashPath := util.FindBashPath() out, err := exec2.RunHostCommand(bashPath, "-c", fmt.Sprintf("%s version | awk '/colima version/ {print $3}'", p)) out = strings.Trim(out, "\r\n ") if err == nil { util.Success("Colima version: %v", out) } } case "docker desktop": dockerutil.IsDockerDesktop() } util.Success("Using docker context: %s (%s)", dockerutil.DockerContext, dockerutil.DockerHost) util.Success("docker-compose: %s", versionInfo["docker-compose"]) dockerHost := os.Getenv("DOCKER_HOST") if dockerHost != "" { util.Success("Using DOCKER_HOST=%s", dockerHost) } dockerContext := os.Getenv("DOCKER_CONTEXT") if dockerContext != "" { util.Success("Using DOCKER_CONTEXT=%s", dockerContext) } dockerVersion, err := dockerutil.GetDockerVersion() if err != nil { util.Failed("Unable to get docker version: %v", err) } util.Success("Docker version: %s", dockerVersion) err = dockerutil.CheckDockerVersion(dockerutil.DockerVersionConstraint) if err != nil { if err.Error() == "no docker" { util.Failed("Docker is not installed or the docker client is not available in the $PATH") } else { util.Warning("The docker version currently installed does not seem to meet ddev's requirements: %v", err) } } client := dockerutil.GetDockerClient() if client == nil { util.Failed("Unable to get docker client") } uid, _, _ := util.GetContainerUIDGid() _, _, err = dockerutil.RunSimpleContainer(versionconstants.GetWebImage(), "", []string{"ls", "/mnt/ddev-global-cache"}, []string{}, []string{}, []string{"ddev-global-cache" + ":/mnt/ddev-globa-cache"}, uid, true, false, nil) if err != nil { util.Warning("Unable to run simple container: %v", err) } else { util.Success("Able to run simple container that mounts a volume.") } _, _, err = dockerutil.RunSimpleContainer(versionconstants.GetWebImage(), "", []string{"curl", "-sfLI", "https://google.com"}, []string{}, []string{}, []string{"ddev-global-cache" + ":/mnt/ddev-globa-cache"}, uid, true, false, nil) if err != nil { util.Warning("Unable to run use internet inside container, many things will fail: %v", err) } else { util.Success("Able to use internet inside container.") } dockerutil.CheckAvailableSpace() }, }
DebugDockercheckCmd implements the ddev debug dockercheck command
var DebugDownloadImagesCmd = &cobra.Command{ Use: "download-images", Short: "Download all images required by ddev", Example: "ddev debug download-images", Run: func(cmd *cobra.Command, args []string) { if len(args) != 0 { util.Failed("This command takes no additional arguments") } app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("No active project was found: %v", err) } _, err = dockerutil.DownloadDockerComposeIfNeeded() if err != nil { util.Warning("Unable to download docker-compose: %v", err) } err = ddevapp.DownloadMutagenIfNeeded(app) if err != nil { util.Warning("Unable to download mutagen: %v", err) } app.DockerEnv() err = app.WriteDockerComposeYAML() if err != nil { util.Failed("Unable to WriteDockerComposeYAML(): %v", err) } err = app.PullContainerImages() if err != nil { util.Failed("Failed to debug download-images: %v", err) } util.Success("Successfully downloaded ddev images") }, }
DebugDownloadImagesCmd implements the ddev debug download-images command
var DebugFixCommandsCmd = &cobra.Command{ Use: "fix-commands", Short: "Fix up custom/shell commands without running ddev start", Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Can't find active project: %v", err) } err = ddevapp.PopulateCustomCommandFiles(app) if err != nil { util.Warning("Failed to populate custom command files: %v", err) } if globalconfig.DdevGlobalConfig.NoBindMounts { err = app.Start() if err != nil { util.Failed("Failed to restart with NoBindMounts set: %v", err) } } }, }
DebugFixCommandsCmd fixes up custom/shell commands without having to do a ddev start
var DebugGetVolumeDBVersion = &cobra.Command{ Use: "get-volume-db-version", Short: "Get the database type/version found in the ddev-dbserver's database volume, which may not be the same as the configured database type/version", Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Can't find active project: %v", err) } dbType, err := app.GetExistingDBType() if err != nil { util.Failed("Failed to get existing DB type/version: %v", err) } util.Success(dbType) }, }
DebugGetVolumeDBVersion gets the DB Type/Version in the ddev-dbserver
var DebugMigrateDatabase = &cobra.Command{ Use: "migrate-database", Short: "Migrate a mysql or mariadb database to a different dbtype:dbversion; works only with mysql and mariadb, not with postgres", Example: `ddev debug migrate-database mysql:8.0 ddev debug migrate-database mariadb:10.7`, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Can't find active project: %v", err) } newDBVersionType := args[0] existingDBType, err := app.GetExistingDBType() if err != nil { util.Failed("Failed to get existing DB type/version: %v", err) } if newDBVersionType == existingDBType { util.Success("database type in the docker volume is already %s", newDBVersionType) return } if !strings.HasPrefix(newDBVersionType, nodeps.MariaDB) && !strings.HasPrefix(newDBVersionType, nodeps.MySQL) { util.Failed("this command can only convert between mariadb and mysql") } if !(nodeps.IsValidMariaDBVersion(newDBVersionType) || nodeps.IsValidMySQLVersion(newDBVersionType)) && !(nodeps.IsValidMariaDBVersion(existingDBType) || nodeps.IsValidMySQLVersion(existingDBType)) { if !util.Confirm(fmt.Sprintf("Is it OK to attempt conversion from %s to %s?\nThis will export your database, create a snapshot,\nthen destroy your current database and import into the new database type.\nIt only migrates the 'db' database", existingDBType, newDBVersionType)) { util.Failed("migrate-database cancelled") } err = os.MkdirAll(app.GetConfigPath(".downloads"), 0755) if err != nil { util.Failed("failed to create %s: %v", app.GetConfigPath(".downloads"), err) } status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { err = app.Start() if err != nil { util.Failed("failed to start %s: %v", app.Name, err) } } err = app.ExportDB(app.GetConfigPath(".downloads/db.sql.gz"), "gzip", "db") if err != nil { util.Failed("failed to export-db to %s: %v", app.GetConfigPath(".downloads/db.sql.gz"), err) } err = app.Stop(true, true) if err != nil { util.Failed("failed to stop and delete %s with snapshot: %v", app.Name, err) } typeVals := strings.Split(newDBVersionType, ":") app.Database.Type = typeVals[0] app.Database.Version = typeVals[1] err = app.WriteConfig() if err != nil { util.Failed("failed to WriteConfig: %v", err) } err = app.Start() if err != nil { util.Failed("failed to start %s: %v", app.Name, err) } err = app.ImportDB(app.GetConfigPath(".downloads/db.sql.gz"), "", true, false, "") if err != nil { util.Failed("failed to import-db %s: %v", app.GetConfigPath(".downloads/db.sql.gz"), err) } util.Success("database was converted to %s", newDBVersionType) return } util.Failed("Invalid target source database type (%s) or target database type (%s)", existingDBType, newDBVersionType) }, }
DebugMigrateDatabase Migrates a database to a new type
var DebugMutagenCmd = &cobra.Command{ Use: "mutagen", Short: "Allows access to any mutagen command", FParseErrWhitelist: cobra.FParseErrWhitelist{ UnknownFlags: true, }, Long: "This simply passes through any mutagen command to the embedded mutagen itself. See Mutagen docs at https://mutagen.io/documentation/introduction", Example: `ddev debug mutagen sync list ddev debug mutagen daemon stop ddev debug mutagen ddev d mutagen sync list `, Run: func(cmd *cobra.Command, args []string) { mutagenPath := globalconfig.GetMutagenPath() _, err := os.Stat(mutagenPath) if err != nil { util.Warning("mutagen does not seem to be set up in %s, not executing command", mutagenPath) return } out, err := exec.RunHostCommand(mutagenPath, os.Args[3:]...) output.UserOut.Printf(out) if err != nil { util.Failed("Error running '%s %v': %v", globalconfig.GetMutagenPath(), args, err) } }, }
DebugMutagenCmd implements the ddev debug mutagen command
var DebugNFSMountCmd = &cobra.Command{ Use: "nfsmount", Short: "Checks to see if nfs mounting works for current project", Example: "ddev debug nfsmount", Run: func(cmd *cobra.Command, args []string) { testVolume := "testnfsmount" containerName := "testnfscontainer" if len(args) != 0 { util.Failed("This command takes no additional arguments") } app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Failed to debug nfsmount: %v", err) } oldContainer, err := dockerutil.FindContainerByName(containerName) if err == nil && oldContainer != nil { err = dockerutil.RemoveContainer(oldContainer.ID, 20) if err != nil { util.Failed("Failed to remove existing test container %s: %v", containerName, err) } } dockerutil.RemoveVolume(testVolume) nfsServerAddr, err := dockerutil.GetNFSServerAddr() if err != nil { util.Failed("failed to GetNFSServerAddr(): %v", err) } shareDir := app.AppRoot if runtime.GOOS == "darwin" && fileutil.IsDirectory(filepath.Join("/System/Volumes/Data", app.AppRoot)) { shareDir = filepath.Join("/System/Volumes/Data", app.AppRoot) } volume, err := dockerutil.CreateVolume(testVolume, "local", map[string]string{"type": "nfs", "o": fmt.Sprintf("addr=%s,hard,nolock,rw,wsize=32768,rsize=32768", nfsServerAddr), "device": ":" + dockerutil.MassageWindowsNFSMount(shareDir)}, nil) defer dockerutil.RemoveVolume(testVolume) if err != nil { util.Failed("Failed to create volume %s: %v", testVolume, err) } _ = volume uidStr, _, _ := util.GetContainerUIDGid() _, out, err := dockerutil.RunSimpleContainer(versionconstants.GetWebImage(), containerName, []string{"sh", "-c", "findmnt -T /nfsmount && ls -d /nfsmount/.ddev"}, []string{}, []string{}, []string{"testnfsmount" + ":/nfsmount"}, uidStr, true, false, nil) if err != nil { util.Warning("NFS does not seem to be set up yet, see debugging instructions at https://ddev.readthedocs.io/en/stable/users/install/performance/#debugging-ddev-start-failures-with-nfs_mount_enabled-true") util.Failed("Details: error=%v\noutput=%v", err, out) } output.UserOut.Printf(strings.TrimSpace(out)) util.Success("") util.Success("Successfully accessed NFS mount of %s", app.AppRoot) switch { case app.NFSMountEnabledGlobal: util.Success("nfs_mount_enabled is set globally") case app.NFSMountEnabled: util.Success("nfs_mount_enabled is true in this project (%s), but is not set globally", app.Name) default: util.Warning("nfs_mount_enabled is not set either globally or in this project. \nUse `ddev config global --nfs-mount-enabled` to enable it.") } }, }
DebugNFSMountCmd implements the ddev debug nfsmount command
var DebugRefreshCmd = &cobra.Command{ Use: "refresh", Short: "Refreshes docker cache for project", Run: func(cmd *cobra.Command, args []string) { projectName := "" if len(args) > 1 { util.Failed("This command only takes one optional argument: project name") } if len(args) == 1 { projectName = args[0] } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get project: %v", err) } status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { if err = app.Start(); err != nil { util.Failed("Failed to start %s: %v", app.Name, err) } } app.DockerEnv() if err = app.WriteDockerComposeYAML(); err != nil { util.Failed("Failed to get compose-config: %v", err) } util.Debug("Executing docker-compose -f %s build --no-cache", app.DockerComposeFullRenderedYAMLPath()) _, _, err = dockerutil.ComposeCmd([]string{app.DockerComposeFullRenderedYAMLPath()}, "build", "--no-cache") if err != nil { util.Failed("Failed to execute docker-compose -f %s build --no-cache: %v", err) } err = app.Restart() if err != nil { util.Failed("Failed to restart project: %v", err) } util.Success("Refreshed docker cache for project %s", app.Name) }, }
DebugRefreshCmd implements the ddev debug refresh command
var DebugRouterNginxConfigCmd = &cobra.Command{ Use: "router-nginx-config", Short: "Prints the nginx config of the router", Example: "ddev debug router-nginx-config", Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Failed to debug router-config : %v", err) } if ddevapp.IsRouterDisabled(app) { util.Warning("Router is disabled by config") os.Exit(0) } container, _ := ddevapp.FindDdevRouter() if container == nil { util.Failed("Router is not running") return } stdout, _, err := dockerutil.Exec(container.ID, "cat /etc/nginx/conf.d/ddev.conf", "") if err != nil { util.Failed("Failed to run docker-gen command in ddev-router container: %v", err) } output.UserOut.Print(strings.TrimSpace(stdout)) }, }
DebugRouterNginxConfigCmd implements the ddev debug router-config command
var DebugTestCmdCmd = &cobra.Command{ Use: "test", Short: "Run diagnostics on ddev using the embedded test_ddev.sh script", Example: "ddev debug test", Run: func(cmd *cobra.Command, args []string) { if len(args) != 0 { util.Failed("This command takes no additional arguments") } tmpDir := os.TempDir() bashPath := util.FindBashPath() err := fileutil.CopyEmbedAssets(bundledAssets, "scripts", tmpDir) if err != nil { util.Failed("Failed to copy test_ddev.sh to %s: %v", tmpDir, err) } p := dockerutil.MassageWindowsHostMountpoint(tmpDir) c := []string{"-c", path.Join(p, "test_ddev.sh")} util.Success("Running %s %v", bashPath, c) err = exec.RunInteractiveCommand(bashPath, c) if err != nil { util.Failed("Failed running test_ddev.sh: %v\n. You can run it manually with `curl -sL -O https://raw.githubusercontent.com/drud/ddev/master/cmd/ddev/cmd/scripts/test_ddev.sh && bash test_ddev.sh`", err) } }, }
DebugTestCmdCmd implements the ddev debug test command
var DeleteCmd = &cobra.Command{ Use: "delete [projectname ...]", Short: "Remove all project information (including database) for an existing project", Long: `Removes all ddev project information (including database) for an existing project, but does not touch the project codebase or the codebase's .ddev folder.'.`, Example: `ddev delete ddev delete proj1 proj2 proj3 ddev delete --omit-snapshot proj1 ddev delete --omit-snapshot --yes proj1 proj2 ddev delete -Oy ddev delete --all`, Run: func(cmd *cobra.Command, args []string) { if noConfirm && deleteAll { util.Failed("Sorry, it's not possible to use flags --all and --yes together") } projects, err := getRequestedProjects(args, deleteAll) if err != nil { util.Failed("Failed to get project(s): %v", err) } if len(projects) > 0 { instrumentationApp = projects[0] } for _, project := range projects { if !noConfirm { prompt := "OK to delete this project and its database?\n %s in %s\nThe code and its .ddev directory will not be touched.\n" if !omitSnapshot { prompt = prompt + "A database snapshot will be made before the database is deleted.\n" } if !util.Confirm(fmt.Sprintf(prompt+"OK to delete %s?", project.Name, project.AppRoot, project.Name)) { continue } } status, _ := project.SiteStatus() if status != ddevapp.SiteRunning && !omitSnapshot { util.Warning("project must be started to do the snapshot") err = project.Start() if err != nil { util.Failed("Failed to start project %s: %v", project.Name, err) } } if err := project.Stop(true, !omitSnapshot); err != nil { util.Failed("Failed to remove project %s: \n%v", project.GetName(), err) } } }, }
DeleteCmd provides the delete command
var DeleteImagesCmd = &cobra.Command{ Use: "images", Short: "Deletes drud/ddev-* docker images not in use by current ddev version", Long: "with --all it deletes all drud/ddev-* docker images", Example: `ddev delete images ddev delete images -y ddev delete images --all`, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { deleteImagesNocConfirm, _ := cmd.Flags().GetBool("yes") if !deleteImagesNocConfirm { if !util.Confirm("Deleting unused ddev images. \nThis is a non-destructive operation, \nbut it may require that the images be downloaded again when you need them. \nOK to continue?") { os.Exit(1) } } util.Success("Powering off ddev to avoid conflicts") ddevapp.PowerOff() deleteAllImages, _ := cmd.Flags().GetBool("all") err := deleteDdevImages(deleteAllImages) if err != nil { util.Failed("Failed to delete image", err) } util.Success("All ddev images discovered were deleted.") }, }
DeleteImagesCmd implements the ddev delete images command
var DescribeCommand = &cobra.Command{ Use: "describe [projectname]", Aliases: []string{"status", "st", "desc"}, Short: "Get a detailed description of a running ddev project.", Long: `Get a detailed description of a running ddev project. Describe provides basic information about a ddev project, including its name, location, url, and status. It also provides details for MySQL connections, and connection information for additional services like MailHog and phpMyAdmin. You can run 'ddev describe' from a project directory to describe that project, or you can specify a project to describe by running 'ddev describe <projectname>'.`, Example: "ddev describe\nddev describe <projectname>\nddev status\nddev st", Run: func(cmd *cobra.Command, args []string) { if len(args) > 1 { util.Failed("Too many arguments provided. Please use 'ddev describe' or 'ddev describe [projectname]'") } apps, err := getRequestedProjects(args, false) if err != nil { util.Failed("Failed to describe project(s): %v", err) } app := apps[0] if err := ddevapp.CheckForMissingProjectFiles(app); err != nil { util.Failed("Failed to describe %s: %v", app.Name, err) } desc, err := app.Describe(false) if err != nil { util.Failed("Failed to describe project %s: %v", app.Name, err) } renderedDesc, err := renderAppDescribe(app, desc) util.CheckErr(err) output.UserOut.WithField("raw", desc).Print(renderedDesc) }, }
DescribeCommand represents the `ddev config` command
var ExportDBCmd = &cobra.Command{ Use: "export-db [project]", Short: "Dump a database to a file or to stdout", Long: `Dump a database to a file or to stdout`, Example: `ddev export-db --file=/tmp/db.sql.gz ddev export-db -f /tmp/db.sql.gz ddev export-db --gzip=false --file /tmp/db.sql ddev export-db > /tmp/db.sql.gz ddev export-db --gzip=false > /tmp/db.sql ddev export-db myproject --gzip=false --file=/tmp/myproject.sql ddev export-db someproject --gzip=false --file=/tmp/someproject.sql `, Args: cobra.RangeArgs(0, 1), PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, Run: func(cmd *cobra.Command, args []string) { projects, err := getRequestedProjects(args, false) if err != nil { util.Failed("Unable to get project(s): %v", err) } app := projects[0] status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { err = app.Start() if err != nil { util.Failed("Failed to start app %s to import-db: %v", app.Name, err) } } compressionType := "" if doGzip { compressionType = "gzip" } if doBzip2 { compressionType = "bzip2" } if doXz { compressionType = "xz" } err = app.ExportDB(outFileName, compressionType, exportTargetDB) if err != nil { util.Failed("Failed to export database for %s: %v", app.GetName(), err) } }, }
ExportDBCmd is the `ddev export-db` command.
var Get = &cobra.Command{ Use: "get <addonOrURL> [project]", Short: "Get/Download a 3rd party add-on (service, provider, etc.)", Long: `Get/Download a 3rd party add-on (service, provider, etc.). This can be a github repo, in which case the latest release will be used, or it can be a link to a .tar.gz in the correct format (like a particular release's .tar.gz) or it can be a local directory. Use 'ddev get --list' or 'ddev get --list --all' to see a list of available add-ons. Without --all it shows only official ddev add-ons.`, Example: `ddev get drud/ddev-drupal9-solr ddev get https://github.com/drud/ddev-drupal9-solr/archive/refs/tags/v0.0.5.tar.gz ddev get /path/to/package ddev get /path/to/tarball.tar.gz ddev get --list ddev get --list --all `, Run: func(cmd *cobra.Command, args []string) { officialOnly := true verbose := false if cmd.Flag("list").Changed { if cmd.Flag("all").Changed { officialOnly = false } repos, err := listAvailable(officialOnly) if err != nil { util.Failed("Failed to list available add-ons: %v", err) } if len(repos) == 0 { util.Warning("No ddev add-ons found with GitHub topic 'ddev-get'.") return } out := renderRepositoryList(repos) output.UserOut.WithField("raw", repos).Print(out) return } if cmd.Flags().Changed("verbose") { verbose = true } if len(args) < 1 { util.Failed("You must specify an add-on to download") } bash := util.FindBashPath() apps, err := getRequestedProjects(args[1:], false) if err != nil { util.Failed("Unable to get project(s) %v: %v", args, err) } if len(apps) == 0 { util.Failed("No project(s) found") } app := apps[0] err = os.Chdir(app.AppRoot) if err != nil { util.Failed("Unable to change directory to project root %s: %v", app.AppRoot, err) } app.DockerEnv() sourceRepoArg := args[0] extractedDir := "" parts := strings.Split(sourceRepoArg, "/") tarballURL := "" var cleanup func() argType := "" owner := "" repo := "" switch { case fileutil.IsDirectory(sourceRepoArg): extractedDir = sourceRepoArg argType = "directory" case fileutil.FileExists(sourceRepoArg) && (strings.HasSuffix(filepath.Base(sourceRepoArg), "tar.gz") || strings.HasSuffix(filepath.Base(sourceRepoArg), "tar") || strings.HasSuffix(filepath.Base(sourceRepoArg), "tgz")): extractedDir, cleanup, err = archive.ExtractTarballWithCleanup(sourceRepoArg, true) if err != nil { util.Failed("Unable to extract %s: %v", sourceRepoArg, err) } argType = "tarball" defer cleanup() case len(parts) == 2: owner = parts[0] repo = parts[1] ctx := context.Background() client := getGithubClient(ctx) releases, resp, err := client.Repositories.ListReleases(ctx, owner, repo, &github.ListOptions{}) if err != nil { var rate github.Rate if resp != nil { rate = resp.Rate } util.Failed("Unable to get releases for %v: %v\nresp.Rate=%v", repo, err, rate) } if len(releases) == 0 { util.Failed("No releases found for %v", repo) } tarballURL = releases[0].GetTarballURL() argType = "github" fallthrough default: if tarballURL == "" { tarballURL = sourceRepoArg } extractedDir, cleanup, err = archive.DownloadAndExtractTarball(tarballURL, true) if err != nil { util.Failed("Unable to download %v: %v", sourceRepoArg, err) } defer cleanup() } yamlFile := filepath.Join(extractedDir, "install.yaml") yamlContent, err := fileutil.ReadFileIntoString(yamlFile) if err != nil { util.Failed("Unable to read %v: %v", yamlFile, err) } var s installDesc err = yaml.Unmarshal([]byte(yamlContent), &s) if err != nil { util.Failed("Unable to parse %v: %v", yamlFile, err) } yamlMap := make(map[string]interface{}) for name, f := range s.YamlReadFiles { f := os.ExpandEnv(string(f)) fullpath := filepath.Join(app.GetAppRoot(), f) yamlMap[name], err = util.YamlFileToMap(fullpath) if err != nil { util.Failed("unable to import yaml file %s: %v", fullpath, err) } } for k, v := range map[string]string{"DdevGlobalConfig": globalconfig.GetGlobalConfigPath(), "DdevProjectConfig": app.GetConfigPath("config.yaml")} { yamlMap[k], err = util.YamlFileToMap(v) if err != nil { util.Failed("unable to read file %s", v) } } dict, err := util.YamlToDict(yamlMap) if err != nil { util.Failed("Unable to YamlToDict: %v", err) } if len(s.PreInstallActions) > 0 { util.Success("\nExecuting pre-install actions:") } for i, action := range s.PreInstallActions { err = processAction(action, dict, bash, verbose) if err != nil { desc := getDdevDescription(action) if err != nil { if !verbose { util.Failed("could not process pre-install action (%d) '%s'. For more detail use ddev get --verbose", i, desc) } else { util.Failed("could not process pre-install action (%d) '%s'; error=%v\n action=%s", i, desc, err, action) } } } } if len(s.ProjectFiles) > 0 { util.Success("\nInstalling project-level components:") } for _, file := range s.ProjectFiles { file := os.ExpandEnv(file) src := filepath.Join(extractedDir, file) dest := app.GetConfigPath(file) if err = fileutil.CheckSignatureOrNoFile(dest, nodeps.DdevFileSignature); err == nil { err = copy.Copy(src, dest) if err != nil { util.Failed("Unable to copy %v to %v: %v", src, dest, err) } util.Success("%c %s", '\U0001F44D', file) } else { util.Warning("NOT overwriting file/directory %s. The #ddev-generated signature was not found in the file, so it will not be overwritten. You can just remove the file and use ddev get again if you want it to be replaced: %v", dest, err) } } globalDotDdev := filepath.Join(globalconfig.GetGlobalDdevDir()) if len(s.GlobalFiles) > 0 { util.Success("\nInstalling global components:") } for _, file := range s.GlobalFiles { file := os.ExpandEnv(file) src := filepath.Join(extractedDir, file) dest := filepath.Join(globalDotDdev, file) if err = fileutil.CheckSignatureOrNoFile(dest, nodeps.DdevFileSignature); err == nil { err = copy.Copy(src, dest) if err != nil { util.Failed("Unable to copy %v to %v: %v", src, dest, err) } util.Success("%c %s", '\U0001F44D', file) } else { util.Warning("NOT overwriting file/directory %s. The #ddev-generated signature was not found in the file, so it will not be overwritten. You can just remove the file and use ddev get again if you want it to be replaced: %v", dest, err) } } origDir, _ := os.Getwd() defer os.Chdir(origDir) err = os.Chdir(app.GetConfigPath("")) if err != nil { util.Failed("Unable to chdir to %v: %v", app.GetConfigPath(""), err) } if len(s.PostInstallActions) > 0 { util.Success("\nExecuting post-install actions:") } for i, action := range s.PostInstallActions { err = processAction(action, dict, bash, verbose) desc := getDdevDescription(action) if err != nil { if !verbose { util.Failed("could not process post-install action (%d) '%s'", i, desc) } else { util.Failed("could not process post-install action (%d) '%s': %v", i, desc, err) } } } util.Success("\nInstalled DDEV add-on %s, use `ddev restart` to enable.", sourceRepoArg) if argType == "github" { util.Success("Please read instructions for this addon at the source repo at\nhttps://github.com/%v/%v\nPlease file issues and create pull requests there to improve it.", owner, repo) } }, }
Get implements the ddev get command
var HostNameCmd = &cobra.Command{ Use: "hostname [hostname] [ip]", Example: "ddev hostname somesite.ddev.local 127.0.0.1", Short: "Manage your hostfile entries.", Long: `Manage your hostfile entries. Managing host names has security and usability implications and requires elevated privileges. You may be asked for a password to allow ddev to modify your hosts file. If you are connected to the internet and using the domain ddev.site this is generally not necessary, because the hosts file never gets manipulated.`, Run: func(cmd *cobra.Command, args []string) { hosts, err := goodhosts.NewHosts() if err != nil { rawResult := make(map[string]interface{}) detail := fmt.Sprintf("Could not open hosts file for reading: %v", err) rawResult["error"] = "READERROR" rawResult["full_error"] = detail output.UserOut.WithField("raw", rawResult).Fatal(detail) return } if !dockerutil.IsWSL2() { if hosts.Flush(); err != nil { rawResult := make(map[string]interface{}) detail := fmt.Sprintf("Please use sudo or execute with administrative privileges: %v", err) rawResult["error"] = "WRITEERROR" rawResult["full_error"] = detail output.UserOut.WithField("raw", rawResult).Fatal(detail) return } } if removeInactive { if len(args) > 0 { util.Failed("Invalid arguments supplied. 'ddev hostname --remove-all' accepts no arguments.") } util.Warning("Attempting to remove inactive hostnames which use TLD %s", nodeps.DdevDefaultTLD) removeInactiveHostnames(hosts) return } if len(args) != 2 { util.Failed("Invalid arguments supplied. Please use 'ddev hostname [hostname] [ip]'") } hostname, ip := args[0], args[1] if removeHostName { removeHostname(hosts, ip, hostname) return } addHostname(hosts, ip, hostname) }, }
HostNameCmd represents the hostname command
var ImportDBCmd = &cobra.Command{ Use: "import-db [project]", Args: cobra.RangeArgs(0, 1), Short: "Import a sql file into the project.", Long: `Import a sql file into the project. The database dump file can be provided as a SQL dump in a .sql, .sql.gz, sql.bz2, sql.xz, .mysql, .mysql.gz, .zip, .tgz, or .tar.gz format. For the zip and tar formats, the path to a .sql file within the archive can be provided if it is not located at the top level of the archive. An optional target database can also be provided; the default is the default database named "db". Also note the related "ddev mysql" command`, Example: `ddev import-db ddev import-db --src=.tarballs/junk.sql ddev import-db --src=.tarballs/junk.sql.gz ddev import-db --target-db=newdb --src=.tarballs/db.sql.gz ddev import-db --src=.tarballs/db.sql.bz2 ddev import-db --src=.tarballs/db.sql.xz ddev import-db <db.sql ddev import-db someproject <db.sql gzip -dc db.sql.gz | ddev import-db`, PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, Run: func(cmd *cobra.Command, args []string) { projects, err := getRequestedProjects(args, false) if err != nil { util.Failed("Unable to get project(s): %v", err) } app := projects[0] status, _ := app.SiteStatus() if status != ddevapp.SiteRunning { err = app.Start() if err != nil { util.Failed("Failed to start app %s to import-db: %v", app.Name, err) } } err = app.ImportDB(dbSource, dbExtPath, progressOption, noDrop, targetDB) if err != nil { util.Failed("Failed to import database %s for %s: %v", targetDB, app.GetName(), err) } util.Success("Successfully imported database '%s' for %v", targetDB, app.GetName()) if noDrop { util.Success("Existing database '%s' was NOT dropped before importing", targetDB) } else { util.Success("Existing database '%s' was dropped before importing", targetDB) } }, }
ImportDBCmd represents the `ddev import-db` command.
var ImportFileCmd = &cobra.Command{ Use: "import-files", Example: `ddev import-files --src=/path/to/files.tar.gz ddev import-files --src=/path/to/dir ddev import-files --src=/path/to/files.tar.xz ddev import-files --src=/path/to/files.tar.bz2`, Short: "Pull the uploaded files directory of an existing project to the default public upload directory of your project.", Long: `Pull the uploaded files directory of an existing project to the default public upload directory of your project. The files can be provided as a directory path or an archive in .tar, .tar.gz, .tar.xz, .tar.bz2, .tgz, or .zip format. For the .zip and tar formats, the path to a directory within the archive can be provided if it is not located at the top-level of the archive. If the destination directory exists, it will be replaced with the assets being imported. The destination directory can be configured in your project's config.yaml under the upload_dir key. If no custom upload directory is defined, the app type's default upload directory will be used.`, PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, Args: cobra.ExactArgs(0), Run: func(cmd *cobra.Command, args []string) { app, err := ddevapp.GetActiveApp("") if err != nil { util.Failed("Failed to import files: %v", err) } var showExtPathPrompt bool if sourcePath == "" { if extPath == "" { showExtPathPrompt = true } promptForFileSource(&sourcePath) } importPath, isArchive, err := appimport.ValidateAsset(sourcePath, "files") if err != nil { util.Failed("Failed to import files for %s: %v", app.GetName(), err) } if isArchive && showExtPathPrompt { promptForExtPath(&extPath) } if err = app.ImportFiles(importPath, extPath); err != nil { util.Failed("Failed to import files for %s: %v", app.GetName(), err) } util.Success("Successfully imported files for %v", app.GetName()) }, }
ImportFileCmd represents the `ddev import-db` command.
var ListCmd = &cobra.Command{ Use: "list", Short: "List projects", Long: `List projects. Shows all projects by default, shows active projects only with --active-only`, Aliases: []string{"l", "ls"}, Example: `ddev list ddev list --active-only ddev list -A`, Run: func(cmd *cobra.Command, args []string) { ddevapp.List(activeOnly, continuous, wrapListTableText, continuousSleepTime) }, }
ListCmd represents the list command
var MutagenCmd = &cobra.Command{ Use: "mutagen [command]", Short: "Commands for mutagen status and sync, etc.", Run: func(cmd *cobra.Command, args []string) { err := cmd.Usage() util.CheckErr(err) }, }
MutagenCmd is the top-level "ddev debug" command
var MutagenLogsCmd = &cobra.Command{ Use: "logs", Short: "Show mutagen logs for debugging", Example: `"ddev mutagen logs"`, Run: func(cmd *cobra.Command, args []string) { ddevapp.StopMutagenDaemon() _ = os.Setenv("MUTAGEN_LOG_LEVEL", "trace") sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) done := make(chan bool, 1) go func() { c := exec.Command(globalconfig.GetMutagenPath(), "daemon", "run") c.Stdout = os.Stdout c.Stderr = os.Stderr err := c.Run() if err != nil { util.Warning("mutagen daemon run failed with %v", err) } done <- true }() <-done util.Success("Completed mutagen logs, now restarting normal mutagen daemon") ddevapp.StartMutagenDaemon() }, }
MutagenLogsCmd implements the ddev mutagen logs command
var MutagenMonitorCmd = &cobra.Command{ Use: "monitor", Short: "Monitor mutagen status", Example: `"ddev mutagen sync", "ddev mutagen monitor <projectname>"`, Run: func(cmd *cobra.Command, args []string) { projectName := "" if len(args) > 1 { util.Failed("This command only takes one optional argument: project-name") } if len(args) == 1 { projectName = args[0] } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get active project: %v", err) } if !(app.IsMutagenEnabled()) { util.Warning("Mutagen is not enabled on project %s", app.Name) return } ddevapp.MutagenMonitor(app) }, }
MutagenMonitorCmd implements the ddev mutagen monitor command
var MutagenResetCmd = &cobra.Command{ Use: "reset", Short: "Reset mutagen for project", Long: "Stops project, removes the mutagen docker volume", Example: `"ddev mutagen reset", "ddev mutagen reset <projectname>"`, Run: func(cmd *cobra.Command, args []string) { projectName := "" if len(args) > 1 { util.Failed("This command only takes one optional argument: project-name") } if len(args) == 1 { projectName = args[0] } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get active project: %v", err) } if !(app.IsMutagenEnabled()) { util.Warning("Mutagen is not enabled on project %s", app.Name) return } err = app.MutagenSyncFlush() if err != nil { if !strings.Contains(err.Error(), "does not exist") { util.Warning("Could not flush mutagen: %v", err) } } err = ddevapp.MutagenReset(app) if err != nil { util.Failed("Could not reset mutagen: %v", err) } util.Success("Mutagen has been reset. You may now `ddev start` with or without mutagen enabled.") }, }
MutagenResetCmd implements the ddev mutagen reset command
var MutagenStatusCmd = &cobra.Command{ Use: "status", Short: "Shows mutagen sync status", Aliases: []string{"st"}, Example: `"ddev mutagen status", "ddev mutagen status <projectname>"`, Run: func(cmd *cobra.Command, args []string) { projectName := "" verbose := false if len(args) > 1 { util.Failed("This command only takes one optional argument: project-name") } if len(args) == 1 { projectName = args[0] } if cmd.Flags().Changed("verbose") { verbose = true } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get active project: %v", err) } if !(app.IsMutagenEnabled()) { util.Warning("Mutagen is not enabled on project %s", app.Name) return } status, shortResult, _, err := app.MutagenStatus() if err != nil { util.Failed("unable to get mutagen status for project %s, output='%s': %v", app.Name, shortResult, err) } ok := "Mutagen: " + status resultOut := shortResult if verbose { fullResult, err := exec.RunHostCommand(globalconfig.GetMutagenPath(), "sync", "list", "-l", ddevapp.MutagenSyncName(app.Name)) if err != nil { util.Failed("unable to get mutagen status for project %s, output='%s': %v", app.Name, fullResult, err) } resultOut = "\n" + fullResult } output.UserOut.Printf("%s: %s", ok, resultOut) }, }
MutagenStatusCmd implements the ddev mutagen status command
var MutagenSyncCmd = &cobra.Command{ Use: "sync", Short: "Explicit sync for mutagen", Example: `"ddev mutagen sync", "ddev mutagen sync <projectname>"`, Run: func(cmd *cobra.Command, args []string) { projectName := "" verbose := false if len(args) > 1 { util.Failed("This command only takes one optional argument: project-name") } if len(args) == 1 { projectName = args[0] } if cmd.Flags().Changed("verbose") { verbose = true } app, err := ddevapp.GetActiveApp(projectName) if err != nil { util.Failed("Failed to get active project: %v", err) } if !(app.IsMutagenEnabled()) { util.Warning("Mutagen is not enabled on project %s", app.Name) return } err = app.MutagenSyncFlush() if err != nil { util.Failed("Failed to flush mutagen: %v", err) } if !verbose { return } _, _, longResult, _ := app.MutagenStatus() output.UserOut.Printf("%s", longResult) }, }
MutagenSyncCmd implements the ddev mutagen sync command
var PoweroffCommand = &cobra.Command{ Use: "poweroff", Short: "Completely stop all projects and containers", Long: `ddev poweroff stops all projects and containers, equivalent to ddev stop -a --stop-ssh-agent`, Example: `ddev poweroff`, Args: cobra.NoArgs, Aliases: []string{"powerdown"}, Run: func(cmd *cobra.Command, args []string) { ddevapp.PowerOff() }, }
PoweroffCommand contains the "ddev share" command
var PullCmd = &cobra.Command{ Use: "pull", Short: "Pull files and database using a configured provider plugin.", Long: `Pull files and database using a configured provider plugin. Running pull will connect to the configured provider and download + import the database and files.`, Example: `ddev pull pantheon ddev pull platform ddev pull pantheon -y ddev pull platform --skip-files -y ddev pull localfile --skip-db -y ddev pull platform --environment=PLATFORM_ENVIRONMENT=main,PLATFORMSH_CLI_TOKEN=abcdef `, Args: cobra.ExactArgs(1), PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, }
PullCmd represents the `ddev pull` command.
var PushCmd = &cobra.Command{ Use: "push", Short: "push files and database using a configured provider plugin.", Long: `push files and database using a configured provider plugin. Running push will connect to the configured provider and export and upload the database and/or files. It is not recommended for most workflows since it is extremely dangerous to your production hosting.`, Example: `ddev push pantheon ddev push platform ddev push pantheon -y ddev push platform --skip-files -y ddev push acquia --skip-db -y ddev push platform --environment=PLATFORM_ENVIRONMENT=main,PLATFORMSH_CLI_TOKEN=abcdef `, Args: cobra.ExactArgs(1), PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, }
PushCmd represents the `ddev push` command.
var RestartCmd = &cobra.Command{ Use: "restart [projects]", Short: "Restart a project or several projects.", Long: `Stops named projects and then starts them back up again.`, Example: `ddev restart ddev restart <project1> <project2> ddev restart --all`, PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, Run: func(cmd *cobra.Command, args []string) { projects, err := getRequestedProjects(args, restartAll) if err != nil { util.Failed("Failed to get project(s): %v", err) } if len(projects) > 0 { instrumentationApp = projects[0] } for _, app := range projects { output.UserOut.Printf("Restarting project %s...", app.GetName()) err = app.Restart() if err != nil { util.Failed("Failed to restart %s: %v", app.GetName(), err) } util.Success("Restarted %s", app.GetName()) httpURLs, urlList, _ := app.GetAllURLs() if globalconfig.GetCAROOT() == "" || ddevapp.IsRouterDisabled(app) { urlList = httpURLs } util.Success("Your project can be reached at %s", strings.Join(urlList, " ")) } }, }
RestartCmd rebuilds an apps settings
var RootCmd = &cobra.Command{ Use: "ddev", Short: "DDEV local development environment", Long: `Create and maintain a local web development environment. Docs: https://ddev.readthedocs.io Support: https://ddev.readthedocs.io/en/stable/users/support`, Version: versionconstants.DdevVersion, PersistentPreRun: func(cmd *cobra.Command, args []string) { command := os.Args[1] output.LogSetUp() if command != "start" && command != "restart" { return } err := dockerutil.CheckDockerVersion(dockerutil.DockerVersionConstraint) if err != nil { if err.Error() == "no docker" { if os.Args[1] != "version" { util.Failed("Could not connect to docker. Please ensure Docker is installed and running.") } } else { util.Warning("The docker version currently installed does not seem to meet ddev's requirements: %v", err) } } updateFile := filepath.Join(globalconfig.GetGlobalDdevDir(), ".update") timeToCheckForUpdates, err := updatecheck.IsUpdateNeeded(updateFile, updateInterval) if err != nil { util.Warning("Could not perform update check: %v", err) } if timeToCheckForUpdates && globalconfig.IsInternetActive() { err = updatecheck.ResetUpdateTime(updateFile) if err != nil { util.Warning("Failed to update updatecheck file %s", updateFile) return } updateNeeded, updateVersion, updateURL, err := updatecheck.AvailableUpdates("drud", "ddev", versionconstants.DdevVersion) if err != nil { util.Warning("Could not check for updates. This is most often caused by a networking issue.") return } if updateNeeded { output.UserOut.Printf(util.ColorizeText(fmt.Sprintf("\n\nUpgraded DDEV %s is available!\nPlease visit %s to get the upgrade.\nFor upgrade help see %s\n\n", updateVersion, updateURL, updateDocURL), "green")) } } }, PersistentPostRun: func(cmd *cobra.Command, args []string) { ignores := map[string]bool{"describe": true, "auth": true, "blackfire": false, "clean": true, "composer": true, "debug": true, "delete": true, "drush": true, "exec": true, "export-db": true, "get": true, "help": true, "hostname": true, "import-db": true, "import-files": true, "list": true, "logs": true, "mutagen": true, "mysql": true, "npm": true, "nvm": true, "pause": true, "php": true, "poweroff": true, "pull": true, "push": true, "service": true, "share": true, "snapshot": true, "ssh": true, "stop": true, "version": true, "xdebug": true, "xhprof": true, "yarn": true} if _, ok := ignores[cmd.CalledAs()]; ok { return } instrumentationNotSetUpWarning() cmdCopy := cmd var fullCommand = make([]string, 0) fullCommand = append(fullCommand, util.GetFirstWord(cmdCopy.Use)) for cmdCopy.HasParent() { fullCommand = append(fullCommand, util.GetFirstWord(cmdCopy.Parent().Use)) cmdCopy = cmdCopy.Parent() } for i := 0; i < len(fullCommand)/2; i++ { j := len(fullCommand) - i - 1 fullCommand[i], fullCommand[j] = fullCommand[j], fullCommand[i] } event := "" if len(fullCommand) > 1 { event = fullCommand[1] } if globalconfig.DdevGlobalConfig.InstrumentationOptIn && versionconstants.SegmentKey != "" && globalconfig.IsInternetActive() && len(fullCommand) > 1 { runTime := util.TimeTrack(time.Now(), "Instrumentation") if instrumentationApp == nil { app, err := ddevapp.NewApp("", false) if err == nil { instrumentationApp = app } } if instrumentationApp != nil { instrumentationApp.SetInstrumentationAppTags() } ddevapp.SetInstrumentationBaseTags() ddevapp.SendInstrumentationEvents(event) runTime() } }, }
RootCmd represents the base command when called without any subcommands
var ServiceCmd = &cobra.Command{ Use: "service [command]", Short: "Add or remove, enable or disable extra services", Run: func(cmd *cobra.Command, args []string) { err := cmd.Usage() util.CheckErr(err) }, }
ServiceCmd is the top-level "ddev service" command
var ServiceDisable = &cobra.Command{ Use: "disable service [project]", Short: "disable a 3rd party service", Long: fmt.Sprintf(`disable a 3rd party service. The docker-compose.*.yaml will be moved from .ddev into .ddev/%s.`, disabledServicesDir), Example: `ddev service disable solr`, Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { util.Failed("You must specify a service to disable") } apps, err := getRequestedProjects(args[1:], false) if err != nil { util.Failed("Unable to get project(s) %v: %v", args, err) } if len(apps) == 0 { util.Failed("No project(s) found") } app := apps[0] serviceName := args[0] fName := fmt.Sprintf("docker-compose.%s.yaml", serviceName) err = os.MkdirAll(app.GetConfigPath(disabledServicesDir), 0755) if err != nil { util.Failed("Unable to create %s: %v", app.GetConfigPath(disabledServicesDir), err) } if !fileutil.FileExists(app.GetConfigPath(fName)) { util.Failed("No file named %s was found in %s", fName, app.GetConfigPath("")) } err = os.Remove(app.GetConfigPath(disabledServicesDir + "/" + fName)) if err != nil { if _, ok := err.(*fs.PathError); !ok { util.Failed("Unable to remove %s: %v", app.GetConfigPath(disabledServicesDir+"/"+fName), err) } } err = fileutil.CopyFile(app.GetConfigPath(fName), app.GetConfigPath(disabledServicesDir+"/"+fName)) if err != nil { util.Failed("Unable to disable service %s: %v", serviceName, err) } err = os.Remove(app.GetConfigPath(fName)) if err != nil { util.Failed("Unable to remove former service file %s: %v", fName, err) } util.Success("disabled service %s, use `ddev restart` to see results.", serviceName) }, }
ServiceDisable implements the ddev service disable command
var ServiceEnable = &cobra.Command{ Use: "enable service [project]", Short: "Enable a 3rd party service", Long: fmt.Sprintf(`Enable a 3rd party service. The service must exist as .ddev/%s/docker-compose.<service>.yaml. Note that you can use "ddev get" to obtain a service not already on your system.`, disabledServicesDir), Example: `ddev service enable solr`, Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { util.Failed("You must specify a service to enable") } apps, err := getRequestedProjects(args[1:], false) if err != nil { util.Failed("Unable to get project(s) %v: %v", args, err) } if len(apps) == 0 { util.Failed("No project(s) found") } app := apps[0] serviceName := args[0] fName := fmt.Sprintf("docker-compose.%s.yaml", serviceName) if fileutil.FileExists(app.GetConfigPath(fName)) { util.Failed("Service %s already enabled, see %s", serviceName, fName) } if !fileutil.FileExists(app.GetConfigPath(disabledServicesDir + "/" + fName)) { util.Failed("No %s found in %s", fName, app.GetConfigPath(disabledServicesDir)) } err = fileutil.CopyFile(app.GetConfigPath(disabledServicesDir+"/"+fName), app.GetConfigPath(fName)) if err != nil { util.Failed("Unable to enable service %s: %v", serviceName, err) } util.Success("Enabled service %s, use `ddev restart` to turn it on.", serviceName) }, }
ServiceEnable implements the ddev service enable command
var StartCmd = &cobra.Command{ Use: "start [projectname ...]", Aliases: []string{"add"}, Short: "Start a ddev project.", Long: `Start initializes and configures the web server and database containers to provide a local development environment. You can run 'ddev start' from a project directory to start that project, or you can start stopped projects in any directory by running 'ddev start projectname [projectname ...]'`, Example: `ddev start ddev start <project1> <project2> ddev start --all`, PreRun: func(cmd *cobra.Command, args []string) { dockerutil.EnsureDdevNetwork() }, Run: func(cmd *cobra.Command, args []string) { skip, err := cmd.Flags().GetBool("skip-confirmation") if err != nil { util.Failed(err.Error()) } err = checkDdevVersionAndOptInInstrumentation(skip) if err != nil { util.Failed(err.Error()) } selectFlag, err := cmd.Flags().GetBool("select") if err != nil { util.Failed(err.Error()) } if selectFlag { inactiveProjects, err := ddevapp.GetInactiveProjects() if err != nil { util.Failed(err.Error()) } if len(inactiveProjects) == 0 { util.Warning("No project to start available") os.Exit(0) } inactiveProjectNames := ddevapp.ExtractProjectNames(inactiveProjects) prompt := promptui.Select{ Label: "Projects", Items: inactiveProjectNames, Templates: &promptui.SelectTemplates{ Label: "{{ . | cyan }}:", }, StartInSearchMode: true, Searcher: func(input string, idx int) bool { return strings.Contains(inactiveProjectNames[idx], input) }, } _, projectName, err := prompt.Run() if err != nil { util.Failed(err.Error()) } args = append(args, projectName) } projects, err := getRequestedProjects(args, startAll) if err != nil { util.Failed("Failed to get project(s): %v", err) } if len(projects) > 0 { instrumentationApp = projects[0] } for _, project := range projects { if err := ddevapp.CheckForMissingProjectFiles(project); err != nil { util.Failed("Failed to start %s: %v", project.GetName(), err) } output.UserOut.Printf("Starting %s...", project.GetName()) if err := project.Start(); err != nil { util.Failed("Failed to start %s: %v", project.GetName(), err) } util.Success("Successfully started %s", project.GetName()) httpURLs, httpsURLs, _ := project.GetAllURLs() if !nodeps.IsGitpod() && (globalconfig.GetCAROOT() == "" || ddevapp.IsRouterDisabled(project)) { httpsURLs = httpURLs } util.Success("Project can be reached at %s", strings.Join(httpsURLs, " ")) } }, }
StartCmd provides the ddev start command
var ValidTypes = map[typeValue]bool{ FtBool: true, FtBoolSlice: false, FtBytesHex: false, FtBytesBase64: false, FtCount: false, FtDuration: false, FtDurationSlice: false, FtFloat32: false, FtFloat32Slice: false, FtFloat64: false, FtFloat64Slice: false, FtInt: true, FtIntSlice: false, FtInt8: false, FtInt16: false, FtInt32: false, FtInt32Slice: false, FtInt64: false, FtInt64Slice: false, FtIP: false, FtIPSlice: false, FtIPMask: false, FtIPNet: false, FtString: true, FtStringArray: false, FtStringSlice: false, FtStringToInt: false, FtStringToInt64: false, FtStringToString: false, FtUint: true, FtUintSlice: false, FtUint8: false, FtUint16: false, FtUint32: false, FtUint64: false, // contains filtered or unexported fields }
ValidTypes defines the valid types, a value of true indicates it's implemented. To implement a new type add the required line to the switch statement in AssignToCommand and set it here to true, that's all. If a new type is added which is not defined here just add a new constant above and here.
Functions ¶
Types ¶
type Flag ¶ added in v1.16.0
type Flag struct { Name nameValue // name as it appears on command line Shorthand shorthandValue // one-letter abbreviated flag Usage usageValue // help message Type typeValue // type, defaults to bool DefValue defValueValue // default value (as text); for usage message NoOptDefVal noOptDefValValue // default value (as text); if the flag is on the command line without any options Annotations annotationsValue // used by cobra.Command bash autocomplete code }
Flag is the structure for the flags, the json from the annotation is unmarshaled into this structure. For more information see also github.com/spf13/pflag/flag.
type Flags ¶ added in v1.16.0
type Flags struct { CommandName string Script string Definition FlagsDefinition }
Flags is the main type used to access flags and methods.
func (*Flags) AssignToCommand ¶ added in v1.16.0
AssignToCommand iterates the flags and assigns it to the provided command.
func (*Flags) LoadFromJSON ¶ added in v1.16.0
LoadFromJSON imports the defs provided by the custom command as json into the flags structure.
type FlagsDefinition ¶ added in v1.16.0
type FlagsDefinition []Flag
FlagsDefinition is an array of Flag holding all defined flags of a command.
Source Files ¶
- a.go
- auth-ssh.go
- auth.go
- clean.go
- cmd_assets.go
- cmd_version.go
- commands.go
- composer-create.go
- composer.go
- config-global.go
- config.go
- debug-capabilities.go
- debug-check-db-match.go
- debug-compose-config.go
- debug-config-yaml.go
- debug-dockercheck.go
- debug-download-images.go
- debug-fixcommands.go
- debug-get-volume-db-version.go
- debug-migrate-database.go
- debug-mutagen.go
- debug-nfsmount.go
- debug-refresh.go
- debug-router-nginx-config.go
- debug-test.go
- debug.go
- delete-images.go
- delete.go
- describe.go
- exec.go
- export-db.go
- flags.go
- get.go
- hostname.go
- import-db.go
- import-files.go
- list.go
- logs.go
- mutagen-logs.go
- mutagen-monitor.go
- mutagen-reset.go
- mutagen-status.go
- mutagen-sync.go
- mutagen.go
- pause.go
- poweroff.go
- pull.go
- push.go
- restart.go
- restore_snapshot.go
- root.go
- service-disable.go
- service-enable.go
- service.go
- share.go
- snapshot.go
- snapshot_restore.go
- ssh.go
- start.go
- stop.go
- utils.go