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", version.SSHAuthImage + ":" + version.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 ComposerCmd = &cobra.Command{ 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()) } if app.SiteStatus() != 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 installation. 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()) } if app.SiteStatus() != 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) 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 installation to composer root") _, _, err = app.Exec(&ddevapp.ExecOpts{ Service: "web", Cmd: fmt.Sprintf(`rsync -a "%s/" "%s/"`, containerInstallPath, app.GetComposerRoot(true, false)), Dir: "/var/www/html", }) if err != nil { util.Failed("Failed to create project: %v", err) } 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", 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 = &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) } if strings.Contains(app.SiteStatus(), ddevapp.SiteStopped) { util.Failed("Project is not currently running. Try 'ddev start'.") } if strings.Contains(app.SiteStatus(), ddevapp.SitePaused) { util.Failed("Project is paused. Run 'ddev start' to start it.") } 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] if strings.Contains(project.SiteStatus(), ddevapp.SiteStopped) { util.Failed("Project is not currently running. Try 'ddev start'.") } 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 if strings.Contains(app.SiteStatus(), ddevapp.SiteStopped) { util.Failed("Project is not currently running. Try 'ddev start'.") } if strings.Contains(app.SiteStatus(), ddevapp.SitePaused) { util.Failed("Project is stopped. Run 'ddev start' to start the environment.") } 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.
Use: "share [project]", Short: "Share project on the internet via ngrok.", Long: `Use "ddev share" or add on extra ngrok commands, like "ddev share --subdomain some-subdomain". 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 --subdomain some-subdomain ddev share myproject`, Run: func(cmd *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] if app.SiteStatus() != 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) }, }
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:") } 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 { if project.SiteStatus() == 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() } 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 DebugCmd = &cobra.Command{ Use: "debug [command]", Short: "A collection of debugging commands", 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 := version.GetDockerVersion() if err != nil { util.Failed("Unable to get docker version: %v", err) } util.Success("Docker version: %s", dockerVersion) err = dockerutil.CheckDockerVersion(version.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(version.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(version.GetWebImage(), "", []string{"curl", "-sLI", "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 DebugMutagenCmd = &cobra.Command{ Use: "mutagen", Short: "Allows access to any mutagen command", 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 `, 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, args...) 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) hostDockerInternal, err := dockerutil.GetHostDockerInternalIP() if err != nil { util.Failed("failed to GetHostDockerInternalIP(): %v", err) } if hostDockerInternal == "" { hostDockerInternal = "host.docker.internal" } 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", hostDockerInternal), "device": ":" + dockerutil.MassageWindowsNFSMount(shareDir)}) 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(version.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/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 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 } } if project.SiteStatus() != 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 ddev docker images not in use by current ddev version", Long: "with --all it deletes all 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) { 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() client := dockerutil.GetDockerClient() images, err := client.ListImages(docker.ListImagesOptions{ All: true, }) if err != nil { util.Failed("Failed to list images: %v", err) } if deleteAllImages { for _, image := range images { for _, tag := range image.RepoTags { if strings.HasPrefix(tag, "drud/ddev-") { if err = dockerutil.RemoveImage(tag); err != nil { util.Warning("Failed to remove %s: %v", tag, err) } } } } util.Success("All ddev images discovered were deleted.") os.Exit(0) } sort.Slice(images, func(i, j int) bool { if images[i].RepoTags == nil || images[j].RepoTags == nil { return false } return images[i].RepoTags[0] > images[j].RepoTags[0] }) webimg := version.GetWebImage() dbaimage := version.GetDBAImage() routerimage := version.RouterImage + ":" + version.RouterTag sshimage := version.SSHAuthImage + ":" + version.SSHAuthTag nameAry := strings.Split(version.GetDBImage(nodeps.MariaDB), ":") keepDBImageTag := "notagfound" if len(nameAry) > 1 { keepDBImageTag = nameAry[1] } for _, image := range images { for _, tag := range image.RepoTags { if strings.HasPrefix(tag, version.WebImg) && !strings.HasPrefix(tag, webimg) && !strings.HasPrefix(tag, webimg+"-built") { if err = dockerutil.RemoveImage(tag); err != nil { util.Warning("Failed to remove %s: %v", tag, err) } } if strings.HasPrefix(tag, "drud/ddev-dbserver") && !strings.HasSuffix(tag, keepDBImageTag) && !strings.HasSuffix(tag, keepDBImageTag+"-built") { if err = dockerutil.RemoveImage(tag); err != nil { util.Warning("Failed to remove %s: %v", tag, err) } } if strings.HasPrefix(tag, version.DBAImg) && !strings.HasPrefix(tag, dbaimage) { if err = dockerutil.RemoveImage(tag); err != nil { util.Warning("Failed to remove %s: %v", tag, err) } } if strings.HasPrefix(tag, version.RouterImage) && !strings.HasPrefix(tag, routerimage) { if err = dockerutil.RemoveImage(tag); err != nil { util.Warning("Failed to remove %s: %v", tag, err) } } if strings.HasPrefix(tag, version.SSHAuthImage) && !strings.HasPrefix(tag, sshimage) && !strings.HasPrefix(tag, sshimage+"-built") { if err = dockerutil.RemoveImage(tag); err != nil { util.Warning("Failed to remove %s: %v", tag, err) } } } } util.Success("Any non-current 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] if app.SiteStatus() != ddevapp.SiteRunning { util.Failed("ddev can't export-db until the project is started, please use ddev start.") } err = app.ExportDB(outFileName, gzipOption, 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 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 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] 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 { util.Failed("Unable to get releases for %v: %v\nresp.Rate=%v", repo, err, resp.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) } for _, action := range s.PreInstallActions { out, err := exec.RunHostCommand(bash, "-c", action) if err != nil { util.Failed("Unable to run action %v: %v, output=%s", action, err, out) } util.Success("%v\n%s", action, out) } for _, file := range s.ProjectFiles { src := filepath.Join(extractedDir, file) dest := app.GetConfigPath(file) err = copy.Copy(src, dest) if err != nil { util.Failed("Unable to copy %v to %v: %v", src, dest, err) } util.Success("Installed file %s", dest) } globalDotDdev := filepath.Join(globalconfig.GetGlobalDdevDir()) for _, file := range s.GlobalFiles { src := filepath.Join(extractedDir, file) dest := filepath.Join(globalDotDdev, file) err = copy.Copy(src, dest) if err != nil { util.Failed("Unable to copy %v to %v: %v", src, dest, err) } util.Success("Installed file %s", dest) } 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) } for _, action := range s.PostInstallActions { out, err := exec.RunHostCommand(bash, "-c", action) if err != nil { util.Failed("Unable to run action %v: %v, output=%s", action, err, out) } util.Success("Executed post-install action %v.", action) } output.UserOut.Printf("Downloaded add-on %s, use `ddev restart` to enable.", sourceRepoArg) if argType == "github" { util.Success("For more information about this add-on visit 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 err := 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 { output.UserOut.Fatal("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 { output.UserOut.Fatal("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, .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/junk.sql.gz 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] if app.SiteStatus() != 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`, 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, .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`, Example: `ddev list ddev list --active-only ddev list -A`, Run: func(cmd *cobra.Command, args []string) { ddevapp.List(activeOnly, continuous, 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 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.Failed("Failed to 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", 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, longResult, _ := app.MutagenStatus() ok := "Mutagen: " + status resultOut := shortResult if verbose { resultOut = "\n" + longResult } 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`, 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`, 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 local development environment", Long: `Create and maintain a local web development environment. Docs: https://ddev.readthedocs.io Support: https://ddev.readthedocs.io/en/stable/#support`, Version: version.DdevVersion, PersistentPreRun: func(cmd *cobra.Command, args []string) { command := os.Args[1] output.LogSetUp() if command != "start" && command != "restart" { return } err := dockerutil.CheckDockerVersion(version.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", version.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{"auth": true, "exec": true, "help": true, "hostname": true, "list": true, "ssh": true, "version": 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 && version.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()) } 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) continue } 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
- cmd_assets.go
- cmd_version.go
- commands.go
- composer-create.go
- composer.go
- config-global.go
- config.go
- debug-compose-config.go
- debug-config-yaml.go
- debug-dockercheck.go
- debug-download-images.go
- debug-mutagen.go
- debug-nfsmount.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-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