diff --git a/.github/workflows/go_generate_update.yml b/.github/workflows/go_generate_update.yml index bdef08a6..6f364ee2 100644 --- a/.github/workflows/go_generate_update.yml +++ b/.github/workflows/go_generate_update.yml @@ -5,6 +5,12 @@ on: schedule: - cron: '0 8-18/4 * * 1-5' +env: + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_NAME: github-actions[bot] + GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com + jobs: update: name: Update generated code @@ -19,16 +25,19 @@ jobs: with: go-version-file: 'go.mod' - - name: Prepare + name: Prepare, generate, and format code run: | rm -rf ~/.platformsh/bin/ - go generate ./ + go generate ./... - name: Check Git status id: git run: | - RESULT=$(git status --untracked-files=no --porcelain) - echo "gitstatus=$RESULT" >> $GITHUB_OUTPUT + { + echo 'gitstatus<> $GITHUB_OUTPUT - name: Test if: steps.git.outputs.gitstatus != '' @@ -36,12 +45,27 @@ jobs: - name: Validate build if: steps.git.outputs.gitstatus != '' run: go run . + - - name: Commit and push the update + name: Commit the update for PSH-related code if: steps.git.outputs.gitstatus != '' run: | - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config user.name "github-actions[bot]" git add local/platformsh/commands.go local/platformsh/config.go - git commit -m "chore: Update supported Platform.sh services" + git diff --staged --quiet || git commit -m "Update supported Platform.sh services" + + - name: Commit the update for Docker-related code + if: steps.git.outputs.gitstatus != '' + run: | + git add envs/docker_version.go + git diff --staged --quiet || git commit -m "Update Docker Client version" + + - name: Commit the update for PHP-related code + if: steps.git.outputs.gitstatus != '' + run: | + git add commands/php_version.go + git diff --staged --quiet || git commit -m "Update latest available PHP version" + + - name: Commit and push the updates + if: steps.git.outputs.gitstatus != '' + run: | git push diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 18e36350..9c3d11a2 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -42,7 +42,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') - name: Prepare - run: go generate ./ + run: go generate ./... - name: Check Git status id: git @@ -66,21 +66,21 @@ jobs: uses: sigstore/cosign-installer@v3 - name: Run GoReleaser for snapshot - uses: goreleaser/goreleaser-action@v5 + uses: goreleaser/goreleaser-action@v6 # only for PRs and push on branches if: ${{ !startsWith(github.ref, 'refs/tags/v') }} with: - version: latest - args: release --clean --snapshot --skip-publish --skip-sign + version: '~> v2' + args: release --clean --snapshot --skip=publish,sign env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v5 + uses: goreleaser/goreleaser-action@v6 # only for tags if: startsWith(github.ref, 'refs/tags/v') with: - version: latest + version: '~> v2' args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 8f4b92b6..82ab262c 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,5 @@ +version: 2 + before: hooks: - go mod download @@ -61,7 +63,7 @@ source: enabled: true snapshot: - name_template: "next" + version_template: "next" universal_binaries: - replace: true @@ -93,12 +95,17 @@ brews: commit_author: name: Fabien Potencier email: fabien@symfony.com - folder: Formula + directory: Formula # Homebrew supports only a single GOARM variant and ARMv6 is upwards # compatible with ARMv7 so let's keep ARMv6 here (default value anyway) goarm: "6" homepage: https://symfony.com description: Symfony CLI helps Symfony developers manage projects, from local code to remote infrastructure + caveats: |- + To install shell completions, add this to your profile: + if command -v symfony &>/dev/null; then + eval "$(symfony completion)" + fi license: AGPL-3.0 test: | system "#{bin}/symfony version" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f8ec4a7d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,153 @@ +# Contributing + +This guide is meant to help you start contributing to the Symfony CLI by +providing some key hints and explaining specifics related to this project. + +## Language choice + +First-time contributors could be surprised by the fact that this project is +written in Go whereas it is highly related to the Symfony Framework which is +written in PHP. + +Go has been picked because it is well suited for system development and has +close-to-zero runtime dependencies which make releasing quite easy. This is +ideal for a tool that is used on a wide range of platforms and potentially on +systems where the requirements to run Symfony are not met. + +Another reason is to make Symfony CLI independent of the PHP version because +one goal of the CLI is to make it possible to use many different versions of +PHP. + +Finally, Go is also usually quite easy to apprehend for PHP developers having +some similarities in their approach. + +## Setup Go + +Contributing to the CLI, implies that one must first setup Go locally on their +machine. Instructions are available on the official +[Go website](https://golang.org/dl). Just pick the latest version available: Go +will automatically download the version currently in use in the project and +dependencies as required. + +## Local setup + +First fork this repository and clone it to some location of your liking. Next, +try to build and run the project: + +```bash +$ go build . +``` + +If any error happen you must fix them before going on. If no error happen, this +should produce a binary in the project directory. By default, this binary is +named `symfony-cli` and suffixed with `.exe` on Windows. + +You should be able to run it right away: + +```bash +$ ./symfony-cli version +``` + +The binary is self-contained: you can copy it as-is to another system and/or +execute it without any installation process. + +> *Tip:* This binary can be executed from anywhere by using it's absolute path. +> This is handy during development when you need to run it in a project +> directory and you don't want to overwrite your system-wide Symfony CLI. + +Finally, before and after changing code you should ensure tests are passing: + +```bash +$ go test ./... +``` + +## Coding style + +The CLI follows the Go standard code formatting. To fix the code formatting one +can use the following command: + +```bash +$ go fmt ./... +``` + +One can also uses the `go vet` command in order to fix common mistakes: + +```bash +$ go vet ./... +``` + +## Cross compilation + +By definition, the CLI has to support multiple platforms which means that at +some point you might need to compile the code for another platform than the one +your are using to develop. + +This can be done using Go cross-platform compiling capabilities. For example +the following command will compile the CLI for Windows: + +```bash +$ GOOS=windows go build . +``` + +`GOOS` and `GOARCH` environment variables are used to target another OS or CPU +architecture, respectively. + +During development, please take into consideration (in particular in the +process and file management sections) that we currently support the following +platforms matrix: + +- Linux / 386 +- Linux / amd64 +- Linux / arm +- Linux / arm64 +- Darwin / amd64 +- Darwin / arm64 +- Windows / 386 +- Windows / amd64 + +## Code generation + +Part of the code is generated automatically. One should not need to regenerate +the code themselves because a GitHub Action is in-charge of it. In the +eventuality one would need to debug it, code generation can be run as follows: + +```bash +$ go generate ./... +``` + +If you add a new code generation command, please also update the GitHub +workflow in `.github/workflows/go_generate_update.yml`. + +## Additional repositories + +Contrary to the Symfony PHP Framework which is a mono-repository, the CLI +tool is developed in multiple repositories. `symfony-cli/symfony-cli` is the +main repository where lies most of the logic and is the only repository +producing a binary. + +Every other repository is mostly independent and it is highly unlikely that +you would need to have a look at them. However, in the eventuality where you +would have to, here is the description of each repository scope: +- `symfony-cli/phpstore` is an independent library in charge of the PHP + installations discovery and the logic to match a specific version to a given + version constraint. +- `symfony-cli/console` is an independent library created to ease the process + of Go command-line application. This library has been created with the goal + of mimicking the look and feel of the Symfony Console for the end-user. +- `symfony-cli/terminal` is a wrapper around the Input and Output in a command + line context. It provides helpers around styling (output formatters and + styling - à la Symfony) and interactivity (spinners and questions helpers) +- `symfony-cli/dumper` is a library similar to Symfony's VarDumper component + providing a `Dump` function useful to introspect variables content and + particularly useful in the strictly typed context of Go. + +If you ever have to work on those package, you can setup your local working +copy of the CLI to work with a local copy of one of those package by using +`go work`: + +```bash +$ go work init +$ go work use . +$ go work use /path/to/package/fork +# repeat last command for each package you want to work with +``` diff --git a/Dockerfile b/Dockerfile index 156db0cd..1ae27216 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,8 @@ COPY symfony /usr/local/bin/ FROM scratch +ENV SYMFONY_ALLOW_ALL_IP=true + ENTRYPOINT ["/usr/local/bin/symfony"] COPY --from=build . . diff --git a/README.md b/README.md index 198d9965..a84d6fad 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Security Issues If you discover a security vulnerability, please follow our [disclosure procedure][11]. -Sponsorship [](https://cloudsmith.io/) +Sponsorship [](https://cloudsmith.io/) ----------- Package repository hosting is graciously provided by diff --git a/book/checkout.go b/book/checkout.go index 1bbd1a6f..33c6b507 100644 --- a/book/checkout.go +++ b/book/checkout.go @@ -65,8 +65,6 @@ func (b *Book) Checkout(step string) error { terminal.Println("[ OK ]") } - // FIXME: SQL dump? - if !b.Force && !b.AutoConfirm && !terminal.AskConfirmation("WARNING All current code, data, and containers are going to be REMOVED, do you confirm?", true) { return nil } @@ -111,7 +109,7 @@ func (b *Book) Checkout(step string) error { } } if hasDocker { - if err := executeCommand(append(dockerComposeBin(), "down", "--remove-orphans"), b.Debug, false, nil); err != nil { + if err := executeCommand(append(dockerComposeBin(), "down", "--remove-orphans", "--volume"), b.Debug, false, nil); err != nil { return err } } else { diff --git a/book/reqs.go b/book/reqs.go index f3f119b8..71347dce 100644 --- a/book/reqs.go +++ b/book/reqs.go @@ -88,6 +88,7 @@ func CheckRequirements() (bool, error) { // PHP extensions if v != nil { exts := map[string]string{ + "iconv": "required", "json": "required", "session": "required", "ctype": "required", diff --git a/commands/cloud_env_debug.go b/commands/cloud_env_debug.go index ac2a1eb2..4a46619d 100644 --- a/commands/cloud_env_debug.go +++ b/commands/cloud_env_debug.go @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package commands import ( diff --git a/commands/completion_others.go b/commands/completion_others.go new file mode 100644 index 00000000..1a825908 --- /dev/null +++ b/commands/completion_others.go @@ -0,0 +1,36 @@ +//go:build !darwin && !linux && !freebsd && !openbsd +// +build !darwin,!linux,!freebsd,!openbsd + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +import ( + "github.com/posener/complete" + "github.com/symfony-cli/console" +) + +func autocompleteComposerWrapper(context *console.Context, args complete.Args) []string { + return []string{} +} + +func autocompleteSymfonyConsoleWrapper(context *console.Context, args complete.Args) []string { + return []string{} +} diff --git a/commands/completion_posix.go b/commands/completion_posix.go new file mode 100644 index 00000000..6f2e1665 --- /dev/null +++ b/commands/completion_posix.go @@ -0,0 +1,102 @@ +//go:build darwin || linux || freebsd || openbsd + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +import ( + "embed" + "fmt" + "io" + "os" + "strconv" + "strings" + + "github.com/posener/complete" + "github.com/symfony-cli/console" + "github.com/symfony-cli/symfony-cli/local/php" + "github.com/symfony-cli/terminal" +) + +// completionTemplates holds our custom shell completions templates. +// +//go:embed resources/completion.* +var completionTemplates embed.FS + +func init() { + // override console completion templates with our custom ones + console.CompletionTemplates = completionTemplates +} + +func autocompleteSymfonyConsoleWrapper(context *console.Context, words complete.Args) []string { + args := buildSymfonyAutocompleteArgs("console", words) + // Composer does not support those options yet, so we only use them for Symfony Console + args = append(args, "-a1", fmt.Sprintf("-s%s", console.GuessShell())) + + if executor, err := php.SymfonyConsoleExecutor(terminal.Logger, args); err == nil { + os.Exit(executor.Execute(false)) + } + + return []string{} +} + +func autocompleteComposerWrapper(context *console.Context, words complete.Args) []string { + args := buildSymfonyAutocompleteArgs("composer", words) + // Composer does not support multiple shell yet, so we only use the default one + args = append(args, "-sbash") + + res := php.Composer("", args, []string{}, context.App.Writer, context.App.ErrWriter, io.Discard, terminal.Logger) + os.Exit(res.ExitCode()) + + // unreachable + return []string{} +} + +func buildSymfonyAutocompleteArgs(wrappedCommand string, words complete.Args) []string { + current, err := strconv.Atoi(os.Getenv("CURRENT")) + if err != nil { + current = 1 + } else { + // we decrease one position corresponding to `symfony` command + current -= 1 + } + + args := make([]string, 0, len(words.All)) + // build the inputs command line that Symfony expects + for _, input := range words.All { + if input = strings.TrimSpace(input); input != "" { + + // remove quotes from typed values + quote := input[0] + if quote == '\'' || quote == '"' { + input = strings.TrimPrefix(input, string(quote)) + input = strings.TrimSuffix(input, string(quote)) + } + + args = append(args, fmt.Sprintf("-i%s", input)) + } + } + + return append([]string{ + "_complete", "--no-interaction", + fmt.Sprintf("-c%d", current), + fmt.Sprintf("-i%s", wrappedCommand), + }, args...) +} diff --git a/commands/data/check-requirements.php b/commands/data/check-requirements.php index 1c9bbb21..45ab9a86 100644 --- a/commands/data/check-requirements.php +++ b/commands/data/check-requirements.php @@ -372,6 +372,8 @@ class ProjectRequirements extends RequirementCollection const REQUIRED_PHP_VERSION_3x = '5.5.9'; const REQUIRED_PHP_VERSION_4x = '7.1.3'; const REQUIRED_PHP_VERSION_5x = '7.2.9'; + const REQUIRED_PHP_VERSION_6x = '8.1.0'; + const REQUIRED_PHP_VERSION_7x = '8.2.0'; public function __construct($rootDir) { @@ -386,12 +388,16 @@ public function __construct($rootDir) $rootDir = $this->getComposerRootDir($rootDir); $options = $this->readComposer($rootDir); - $phpVersion = self::REQUIRED_PHP_VERSION_3x; + $phpVersion = self::REQUIRED_PHP_VERSION_7x; if (null !== $symfonyVersion) { - if (version_compare($symfonyVersion, '5.0.0', '>=')) { + if (version_compare($symfonyVersion, '6.0.0', '>=')) { + $phpVersion = self::REQUIRED_PHP_VERSION_6x; + } elseif (version_compare($symfonyVersion, '5.0.0', '>=')) { $phpVersion = self::REQUIRED_PHP_VERSION_5x; } elseif (version_compare($symfonyVersion, '4.0.0', '>=')) { $phpVersion = self::REQUIRED_PHP_VERSION_4x; + } elseif (version_compare($symfonyVersion, '3.0.0', '>=')) { + $phpVersion = self::REQUIRED_PHP_VERSION_3x; } } @@ -929,7 +935,7 @@ private function getUploadMaxFilesize() $requirements = $symfonyRequirements->getRequirements(); // specific directory to check? -$dir = isset($args[1]) ? $args[1] : (file_exists(getcwd().'/composer.json') ? getcwd().'/composer.json' : null); +$dir = isset($args[1]) ? $args[1] : (file_exists(getcwd().'/composer.json') ? getcwd() : null); if (null !== $dir) { $projectRequirements = new ProjectRequirements($dir); $requirements = array_merge($requirements, $projectRequirements->getRequirements()); diff --git a/commands/doctrine_check_server_version_setting.go b/commands/doctrine_check_server_version_setting.go new file mode 100644 index 00000000..a2b67903 --- /dev/null +++ b/commands/doctrine_check_server_version_setting.go @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +import ( + "fmt" + + "github.com/rs/zerolog" + "github.com/symfony-cli/console" + "github.com/symfony-cli/terminal" +) + +var doctrineCheckServerVersionSettingCmd = &console.Command{ + Name: "doctrine:check-server-version-setting", + Usage: "Check if Doctrine server version is configured explicitly", + Hidden: console.Hide, + Flags: []console.Flag{ + dirFlag, + }, + Action: func(c *console.Context) error { + projectDir, err := getProjectDir(c.String("dir")) + if err != nil { + return err + } + + logger := terminal.Logger.Output(zerolog.ConsoleWriter{Out: terminal.Stderr}).With().Timestamp().Logger() + if err := checkDoctrineServerVersionSetting(projectDir, logger); err != nil { + return err + } + + fmt.Println("✅ Doctrine server version is set properly.") + return nil + }, +} diff --git a/commands/doctrine_server_version_check.go b/commands/doctrine_server_version_check.go new file mode 100644 index 00000000..0350e2e3 --- /dev/null +++ b/commands/doctrine_server_version_check.go @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +import ( + "fmt" + + "github.com/rs/zerolog" + "github.com/symfony-cli/symfony-cli/local/platformsh" +) + +// checkDoctrineServerVersionSetting checks that project has a DB and that server version is set properly +func checkDoctrineServerVersionSetting(projectDir string, logger zerolog.Logger) error { + if len(platformsh.FindLocalApplications(projectDir)) > 1 { + logger.Debug().Msg("Doctrine server version check disabled on a multiple applications project") + return nil + } + + configFile, dbName, dbVersion := platformsh.ReadDBVersionFromPlatformServiceYAML(projectDir, logger) + if dbName == "" { + // no DB + return nil + } + + errorTpl := fmt.Sprintf(` +The "%s" file defines +a "%s" version %s database service +but %%s. + +Before deploying, fix the version mismatch. + `, configFile, dbName, dbVersion) + + dotEnvVersion, err := platformsh.ReadDBVersionFromDotEnv(projectDir) + if err != nil { + return nil + } + if platformsh.DatabaseVersiondUnsynced(dotEnvVersion, dbVersion) { + return fmt.Errorf(errorTpl, fmt.Sprintf("the \".env\" file requires version %s", dotEnvVersion)) + } + + doctrineConfigVersion, err := platformsh.ReadDBVersionFromDoctrineConfigYAML(projectDir) + if err != nil { + return nil + } + if platformsh.DatabaseVersiondUnsynced(doctrineConfigVersion, dbVersion) { + return fmt.Errorf(errorTpl, fmt.Sprintf("the \"config/packages/doctrine.yaml\" file requires version %s", doctrineConfigVersion)) + } + + if dotEnvVersion == "" && doctrineConfigVersion == "" { + return fmt.Errorf(` +The "%s" file defines a "%s" database service. + +When deploying, Doctrine needs to know the database version to determine the supported SQL syntax. + +As the database is not available when Doctrine is warming up its cache on %s, +you need to explicitly set the database version in the ".env" or "config/packages/doctrine.yaml" file. + +Set the "server_version" parameter to "%s" in "config/packages/doctrine.yaml". + `, configFile, dbName, platformsh.GuessCloudFromDirectory(projectDir).Name, dbVersion) + } + + return nil +} diff --git a/commands/generator/main.go b/commands/generator/main.go new file mode 100644 index 00000000..c6e636f8 --- /dev/null +++ b/commands/generator/main.go @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + + "github.com/hashicorp/go-version" +) + +func main() { + generateLatestPhpVersion() +} + +func generateLatestPhpVersion() { + resp, err := http.Get("https://www.php.net/releases/active.php") + if err != nil { + panic(err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + var result map[int]map[string]struct { + Announcement bool + LatestMinor string `json:"version"` + } + + if err := json.Unmarshal(body, &result); err != nil { + panic(err) + } + + var latestVersion *version.Version + + for _, versions := range result { + for _, versionInfo := range versions { + if !versionInfo.Announcement { + continue + } + + ver, err := version.NewVersion(versionInfo.LatestMinor) + if err != nil { + panic(err) + } + + if latestVersion == nil || ver.GreaterThan(latestVersion) { + latestVersion = ver + } + } + } + + f, err := os.Create("php_version.go") + if err != nil { + panic(err) + } + f.WriteString(`// Code generated by commands/generator/main.go +// DO NOT EDIT + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +const LatestPhpMajorVersion = "` + fmt.Sprintf("%d.%d", latestVersion.Segments()[0], latestVersion.Segments()[1]) + `" +const LatestPhpMinorVersion = "` + latestVersion.Original() + `" +`) +} diff --git a/commands/local_check_security.go b/commands/local_check_security.go index 8c88775b..41b8231d 100644 --- a/commands/local_check_security.go +++ b/commands/local_check_security.go @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package commands import ( @@ -23,7 +42,7 @@ a specific "composer.lock" file.`, &console.StringFlag{ Name: "format", DefaultValue: "ansi", - Usage: "The output format (ansi, markdown, json, junit, or yaml)", + Usage: "The output format (ansi, text, markdown, json, junit, or yaml)", Validator: func(ctx *console.Context, format string) error { if format != "" && format != "markdown" && format != "json" && format != "yaml" && format != "ansi" && format != "junit" { return errors.Errorf(`format "%s" does not exist (supported formats: markdown, ansi, json, junit, and yaml)`, format) diff --git a/commands/local_new.go b/commands/local_new.go index 28856244..114c600b 100644 --- a/commands/local_new.go +++ b/commands/local_new.go @@ -137,9 +137,6 @@ var localNewCmd = &console.Command{ if symfonyVersion != "" && c.Bool("demo") { return console.Exit("The --version flag is not supported for the Symfony Demo", 1) } - if c.Bool("webapp") && c.Bool("no-git") { - return console.Exit("The --webapp flag cannot be used with --no-git", 1) - } if c.Bool("webapp") && c.Bool("api") { return console.Exit("The --api flag cannot be used with --webapp", 1) } @@ -147,6 +144,9 @@ var localNewCmd = &console.Command{ if len(c.StringSlice("service")) > 0 && !withCloud { return console.Exit("The --service flag cannot be used without --cloud or --upsun", 1) } + if withCloud && c.Bool("no-git") { + return console.Exit("The --no-git flag cannot be used with --cloud or --upsun", 1) + } s := terminal.NewSpinner(terminal.Stderr) s.Start() @@ -178,11 +178,12 @@ var localNewCmd = &console.Command{ if c.Bool("webapp") { if err := runComposer(c, dir, []string{"require", "webapp"}, c.Bool("debug")); err != nil { return err - } - buf, err := git.AddAndCommit(dir, []string{"."}, "Add webapp packages", c.Bool("debug")) - if err != nil { - fmt.Print(buf.String()) - return err + } else if !c.Bool("no-git") { + buf, err := git.AddAndCommit(dir, []string{"."}, "Add webapp packages", c.Bool("debug")) + if err != nil { + fmt.Print(buf.String()) + return err + } } } diff --git a/commands/local_php_list.go b/commands/local_php_list.go index f687596d..1c76d713 100644 --- a/commands/local_php_list.go +++ b/commands/local_php_list.go @@ -19,6 +19,8 @@ package commands +//go:generate go run generator/main.go + import ( "os" "strings" @@ -88,7 +90,7 @@ var localPhpListCmd = &console.Command{ } terminal.Println("") - terminal.Println("To control the version used in a directory, create a .php-version file that contains the version number (e.g. 8.2 or 8.2.16),") + terminal.Println("To control the version used in a directory, create a .php-version file that contains the version number (e.g. " + LatestPhpMajorVersion + " or " + LatestPhpMinorVersion + "),") terminal.Println("or define config.platform.php inside composer.json.") terminal.Println("If you're using Platform.sh or Upsun, the version can also be specified in their configuration files.") diff --git a/commands/local_server_start.go b/commands/local_server_start.go index a3af3fdd..1ddb5016 100644 --- a/commands/local_server_start.go +++ b/commands/local_server_start.go @@ -52,6 +52,7 @@ import ( var localWebServerProdWarningMsg = "The local web server is optimized for local development and MUST never be used in a production setup." var localWebServerTlsKeyLogWarningMsg = "Logging TLS master key is enabled. It means TLS connections between the client and this server will be INSECURE. This is NOT recommended unless you are debugging the connections." +var localWebServerAllowsCORSLogWarningMsg = "Cross-origin resource sharing (CORS) is enabled for all requests.\nYou may want to use https://github.com/nelmio/NelmioCorsBundle to have better control over HTTP headers." var localServerStartCmd = &console.Command{ Category: "local", @@ -65,6 +66,8 @@ var localServerStartCmd = &console.Command{ &console.StringFlag{Name: "document-root", Usage: "Project document root (auto-configured by default)"}, &console.StringFlag{Name: "passthru", Usage: "Project passthru index (auto-configured by default)"}, &console.IntFlag{Name: "port", DefaultValue: 8000, Usage: "Preferred HTTP port"}, + &console.StringFlag{Name: "listen-ip", DefaultValue: "127.0.0.1", Usage: "The IP on which the CLI should listen"}, + &console.BoolFlag{Name: "allow-all-ip", Usage: "Listen on all the available interfaces"}, &console.BoolFlag{Name: "daemon", Aliases: []string{"d"}, Usage: "Run the server in the background"}, &console.BoolFlag{Name: "no-humanize", Usage: "Do not format JSON logs"}, &console.StringFlag{Name: "p12", Usage: "Name of the file containing the TLS certificate to use in p12 format"}, @@ -81,6 +84,7 @@ var localServerStartCmd = &console.Command{ EnvVars: []string{"SSLKEYLOGFILE"}, }, &console.BoolFlag{Name: "no-workers", Usage: "Do not start workers"}, + &console.BoolFlag{Name: "allow-cors", Usage: "Allow Cross-origin resource sharing (CORS) requests"}, }, Action: func(c *console.Context) error { ui := terminal.SymfonyStyle(terminal.Stdout, terminal.Stdin) @@ -186,6 +190,10 @@ var localServerStartCmd = &console.Command{ ui.Warning(localWebServerTlsKeyLogWarningMsg) } + if config.AllowCORS { + ui.Warning(localWebServerAllowsCORSLogWarningMsg) + } + lw, err := pidFile.LogWriter() if err != nil { return err @@ -302,6 +310,10 @@ var localServerStartCmd = &console.Command{ reexec.NotifyForeground("listening") ui.Warning(localWebServerProdWarningMsg) + if config.ListenIp == "127.0.0.1" { + ui.Warning(`Please note that the Symfony CLI only listens on 127.0.0.1 by default since version 5.10.3. + You can use the --allow-all-ip or --listen-ip flags to change this behavior.`) + } ui.Success(msg) } @@ -325,6 +337,7 @@ var localServerStartCmd = &console.Command{ continue } pidFile.Watched = worker.Watch + pidFile.CustomName = name // we run each worker in its own goroutine for several reasons: // * to get things up and running faster @@ -400,7 +413,13 @@ var localServerStartCmd = &console.Command{ case <-shutdownCh: terminal.Eprintln("") terminal.Eprintln("Shutting down! Waiting for all workers to be done.") - if err := waitForWorkers(projectDir, pidFile); err != nil { + err := waitForWorkers(projectDir, pidFile) + // wait for the PHP Server to be done cleaning up + if p.PHPServer != nil { + <-p.PHPServer.StoppedChan + } + pidFile.CleanupDirectories() + if err != nil { return err } terminal.Eprintln("") diff --git a/commands/openers.go b/commands/openers.go index 3607e5d1..f8afbdeb 100644 --- a/commands/openers.go +++ b/commands/openers.go @@ -54,7 +54,7 @@ var projectLocalOpenCmd = &console.Command{ } host := fmt.Sprintf("127.0.0.1:%d", pidFile.Port) if proxyConf, err := proxy.Load(util.GetHomeDir()); err == nil { - domains := proxyConf.GetDomains(projectDir) + domains := proxyConf.GetReachableDomains(projectDir) if len(domains) > 0 { host = domains[0] } diff --git a/commands/php_version.go b/commands/php_version.go new file mode 100644 index 00000000..7df9b51a --- /dev/null +++ b/commands/php_version.go @@ -0,0 +1,26 @@ +// Code generated by commands/generator/main.go +// DO NOT EDIT + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +const LatestPhpMajorVersion = "8.4" +const LatestPhpMinorVersion = "8.4.7" diff --git a/commands/platformsh_hooks.go b/commands/platformsh_hooks.go index b8e77cd6..b29641a3 100644 --- a/commands/platformsh_hooks.go +++ b/commands/platformsh_hooks.go @@ -20,8 +20,7 @@ package commands import ( - "fmt" - + "github.com/rs/zerolog" "github.com/symfony-cli/console" "github.com/symfony-cli/symfony-cli/envs" "github.com/symfony-cli/symfony-cli/local/platformsh" @@ -35,59 +34,7 @@ var platformshBeforeHooks = map[string]console.BeforeFunc{ if err != nil { return err } - - if len(platformsh.FindLocalApplications(projectDir)) > 1 { - // not implemented yet as more complex - return nil - } - - dbName, dbVersion, err := platformsh.ReadDBVersionFromPlatformServiceYAML(projectDir) - if err != nil { - return nil - } - if dbName == "" { - // no DB - return nil - } - - errorTpl := fmt.Sprintf(` -The ".platform/services.yaml" file defines -a "%s" version %s database service -but %%s. - -Before deploying, fix the version mismatch. -`, dbName, dbVersion) - - dotEnvVersion, err := platformsh.ReadDBVersionFromDotEnv(projectDir) - if err != nil { - return nil - } - if platformsh.DatabaseVersiondUnsynced(dotEnvVersion, dbVersion) { - return fmt.Errorf(errorTpl, fmt.Sprintf("the \".env\" file requires version %s", dotEnvVersion)) - } - - doctrineConfigVersion, err := platformsh.ReadDBVersionFromDoctrineConfigYAML(projectDir) - if err != nil { - return nil - } - if platformsh.DatabaseVersiondUnsynced(doctrineConfigVersion, dbVersion) { - return fmt.Errorf(errorTpl, fmt.Sprintf("the \"config/packages/doctrine.yaml\" file requires version %s", doctrineConfigVersion)) - } - - if dotEnvVersion == "" && doctrineConfigVersion == "" { - return fmt.Errorf(` -The ".platform/services.yaml" file defines a "%s" database service. - -When deploying, Doctrine needs to know the database version to determine the supported SQL syntax. - -As the database is not available when Doctrine is warming up its cache on Platform.sh, -you need to explicitly set the database version in the ".env" or "config/packages/doctrine.yaml" file. - -Set the "server_version" parameter to "%s" in "config/packages/doctrine.yaml". -`, dbName, dbVersion) - } - - return nil + return checkDoctrineServerVersionSetting(projectDir, zerolog.Nop()) }, "tunnel:close": func(c *console.Context) error { terminal.Eprintln("Stop exposing tunnel service environment variables") diff --git a/commands/resources/completion.bash b/commands/resources/completion.bash new file mode 100644 index 00000000..f6a3c601 --- /dev/null +++ b/commands/resources/completion.bash @@ -0,0 +1,92 @@ +# Copyright (c) 2021-present Fabien Potencier +# +# This file is part of Symfony CLI project +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Bash completions for the CLI binary +# +# References: +# - https://github.com/symfony/symfony/blob/6.4/src/Symfony/Component/Console/Resources/completion.bash +# - https://github.com/posener/complete/blob/master/install/bash.go +# - https://github.com/scop/bash-completion/blob/master/completions/sudo +# + +_complete_{{ .App.HelpName }}() { + + # Use the default completion for shell redirect operators. + for w in '>' '>>' '&>' '<'; do + if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then + compopt -o filenames + COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")) + return 0 + fi + done + + for (( i=1; i <= COMP_CWORD; i++ )); do + if [[ "${COMP_WORDS[i]}" != -* ]]; then + case "${COMP_WORDS[i]}" in + {{range $i, $name := (.App.Command "php").Names }}{{if $i}}|{{end}}{{$name}}{{end}}{{range $name := (.App.Command "run").Names }}|{{$name}}{{end}}) + _command_offset $i + return + ;; + esac; + fi + done + + # Use newline as only separator to allow space in completion values + local IFS=$'\n' + + local cur prev words cword + _get_comp_words_by_ref -n := cur prev words cword + + local sfcomplete + if sfcomplete=$(COMP_LINE="${COMP_LINE}" COMP_POINT="${COMP_POINT}" COMP_DEBUG="$COMP_DEBUG" CURRENT="$cword" {{ .CurrentBinaryPath }} self:autocomplete 2>&1); then + local quote suggestions + quote=${cur:0:1} + + # Use single quotes by default if suggestions contains backslash (FQCN) + if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then + quote=\' + fi + + if [ "$quote" == \' ]; then + # single quotes: no additional escaping (does not accept ' in values) + suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) + elif [ "$quote" == \" ]; then + # double quotes: double escaping for \ $ ` " + suggestions=$(for s in $sfcomplete; do + s=${s//\\/\\\\} + s=${s//\$/\\\$} + s=${s//\`/\\\`} + s=${s//\"/\\\"} + printf $'%q%q%q\n' "$quote" "$s" "$quote"; + done) + else + # no quotes: double escaping + suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done) + fi + COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur"))) + __ltrim_colon_completions "$cur" + else + if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then + >&2 echo + >&2 echo $sfcomplete + fi + + return 1 + fi +} + +complete -F _complete_{{ .App.HelpName }} {{ .App.HelpName }} diff --git a/commands/resources/completion.fish b/commands/resources/completion.fish new file mode 100644 index 00000000..81991327 --- /dev/null +++ b/commands/resources/completion.fish @@ -0,0 +1,36 @@ +# Copyright (c) 2021-present Fabien Potencier +# +# This file is part of Symfony CLI project +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Fish completions for the CLI binary +# +# References: +# - https://github.com/symfony/symfony/blob/6.4/src/Symfony/Component/Console/Resources/completion.fish +# - https://github.com/posener/complete/blob/master/install/fish.go +# - https://github.com/fish-shell/fish-shell/blob/master/share/completions/sudo.fish +# + +function __complete_{{ .App.HelpName }} + set -lx COMP_LINE (commandline -cp) + test -z (commandline -ct) + and set COMP_LINE "$COMP_LINE " + set -x CURRENT (count (commandline -oc)) + {{ .CurrentBinaryInvocation }} self:autocomplete +end + +complete -f -c '{{ .App.HelpName }}' -n "__fish_seen_subcommand_from {{range $i, $name := (.App.Command "php").Names }}{{if $i}} {{end}}{{$name}}{{end}}" -a '(__fish_complete_subcommand)' +complete -f -c '{{ .App.HelpName }}' -n "__fish_seen_subcommand_from {{range $i, $name := (.App.Command "run").Names }}{{if $i}} {{end}}{{$name}}{{end}}" -a '(__fish_complete_subcommand --fcs-skip=2)' +complete -f -c '{{ .App.HelpName }}' -n "not __fish_seen_subcommand_from {{range $i, $name := (.App.Command "php").Names }}{{if $i}} {{end}}{{$name}}{{end}} {{range $i, $name := (.App.Command "run").Names }}{{if $i}} {{end}}{{$name}}{{end}}" -a '(__complete_{{ .App.HelpName }})' diff --git a/commands/resources/completion.zsh b/commands/resources/completion.zsh new file mode 100644 index 00000000..77c731db --- /dev/null +++ b/commands/resources/completion.zsh @@ -0,0 +1,89 @@ +#compdef {{ .App.HelpName }} + +# Copyright (c) 2021-present Fabien Potencier +# +# This file is part of Symfony CLI project +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +# +# zsh completions for {{ .App.HelpName }} +# +# References: +# - https://github.com/symfony/symfony/blob/6.4/src/Symfony/Component/Console/Resources/completion.zsh +# - https://github.com/posener/complete/blob/master/install/zsh.go +# - https://stackoverflow.com/a/13547531 +# + +_complete_{{ .App.HelpName }}() { + local lastParam flagPrefix requestComp out comp + local -a completions + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $CURRENT location, so we need + # to truncate the command-line ($words) up to the $CURRENT location. + # (We cannot use $CURSOR as its value does not work when a command is an alias.) + words=("${=words[1,CURRENT]}") lastParam=${words[-1]} + + # For zsh, when completing a flag with an = (e.g., {{ .App.HelpName }} -n=) + # completions must be prefixed with the flag + setopt local_options BASH_REMATCH + if [[ "${lastParam}" =~ '-.*=' ]]; then + # We are dealing with a flag with an = + flagPrefix="-P ${BASH_REMATCH}" + fi + + # detect if we are in a wrapper command and need to "forward" completion to it + for ((i = 1; i <= $#words; i++)); do + if [[ "${words[i]}" != -* ]]; then + case "${words[i]}" in + console|composer) + (( CURRENT-- )) + ;; + {{range $i, $name := (.App.Command "php").Names }}{{if $i}}|{{end}}{{$name}}{{end}}) + shift words + (( CURRENT-- )) + _normal + return + ;; + {{range $i, $name := (.App.Command "local:run").Names }}{{if $i}}|{{end}}{{$name}}{{end}}) + shift words + (( CURRENT-- )) + shift words + (( CURRENT-- )) + _normal + return + ;; + esac; + fi + done + + while IFS='\n' read -r comp; do + if [ -n "$comp" ]; then + # If requested, completions are returned with a description. + # The description is preceded by a TAB character. + # For zsh's _describe, we need to use a : instead of a TAB. + # We first need to escape any : as part of the completion itself. + comp=${comp//:/\\:} + local tab=$(printf '\t') + comp=${comp//$tab/:} + completions+=${comp} + fi + done < <(COMP_LINE="$words" CURRENT="$CURRENT" ${words[0]} ${_SF_CMD:-${words[1]}} self:autocomplete) + + # Let inbuilt _describe handle completions + eval _describe "completions" completions $flagPrefix +} + +compdef _complete_{{ .App.HelpName }} {{ .App.HelpName }} diff --git a/commands/root.go b/commands/root.go index bc05012b..606191ef 100644 --- a/commands/root.go +++ b/commands/root.go @@ -25,6 +25,7 @@ import ( "github.com/pkg/errors" "github.com/symfony-cli/console" + "github.com/symfony-cli/symfony-cli/envs" "github.com/symfony-cli/symfony-cli/local/platformsh" "github.com/symfony-cli/symfony-cli/reexec" "github.com/symfony-cli/symfony-cli/updater" @@ -55,6 +56,7 @@ func CommonCommands() []*console.Command { bookCheckReqsCmd, bookCheckoutCmd, cloudEnvDebugCmd, + doctrineCheckServerVersionSettingCmd, localNewCmd, localPhpListCmd, localPhpRefreshCmd, @@ -98,6 +100,10 @@ func init() { } func InitAppFunc(c *console.Context) error { + checkWSL() + + envs.ComputeDockerUserAgent(c.App.Name, c.App.Version) + psh, err := platformsh.Get() if err != nil { return err @@ -173,6 +179,7 @@ Environment variables to use Platform.sh/Upsun relationships or Docker services {{with .Command "composer"}} {{.PreferredName}}{{"\t"}}{{.Usage}}{{end}} {{with .Command "console"}} {{.PreferredName}}{{"\t"}}{{.Usage}}{{end}} {{with .Command "php"}} {{.PreferredName}}{{"\t"}}{{.Usage}}{{end}} +{{with .Command "pie"}} {{.PreferredName}}{{"\t"}}{{.Usage}}{{end}} ` } diff --git a/commands/testdata/project/.platform.app.yaml b/commands/testdata/project/.platform.app.yaml index 67698ab3..84e0accc 100644 --- a/commands/testdata/project/.platform.app.yaml +++ b/commands/testdata/project/.platform.app.yaml @@ -34,7 +34,7 @@ web: passthru: "/index.php" mounts: - "/var": { source: local, source_path: var } + "/var/cache": { source: local, source_path: var/cache } relationships: @@ -48,7 +48,7 @@ hooks: curl -fs https://get.symfony.com/cloud/configurator | bash - NODE_VERSION=18 symfony-build + NODE_VERSION=22 symfony-build deploy: | set -x -e @@ -58,8 +58,10 @@ hooks: crons: security-check: # Check that no security issues have been found for PHP packages deployed in production - # See https://github.com/fabpot/local-php-security-checker spec: '50 23 * * *' - cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape php-security-checker; fi + cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape COMPOSER_ROOT_VERSION=1.0.0 COMPOSER_AUDIT_ABANDONED=ignore composer audit --no-cache; fi + clean-expired-sessions: + spec: '17,47 * * * *' + cmd: croncape php-session-clean diff --git a/commands/testdata/project/.upsun/config.yaml b/commands/testdata/project/.upsun/config.yaml index d29f4321..c1e767bc 100644 --- a/commands/testdata/project/.upsun/config.yaml +++ b/commands/testdata/project/.upsun/config.yaml @@ -61,7 +61,7 @@ applications: curl -fs https://get.symfony.com/cloud/configurator | bash - NODE_VERSION=18 symfony-build + NODE_VERSION=22 symfony-build deploy: | set -x -e @@ -71,8 +71,10 @@ applications: crons: security-check: # Check that no security issues have been found for PHP packages deployed in production - # See https://github.com/fabpot/local-php-security-checker spec: '50 23 * * *' - cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape php-security-checker; fi + cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape COMPOSER_ROOT_VERSION=1.0.0 COMPOSER_AUDIT_ABANDONED=ignore composer audit --no-cache; fi + clean-expired-sessions: + spec: '17,47 * * * *' + cmd: croncape php-session-clean diff --git a/commands/wrappers.go b/commands/wrappers.go index ae6a4fd1..1326524b 100644 --- a/commands/wrappers.go +++ b/commands/wrappers.go @@ -27,32 +27,46 @@ import ( var ( composerWrapper = &console.Command{ - Name: "composer", Usage: "Runs Composer without memory limit", Hidden: console.Hide, + // we use an alias to avoid the command being shown in the help but + // still be available for completion + Aliases: []*console.Alias{{Name: "composer"}}, + ShellComplete: autocompleteComposerWrapper, Action: func(c *console.Context) error { return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony composer"`)} }, } binConsoleWrapper = &console.Command{ - Name: "console", Usage: "Runs the Symfony Console (bin/console) for current project", Hidden: console.Hide, + // we use an alias to avoid the command being shown in the help but + // still be available for completion + Aliases: []*console.Alias{{Name: "console"}}, Action: func(c *console.Context) error { - return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony console"`)} + return errors.New(`No Symfony console detected to run "symfony console"`) }, + ShellComplete: autocompleteSymfonyConsoleWrapper, } phpWrapper = &console.Command{ Usage: "Runs the named binary using the configured PHP version", Hidden: console.Hide, + // we use aliases to avoid the command being shown in the help but + // still be available for completion + Aliases: func() []*console.Alias { + binNames := php.GetBinaryNames() + aliases := make([]*console.Alias, 0, len(binNames)+1) + + for _, name := range php.GetBinaryNames() { + aliases = append(aliases, &console.Alias{Name: name}) + } + + aliases = append(aliases, &console.Alias{Name: "pie"}) + + return aliases + }(), Action: func(c *console.Context) error { return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony php*"`)} }, } ) - -func init() { - for _, name := range php.GetBinaryNames() { - phpWrapper.Aliases = append(phpWrapper.Aliases, &console.Alias{Name: name, Hidden: console.Hide()}) - } -} diff --git a/commands/wsl_others.go b/commands/wsl_others.go new file mode 100644 index 00000000..9ddae2ed --- /dev/null +++ b/commands/wsl_others.go @@ -0,0 +1,26 @@ +//go:build !windows +// +build !windows + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +func checkWSL() { +} diff --git a/commands/wsl_windows.go b/commands/wsl_windows.go new file mode 100644 index 00000000..10301a4b --- /dev/null +++ b/commands/wsl_windows.go @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package commands + +import ( + "os" + + "github.com/symfony-cli/terminal" +) + +func checkWSL() { + if fi, err := os.Stat("/proc/version"); fi == nil || err != nil { + return + } + + ui := terminal.SymfonyStyle(terminal.Stdout, terminal.Stdin) + ui.Error("Wrong binary for WSL") + terminal.Println(`You are trying to run the Windows version of the Symfony CLI on WSL (Linux). +You must use the Linux version to use the Symfony CLI on WSL. + +Download it at https://symfony.com/download +`) + os.Exit(1) +} diff --git a/envs/docker.go b/envs/docker.go index ee5eab42..7efe2cb2 100644 --- a/envs/docker.go +++ b/envs/docker.go @@ -19,11 +19,12 @@ package envs +//go:generate sh generate_docker_version + import ( "bytes" "context" "fmt" - "net" "net/url" "os" "path/filepath" @@ -33,18 +34,25 @@ import ( "strings" "time" - "github.com/docker/docker/api/types" + compose "github.com/compose-spec/compose-go/cli" + composeConsts "github.com/compose-spec/compose-go/consts" "github.com/docker/docker/api/types/container" docker "github.com/docker/docker/client" "github.com/symfony-cli/terminal" + "gopkg.in/yaml.v2" ) var ( dockerComposeNormalizeRegexp = regexp.MustCompile("[^-_a-z0-9]") dockerComposeNormalizeRegexpLegacy = regexp.MustCompile("[^a-z0-9]") + dockerUserAgent = "Docker-Client/unknown version" ) -type sortedPorts []types.Port +func ComputeDockerUserAgent(appName, appVersion string) { + dockerUserAgent = fmt.Sprintf("Docker-Client/%s %s/%s", dockerClientVersion, appName, appVersion) +} + +type sortedPorts []container.Port func (ps sortedPorts) Len() int { return len(ps) } func (ps sortedPorts) Swap(i, j int) { ps[i], ps[j] = ps[j], ps[i] } @@ -69,17 +77,17 @@ func (l *Local) RelationshipsFromDocker() Relationships { return nil } - opts := [](docker.Opt){docker.FromEnv} - if host := os.Getenv(docker.EnvOverrideHost); host != "" && !strings.HasPrefix(host, "unix://") { - // Setting a dialer on top of a unix socket breaks the connection - // as the client then tries to connect to http:///path/to/socket and - // thus tries to resolve the /path/to/socket host - dialer := &net.Dialer{ - Timeout: 2 * time.Second, - } - opts = append(opts, docker.WithDialContext(dialer.DialContext)) - } - client, err := docker.NewClientWithOpts(opts...) + client, err := docker.NewClientWithOpts( + docker.FromEnv, + dockerUseDesktopSocketIfAvailable, + docker.WithAPIVersionNegotiation(), + // we use a short timeout here because we don't want to impact + // negatively performance when Docker is not reachable + docker.WithTimeout(2*time.Second), + // defining a User Agent to avoid having the Docker API being slow + // see https://github.com/docker/for-mac/issues/7575 + docker.WithUserAgent(dockerUserAgent), + ) if err != nil { if l.Debug { fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) @@ -88,13 +96,12 @@ func (l *Local) RelationshipsFromDocker() Relationships { } defer client.Close() - client.NegotiateAPIVersion(context.Background()) - containers, err := client.ContainerList(context.Background(), container.ListOptions{}) if err != nil { if docker.IsErrConnectionFailed(err) { terminal.Logger.Warn().Msg(err.Error()) - } else if l.Debug { + } + if l.Debug { fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) } return nil @@ -140,7 +147,7 @@ func (l *Local) RelationshipsFromDocker() Relationships { return relationships } -func (l *Local) dockerServiceToRelationship(client *docker.Client, container types.Container) map[string]map[string]interface{} { +func (l *Local) dockerServiceToRelationship(client *docker.Client, container container.Summary) map[string]map[string]interface{} { if l.Debug { fmt.Fprintf(os.Stderr, `found Docker container "%s" for project "%s" (image "%s")`+"\n", container.Labels["com.docker.compose.service"], container.Labels["com.docker.compose.project"], container.Image) } @@ -196,281 +203,304 @@ func (l *Local) dockerServiceToRelationship(client *docker.Client, container typ } } + if len(exposedPorts) < 1 { + return nil + } + sort.Sort(exposedPorts) - for _, p := range exposedPorts { - rels := make(map[string]map[string]interface{}) - if p.PrivatePort == 1025 { - // recommended image: sj26/mailcatcher or axllent/mailpit (default now) - for _, pw := range exposedPorts { - if pw.PrivatePort == 1080 || pw.PrivatePort == 8025 { - rels["-web"] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(pw.PublicPort), - "rel": "mailer", - "scheme": "http", - } - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "mailer", - "scheme": "smtp", - } - return rels + p := exposedPorts[0] + + rels := make(map[string]map[string]interface{}) + if p.PrivatePort == 1025 { + // recommended image: sj26/mailcatcher or axllent/mailpit (default now) + for _, pw := range exposedPorts { + if pw.PrivatePort == 1080 || pw.PrivatePort == 8025 { + rels["-web"] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(pw.PublicPort), + "rel": "mailer", + "scheme": "http", } - } - } else if p.PrivatePort == 25 { - // recommended image: djfarrelly/maildev - for _, pw := range exposedPorts { - if pw.PrivatePort == 80 { - rels["-web"] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(pw.PublicPort), - "rel": "mailer", - "scheme": "http", - } - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "mailer", - "scheme": "smtp", - } - return rels + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "mailer", + "scheme": "smtp", } + return rels } - } else if p.PrivatePort == 8707 || p.PrivatePort == 8307 { - // Blackfire - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "blackfire", - "scheme": "tcp", - } - return rels - } else if p.PrivatePort == 3306 { - username := "" - password := "" - path := "" - version := "" - // MARIADB is used by bitnami/mariadb - for _, prefix := range []string{"MYSQL", "MARIADB"} { - for _, env := range c.Config.Env { - if strings.HasPrefix(env, prefix+"_ROOT_PASSWORD") && password == "" { - // *_PASSWORD has precedence over *_ROOT_PASSWORD - password = getEnvValue(env, prefix+"_ROOT_PASSWORD") - username = "root" - } else if strings.HasPrefix(env, prefix+"_USER") { - username = getEnvValue(env, prefix+"_USER") - } else if strings.HasPrefix(env, prefix+"_PASSWORD") { - password = getEnvValue(env, prefix+"_PASSWORD") - } else if strings.HasPrefix(env, prefix+"_DATABASE") { - path = getEnvValue(env, prefix+"_DATABASE") - } else if strings.HasPrefix(env, prefix+"_VERSION") { - version = getEnvValue(env, prefix+"_VERSION") - } + } + } else if p.PrivatePort == 25 { + // recommended image: djfarrelly/maildev + for _, pw := range exposedPorts { + if pw.PrivatePort == 80 { + rels["-web"] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(pw.PublicPort), + "rel": "mailer", + "scheme": "http", } - } - if path == "" { - path = username - } - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "username": username, - "password": password, - "path": path, - "version": version, - "port": formatDockerPort(p.PublicPort), - "query": map[string]bool{ - "is_master": true, - }, - "rel": "mysql", - "scheme": "mysql", - } - return rels - } else if p.PrivatePort == 5432 { - username := "" - password := "" - path := "" - version := "" - for _, env := range c.Config.Env { - if strings.HasPrefix(env, "POSTGRES_USER") { - username = getEnvValue(env, "POSTGRES_USER") - } else if strings.HasPrefix(env, "POSTGRES_PASSWORD") { - password = getEnvValue(env, "POSTGRES_PASSWORD") - } else if strings.HasPrefix(env, "POSTGRES_DB") { - path = getEnvValue(env, "POSTGRES_DB") - } else if strings.HasPrefix(env, "PG_VERSION") { - version = getEnvValue(env, "PG_VERSION") + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "mailer", + "scheme": "smtp", } + return rels } - if path == "" { - path = username - } - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "username": username, - "password": password, - "path": path, - "version": version, - "port": formatDockerPort(p.PublicPort), - "query": map[string]bool{ - "is_master": true, - }, - "rel": "pgsql", - "scheme": "pgsql", - } - return rels - } else if p.PrivatePort == 6379 { - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "redis", - "scheme": "redis", - } - return rels - } else if p.PrivatePort == 11211 { - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "memcached", - "scheme": "memcached", - } - return rels - } else if p.PrivatePort == 5672 { - username := "guest" - password := "guest" + } + } else if p.PrivatePort == 8707 || p.PrivatePort == 8307 { + // Blackfire + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "blackfire", + "scheme": "tcp", + } + return rels + } else if p.PrivatePort == 3306 { + username := "" + password := "" + path := "" + version := "" + // MARIADB is used by bitnami/mariadb + for _, prefix := range []string{"MYSQL", "MARIADB"} { for _, env := range c.Config.Env { - // that's our local convention - if strings.HasPrefix(env, "RABBITMQ_DEFAULT_USER") { - username = getEnvValue(env, "RABBITMQ_DEFAULT_USER") - } else if strings.HasPrefix(env, "RABBITMQ_DEFAULT_PASS") { - password = getEnvValue(env, "RABBITMQ_DEFAULT_PASS") + if strings.HasPrefix(env, prefix+"_ROOT_PASSWORD") && password == "" { + // *_PASSWORD has precedence over *_ROOT_PASSWORD + password = getEnvValue(env, prefix+"_ROOT_PASSWORD") + username = "root" + } else if strings.HasPrefix(env, prefix+"_USER") { + username = getEnvValue(env, prefix+"_USER") + } else if strings.HasPrefix(env, prefix+"_PASSWORD") { + password = getEnvValue(env, prefix+"_PASSWORD") + } else if strings.HasPrefix(env, prefix+"_DATABASE") { + path = getEnvValue(env, prefix+"_DATABASE") + } else if strings.HasPrefix(env, prefix+"_VERSION") { + version = getEnvValue(env, prefix+"_VERSION") } } - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "username": username, - "password": password, - "rel": "amqp", - "scheme": "amqp", - } - // management plugin? - for _, pw := range exposedPorts { - if pw.PrivatePort == 15672 { - rels["-management"] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(pw.PublicPort), - "rel": "amqp", - "scheme": "http", - } - break - } - } - return rels - } else if p.PrivatePort == 9200 { - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "path": "/", - "rel": "elasticsearch", - "scheme": "http", + } + if path == "" { + path = username + } + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "username": username, + "password": password, + "path": path, + "version": version, + "port": formatDockerPort(p.PublicPort), + "query": map[string]bool{ + "is_master": true, + }, + "rel": "mysql", + "scheme": "mysql", + } + return rels + } else if p.PrivatePort == 5432 { + username := "" + password := "" + path := "" + version := "" + for _, env := range c.Config.Env { + if strings.HasPrefix(env, "POSTGRES_USER") { + username = getEnvValue(env, "POSTGRES_USER") + } else if strings.HasPrefix(env, "POSTGRES_PASSWORD") { + password = getEnvValue(env, "POSTGRES_PASSWORD") + } else if strings.HasPrefix(env, "POSTGRES_DB") { + path = getEnvValue(env, "POSTGRES_DB") + } else if strings.HasPrefix(env, "PG_VERSION") { + version = getEnvValue(env, "PG_VERSION") } - return rels - } else if p.PrivatePort == 5601 { - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "path": "/", - "rel": "kibana", - "scheme": "http", + } + if path == "" { + path = username + } + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "username": username, + "password": password, + "path": path, + "version": version, + "port": formatDockerPort(p.PublicPort), + "query": map[string]bool{ + "is_master": true, + }, + "rel": "pgsql", + "scheme": "pgsql", + } + return rels + } else if p.PrivatePort == 6379 { + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "redis", + "scheme": "redis", + } + return rels + } else if p.PrivatePort == 11211 { + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "memcached", + "scheme": "memcached", + } + return rels + } else if p.PrivatePort == 5672 { + username := "guest" + password := "guest" + for _, env := range c.Config.Env { + // that's our local convention + if strings.HasPrefix(env, "RABBITMQ_DEFAULT_USER") { + username = getEnvValue(env, "RABBITMQ_DEFAULT_USER") + } else if strings.HasPrefix(env, "RABBITMQ_DEFAULT_PASS") { + password = getEnvValue(env, "RABBITMQ_DEFAULT_PASS") } - return rels - } else if p.PrivatePort == 27017 || p.PrivatePort == 27018 || p.PrivatePort == 27019 { - username := "" - password := "" - path := "" - for _, env := range c.Config.Env { - // that's our local convention - if strings.HasPrefix(env, "MONGO_DATABASE") { - path = getEnvValue(env, "MONGO_DATABASE") - } else if strings.HasPrefix(env, "MONGO_INITDB_DATABASE") { - path = getEnvValue(env, "MONGO_INITDB_DATABASE") - } else if strings.HasPrefix(env, "MONGO_INITDB_ROOT_USERNAME") { - username = getEnvValue(env, "MONGO_INITDB_ROOT_USERNAME") - } else if strings.HasPrefix(env, "MONGO_INITDB_ROOT_PASSWORD") { - password = getEnvValue(env, "MONGO_INITDB_ROOT_PASSWORD") + } + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "username": username, + "password": password, + "rel": "amqp", + "scheme": "amqp", + } + // management plugin? + for _, pw := range exposedPorts { + if pw.PrivatePort == 15672 { + rels["-management"] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(pw.PublicPort), + "rel": "amqp", + "scheme": "http", } + break } - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "username": username, - "password": password, - "path": path, - "port": formatDockerPort(p.PublicPort), - "rel": "mongodb", - "scheme": "mongodb", - } - return rels - } else if p.PrivatePort == 9092 { - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "kafka", - "scheme": "kafka", - } - return rels - } else if p.PrivatePort == 80 && container.Image == "dunglas/mercure" { - rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "mercure", - "scheme": "http", + } + return rels + } else if p.PrivatePort == 9200 { + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "path": "/", + "rel": "elasticsearch", + "scheme": "http", + } + return rels + } else if p.PrivatePort == 5601 { + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "path": "/", + "rel": "kibana", + "scheme": "http", + } + return rels + } else if p.PrivatePort == 27017 || p.PrivatePort == 27018 || p.PrivatePort == 27019 { + username := "" + password := "" + path := "" + for _, env := range c.Config.Env { + // that's our local convention + if strings.HasPrefix(env, "MONGO_DATABASE") { + path = getEnvValue(env, "MONGO_DATABASE") + } else if strings.HasPrefix(env, "MONGO_INITDB_DATABASE") { + path = getEnvValue(env, "MONGO_INITDB_DATABASE") + } else if strings.HasPrefix(env, "MONGO_INITDB_ROOT_USERNAME") { + username = getEnvValue(env, "MONGO_INITDB_ROOT_USERNAME") + } else if strings.HasPrefix(env, "MONGO_INITDB_ROOT_PASSWORD") { + password = getEnvValue(env, "MONGO_INITDB_ROOT_PASSWORD") } - return rels } - - if l.Debug { - fmt.Fprintln(os.Stderr, " exposing port") + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "username": username, + "password": password, + "path": path, + "port": formatDockerPort(p.PublicPort), + "rel": "mongodb", + "scheme": "mongodb", } - + return rels + } else if p.PrivatePort == 9092 { rels[""] = map[string]interface{}{ - "host": host, - "ip": host, - "port": formatDockerPort(p.PublicPort), - "rel": "simple", + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "kafka", + "scheme": "kafka", } - // Official HTTP(s) ports or well know alternatives - if p.PrivatePort == 80 || p.PrivatePort == 8008 || p.PrivatePort == 8080 || p.PrivatePort == 8081 { - rels[""]["scheme"] = "http" - } else if p.PrivatePort == 443 || p.PrivatePort == 8443 { - rels[""]["scheme"] = "https" + return rels + } else if p.PrivatePort == 80 && strings.Contains(container.Image, "dunglas/mercure") { + // for podman the image name is docker.io/dunglas/mercure:latest + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "mercure", + "scheme": "http", } return rels } - return nil + if l.Debug { + fmt.Fprintln(os.Stderr, " exposing port") + } + + rels[""] = map[string]interface{}{ + "host": host, + "ip": host, + "port": formatDockerPort(p.PublicPort), + "rel": "simple", + } + // Official HTTP(s) ports or well know alternatives + if p.PrivatePort == 80 || p.PrivatePort == 8008 || p.PrivatePort == 8080 || p.PrivatePort == 8081 { + rels[""]["scheme"] = "http" + } else if p.PrivatePort == 443 || p.PrivatePort == 8443 { + rels[""]["scheme"] = "https" + } else { + rels[""]["scheme"] = "tcp" + } + return rels } func formatDockerPort(port uint16) string { return strconv.FormatInt(int64(port), 10) } +func dockerUseDesktopSocketIfAvailable(c *docker.Client) error { + if c.DaemonHost() != docker.DefaultDockerHost { + return nil + } + + homeDir, err := os.UserHomeDir() + if err != nil { + return err + } + + socketPath := filepath.Join(homeDir, ".docker/run/docker.sock") + if _, err := os.Stat(socketPath); err != nil { + return nil + } + + return docker.WithHost(`unix://` + socketPath)(c) +} + func getEnvValue(env string, key string) string { if len(key) == len(env) { return "" @@ -481,7 +511,7 @@ func getEnvValue(env string, key string) string { func (l *Local) getComposeProjectName() string { // https://docs.docker.com/compose/reference/envvars/#compose_project_name - if project := os.Getenv("COMPOSE_PROJECT_NAME"); project != "" { + if project := os.Getenv(composeConsts.ComposeProjectName); project != "" { return project } @@ -497,13 +527,36 @@ func (l *Local) getComposeProjectName() string { if _, err := os.Stat(filepath.Join(composeDir, ".env")); err == nil { if contents, err := os.ReadFile(filepath.Join(composeDir, ".env")); err == nil { for _, line := range bytes.Split(contents, []byte("\n")) { - if bytes.HasPrefix(line, []byte("COMPOSE_PROJECT_NAME=")) { - return string(line[len("COMPOSE_PROJECT_NAME="):]) + if bytes.HasPrefix(line, []byte(composeConsts.ComposeProjectName+"=")) { + return string(line[len(composeConsts.ComposeProjectName)+1:]) } } } } + // Compose project name can be set in every Docker Compose file + for index, filename := range compose.DefaultFileNames { + if _, err := os.Stat(filepath.Join(composeDir, filename)); err != nil { + continue + } + + for _, filename := range []string{compose.DefaultOverrideFileNames[index], filename} { + buf, err := os.ReadFile(filepath.Join(composeDir, filename)) + if err != nil { + continue + } + + config := struct { + ProjectName string `yaml:"name"` + }{} + + // unmarshall the content of the file to get the project name + if err := yaml.Unmarshal(buf, &config); err == nil && config.ProjectName != "" { + return config.ProjectName + } + } + } + return filepath.Base(composeDir) } @@ -516,7 +569,7 @@ func (l *Local) getComposeDir() string { // look for the first dir up with a docker-composer.ya?ml file (in case of a multi-project) dir := l.Dir for { - for _, filename := range []string{"compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"} { + for _, filename := range compose.DefaultFileNames { if _, err := os.Stat(filepath.Join(dir, filename)); err == nil { return dir } diff --git a/envs/docker_version.go b/envs/docker_version.go new file mode 100644 index 00000000..8b319b58 --- /dev/null +++ b/envs/docker_version.go @@ -0,0 +1,25 @@ +// Code generated by envs/generate_docker_version +// DO NOT EDIT + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package envs + +const dockerClientVersion = "v28.0.0" diff --git a/envs/dotenv.go b/envs/dotenv.go index da2d9806..d648cf4c 100644 --- a/envs/dotenv.go +++ b/envs/dotenv.go @@ -50,6 +50,23 @@ func LoadDotEnv(vars map[string]string, scriptDir string) map[string]string { return vars } +// LookupEnv allows one to lookup for a single environment variable in the same +// way os.LookupEnv would. It automatically let the environment variable take +// over if defined. +func LookupEnv(dotEnvDir, key string) (string, bool) { + // first check if the user defined it in its environment + if value, isUserDefined := os.LookupEnv(key); isUserDefined { + return value, isUserDefined + } + + dotEnvEnv := lookupDotEnv(dotEnvDir) + if value, isDefined := dotEnvEnv[key]; isDefined { + return value, isDefined + } + + return "", false +} + // algorithm is here: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/3.3/config/bootstrap.php func lookupDotEnv(dir string) map[string]string { var err error diff --git a/envs/envs.go b/envs/envs.go index b8832353..c36a2d1d 100644 --- a/envs/envs.go +++ b/envs/envs.go @@ -123,8 +123,11 @@ func extractRelationshipsEnvs(env Environment) Envs { } prefix = strings.Replace(prefix, "-", "_", -1) - if scheme == "pgsql" || scheme == "mysql" { - if scheme == "pgsql" { + // HA support via scheme-replica + isPostgreSQL := strings.HasPrefix(scheme.(string), "pgsql") + isMySQL := strings.HasPrefix(scheme.(string), "mysql") + if isPostgreSQL || isMySQL { + if isPostgreSQL { // works for both Doctrine and Go endpoint["scheme"] = "postgres" } @@ -152,7 +155,7 @@ func extractRelationshipsEnvs(env Environment) Envs { charset := "utf8" if envCharset := os.Getenv(fmt.Sprintf("%sCHARSET", prefix)); envCharset != "" { charset = envCharset - } else if scheme == "mysql" { + } else if isMySQL { charset = "utf8mb4" } values[fmt.Sprintf("%sURL", prefix)] = values[fmt.Sprintf("%sURL", prefix)] + "&charset=" + charset @@ -172,7 +175,7 @@ func extractRelationshipsEnvs(env Environment) Envs { version := strings.SplitN(v.(string), ":", 2)[1] // we actually provide mariadb not mysql - if endpoint["scheme"].(string) == "mysql" { + if isMySQL { minor := 0 if version == "10.2" { minor = 7 @@ -205,13 +208,13 @@ func extractRelationshipsEnvs(env Environment) Envs { values[fmt.Sprintf("%sDATABASE", prefix)] = path if env.Local() { - if scheme == "pgsql" { + if isPostgreSQL { values["PGHOST"] = endpoint["host"].(string) values["PGPORT"] = formatInt(endpoint["port"]) values["PGDATABASE"] = path values["PGUSER"] = endpoint["username"].(string) values["PGPASSWORD"] = endpoint["password"].(string) - } else if scheme == "mysql" { + } else if isMySQL { values["MYSQL_HOST"] = endpoint["host"].(string) values["MYSQL_TCP_PORT"] = formatInt(endpoint["port"]) } diff --git a/envs/envs_test.go b/envs/envs_test.go index 09431a1e..d02a62c5 100644 --- a/envs/envs_test.go +++ b/envs/envs_test.go @@ -193,6 +193,99 @@ func (s *ScenvSuite) TestCloudTunnelDatabaseURLs(c *C) { c.Assert(rels["POSTGRESQL_URL"], Equals, "postgres://main:main@127.0.0.1:30000/main?sslmode=disable&charset=utf8&serverVersion=13") } +func (s *ScenvSuite) TestCloudHADatabaseURLs(c *C) { + env := fakeEnv{ + Rels: map[string][]map[string]interface{}{ + "database-replica": { + { + "username": "user", + "scheme": "mysql", + "service": "db", + "fragment": interface{}(nil), + "ip": "169.254.150.110", + "hostname": "e3n2frcxjqipslsc6sq7rfmwzm.db.service.._.platform.sh", + "port": 3306, + "cluster": "gqiujktuqrcxm-main-bvxea6i", + "host": "database-replica.internal", + "rel": "mysql-replica", + "path": "main", + "query": map[string]interface{}{"is_master": false}, + "password": "", + "type": "mysql:10.6", + "public": false, + "host_mapped": false, + }, + }, + "database": { + { + "username": "user", + "scheme": "mysql", + "service": "db", + "fragment": interface{}(nil), + "ip": "169.254.193.18", + "hostname": "jvlu7c7jx3nzt3cowwkcrslhcq.db.service.._.platform.sh", + "port": 3306, + "cluster": "gqiujktuqrcxm-main-bvxea6i", + "host": "database.internal", + "rel": "mysql", + "path": "main", + "query": map[string]interface{}{"is_master": true}, + "password": "", + "type": "mysql:10.6", + "public": false, + "host_mapped": false, + }, + }, + "psql-replica": { + { + "username": "user", + "scheme": "pgsql", + "service": "db", + "fragment": interface{}(nil), + "ip": "169.254.150.110", + "hostname": "e3n2frcxjqipslsc6sq7rfmwzm.db.service.._.platform.sh", + "port": 5432, + "cluster": "gqiujktuqrcxm-main-bvxea6i", + "host": "psql-replica.internal", + "rel": "pgsql-replica", + "path": "main", + "query": map[string]interface{}{"is_master": false}, + "password": "", + "type": "postgresql:15", + "public": false, + "host_mapped": false, + }, + }, + "psql": { + { + "username": "user", + "scheme": "pgsql", + "service": "db", + "fragment": interface{}(nil), + "ip": "169.254.193.18", + "hostname": "jvlu7c7jx3nzt3cowwkcrslhcq.db.service.._.platform.sh", + "port": 5432, + "cluster": "gqiujktuqrcxm-main-bvxea6i", + "host": "psql.internal", + "rel": "pgsql", + "path": "main", + "query": map[string]interface{}{"is_master": true}, + "password": "", + "type": "postgresql:15", + "public": false, + "host_mapped": false, + }, + }, + }, + } + + rels := extractRelationshipsEnvs(env) + c.Assert(rels["DATABASE_URL"], Equals, "mysql://user@database.internal:3306/main?sslmode=disable&charset=utf8mb4&serverVersion=10.6.0-MariaDB") + c.Assert(rels["DATABASE_REPLICA_URL"], Equals, "mysql://user@database-replica.internal:3306/main?sslmode=disable&charset=utf8mb4&serverVersion=10.6.0-MariaDB") + c.Assert(rels["PSQL_URL"], Equals, "postgres://user@psql.internal:5432/main?sslmode=disable&charset=utf8&serverVersion=15") + c.Assert(rels["PSQL_REPLICA_URL"], Equals, "postgres://user@psql-replica.internal:5432/main?sslmode=disable&charset=utf8&serverVersion=15") +} + func (s *ScenvSuite) TestDoctrineConfigTakesPrecedenceDatabaseURLs(c *C) { env := fakeEnv{ Rels: map[string][]map[string]interface{}{ diff --git a/envs/generate_docker_version b/envs/generate_docker_version new file mode 100644 index 00000000..b5b42fb7 --- /dev/null +++ b/envs/generate_docker_version @@ -0,0 +1,29 @@ +#!/usr/bin/env sh + +cat < docker_version.go +// Code generated by envs/generate_docker_version +// DO NOT EDIT + +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package envs + +const dockerClientVersion = "$(go list -m all | grep github.com/docker/docker | awk -F '[ +]' '{print $2}')" +EOF diff --git a/envs/local.go b/envs/local.go index 2eee8089..46f5a3bc 100644 --- a/envs/local.go +++ b/envs/local.go @@ -259,15 +259,15 @@ func (l *Local) webServer() Envs { host := fmt.Sprintf("127.0.0.1:%s", port) if proxyConf, err := proxy.Load(util.GetHomeDir()); err == nil { - for _, domain := range proxyConf.GetDomains(l.Dir) { + domains := proxyConf.GetDomains(l.Dir) + if len(domains) > 0 { // we get the first one only - host = domain + host = domains[0] if pidFile.Scheme == "http" { port = "80" } else { port = "443" } - break } } diff --git a/go.mod b/go.mod index f5ad9910..ad27bb1e 100644 --- a/go.mod +++ b/go.mod @@ -1,35 +1,36 @@ module github.com/symfony-cli/symfony-cli -go 1.22.2 +go 1.24.0 require ( github.com/NYTimes/gziphandler v1.1.1 github.com/blackfireio/osinfo v1.0.5 github.com/compose-spec/compose-go v1.20.2 - github.com/docker/docker v26.1.0+incompatible - github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 - github.com/fabpot/local-php-security-checker/v2 v2.0.6 + github.com/docker/docker v28.0.0+incompatible + github.com/elazarl/goproxy v1.7.0 + github.com/fabpot/local-php-security-checker/v2 v2.1.3 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 - github.com/hashicorp/go-version v1.6.0 + github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/arc/v2 v2.0.7 github.com/joho/godotenv v1.5.1 github.com/mitchellh/go-homedir v1.1.0 github.com/nxadm/tail v1.4.11 github.com/olekukonko/tablewriter v0.0.5 github.com/pkg/errors v0.9.1 + github.com/posener/complete v1.2.3 github.com/rjeczalik/notify v0.9.3 - github.com/rs/xid v1.5.0 - github.com/rs/zerolog v1.32.0 - github.com/schollz/progressbar/v3 v3.14.2 + github.com/rs/xid v1.6.0 + github.com/rs/zerolog v1.33.0 + github.com/schollz/progressbar/v3 v3.18.0 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/soheilhy/cmux v0.1.5 github.com/stoicperlman/fls v0.0.0-20171222144224-f073b7a01081 - github.com/symfony-cli/cert v1.0.5 - github.com/symfony-cli/console v1.0.4 - github.com/symfony-cli/phpstore v1.0.11 - github.com/symfony-cli/terminal v1.0.6 - golang.org/x/sync v0.7.0 - golang.org/x/text v0.14.0 + github.com/symfony-cli/cert v1.0.6 + github.com/symfony-cli/console v1.2.1 + github.com/symfony-cli/phpstore v1.0.12 + github.com/symfony-cli/terminal v1.0.7 + golang.org/x/sync v0.11.0 + golang.org/x/text v0.22.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 ) @@ -42,47 +43,50 @@ require ( github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/term v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect - go.opentelemetry.io/otel v1.25.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 // indirect - go.opentelemetry.io/otel/metric v1.25.0 // indirect - go.opentelemetry.io/otel/sdk v1.25.0 // indirect - go.opentelemetry.io/otel/trace v1.25.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/time v0.5.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/term v0.29.0 // indirect + golang.org/x/time v0.10.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.1 // indirect - software.sslmate.com/src/go-pkcs12 v0.4.0 // indirect + software.sslmate.com/src/go-pkcs12 v0.5.0 // indirect ) diff --git a/go.sum b/go.sum index 280e6e5b..a4697627 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -10,6 +10,8 @@ github.com/blackfireio/osinfo v1.0.5 h1:6hlaWzfcpb87gRmznVf7wSdhysGqLRz9V/xuSdCE github.com/blackfireio/osinfo v1.0.5/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= +github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= github.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ= github.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -21,41 +23,47 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.1.0+incompatible h1:W1G9MPNbskA6VZWL7b3ZljTh0pXI68FpINx0GKaOdaM= -github.com/docker/docker v26.1.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.0.0+incompatible h1:Olh0KS820sJ7nPsBKChVhk5pzqcwDR15fumfAd/p9hM= +github.com/docker/docker v28.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 h1:m62nsMU279qRD9PQSWD1l66kmkXzuYcnVJqL4XLeV2M= -github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= -github.com/fabpot/local-php-security-checker/v2 v2.0.6 h1:m1znXkwzIPFkJWOnH8Fgt1mHY9hq8u+GY4AC6CPnDME= -github.com/fabpot/local-php-security-checker/v2 v2.0.6/go.mod h1:bDff0jDpxt1pHsDtQ3v++cc/QuCM9K7Nq0dv65P1Ai8= +github.com/elazarl/goproxy v1.7.0 h1:EXv2nV4EjM60ZtsEVLYJG4oBXhDGutMKperpHsZ/v+0= +github.com/elazarl/goproxy v1.7.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= +github.com/fabpot/local-php-security-checker/v2 v2.1.3 h1:sL69IHlEvlmaOnyzfOhIAbrG1Ugp2IibM3f6JVxV+yk= +github.com/fabpot/local-php-security-checker/v2 v2.1.3/go.mod h1:t4Qk2u9Mj4ZM05X4cnwuwqrHGDKohweR8ox5rFBPBls= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru/arc/v2 v2.0.7 h1:QxkVTxwColcduO+LP7eJO56r2hFiG8zEbfAAzRv52KQ= github.com/hashicorp/golang-lru/arc/v2 v2.0.7/go.mod h1:Pe7gBlGdc8clY5LJ0LpJXMt5AmgmWNH1g+oFFVUHOEc= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -65,7 +73,6 @@ github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+h github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -75,15 +82,16 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= @@ -94,8 +102,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= @@ -113,21 +121,23 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= -github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/schollz/progressbar/v3 v3.14.2 h1:EducH6uNLIWsr560zSV1KrTeUb/wZGAHqyMFIEa99ks= -github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA= +github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= @@ -138,17 +148,18 @@ github.com/stoicperlman/fls v0.0.0-20171222144224-f073b7a01081 h1:vEf6LukDDCcMnR github.com/stoicperlman/fls v0.0.0-20171222144224-f073b7a01081/go.mod h1:mXF6uSYLo1a2BZPcVHpP8RstMYoQnCaFF+dmIY726NY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/symfony-cli/cert v1.0.5 h1:U0H97eRf4bMhlD2WWB42fuapQ/wImqZVHP+PW2z5T1c= -github.com/symfony-cli/cert v1.0.5/go.mod h1:9axy74P/rAP0Jia6JFfqst26tn2h2U0JCJj288t8iuc= -github.com/symfony-cli/console v1.0.4 h1:IPgT2R2jn8WrInJ3qJ4LOSoz8Awxz8AFnlBeWWegCcw= -github.com/symfony-cli/console v1.0.4/go.mod h1:Jz4c7ozPC0vjzuP2KVt5W07137r0UU5U8bMwQxljEd0= -github.com/symfony-cli/phpstore v1.0.11 h1:33aTDnFeNtA/xAaGpcvejeYC8AwPSy/6r06GAcU989M= -github.com/symfony-cli/phpstore v1.0.11/go.mod h1:Pug4pGst4b5DcGUwYz2DB1LjltohPgvE4OusDe1z2Xg= -github.com/symfony-cli/terminal v1.0.6 h1:DFjJULx0QZ8ojOahf/NnLkRtt0EaIkdVWRMHstFWtpE= -github.com/symfony-cli/terminal v1.0.6/go.mod h1:ehBd2bz31MHHQgy4qPb9vAGFtnxOazUhAO77GEd1vAM= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/symfony-cli/cert v1.0.6 h1:FKdNRhKSxc+IcOkSRYvcOjr4jyZxGHiNS0xCN0uXZQI= +github.com/symfony-cli/cert v1.0.6/go.mod h1:7Lt0uwi9z6DYTwLQeKsdPrsTqvTZRTqdlVSDJJqKUVo= +github.com/symfony-cli/console v1.2.1 h1:j3ft4sWNXmFmmHACsXUZrAvZE52rIopg/FpZMkknZz4= +github.com/symfony-cli/console v1.2.1/go.mod h1:AB4ZxA593cyS/1NhwnDEUChIPaGuddFqooipam1vyS8= +github.com/symfony-cli/phpstore v1.0.12 h1:2mKJrDielSCW+7B+63w6HebmSBcB4qV7uuvNrIjLkoA= +github.com/symfony-cli/phpstore v1.0.12/go.mod h1:U29bdJBPs9p28PzLIRKfKfKkaiH0kacdyufl3eSB1d4= +github.com/symfony-cli/terminal v1.0.7 h1:57L9PUTE2cHfQtP8Ti8dyiiPEYlQ1NBIDpMJ3RPEGPc= +github.com/symfony-cli/terminal v1.0.7/go.mod h1:Etv22IyeGiMoIQPPj51hX31j7xuYl1njyuAFkrvybqU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -158,29 +169,31 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= -go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= -go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -188,13 +201,13 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -204,18 +217,16 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -224,20 +235,21 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= -google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -247,5 +259,5 @@ gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= -software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= +software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M= +software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/installer/bash-installer b/installer/bash-installer index fa69881e..18940615 100755 --- a/installer/bash-installer +++ b/installer/bash-installer @@ -22,7 +22,10 @@ CLI_CONFIG_DIR=".symfony5" CLI_EXECUTABLE="symfony" CLI_TMP_NAME="$CLI_EXECUTABLE-"$(date +"%s") CLI_NAME="Symfony CLI" -CLI_DOWNLOAD_URL_PATTERN="https://github.com/symfony-cli/symfony-cli/releases/latest/download/symfony-cli_~platform~.tar.gz" +CLI_VERSION="${CLI_VERSION:-latest}" +CLI_DOWNLOAD_URL_LATEST_PATTERN="https://github.com/symfony-cli/symfony-cli/releases/latest/download/symfony-cli_~platform~.tar.gz" +CLI_DOWNLOAD_URL_VERSION_PATTERN="https://github.com/symfony-cli/symfony-cli/releases/download/v~version~/symfony-cli_~platform~.tar.gz" + CLI_TMPDIR="${TMPDIR:-/tmp}" function output { @@ -53,7 +56,6 @@ function output { } output "${CLI_NAME} installer" "heading" - binary_dest="${HOME}/${CLI_CONFIG_DIR}/bin" custom_dir="false" @@ -79,6 +81,16 @@ case $1 in esac done +output "\nSanity check" "heading" + +# Check that the version is valid +if [[ "$CLI_VERSION" =~ ^[0-9]+(\.[0-9]+)*$ || "$CLI_VERSION" == 'latest' ]]; then + output " [*] Version has valid format" "success" +else + output " [ ] ERROR: Version has invalid format." "error" + exit 1 +fi + # Run environment checks. output "\nEnvironment check" "heading" @@ -163,14 +175,19 @@ platform="${kernel}_${machine}" # The necessary checks have passed. Start downloading the right version. output "\nDownload" "heading" -latest_url=${CLI_DOWNLOAD_URL_PATTERN/~platform~/${platform}} -output " Downloading ${latest_url}..."; +download_url="${CLI_DOWNLOAD_URL_LATEST_PATTERN}" +if [[ "$CLI_VERSION" != 'latest' ]]; then + download_url=${CLI_DOWNLOAD_URL_VERSION_PATTERN/~version~/${CLI_VERSION}} +fi + +download_url=${download_url/~platform~/${platform}} +output " Downloading ${download_url}..."; case $downloader in "curl") - curl --fail --location "${latest_url}" > "${CLI_TMPDIR}/${CLI_TMP_NAME}.tar.gz" + curl --fail --location "${download_url}" > "${CLI_TMPDIR}/${CLI_TMP_NAME}.tar.gz" ;; "wget") - wget -q --show-progress "${latest_url}" -O "${CLI_TMPDIR}/${CLI_TMP_NAME}.tar.gz" + wget -q --show-progress "${download_url}" -O "${CLI_TMPDIR}/${CLI_TMP_NAME}.tar.gz" ;; esac diff --git a/local/http/cors.go b/local/http/cors.go new file mode 100644 index 00000000..56abf2bd --- /dev/null +++ b/local/http/cors.go @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package http + +import ( + "net/http" + + "github.com/rs/zerolog" +) + +func corsWrapper(h http.Handler, logger zerolog.Logger) http.Handler { + var corsHeaders = []string{"Access-Control-Allow-Origin", "Access-Control-Allow-Methods", "Access-Control-Allow-Headers"} + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for _, corsHeader := range corsHeaders { + w.Header().Set(corsHeader, "*") + } + + h.ServeHTTP(w, r) + + for _, corsHeader := range corsHeaders { + if headers, exists := w.Header()[corsHeader]; !exists || len(headers) < 2 { + continue + } + + logger.Warn().Msgf(`Multiple entries detected for header "%s". Only one should be set: you should enable CORS handling in the CLI only if the application does not handle them.`, corsHeader) + } + }) +} diff --git a/local/http/http.go b/local/http/http.go index ddac3163..650ed678 100644 --- a/local/http/http.go +++ b/local/http/http.go @@ -49,12 +49,14 @@ type Server struct { Callback ServerCallback Port int PreferredPort int + ListenIp string PKCS12 string AllowHTTP bool Logger zerolog.Logger Appversion string UseGzip bool TlsKeyLogFile string + AllowCORS bool httpserver *http.Server httpsserver *http.Server @@ -79,7 +81,7 @@ var gzipContentTypes = []string{ // Start starts the server func (s *Server) Start(errChan chan error) (int, error) { - ln, port, err := process.CreateListener(s.Port, s.PreferredPort) + ln, port, err := process.CreateListener(s.ListenIp, s.Port, s.PreferredPort) if err != nil { return port, errors.WithStack(err) } @@ -97,6 +99,10 @@ func (s *Server) Start(errChan chan error) (int, error) { proxyHandler = gzipWrapper(proxyHandler) } + if s.AllowCORS { + proxyHandler = corsWrapper(proxyHandler, s.Logger) + } + s.httpserver = &http.Server{ Handler: proxyHandler, } diff --git a/local/logs/tailer.go b/local/logs/tailer.go index 56f226d6..628697b4 100644 --- a/local/logs/tailer.go +++ b/local/logs/tailer.go @@ -253,7 +253,7 @@ func tailFile(filename string, follow bool, nblines int64) (*tail.Tail, error) { return tail.TailFile(filename, tail.Config{ Location: &tail.SeekInfo{ Offset: pos, - Whence: os.SEEK_SET, + Whence: io.SeekStart, }, ReOpen: follow, Follow: follow, diff --git a/local/php/cgi.go b/local/php/cgi.go index f1b1ff67..e1eb3217 100644 --- a/local/php/cgi.go +++ b/local/php/cgi.go @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package php import ( diff --git a/local/php/composer.go b/local/php/composer.go index 04d20983..a3b5de6e 100644 --- a/local/php/composer.go +++ b/local/php/composer.go @@ -20,7 +20,6 @@ package php import ( - "bufio" "bytes" "crypto/sha512" "encoding/hex" @@ -73,47 +72,41 @@ func Composer(dir string, args, env []string, stdout, stderr, logger io.Writer, if composerVersion() == 2 { composerBin = "composer2" } - path, err := e.findComposer(composerBin) - if err != nil || !isPHPScript(path) { - fmt.Fprintln(logger, " WARNING: Unable to find Composer, downloading one. It is recommended to install Composer yourself at https://getcomposer.org/download/") + + if composerPath := os.Getenv("SYMFONY_COMPOSER_PATH"); composerPath != "" { + debugLogger.Debug().Str("SYMFONY_COMPOSER_PATH", composerPath).Msg("SYMFONY_COMPOSER_PATH has been defined. User is taking control over Composer detection and execution.") + e.Args = append([]string{composerPath}, args...) + } else if path, err := e.findComposer(composerBin); err == nil && isPHPScript(path) { + e.Args = append([]string{"php", path}, args...) + } else { + reason := "No Composer installation found." + if path != "" { + reason = fmt.Sprintf("Detected Composer file (%s) is not a valid PHAR or PHP script.", path) + } + fmt.Fprintln(logger, " WARNING:", reason) + fmt.Fprintln(logger, " Downloading Composer for you, but it is recommended to install Composer yourself, instructions available at https://getcomposer.org/download/") // we don't store it under bin/ to avoid it being found by findComposer as we want to only use it as a fallback binDir := filepath.Join(util.GetHomeDir(), "composer") - if path, err = downloadComposer(binDir); err != nil { + if path, err = downloadComposer(binDir, debugLogger); err != nil { return ComposerResult{ code: 1, error: errors.Wrap(err, "unable to find composer, get it at https://getcomposer.org/download/"), } } + e.Args = append([]string{"php", path}, args...) + fmt.Fprintf(logger, " (running %s)\n\n", e.CommandLine()) } - e.Args = append([]string{"php", path}, args...) - fmt.Fprintf(logger, " (running %s %s)\n\n", path, strings.TrimSpace(strings.Join(args, " "))) ret := e.Execute(false) if ret != 0 { return ComposerResult{ code: ret, - error: errors.Errorf("unable to run %s %s", path, strings.Join(args, " ")), + error: errors.Errorf("unable to run %s", e.CommandLine()), } } return ComposerResult{} } -// isPHPScript checks that the composer file is indeed a phar/PHP script (not a .bat file) -func isPHPScript(path string) bool { - file, err := os.Open(path) - if err != nil { - return false - } - defer file.Close() - reader := bufio.NewReader(file) - byteSlice, _, err := reader.ReadLine() - if err != nil { - return false - } - - return bytes.HasPrefix(byteSlice, []byte("#!/")) && bytes.HasSuffix(byteSlice, []byte("php")) -} - func composerVersion() int { var lock struct { Version string `json:"plugin-api-version"` @@ -135,19 +128,21 @@ func composerVersion() int { return DefaultComposerVersion } -func findComposer(extraBin string) (string, error) { +func findComposer(extraBin string, logger zerolog.Logger) (string, error) { // Special support for OS specific things. They need to run before the // PATH detection because most of them adds shell wrappers that we // can't run via PHP. - if pharPath := findComposerSystemSpecific(extraBin); pharPath != "" { + if pharPath := findComposerSystemSpecific(); pharPath != "" { return pharPath, nil } for _, file := range []string{extraBin, "composer", "composer.phar"} { + logger.Debug().Str("source", "Composer").Msgf(`Looking for Composer in the PATH as "%s"`, file) if pharPath, _ := LookPath(file); pharPath != "" { // On Windows, we don't want the .bat, but the real composer phar/PHP file if strings.HasSuffix(pharPath, ".bat") { pharPath = pharPath[:len(pharPath)-4] + ".phar" } + logger.Debug().Str("source", "Composer").Msgf(`Found potential Composer as "%s"`, pharPath) return pharPath, nil } } @@ -155,7 +150,7 @@ func findComposer(extraBin string) (string, error) { return "", os.ErrNotExist } -func downloadComposer(dir string) (string, error) { +func downloadComposer(dir string, debugLogger zerolog.Logger) (string, error) { if err := os.MkdirAll(dir, 0755); err != nil { return "", err } @@ -191,6 +186,7 @@ func downloadComposer(dir string) (string, error) { SkipNbArgs: 1, Stdout: &stdout, Stderr: &stdout, + Logger: debugLogger, } ret := e.Execute(false) if ret == 1 { diff --git a/local/php/composer_test.go b/local/php/composer_test.go deleted file mode 100644 index ad01c475..00000000 --- a/local/php/composer_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package php - -import ( - "path/filepath" - - . "gopkg.in/check.v1" -) - -type ComposerSuite struct{} - -var _ = Suite(&ComposerSuite{}) - -func (s *ComposerSuite) TestIsComposerPHPScript(c *C) { - dir, err := filepath.Abs("testdata/php_scripts") - c.Assert(err, IsNil) - - c.Assert(isPHPScript(filepath.Join(dir, "unknown")), Equals, false) - c.Assert(isPHPScript(filepath.Join(dir, "invalid")), Equals, false) - - for _, validScripts := range []string{ - "usual-one", - "debian-style", - "custom-one", - } { - c.Assert(isPHPScript(filepath.Join(dir, validScripts)), Equals, true) - } -} diff --git a/local/php/composer_unix.go b/local/php/composer_unix.go index ab14f6d5..54d0fc1a 100644 --- a/local/php/composer_unix.go +++ b/local/php/composer_unix.go @@ -28,7 +28,7 @@ import ( "strings" ) -func findComposerSystemSpecific(extraBin string) string { +func findComposerSystemSpecific() string { // Special Support for NixOS for _, path := range strings.Split(os.Getenv("buildInputs"), " ") { nixPharPath := filepath.Join(path, "libexec/composer/composer.phar") diff --git a/local/php/composer_windows.go b/local/php/composer_windows.go index 56e6a67c..2b496d87 100644 --- a/local/php/composer_windows.go +++ b/local/php/composer_windows.go @@ -20,13 +20,14 @@ package php import ( - "github.com/mitchellh/go-homedir" "os" "os/exec" "path/filepath" + + "github.com/mitchellh/go-homedir" ) -func findComposerSystemSpecific(extraBin string) string { +func findComposerSystemSpecific() string { // Special Support for Scoop scoopPaths := []string{} diff --git a/local/php/context.go b/local/php/context.go index 8a51b9a4..b48fd1a5 100644 --- a/local/php/context.go +++ b/local/php/context.go @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package php type phpServerContextKey string diff --git a/local/php/executor.go b/local/php/executor.go index 28fc58f6..740f8476 100644 --- a/local/php/executor.go +++ b/local/php/executor.go @@ -29,6 +29,7 @@ import ( "runtime" "strings" "syscall" + "time" "github.com/pkg/errors" "github.com/rs/xid" @@ -73,6 +74,10 @@ func GetBinaryNames() []string { return []string{"php", "pecl", "pear", "php-fpm", "php-cgi", "php-config", "phpdbg", "phpize"} } +func (e Executor) CommandLine() string { + return strings.TrimSpace(strings.Join(e.Args, " ")) +} + func (e *Executor) lookupPHP(cliDir string, forceReload bool) (*phpstore.Version, string, bool, error) { phpStore := phpstore.New(cliDir, forceReload, nil) v, source, warning, err := phpStore.BestVersionForDir(e.scriptDir) @@ -163,7 +168,11 @@ func (e *Executor) DetectScriptDir() (string, error) { return e.scriptDir, nil } -// Config determines the right version of PHP depending on the configuration (+ its configuration) +// Config determines the right version of PHP depending on the configuration +// (+ its configuration). It also creates some symlinks to ease the integration +// with underlying tools that could try to run PHP. This is the responsibility +// of the caller to clean those temporary files. One can call +// CleanupTemporaryDirectories to do so. func (e *Executor) Config(loadDotEnv bool) error { // reset environment e.environ = make([]string, 0) @@ -220,8 +229,10 @@ func (e *Executor) Config(loadDotEnv bool) error { // prepending the PHP directory in the PATH does not work well if the PHP binary is not named "php" (like php7.3 for instance) // in that case, we create a temp directory with a symlink // we also link php-config for pecl to pick up the right one (it is always looks for something called php-config) - phpDir := filepath.Join(cliDir, "tmp", xid.New().String(), "bin") - e.tempDir = phpDir + if e.tempDir == "" { + e.tempDir = filepath.Join(cliDir, "tmp", xid.New().String()) + } + phpDir := filepath.Join(e.tempDir, "bin") if err := os.MkdirAll(phpDir, 0755); err != nil { return err } @@ -277,31 +288,153 @@ func (e *Executor) Config(loadDotEnv bool) error { } } - // args[0] MUST be the same as path - // but as we change the path, we should update args[0] accordingly - e.Args[0] = path + if IsBinaryName(e.Args[0]) { + // args[0] MUST be the same as path + // but as we change the path, we should update args[0] accordingly + e.Args[0] = path + } return err } +func (e *Executor) CleanupTemporaryDirectories() { + backgroundCleanup := make(chan bool, 1) + go cleanupStaleTemporaryDirectories(e.Logger, backgroundCleanup) + + if e.iniDir != "" { + os.RemoveAll(e.iniDir) + } + if e.tempDir != "" { + os.RemoveAll(e.tempDir) + } + + // give some room to the background clean up job to do its work + select { + case <-backgroundCleanup: + case <-time.After(100 * time.Millisecond): + e.Logger.Debug().Msg("Allocated time for temporary directories to be cleaned up is over, it will resume later on") + } +} + +// The Symfony CLI used to leak temporary directories until v5.10.8. The bug is +// fixed but because directories names are random they are not going to be +// reused and thus are not going to be cleaned up. And because they might be +// in-use by running servers we can't simply delete the parent directory. This +// is why we make our best to find the oldest directories and remove then, +// cleaning the directory little by little. +func cleanupStaleTemporaryDirectories(mainLogger zerolog.Logger, doneCh chan<- bool) { + defer func() { + doneCh <- true + }() + parentDirectory := filepath.Join(util.GetHomeDir(), "tmp") + mainLogger = mainLogger.With().Str("dir", parentDirectory).Logger() + + if len(parentDirectory) < 6 { + mainLogger.Warn().Msg("temporary dir path looks too short") + return + } + + mainLogger.Debug().Msg("Starting temporary directory cleanup...") + dir, err := os.Open(parentDirectory) + if err != nil { + mainLogger.Warn().Err(err).Msg("Failed to open temporary directory") + return + } + defer dir.Close() + + // the duration after which we consider temporary directories as + // stale and can be removed + cutoff := time.Now().Add(-7 * 24 * time.Hour) + + for { + // we might have a lof of entries so we need to work in batches + entries, err := dir.Readdirnames(30) + if err == io.EOF { + mainLogger.Debug().Msg("Cleaning is done...") + return + } + if err != nil { + mainLogger.Warn().Err(err).Msg("Failed to read entries") + return + } + + for _, entry := range entries { + logger := mainLogger.With().Str("entry", entry).Logger() + + // we generate temporary directory names with + // `xid.New().String()` which is always 20 char long + if len(entry) != 20 { + logger.Debug().Msg("found an entry that is not from us") + continue + } else if _, err := xid.FromString(entry); err != nil { + logger.Debug().Err(err).Msg("found an entry that is not from us") + continue + } + + entryPath := filepath.Join(parentDirectory, entry) + file, err := os.Open(entryPath) + if err != nil { + logger.Warn().Err(err).Msg("failed to read entry") + continue + } else if fi, err := file.Stat(); err != nil { + logger.Warn().Err(err).Msg("failed to read entry") + continue + } else if !fi.IsDir() { + logger.Warn().Err(err).Msg("entry is not a directory") + continue + } else if fi.ModTime().After(cutoff) { + logger.Debug().Any("cutoff", cutoff).Msg("entry is more recent than cutoff, keeping it for now") + continue + } + + logger.Debug().Str("entry", entry).Msg("entry matches the criterias, removing it") + if err := os.RemoveAll(entryPath); err != nil { + logger.Warn().Err(err).Msg("failed to remove entry") + } + } + } +} + // Find composer depending on the configuration func (e *Executor) findComposer(extraBin string) (string, error) { if scriptDir, err := e.DetectScriptDir(); err == nil { for _, file := range []string{extraBin, "composer.phar", "composer"} { path := filepath.Join(scriptDir, file) + e.Logger.Debug().Str("source", "Composer").Msgf(`Looking for Composer under "%s"`, path) d, err := os.Stat(path) if err != nil { continue } if m := d.Mode(); !m.IsDir() { // Yep! + e.Logger.Debug().Str("source", "Composer").Msgf(`Found potential Composer as "%s"`, path) return path, nil } } } // fallback to default composer detection - return findComposer(extraBin) + return findComposer(extraBin, e.Logger) +} + +// findPie locates the PIE binary depending on the configuration +func (e *Executor) findPie() (string, error) { + if scriptDir, err := e.DetectScriptDir(); err == nil { + for _, file := range []string{"pie.phar", "pie"} { + path := filepath.Join(scriptDir, file) + e.Logger.Debug().Str("source", "PIE").Msgf(`Looking for PIE under "%s"`, path) + d, err := os.Stat(path) + if err != nil { + continue + } + if m := d.Mode(); !m.IsDir() { + e.Logger.Debug().Str("source", "PIE").Msgf(`Found potential PIE as "%s"`, path) + return path, nil + } + } + } + + return findPie(e.Logger) } // Execute executes the right version of PHP depending on the configuration @@ -310,14 +443,7 @@ func (e *Executor) Execute(loadDotEnv bool) int { fmt.Fprintln(os.Stderr, err) return 1 } - defer func() { - if e.iniDir != "" { - os.RemoveAll(e.iniDir) - } - if e.tempDir != "" { - os.RemoveAll(e.tempDir) - } - }() + defer e.CleanupTemporaryDirectories() cmd := execCommand(e.Args[0], e.Args[1:]...) environ := append(os.Environ(), e.environ...) gpathname := "PATH" @@ -357,7 +483,7 @@ func (e *Executor) Execute(loadDotEnv bool) int { close(waitCh) }() - sigChan := make(chan os.Signal) + sigChan := make(chan os.Signal, 1) signal.Notify(sigChan) defer signal.Stop(sigChan) diff --git a/local/php/executor_test.go b/local/php/executor_test.go index 9123960d..2608820c 100644 --- a/local/php/executor_test.go +++ b/local/php/executor_test.go @@ -99,11 +99,12 @@ func TestHelperProcess(t *testing.T) { for _, v := range os.Environ() { fmt.Println(v) } + os.Exit(0) case "exit-code": code, _ := strconv.Atoi(os.Args[4]) os.Exit(code) } - os.Exit(0) + os.Exit(1) } func (s *ExecutorSuite) TestNotEnoughArgs(c *C) { @@ -112,6 +113,14 @@ func (s *ExecutorSuite) TestNotEnoughArgs(c *C) { c.Assert((&Executor{BinName: "php"}).Execute(true), Equals, 1) } +func (s *ExecutorSuite) TestCommandLineFormatting(c *C) { + c.Assert((&Executor{}).CommandLine(), Equals, "") + + c.Assert((&Executor{Args: []string{"php"}}).CommandLine(), Equals, "php") + + c.Assert((&Executor{Args: []string{"php", "-dmemory_limit=-1", "/path/to/composer.phar"}}).CommandLine(), Equals, "php -dmemory_limit=-1 /path/to/composer.phar") +} + func (s *ExecutorSuite) TestForwardExitCode(c *C) { defer restoreExecCommand() fakeExecCommand("exit-code", "5") @@ -131,6 +140,63 @@ func (s *ExecutorSuite) TestForwardExitCode(c *C) { c.Assert((&Executor{BinName: "php", Args: []string{"php"}}).Execute(true), Equals, 5) } +func (s *ExecutorSuite) TestExecutorRunsPHP(c *C) { + defer restoreExecCommand() + execCommand = func(name string, arg ...string) *exec.Cmd { + c.Assert(name, Equals, "../bin/php") + + cmd := exec.Command(os.Args[0], "-test.run=TestHelperProcess", "--", "exit-code", "0") + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + // Set the working directory right now so that it can be changed by + // calling test case + cmd.Dir, _ = os.Getwd() + return cmd + } + + home, err := filepath.Abs("testdata/executor") + c.Assert(err, IsNil) + + homedir.Reset() + os.Setenv("HOME", home) + defer homedir.Reset() + + oldwd, _ := os.Getwd() + defer os.Chdir(oldwd) + os.Chdir(filepath.Join(home, "project")) + defer cleanupExecutorTempFiles() + + c.Assert((&Executor{BinName: "php", Args: []string{"php"}}).Execute(true), Equals, 0) + +} + +func (s *ExecutorSuite) TestBinaryOtherThanPhp(c *C) { + defer restoreExecCommand() + execCommand = func(name string, arg ...string) *exec.Cmd { + c.Assert(name, Equals, "not-php") + + cmd := exec.Command(os.Args[0], "-test.run=TestHelperProcess", "--", "exit-code", "0") + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + // Set the working directory right now so that it can be changed by + // calling test case + cmd.Dir, _ = os.Getwd() + return cmd + } + + home, err := filepath.Abs("testdata/executor") + c.Assert(err, IsNil) + + homedir.Reset() + os.Setenv("HOME", home) + defer homedir.Reset() + + oldwd, _ := os.Getwd() + defer os.Chdir(oldwd) + os.Chdir(filepath.Join(home, "project")) + defer cleanupExecutorTempFiles() + + c.Assert((&Executor{BinName: "php", Args: []string{"not-php"}}).Execute(true), Equals, 0) +} + func (s *ExecutorSuite) TestEnvInjection(c *C) { defer restoreExecCommand() fakeExecCommand("dump-env") diff --git a/local/php/fpm.go b/local/php/fpm.go index 364c8c63..e783dcb3 100644 --- a/local/php/fpm.go +++ b/local/php/fpm.go @@ -92,7 +92,7 @@ daemonize = no listen = %s listen.allowed_clients = 127.0.0.1 pm = dynamic -pm.max_children = 5 +pm.max_children = 30 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 @@ -114,9 +114,5 @@ env['LC_ALL'] = C } func (p *Server) fpmConfigFile() string { - path := filepath.Join(p.homeDir, fmt.Sprintf("php/%s/fpm-%s.ini", name(p.projectDir), p.Version.Version)) - if _, err := os.Stat(filepath.Dir(path)); os.IsNotExist(err) { - _ = os.MkdirAll(filepath.Dir(path), 0755) - } - return path + return filepath.Join(p.tempDir, fmt.Sprintf("fpm-%s.ini", p.Version.Version)) } diff --git a/local/php/php_builtin_server.go b/local/php/php_builtin_server.go index 88638d75..3a394e55 100644 --- a/local/php/php_builtin_server.go +++ b/local/php/php_builtin_server.go @@ -21,7 +21,6 @@ package php import ( "fmt" - "os" "path/filepath" ) @@ -61,9 +60,5 @@ require $script; `) func (p *Server) phpRouterFile() string { - path := filepath.Join(p.homeDir, fmt.Sprintf("php/%s-router.php", name(p.projectDir))) - if _, err := os.Stat(filepath.Dir(path)); os.IsNotExist(err) { - _ = os.MkdirAll(filepath.Dir(path), 0755) - } - return path + return filepath.Join(p.tempDir, fmt.Sprintf("%s-router.php", p.Version.Version)) } diff --git a/local/php/php_server.go b/local/php/php_server.go index 44c8a001..56adacd0 100644 --- a/local/php/php_server.go +++ b/local/php/php_server.go @@ -21,9 +21,7 @@ package php import ( "context" - "crypto/sha1" "fmt" - "io" "net" "net/http" "net/http/httputil" @@ -48,8 +46,9 @@ import ( type Server struct { Version *phpstore.Version logger zerolog.Logger + StoppedChan chan bool appVersion string - homeDir string + tempDir string projectDir string documentRoot string passthru string @@ -75,16 +74,22 @@ func NewServer(homeDir, projectDir, documentRoot, passthru, appVersion string, l Version: version, logger: logger.With().Str("source", "PHP").Str("php", version.Version).Str("path", version.ServerPath()).Logger(), appVersion: appVersion, - homeDir: homeDir, projectDir: projectDir, documentRoot: documentRoot, passthru: passthru, + StoppedChan: make(chan bool, 1), }, nil } // Start starts a PHP server func (p *Server) Start(ctx context.Context, pidFile *pid.PidFile) (*pid.PidFile, func() error, error) { - var pathsToRemove []string + p.tempDir = pidFile.TempDirectory() + if _, err := os.Stat(p.tempDir); os.IsNotExist(err) { + if err = os.MkdirAll(p.tempDir, 0755); err != nil { + return nil, nil, err + } + } + port, err := process.FindAvailablePort() if err != nil { p.logger.Debug().Err(err).Msg("unable to find an available port") @@ -123,7 +128,6 @@ func (p *Server) Start(ctx context.Context, pidFile *pid.PidFile) (*pid.PidFile, return nil, nil, errors.WithStack(err) } p.proxy.Transport = &cgiTransport{} - pathsToRemove = append(pathsToRemove, fpmConfigFile) binName = "php-fpm" workerName = "PHP-FPM" args = []string{p.Version.ServerPath(), "--nodaemonize", "--fpm-config", fpmConfigFile} @@ -149,7 +153,6 @@ func (p *Server) Start(ctx context.Context, pidFile *pid.PidFile) (*pid.PidFile, if err := os.WriteFile(routerPath, phprouter, 0644); err != nil { return nil, nil, errors.WithStack(err) } - pathsToRemove = append(pathsToRemove, routerPath) binName = "php" workerName = "PHP" args = []string{p.Version.ServerPath(), "-S", "127.0.0.1:" + strconv.Itoa(port), "-d", "variables_order=EGPCS", routerPath} @@ -161,6 +164,7 @@ func (p *Server) Start(ctx context.Context, pidFile *pid.PidFile) (*pid.PidFile, BinName: binName, Args: args, scriptDir: p.projectDir, + Logger: p.logger, } p.logger.Info().Int("port", port).Msg("listening") @@ -192,9 +196,8 @@ func (p *Server) Start(ctx context.Context, pidFile *pid.PidFile) (*pid.PidFile, return phpPidFile, func() error { defer func() { - for _, path := range pathsToRemove { - os.RemoveAll(path) - } + e.CleanupTemporaryDirectories() + p.StoppedChan <- true }() return errors.Wrap(errors.WithStack(runner.Run()), "PHP server exited unexpectedly") @@ -233,9 +236,3 @@ func (p *Server) Serve(w http.ResponseWriter, r *http.Request, env map[string]st p.proxy.ServeHTTP(w, r) return nil } - -func name(dir string) string { - h := sha1.New() - io.WriteString(h, dir) - return fmt.Sprintf("%x", h.Sum(nil)) -} diff --git a/local/php/pie.go b/local/php/pie.go new file mode 100644 index 00000000..9dea548b --- /dev/null +++ b/local/php/pie.go @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package php + +import ( + "fmt" + "io" + "net/http" + "os" + "path/filepath" + + "github.com/pkg/errors" + "github.com/rs/zerolog" + "github.com/symfony-cli/symfony-cli/util" +) + +type PieResult struct { + code int + error error +} + +func (p PieResult) Error() string { + if p.error != nil { + return p.error.Error() + } + + return "" +} + +func (p PieResult) ExitCode() int { + return p.code +} + +func Pie(dir string, args, env []string, stdout, stderr, logger io.Writer, debugLogger zerolog.Logger) PieResult { + e := &Executor{ + Dir: dir, + BinName: "php", + Stdout: stdout, + Stderr: stderr, + SkipNbArgs: -1, + ExtraEnv: env, + Logger: debugLogger, + } + + if piePath := os.Getenv("SYMFONY_PIE_PATH"); piePath != "" { + debugLogger.Debug().Str("SYMFONY_PIE_PATH", piePath).Msg("SYMFONY_PIE_PATH has been defined. User is taking control over PIE detection and execution.") + e.Args = append([]string{piePath}, args...) + } else if path, err := e.findPie(); err == nil && isPHPScript(path) { + e.Args = append([]string{"php", path}, args...) + } else { + reason := "No PIE installation found." + if path != "" { + reason = fmt.Sprintf("Detected PIE file (%s) is not a valid PHAR or PHP script.", path) + } + fmt.Fprintln(logger, " WARNING:", reason) + fmt.Fprintln(logger, " Downloading PIE for you, but it is recommended to install PIE yourself, instructions available at https://github.com/php/pie") + // we don't store it under bin/ to avoid it being found by findPie as we want to only use it as a fallback + binDir := filepath.Join(util.GetHomeDir(), "pie") + if path, err = downloadPie(binDir); err != nil { + return PieResult{ + code: 1, + error: errors.Wrap(err, "unable to find pie, get it at https://github.com/php/pie"), + } + } + e.Args = append([]string{"php", path}, args...) + fmt.Fprintf(logger, " (running %s)\n\n", e.CommandLine()) + } + + ret := e.Execute(false) + if ret != 0 { + return PieResult{ + code: ret, + error: errors.Errorf("unable to run %s", e.CommandLine()), + } + } + return PieResult{} +} + +func findPie(logger zerolog.Logger) (string, error) { + for _, file := range []string{"pie", "pie.phar"} { + logger.Debug().Str("source", "PIE").Msgf(`Looking for PIE in the PATH as "%s"`, file) + if pharPath, _ := LookPath(file); pharPath != "" { + logger.Debug().Str("source", "PIE").Msgf(`Found potential PIE as "%s"`, pharPath) + return pharPath, nil + } + } + + return "", os.ErrNotExist +} + +func downloadPie(dir string) (string, error) { + if err := os.MkdirAll(dir, 0755); err != nil { + return "", err + } + path := filepath.Join(dir, "pie.phar") + if _, err := os.Stat(path); err == nil { + return path, nil + } + + piePhar, err := downloadPiePhar() + if err != nil { + return "", err + } + + err = os.WriteFile(path, piePhar, 0755) + if err != nil { + return "", err + } + + return path, nil +} + +func downloadPiePhar() ([]byte, error) { + resp, err := http.Get("https://github.com/php/pie/releases/latest/download/pie.phar") + if err != nil { + return nil, err + } + defer resp.Body.Close() + return io.ReadAll(resp.Body) +} diff --git a/local/php/symfony.go b/local/php/symfony.go new file mode 100644 index 00000000..235a2ccc --- /dev/null +++ b/local/php/symfony.go @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package php + +import ( + "os" + "path/filepath" + + "github.com/pkg/errors" + "github.com/rs/zerolog" + "github.com/symfony-cli/symfony-cli/envs" +) + +// SymfonyConsoleExecutor returns an Executor prepared to run Symfony Console. +// It returns an error if no console binary is found. +func SymfonyConsoleExecutor(logger zerolog.Logger, args []string) (*Executor, error) { + dir, err := os.Getwd() + if err != nil { + return nil, errors.WithStack(err) + } + + for { + consolePaths := []string{"bin/console", "app/console"} + if consolePath, isConsolePathSpecified := envs.LookupEnv(dir, "SYMFONY_CONSOLE_PATH"); isConsolePathSpecified { + consolePaths = []string{consolePath} + } + + for _, consolePath := range consolePaths { + logger.Debug().Str("consolePath", consolePath).Str("directory", dir).Msgf("Looking for Symfony console") + consolePath = filepath.Join(dir, consolePath) + if _, err := os.Stat(consolePath); err == nil { + return &Executor{ + BinName: "php", + Logger: logger, + Args: append([]string{"php", consolePath}, args...), + }, nil + } + } + + upDir := filepath.Dir(dir) + if upDir == dir || upDir == "." { + break + } + dir = upDir + } + + return nil, errors.New("No console binary found") +} diff --git a/local/php/testdata/php_scripts/plain-one.php b/local/php/testdata/php_scripts/plain-one.php new file mode 100755 index 00000000..06156917 --- /dev/null +++ b/local/php/testdata/php_scripts/plain-one.php @@ -0,0 +1,3 @@ + + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package php + +import ( + "path/filepath" + + . "gopkg.in/check.v1" +) + +type UtilsSuite struct{} + +var _ = Suite(&UtilsSuite{}) + +func (s *UtilsSuite) TestIsPHPScript(c *C) { + dir, err := filepath.Abs("testdata/php_scripts") + c.Assert(err, IsNil) + + c.Assert(isPHPScript(""), Equals, false) + c.Assert(isPHPScript(filepath.Join(dir, "unknown")), Equals, false) + c.Assert(isPHPScript(filepath.Join(dir, "invalid")), Equals, false) + + for _, validScripts := range []string{ + "usual-one", + "debian-style", + "custom-one", + "plain-one.php", + } { + c.Assert(isPHPScript(filepath.Join(dir, validScripts)), Equals, true) + } +} diff --git a/local/php/xsendfile.go b/local/php/xsendfile.go index 7e82d140..a72673f4 100644 --- a/local/php/xsendfile.go +++ b/local/php/xsendfile.go @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package php import ( diff --git a/local/pid/pidfile.go b/local/pid/pidfile.go index b5e41f28..243a2012 100644 --- a/local/pid/pidfile.go +++ b/local/pid/pidfile.go @@ -232,6 +232,19 @@ func (p *PidFile) WorkerPidDir() string { return filepath.Join(util.GetHomeDir(), "var", name(p.Dir)) } +func (p *PidFile) TempDirectory() string { + return filepath.Join(util.GetHomeDir(), "php", name(p.Dir)) +} + +func (p *PidFile) CleanupDirectories() { + os.RemoveAll(p.TempDirectory()) + // We don't want to force removal of log and pid files, we only want to + // clean up empty directories. To do so we use `os.Remove` instead of + // `os.RemoveAll` + os.Remove(p.WorkerLogDir()) + os.Remove(p.WorkerPidDir()) +} + func (p *PidFile) LogReader() (io.ReadCloser, error) { logFile := p.LogFile() if err := os.MkdirAll(filepath.Dir(logFile), 0755); err != nil { diff --git a/local/platformsh/commands.go b/local/platformsh/commands.go index 48d50d2e..56b8f13f 100644 --- a/local/platformsh/commands.go +++ b/local/platformsh/commands.go @@ -30,155 +30,157 @@ var Commands = []*console.Command{ { Category: "cloud", Name: "_completion", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:_completion", Hidden: true}, }, - Usage: "BASH completion hook.", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.BoolFlag{Name: "generate-hook", Aliases: []string{"g"},}, - &console.BoolFlag{Name: "multiple", Aliases: []string{"m"},}, - &console.StringFlag{Name: "program", Aliases: []string{"p"},}, - &console.StringFlag{Name: "shell-type",}, + Usage: "BASH completion hook.", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.BoolFlag{Name: "generate-hook", Aliases: []string{"g"}}, + &console.BoolFlag{Name: "multiple", Aliases: []string{"m"}}, + &console.StringFlag{Name: "program", Aliases: []string{"p"}}, + &console.StringFlag{Name: "shell-type"}, }, }, { Category: "cloud", Name: "bot", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:bot", Hidden: true}, }, - Usage: "The Platform.sh/Upsun Bot", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.BoolFlag{Name: "parrot",}, - &console.BoolFlag{Name: "party",}, + Usage: "The Platform.sh/Upsun Bot", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.BoolFlag{Name: "parrot"}, + &console.BoolFlag{Name: "party"}, }, }, { Category: "cloud", Name: "clear-cache", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:clear-cache", Hidden: true}, {Name: "cloud:cc"}, {Name: "upsun:cc", Hidden: true}, }, - Usage: "Clear the CLI cache", + Usage: "Clear the CLI cache", + }, + { + Category: "cloud", + Name: "console", + Aliases: []*console.Alias{ + {Name: "upsun:console", Hidden: true}, + {Name: "cloud:web"}, + {Name: "upsun:web", Hidden: true}, + }, + Usage: "Open the project in the Console", + Flags: []console.Flag{ + &console.StringFlag{Name: "browser"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + }, }, { Category: "cloud", Name: "docs", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:docs", Hidden: true}, }, - Usage: "Open the online documentation", - Flags: []console.Flag{ - &console.StringFlag{Name: "browser",}, - &console.BoolFlag{Name: "pipe",}, + Usage: "Open the online documentation", + Flags: []console.Flag{ + &console.StringFlag{Name: "browser"}, + &console.BoolFlag{Name: "pipe"}, }, }, { Category: "cloud", Name: "legacy-migrate", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:legacy-migrate", Hidden: true}, }, - Usage: "Migrate from the legacy file structure", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.BoolFlag{Name: "no-backup",}, + Usage: "Migrate from the legacy file structure", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.BoolFlag{Name: "no-backup"}, }, }, { Category: "cloud", Name: "multi", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:multi", Hidden: true}, }, - Usage: "Execute a command on multiple projects", - Flags: []console.Flag{ - &console.BoolFlag{Name: "continue",}, - &console.StringFlag{Name: "projects", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "reverse",}, - &console.StringFlag{Name: "sort", DefaultValue: "title",}, - }, - }, - { - Category: "cloud", - Name: "web", - Aliases: []*console.Alias{ - {Name: "upsun:web", Hidden: true}, - }, - Usage: "Open the project in the Web Console", - Flags: []console.Flag{ - &console.StringFlag{Name: "browser",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Execute a command on multiple projects", + Flags: []console.Flag{ + &console.BoolFlag{Name: "continue"}, + &console.StringFlag{Name: "projects", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "reverse"}, + &console.StringFlag{Name: "sort", DefaultValue: "title"}, }, }, { Category: "cloud", Name: "welcome", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:welcome", Hidden: true}, }, - Usage: "Welcome to Platform.sh/Upsun", - Hidden: console.Hide, + Usage: "Welcome to Platform.sh/Upsun", + Hidden: console.Hide, }, { Category: "cloud", Name: "winky", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:winky", Hidden: true}, }, - Usage: "", - Hidden: console.Hide, + Usage: "", + Hidden: console.Hide, }, { Category: "cloud:activity", Name: "cancel", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "activity:cancel", Hidden: true}, {Name: "upsun:activity:cancel", Hidden: true}, }, - Usage: "Cancel an activity", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "type", Aliases: []string{"t"},}, + Usage: "Cancel an activity", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "type", Aliases: []string{"t"}}, }, }, { Category: "cloud:activity", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "activity:get", Hidden: true}, {Name: "upsun:activity:get", Hidden: true}, }, - Usage: "View detailed information on a single activity", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, - &console.StringFlag{Name: "result",}, - &console.StringFlag{Name: "state",}, - &console.StringFlag{Name: "type", Aliases: []string{"t"},}, + Usage: "View detailed information on a single activity", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, + &console.StringFlag{Name: "result"}, + &console.StringFlag{Name: "state"}, + &console.StringFlag{Name: "type", Aliases: []string{"t"}}, }, }, { Category: "cloud:activity", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "activity:list", Hidden: true}, {Name: "upsun:activity:list", Hidden: true}, {Name: "cloud:activities"}, @@ -188,376 +190,379 @@ var Commands = []*console.Command{ {Name: "upsun:act", Hidden: true}, {Name: "act", Hidden: true}, }, - Usage: "Get a list of activities for an environment or project", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"},}, - &console.StringFlag{Name: "limit",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "result",}, - &console.StringFlag{Name: "start",}, - &console.StringFlag{Name: "state",}, - &console.StringFlag{Name: "type", Aliases: []string{"t"},}, + Usage: "Get a list of activities for an environment or project", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"}}, + &console.StringFlag{Name: "limit"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "result"}, + &console.StringFlag{Name: "start"}, + &console.StringFlag{Name: "state"}, + &console.StringFlag{Name: "type", Aliases: []string{"t"}}, }, }, { Category: "cloud:activity", Name: "log", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "activity:log", Hidden: true}, {Name: "upsun:activity:log", Hidden: true}, }, - Usage: "Display the log for an activity", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"},}, - &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "refresh",}, - &console.StringFlag{Name: "result",}, - &console.StringFlag{Name: "state",}, - &console.BoolFlag{Name: "timestamps", Aliases: []string{"t"},}, - &console.StringFlag{Name: "type",}, + Usage: "Display the log for an activity", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"}}, + &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "refresh"}, + &console.StringFlag{Name: "result"}, + &console.StringFlag{Name: "state"}, + &console.BoolFlag{Name: "timestamps", Aliases: []string{"t"}}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:api", Name: "curl", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "api:curl", Hidden: true}, {Name: "upsun:api:curl", Hidden: true}, }, - Usage: "Run an authenticated cURL request on the Platform.sh/Upsun API", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "data", Aliases: []string{"d"},}, - &console.BoolFlag{Name: "disable-compression",}, - &console.BoolFlag{Name: "enable-glob",}, - &console.BoolFlag{Name: "fail", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "head", Aliases: []string{"I"},}, - &console.StringFlag{Name: "header", Aliases: []string{"H"},}, - &console.BoolFlag{Name: "include", Aliases: []string{"i"},}, - &console.StringFlag{Name: "json",}, - &console.StringFlag{Name: "request", Aliases: []string{"X"},}, + Usage: "Run an authenticated cURL request on the Platform.sh/Upsun API", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "data", Aliases: []string{"d"}}, + &console.BoolFlag{Name: "disable-compression"}, + &console.BoolFlag{Name: "enable-glob"}, + &console.BoolFlag{Name: "fail", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "head", Aliases: []string{"I"}}, + &console.StringFlag{Name: "header", Aliases: []string{"H"}}, + &console.BoolFlag{Name: "include", Aliases: []string{"i"}}, + &console.StringFlag{Name: "json"}, + &console.BoolFlag{Name: "no-retry-401"}, + &console.StringFlag{Name: "request", Aliases: []string{"X"}}, }, }, { Category: "cloud:app", Name: "config-get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "app:config-get", Hidden: true}, {Name: "upsun:app:config-get", Hidden: true}, }, - Usage: "View the configuration of an app", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "identity-file", Aliases: []string{"i"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "View the configuration of an app", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "identity-file", Aliases: []string{"i"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:app", Name: "config-validate", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "app:config-validate", Hidden: true}, {Name: "upsun:app:config-validate", Hidden: true}, }, - Usage: "Validate the config files of a project", + Usage: "Validate the config files of a project", }, { Category: "cloud:app", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "app:list", Hidden: true}, {Name: "upsun:app:list", Hidden: true}, {Name: "cloud:apps"}, {Name: "upsun:apps", Hidden: true}, {Name: "apps", Hidden: true}, }, - Usage: "List apps in the project", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "List apps in the project", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:auth", Name: "api-token-login", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "auth:api-token-login", Hidden: true}, {Name: "upsun:auth:api-token-login", Hidden: true}, }, - Usage: "Log in to Platform.sh/Upsun using an API token", + Usage: "Log in to Platform.sh/Upsun using an API token", }, { Category: "cloud:auth", Name: "browser-login", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "auth:browser-login", Hidden: true}, {Name: "upsun:auth:browser-login", Hidden: true}, {Name: "cloud:login"}, {Name: "upsun:login", Hidden: true}, {Name: "login", Hidden: true}, }, - Usage: "Log in to Platform.sh/Upsun via a browser", - Flags: []console.Flag{ - &console.StringFlag{Name: "browser",}, - &console.BoolFlag{Name: "force", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "pipe",}, + Usage: "Log in to Platform.sh/Upsun via a browser", + Flags: []console.Flag{ + &console.StringFlag{Name: "browser"}, + &console.BoolFlag{Name: "force", Aliases: []string{"f"}}, + &console.StringFlag{Name: "max-age"}, + &console.StringFlag{Name: "method"}, + &console.BoolFlag{Name: "pipe"}, }, }, { Category: "cloud:auth", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "auth:info", Hidden: true}, {Name: "upsun:auth:info", Hidden: true}, }, - Usage: "Display your account information", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-auto-login",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "Display your account information", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-auto-login"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:auth", Name: "logout", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "auth:logout", Hidden: true}, {Name: "upsun:auth:logout", Hidden: true}, {Name: "cloud:logout"}, {Name: "upsun:logout", Hidden: true}, {Name: "logout", Hidden: true}, }, - Usage: "Log out of Platform.sh/Upsun", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.BoolFlag{Name: "other",}, + Usage: "Log out of Platform.sh/Upsun", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.BoolFlag{Name: "other"}, }, }, { Category: "cloud:auth", Name: "token", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "auth:token", Hidden: true}, {Name: "upsun:auth:token", Hidden: true}, }, - Usage: "Obtain an OAuth 2 access token for requests to Platform.sh/Upsun APIs", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.BoolFlag{Name: "header", Aliases: []string{"H"},}, - &console.BoolFlag{Name: "no-warn", Aliases: []string{"W"},}, + Usage: "Obtain an OAuth 2 access token for requests to Platform.sh/Upsun APIs", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.BoolFlag{Name: "header", Aliases: []string{"H"}}, + &console.BoolFlag{Name: "no-warn", Aliases: []string{"W"}}, }, }, { Category: "cloud:auth", Name: "verify-phone-number", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "auth:verify-phone-number", Hidden: true}, {Name: "upsun:auth:verify-phone-number", Hidden: true}, }, - Usage: "Verify your phone number interactively", + Usage: "Verify your phone number interactively", }, { Category: "cloud:backup", Name: "create", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "backup:create", Hidden: true}, {Name: "upsun:backup:create", Hidden: true}, {Name: "cloud:backup"}, {Name: "upsun:backup", Hidden: true}, {Name: "backup", Hidden: true}, }, - Usage: "Make a backup of an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "live",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Make a backup of an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "live"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:backup", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "backup:delete", Hidden: true}, {Name: "upsun:backup:delete", Hidden: true}, }, - Usage: "Delete an environment backup", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete an environment backup", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:backup", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "backup:get", Hidden: true}, {Name: "upsun:backup:get", Hidden: true}, }, - Usage: "View an environment backup", - Flags: []console.Flag{ - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View an environment backup", + Flags: []console.Flag{ + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:backup", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "backup:list", Hidden: true}, {Name: "upsun:backup:list", Hidden: true}, {Name: "cloud:backups"}, {Name: "upsun:backups", Hidden: true}, {Name: "backups", Hidden: true}, }, - Usage: "List available backups of an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List available backups of an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:backup", Name: "restore", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "backup:restore", Hidden: true}, {Name: "upsun:backup:restore", Hidden: true}, }, - Usage: "Restore an environment backup", - Flags: []console.Flag{ - &console.StringFlag{Name: "branch-from",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "restore-code",}, - &console.StringFlag{Name: "target",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Restore an environment backup", + Flags: []console.Flag{ + &console.StringFlag{Name: "branch-from"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-code"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "target"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:blue-green", Name: "conclude", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "blue-green:conclude", Hidden: true}, {Name: "upsun:blue-green:conclude", Hidden: true}, }, - Usage: "ALPHA Conclude a blue/green deployment", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "ALPHA Conclude a blue/green deployment", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:blue-green", Name: "deploy", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "blue-green:deploy", Hidden: true}, {Name: "upsun:blue-green:deploy", Hidden: true}, }, - Usage: "ALPHA Perform a blue/green deployment", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "routing-percentage",}, + Usage: "ALPHA Perform a blue/green deployment", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "routing-percentage"}, }, }, { Category: "cloud:blue-green", Name: "enable", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "blue-green:enable", Hidden: true}, {Name: "upsun:blue-green:enable", Hidden: true}, }, - Usage: "ALPHA Enable blue/green deployments", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "routing-percentage", Aliases: []string{"%"},}, + Usage: "ALPHA Enable blue/green deployments", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "routing-percentage", Aliases: []string{"%"}}, }, }, { Category: "cloud:certificate", Name: "add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "certificate:add", Hidden: true}, {Name: "upsun:certificate:add", Hidden: true}, }, - Usage: "Add an SSL certificate to the project", - Flags: []console.Flag{ - &console.StringFlag{Name: "cert",}, - &console.StringFlag{Name: "chain",}, - &console.StringFlag{Name: "key",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Add an SSL certificate to the project", + Flags: []console.Flag{ + &console.StringFlag{Name: "cert"}, + &console.StringFlag{Name: "chain"}, + &console.StringFlag{Name: "key"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:certificate", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "certificate:delete", Hidden: true}, {Name: "upsun:certificate:delete", Hidden: true}, }, - Usage: "Delete a certificate from the project", - Flags: []console.Flag{ - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete a certificate from the project", + Flags: []console.Flag{ + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:certificate", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "certificate:get", Hidden: true}, {Name: "upsun:certificate:get", Hidden: true}, }, - Usage: "View a certificate", - Flags: []console.Flag{ - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View a certificate", + Flags: []console.Flag{ + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:certificate", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "certificate:list", Hidden: true}, {Name: "upsun:certificate:list", Hidden: true}, {Name: "cloud:certificates"}, @@ -567,352 +572,356 @@ var Commands = []*console.Command{ {Name: "upsun:certs", Hidden: true}, {Name: "certs", Hidden: true}, }, - Usage: "List project certificates", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "domain",}, - &console.StringFlag{Name: "exclude-domain",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "ignore-expiry",}, - &console.StringFlag{Name: "issuer",}, - &console.BoolFlag{Name: "no-auto",}, - &console.BoolFlag{Name: "no-expired",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "only-auto",}, - &console.BoolFlag{Name: "only-expired",}, - &console.BoolFlag{Name: "pipe-domains",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List project certificates", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "domain"}, + &console.StringFlag{Name: "exclude-domain"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "ignore-expiry"}, + &console.StringFlag{Name: "issuer"}, + &console.BoolFlag{Name: "no-auto"}, + &console.BoolFlag{Name: "no-expired"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "only-auto"}, + &console.BoolFlag{Name: "only-expired"}, + &console.BoolFlag{Name: "pipe-domains"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:commit", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "commit:get", Hidden: true}, {Name: "upsun:commit:get", Hidden: true}, }, - Usage: "Show commit details", - Flags: []console.Flag{ - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "Show commit details", + Flags: []console.Flag{ + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:commit", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "commit:list", Hidden: true}, {Name: "upsun:commit:list", Hidden: true}, {Name: "cloud:commits"}, {Name: "upsun:commits", Hidden: true}, {Name: "commits", Hidden: true}, }, - Usage: "List commits", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "limit",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List commits", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "limit"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:db", Name: "dump", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "db:dump", Hidden: true}, {Name: "upsun:db:dump", Hidden: true}, }, - Usage: "Create a local dump of the remote database", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "charset",}, - &console.StringFlag{Name: "directory", Aliases: []string{"d"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude-table",}, - &console.StringFlag{Name: "file", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "gzip", Aliases: []string{"z"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, - &console.StringFlag{Name: "schema",}, - &console.BoolFlag{Name: "schema-only",}, - &console.BoolFlag{Name: "stdout", Aliases: []string{"o"},}, - &console.StringFlag{Name: "table",}, - &console.BoolFlag{Name: "timestamp", Aliases: []string{"t"},}, + Usage: "Create a local dump of the remote database", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "charset"}, + &console.StringFlag{Name: "directory", Aliases: []string{"d"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude-table"}, + &console.StringFlag{Name: "file", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "gzip", Aliases: []string{"z"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, + &console.StringFlag{Name: "schema"}, + &console.BoolFlag{Name: "schema-only"}, + &console.BoolFlag{Name: "stdout", Aliases: []string{"o"}}, + &console.StringFlag{Name: "table"}, + &console.BoolFlag{Name: "timestamp", Aliases: []string{"t"}}, }, }, { Category: "cloud:db", Name: "sql", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "db:sql", Hidden: true}, {Name: "upsun:db:sql", Hidden: true}, {Name: "cloud:sql"}, {Name: "upsun:sql", Hidden: true}, {Name: "sql", Hidden: true}, }, - Usage: "Run SQL on the remote database", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "raw",}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, - &console.StringFlag{Name: "schema",}, + Usage: "Run SQL on the remote database", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "raw"}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, + &console.StringFlag{Name: "schema"}, }, }, { Category: "cloud:domain", Name: "add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "domain:add", Hidden: true}, {Name: "upsun:domain:add", Hidden: true}, }, - Usage: "Add a new domain to the project", - Flags: []console.Flag{ - &console.StringFlag{Name: "attach",}, - &console.StringFlag{Name: "cert",}, - &console.StringFlag{Name: "chain",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "key",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Add a new domain to the project", + Flags: []console.Flag{ + &console.StringFlag{Name: "attach"}, + &console.StringFlag{Name: "cert"}, + &console.StringFlag{Name: "chain"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "key"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:domain", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "domain:delete", Hidden: true}, {Name: "upsun:domain:delete", Hidden: true}, }, - Usage: "Delete a domain from the project", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete a domain from the project", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:domain", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "domain:get", Hidden: true}, {Name: "upsun:domain:get", Hidden: true}, }, - Usage: "Show detailed information for a domain", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "Show detailed information for a domain", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:domain", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "domain:list", Hidden: true}, {Name: "upsun:domain:list", Hidden: true}, {Name: "cloud:domains"}, {Name: "upsun:domains", Hidden: true}, {Name: "domains", Hidden: true}, }, - Usage: "Get a list of all domains", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Get a list of all domains", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:domain", Name: "update", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "domain:update", Hidden: true}, {Name: "upsun:domain:update", Hidden: true}, }, - Usage: "Update a domain", - Flags: []console.Flag{ - &console.StringFlag{Name: "cert",}, - &console.StringFlag{Name: "chain",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "key",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Update a domain", + Flags: []console.Flag{ + &console.StringFlag{Name: "cert"}, + &console.StringFlag{Name: "chain"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "key"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "activate", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:activate", Hidden: true}, {Name: "upsun:environment:activate", Hidden: true}, }, - Usage: "Activate an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "parent",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Activate an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "parent"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "branch", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:branch", Hidden: true}, {Name: "upsun:environment:branch", Hidden: true}, {Name: "cloud:branch"}, {Name: "upsun:branch", Hidden: true}, {Name: "branch", Hidden: true}, }, - Usage: "Branch an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-checkout",}, - &console.BoolFlag{Name: "no-clone-parent",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "title",}, - &console.StringFlag{Name: "type",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Branch an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-checkout"}, + &console.BoolFlag{Name: "no-clone-parent"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "title"}, + &console.StringFlag{Name: "type"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "checkout", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:checkout", Hidden: true}, {Name: "upsun:environment:checkout", Hidden: true}, {Name: "cloud:checkout"}, {Name: "upsun:checkout", Hidden: true}, {Name: "checkout", Hidden: true}, }, - Usage: "Check out an environment", + Usage: "Check out an environment", }, { Category: "cloud:environment", Name: "curl", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:curl", Hidden: true}, {Name: "upsun:environment:curl", Hidden: true}, }, - Usage: "Run an authenticated cURL request on an environment's API", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "data", Aliases: []string{"d"},}, - &console.BoolFlag{Name: "disable-compression",}, - &console.BoolFlag{Name: "enable-glob",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "fail", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "head", Aliases: []string{"I"},}, - &console.StringFlag{Name: "header", Aliases: []string{"H"},}, - &console.BoolFlag{Name: "include", Aliases: []string{"i"},}, - &console.StringFlag{Name: "json",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "request", Aliases: []string{"X"},}, + Usage: "Run an authenticated cURL request on an environment's API", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "data", Aliases: []string{"d"}}, + &console.BoolFlag{Name: "disable-compression"}, + &console.BoolFlag{Name: "enable-glob"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "fail", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "head", Aliases: []string{"I"}}, + &console.StringFlag{Name: "header", Aliases: []string{"H"}}, + &console.BoolFlag{Name: "include", Aliases: []string{"i"}}, + &console.StringFlag{Name: "json"}, + &console.BoolFlag{Name: "no-retry-401"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "request", Aliases: []string{"X"}}, }, }, { Category: "cloud:environment", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:delete", Hidden: true}, {Name: "upsun:environment:delete", Hidden: true}, }, - Usage: "Delete one or more environments", - Flags: []console.Flag{ - &console.BoolFlag{Name: "allow-delete-parent",}, - &console.BoolFlag{Name: "delete-branch",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude",}, - &console.StringFlag{Name: "exclude-type",}, - &console.BoolFlag{Name: "inactive",}, - &console.BoolFlag{Name: "merged",}, - &console.BoolFlag{Name: "no-delete-branch",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "only-type", Aliases: []string{"t"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "type",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete one or more environments", + Flags: []console.Flag{ + &console.BoolFlag{Name: "allow-delete-parent"}, + &console.BoolFlag{Name: "delete-branch"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude"}, + &console.StringFlag{Name: "exclude-status"}, + &console.StringFlag{Name: "exclude-type"}, + &console.BoolFlag{Name: "inactive"}, + &console.BoolFlag{Name: "merged"}, + &console.BoolFlag{Name: "no-delete-branch"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "only-status"}, + &console.StringFlag{Name: "only-type", Aliases: []string{"t"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "status"}, + &console.StringFlag{Name: "type"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "http-access", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:http-access", Hidden: true}, {Name: "upsun:environment:http-access", Hidden: true}, {Name: "cloud:httpaccess"}, {Name: "upsun:httpaccess", Hidden: true}, {Name: "httpaccess", Hidden: true}, }, - Usage: "Update HTTP access settings for an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "access",}, - &console.StringFlag{Name: "auth",}, - &console.StringFlag{Name: "enabled",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Update HTTP access settings for an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "access"}, + &console.StringFlag{Name: "auth"}, + &console.StringFlag{Name: "enabled"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:info", Hidden: true}, {Name: "upsun:environment:info", Hidden: true}, }, - Usage: "Read or set properties for an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Read or set properties for an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "init", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:init", Hidden: true}, {Name: "upsun:environment:init", Hidden: true}, }, - Usage: "Initialize an environment from a public Git repository", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "profile",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Initialize an environment from a public Git repository", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "profile"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:list", Hidden: true}, {Name: "upsun:environment:list", Hidden: true}, {Name: "cloud:environments"}, @@ -922,78 +931,79 @@ var Commands = []*console.Command{ {Name: "upsun:env", Hidden: true}, {Name: "env", Hidden: true}, }, - Usage: "Get a list of environments", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "no-inactive", Aliases: []string{"I"},}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "refresh",}, - &console.BoolFlag{Name: "reverse",}, - &console.StringFlag{Name: "sort", DefaultValue: "title",}, - &console.StringFlag{Name: "type",}, + Usage: "Get a list of environments", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "no-inactive", Aliases: []string{"I"}}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "refresh"}, + &console.BoolFlag{Name: "reverse"}, + &console.StringFlag{Name: "sort", DefaultValue: "title"}, + &console.StringFlag{Name: "status"}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:environment", Name: "logs", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:logs", Hidden: true}, {Name: "upsun:environment:logs", Hidden: true}, {Name: "cloud:log"}, {Name: "upsun:log", Hidden: true}, {Name: "log", Hidden: true}, }, - Usage: "Read an environment's logs", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.StringFlag{Name: "lines",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "tail",}, - &console.StringFlag{Name: "worker",}, + Usage: "Read an environment's logs", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.StringFlag{Name: "lines"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "tail"}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:environment", Name: "merge", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:merge", Hidden: true}, {Name: "upsun:environment:merge", Hidden: true}, {Name: "cloud:merge"}, {Name: "upsun:merge", Hidden: true}, {Name: "merge", Hidden: true}, }, - Usage: "Merge an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Merge an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "pause", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:pause", Hidden: true}, {Name: "upsun:environment:pause", Hidden: true}, }, - Usage: "Pause an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Pause an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "push", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:push", Hidden: true}, {Name: "upsun:environment:push", Hidden: true}, {Name: "cloud:push"}, @@ -1003,44 +1013,44 @@ var Commands = []*console.Command{ {Name: "cloud:deploy"}, {Name: "upsun:deploy", Hidden: true}, }, - Usage: "Push code to an environment", - Flags: []console.Flag{ - &console.BoolFlag{Name: "activate",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "force", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "force-with-lease",}, - &console.BoolFlag{Name: "no-clone-parent",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "parent",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "set-upstream", Aliases: []string{"u"},}, - &console.StringFlag{Name: "target",}, - &console.StringFlag{Name: "type",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Push code to an environment", + Flags: []console.Flag{ + &console.BoolFlag{Name: "activate"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "force", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "force-with-lease"}, + &console.BoolFlag{Name: "no-clone-parent"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "parent"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "set-upstream", Aliases: []string{"u"}}, + &console.StringFlag{Name: "target"}, + &console.StringFlag{Name: "type"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "redeploy", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:redeploy", Hidden: true}, {Name: "upsun:environment:redeploy", Hidden: true}, {Name: "cloud:redeploy"}, {Name: "upsun:redeploy", Hidden: true}, {Name: "redeploy", Hidden: true}, }, - Usage: "Redeploy an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Redeploy an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "relationships", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:relationships", Hidden: true}, {Name: "upsun:environment:relationships", Hidden: true}, {Name: "cloud:relationships"}, @@ -1050,380 +1060,381 @@ var Commands = []*console.Command{ {Name: "upsun:rel", Hidden: true}, {Name: "rel", Hidden: true}, }, - Usage: "Show an environment's relationships", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "Show an environment's relationships", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:environment", Name: "resume", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:resume", Hidden: true}, {Name: "upsun:environment:resume", Hidden: true}, }, - Usage: "Resume a paused environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Resume a paused environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "scp", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:scp", Hidden: true}, {Name: "upsun:environment:scp", Hidden: true}, {Name: "cloud:scp"}, {Name: "upsun:scp", Hidden: true}, {Name: "scp", Hidden: true}, }, - Usage: "Copy files to and from an environment using scp", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "recursive", Aliases: []string{"r"},}, - &console.StringFlag{Name: "worker",}, + Usage: "Copy files to and from an environment using scp", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "recursive", Aliases: []string{"r"}}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:environment", Name: "set-remote", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:set-remote", Hidden: true}, {Name: "upsun:environment:set-remote", Hidden: true}, }, - Usage: "Set the remote environment to map to a branch", - Hidden: console.Hide, + Usage: "Set the remote environment to map to a branch", + Hidden: console.Hide, }, { Category: "cloud:environment", Name: "ssh", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:ssh", Hidden: true}, {Name: "upsun:environment:ssh", Hidden: true}, {Name: "cloud:ssh"}, {Name: "upsun:ssh", Hidden: true}, {Name: "ssh", Hidden: true}, }, - Usage: "SSH to the current environment", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all",}, - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.StringFlag{Name: "option", Aliases: []string{"o"},}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "worker",}, + Usage: "SSH to the current environment", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all"}, + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.StringFlag{Name: "option", Aliases: []string{"o"}}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:environment", Name: "synchronize", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:synchronize", Hidden: true}, {Name: "upsun:environment:synchronize", Hidden: true}, {Name: "cloud:sync"}, {Name: "upsun:sync", Hidden: true}, {Name: "sync", Hidden: true}, }, - Usage: "Synchronize an environment's code and/or data from its parent", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "rebase",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Synchronize an environment's code and/or data from its parent", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "rebase"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:environment", Name: "url", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:url", Hidden: true}, {Name: "upsun:environment:url", Hidden: true}, {Name: "cloud:url"}, {Name: "upsun:url", Hidden: true}, {Name: "url", Hidden: true}, }, - Usage: "Get the public URLs of an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "browser",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "pipe",}, - &console.BoolFlag{Name: "primary", Aliases: []string{"1"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Get the public URLs of an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "browser"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "pipe"}, + &console.BoolFlag{Name: "primary", Aliases: []string{"1"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:environment", Name: "xdebug", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "environment:xdebug", Hidden: true}, {Name: "upsun:environment:xdebug", Hidden: true}, {Name: "cloud:xdebug"}, {Name: "upsun:xdebug", Hidden: true}, {Name: "xdebug", Hidden: true}, }, - Usage: "Open a tunnel to Xdebug on the environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.StringFlag{Name: "port",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "worker",}, + Usage: "Open a tunnel to Xdebug on the environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.StringFlag{Name: "port"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:integration", Name: "activity:get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:activity:get", Hidden: true}, {Name: "upsun:integration:activity:get", Hidden: true}, }, - Usage: "View detailed information on a single integration activity", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View detailed information on a single integration activity", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:integration", Name: "activity:list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:activity:list", Hidden: true}, {Name: "upsun:integration:activity:list", Hidden: true}, - {Name: "cloud:int:act"}, - {Name: "upsun:int:act", Hidden: true}, - {Name: "int:act", Hidden: true}, - }, - Usage: "Get a list of activities for an integration", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"},}, - &console.StringFlag{Name: "limit",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "result",}, - &console.StringFlag{Name: "start",}, - &console.StringFlag{Name: "state",}, - &console.StringFlag{Name: "type",}, + {Name: "cloud:integration:activities"}, + {Name: "upsun:integration:activities", Hidden: true}, + {Name: "integration:activities", Hidden: true}, + }, + Usage: "Get a list of activities for an integration", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude-type", Aliases: []string{"x"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "incomplete", Aliases: []string{"i"}}, + &console.StringFlag{Name: "limit"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "result"}, + &console.StringFlag{Name: "start"}, + &console.StringFlag{Name: "state"}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:integration", Name: "activity:log", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:activity:log", Hidden: true}, {Name: "upsun:integration:activity:log", Hidden: true}, }, - Usage: "Display the log for an integration activity", - Flags: []console.Flag{ - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "timestamps", Aliases: []string{"t"},}, + Usage: "Display the log for an integration activity", + Flags: []console.Flag{ + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "timestamps", Aliases: []string{"t"}}, }, }, { Category: "cloud:integration", Name: "add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:add", Hidden: true}, {Name: "upsun:integration:add", Hidden: true}, }, - Usage: "Add an integration to the project", - Flags: []console.Flag{ - &console.StringFlag{Name: "auth-mode", DefaultValue: "prefix",}, - &console.StringFlag{Name: "auth-token",}, - &console.StringFlag{Name: "base-url",}, - &console.StringFlag{Name: "bitbucket-url",}, - &console.BoolFlag{Name: "build-draft-pull-requests", DefaultValue: true,}, - &console.BoolFlag{Name: "build-merge-requests", DefaultValue: true,}, - &console.BoolFlag{Name: "build-pull-requests", DefaultValue: true,}, - &console.BoolFlag{Name: "build-pull-requests-post-merge",}, - &console.BoolFlag{Name: "build-wip-merge-requests", DefaultValue: true,}, - &console.StringFlag{Name: "category",}, - &console.StringFlag{Name: "channel",}, - &console.StringFlag{Name: "environments",}, - &console.StringFlag{Name: "events",}, - &console.StringFlag{Name: "excluded-environments",}, - &console.StringFlag{Name: "facility",}, - &console.BoolFlag{Name: "fetch-branches", DefaultValue: true,}, - &console.StringFlag{Name: "file",}, - &console.StringFlag{Name: "from-address",}, - &console.StringFlag{Name: "header",}, - &console.StringFlag{Name: "index",}, - &console.StringFlag{Name: "key",}, - &console.StringFlag{Name: "license-key",}, - &console.BoolFlag{Name: "merge-requests-clone-parent-data", DefaultValue: true,}, - &console.StringFlag{Name: "message-format", DefaultValue: "rfc5424",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "protocol", DefaultValue: "tls",}, - &console.BoolFlag{Name: "prune-branches", DefaultValue: true,}, - &console.BoolFlag{Name: "pull-requests-clone-parent-data", DefaultValue: true,}, - &console.StringFlag{Name: "recipients",}, - &console.StringFlag{Name: "repository",}, - &console.StringFlag{Name: "resources-init", DefaultValue: "parent",}, - &console.BoolFlag{Name: "resync-pull-requests",}, - &console.StringFlag{Name: "routing-key",}, - &console.StringFlag{Name: "secret",}, - &console.StringFlag{Name: "server-project",}, - &console.StringFlag{Name: "shared-key",}, - &console.StringFlag{Name: "sourcetype",}, - &console.StringFlag{Name: "states",}, - &console.StringFlag{Name: "syslog-host",}, - &console.StringFlag{Name: "syslog-port",}, - &console.StringFlag{Name: "token",}, - &console.StringFlag{Name: "type",}, - &console.StringFlag{Name: "url",}, - &console.StringFlag{Name: "username",}, - &console.BoolFlag{Name: "verify-tls", DefaultValue: true,}, - &console.BoolFlag{Name: "wait",}, + Usage: "Add an integration to the project", + Flags: []console.Flag{ + &console.StringFlag{Name: "auth-mode", DefaultValue: "prefix"}, + &console.StringFlag{Name: "auth-token"}, + &console.StringFlag{Name: "base-url"}, + &console.StringFlag{Name: "bitbucket-url"}, + &console.BoolFlag{Name: "build-draft-pull-requests", DefaultValue: true}, + &console.BoolFlag{Name: "build-merge-requests", DefaultValue: true}, + &console.BoolFlag{Name: "build-pull-requests", DefaultValue: true}, + &console.BoolFlag{Name: "build-pull-requests-post-merge"}, + &console.BoolFlag{Name: "build-wip-merge-requests", DefaultValue: true}, + &console.StringFlag{Name: "category"}, + &console.StringFlag{Name: "channel"}, + &console.StringFlag{Name: "environments"}, + &console.StringFlag{Name: "events"}, + &console.StringFlag{Name: "excluded-environments"}, + &console.StringFlag{Name: "facility"}, + &console.BoolFlag{Name: "fetch-branches", DefaultValue: true}, + &console.StringFlag{Name: "file"}, + &console.StringFlag{Name: "from-address"}, + &console.StringFlag{Name: "header"}, + &console.StringFlag{Name: "index"}, + &console.StringFlag{Name: "key"}, + &console.StringFlag{Name: "license-key"}, + &console.BoolFlag{Name: "merge-requests-clone-parent-data", DefaultValue: true}, + &console.StringFlag{Name: "message-format", DefaultValue: "rfc5424"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "protocol", DefaultValue: "tls"}, + &console.BoolFlag{Name: "prune-branches", DefaultValue: true}, + &console.BoolFlag{Name: "pull-requests-clone-parent-data", DefaultValue: true}, + &console.StringFlag{Name: "recipients"}, + &console.StringFlag{Name: "repository"}, + &console.StringFlag{Name: "resources-init", DefaultValue: "parent"}, + &console.BoolFlag{Name: "resync-pull-requests"}, + &console.StringFlag{Name: "routing-key"}, + &console.StringFlag{Name: "secret"}, + &console.StringFlag{Name: "server-project"}, + &console.StringFlag{Name: "shared-key"}, + &console.StringFlag{Name: "sourcetype"}, + &console.StringFlag{Name: "states"}, + &console.StringFlag{Name: "syslog-host"}, + &console.StringFlag{Name: "syslog-port"}, + &console.StringFlag{Name: "token"}, + &console.StringFlag{Name: "type"}, + &console.StringFlag{Name: "url"}, + &console.StringFlag{Name: "username"}, + &console.BoolFlag{Name: "verify-tls", DefaultValue: true}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:integration", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:delete", Hidden: true}, {Name: "upsun:integration:delete", Hidden: true}, }, - Usage: "Delete an integration from a project", - Flags: []console.Flag{ - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete an integration from a project", + Flags: []console.Flag{ + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:integration", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:get", Hidden: true}, {Name: "upsun:integration:get", Hidden: true}, }, - Usage: "View details of an integration", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View details of an integration", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:integration", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:list", Hidden: true}, {Name: "upsun:integration:list", Hidden: true}, {Name: "cloud:integrations"}, {Name: "upsun:integrations", Hidden: true}, {Name: "integrations", Hidden: true}, }, - Usage: "View a list of project integration(s)", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "View a list of project integration(s)", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "type", Aliases: []string{"t"}}, }, }, { Category: "cloud:integration", Name: "update", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:update", Hidden: true}, {Name: "upsun:integration:update", Hidden: true}, }, - Usage: "Update an integration", - Flags: []console.Flag{ - &console.StringFlag{Name: "auth-mode", DefaultValue: "prefix",}, - &console.StringFlag{Name: "auth-token",}, - &console.StringFlag{Name: "base-url",}, - &console.StringFlag{Name: "bitbucket-url",}, - &console.BoolFlag{Name: "build-draft-pull-requests", DefaultValue: true,}, - &console.BoolFlag{Name: "build-merge-requests", DefaultValue: true,}, - &console.BoolFlag{Name: "build-pull-requests", DefaultValue: true,}, - &console.BoolFlag{Name: "build-pull-requests-post-merge",}, - &console.BoolFlag{Name: "build-wip-merge-requests", DefaultValue: true,}, - &console.StringFlag{Name: "category",}, - &console.StringFlag{Name: "channel",}, - &console.StringFlag{Name: "environments",}, - &console.StringFlag{Name: "events",}, - &console.StringFlag{Name: "excluded-environments",}, - &console.StringFlag{Name: "facility",}, - &console.BoolFlag{Name: "fetch-branches", DefaultValue: true,}, - &console.StringFlag{Name: "file",}, - &console.StringFlag{Name: "from-address",}, - &console.StringFlag{Name: "header",}, - &console.StringFlag{Name: "index",}, - &console.StringFlag{Name: "key",}, - &console.StringFlag{Name: "license-key",}, - &console.BoolFlag{Name: "merge-requests-clone-parent-data", DefaultValue: true,}, - &console.StringFlag{Name: "message-format", DefaultValue: "rfc5424",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "protocol", DefaultValue: "tls",}, - &console.BoolFlag{Name: "prune-branches", DefaultValue: true,}, - &console.BoolFlag{Name: "pull-requests-clone-parent-data", DefaultValue: true,}, - &console.StringFlag{Name: "recipients",}, - &console.StringFlag{Name: "repository",}, - &console.StringFlag{Name: "resources-init", DefaultValue: "parent",}, - &console.BoolFlag{Name: "resync-pull-requests",}, - &console.StringFlag{Name: "routing-key",}, - &console.StringFlag{Name: "secret",}, - &console.StringFlag{Name: "server-project",}, - &console.StringFlag{Name: "shared-key",}, - &console.StringFlag{Name: "sourcetype",}, - &console.StringFlag{Name: "states",}, - &console.StringFlag{Name: "syslog-host",}, - &console.StringFlag{Name: "syslog-port",}, - &console.StringFlag{Name: "token",}, - &console.StringFlag{Name: "type",}, - &console.StringFlag{Name: "url",}, - &console.StringFlag{Name: "username",}, - &console.BoolFlag{Name: "verify-tls", DefaultValue: true,}, - &console.BoolFlag{Name: "wait",}, + Usage: "Update an integration", + Flags: []console.Flag{ + &console.StringFlag{Name: "auth-mode", DefaultValue: "prefix"}, + &console.StringFlag{Name: "auth-token"}, + &console.StringFlag{Name: "base-url"}, + &console.StringFlag{Name: "bitbucket-url"}, + &console.BoolFlag{Name: "build-draft-pull-requests", DefaultValue: true}, + &console.BoolFlag{Name: "build-merge-requests", DefaultValue: true}, + &console.BoolFlag{Name: "build-pull-requests", DefaultValue: true}, + &console.BoolFlag{Name: "build-pull-requests-post-merge"}, + &console.BoolFlag{Name: "build-wip-merge-requests", DefaultValue: true}, + &console.StringFlag{Name: "category"}, + &console.StringFlag{Name: "channel"}, + &console.StringFlag{Name: "environments"}, + &console.StringFlag{Name: "events"}, + &console.StringFlag{Name: "excluded-environments"}, + &console.StringFlag{Name: "facility"}, + &console.BoolFlag{Name: "fetch-branches", DefaultValue: true}, + &console.StringFlag{Name: "file"}, + &console.StringFlag{Name: "from-address"}, + &console.StringFlag{Name: "header"}, + &console.StringFlag{Name: "index"}, + &console.StringFlag{Name: "key"}, + &console.StringFlag{Name: "license-key"}, + &console.BoolFlag{Name: "merge-requests-clone-parent-data", DefaultValue: true}, + &console.StringFlag{Name: "message-format", DefaultValue: "rfc5424"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "protocol", DefaultValue: "tls"}, + &console.BoolFlag{Name: "prune-branches", DefaultValue: true}, + &console.BoolFlag{Name: "pull-requests-clone-parent-data", DefaultValue: true}, + &console.StringFlag{Name: "recipients"}, + &console.StringFlag{Name: "repository"}, + &console.StringFlag{Name: "resources-init", DefaultValue: "parent"}, + &console.BoolFlag{Name: "resync-pull-requests"}, + &console.StringFlag{Name: "routing-key"}, + &console.StringFlag{Name: "secret"}, + &console.StringFlag{Name: "server-project"}, + &console.StringFlag{Name: "shared-key"}, + &console.StringFlag{Name: "sourcetype"}, + &console.StringFlag{Name: "states"}, + &console.StringFlag{Name: "syslog-host"}, + &console.StringFlag{Name: "syslog-port"}, + &console.StringFlag{Name: "token"}, + &console.StringFlag{Name: "type"}, + &console.StringFlag{Name: "url"}, + &console.StringFlag{Name: "username"}, + &console.BoolFlag{Name: "verify-tls", DefaultValue: true}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:integration", Name: "validate", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "integration:validate", Hidden: true}, {Name: "upsun:integration:validate", Hidden: true}, }, - Usage: "Validate an existing integration", - Flags: []console.Flag{ - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Validate an existing integration", + Flags: []console.Flag{ + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:metrics", Name: "all", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "metrics:all", Hidden: true}, {Name: "upsun:metrics:all", Hidden: true}, {Name: "cloud:metrics"}, @@ -1433,104 +1444,105 @@ var Commands = []*console.Command{ {Name: "upsun:met", Hidden: true}, {Name: "met", Hidden: true}, }, - Usage: "Show CPU, disk and memory metrics for an environment", - Flags: []console.Flag{ - &console.BoolFlag{Name: "bytes", Aliases: []string{"B"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "interval", Aliases: []string{"i"},}, - &console.BoolFlag{Name: "latest", Aliases: []string{"1"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "range", Aliases: []string{"r"},}, - &console.StringFlag{Name: "service", Aliases: []string{"s"},}, - &console.StringFlag{Name: "to",}, - &console.StringFlag{Name: "type",}, + Usage: "Show CPU, disk and memory metrics for an environment", + Flags: []console.Flag{ + &console.BoolFlag{Name: "bytes", Aliases: []string{"B"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "interval", Aliases: []string{"i"}}, + &console.BoolFlag{Name: "latest", Aliases: []string{"1"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "range", Aliases: []string{"r"}}, + &console.StringFlag{Name: "service", Aliases: []string{"s"}}, + &console.StringFlag{Name: "to"}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:metrics", Name: "cpu", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "metrics:cpu", Hidden: true}, {Name: "upsun:metrics:cpu", Hidden: true}, {Name: "cloud:cpu"}, {Name: "upsun:cpu", Hidden: true}, {Name: "cpu", Hidden: true}, }, - Usage: "Show CPU usage of an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "interval", Aliases: []string{"i"},}, - &console.BoolFlag{Name: "latest", Aliases: []string{"1"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "range", Aliases: []string{"r"},}, - &console.StringFlag{Name: "service", Aliases: []string{"s"},}, - &console.StringFlag{Name: "to",}, - &console.StringFlag{Name: "type",}, + Usage: "Show CPU usage of an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "interval", Aliases: []string{"i"}}, + &console.BoolFlag{Name: "latest", Aliases: []string{"1"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "range", Aliases: []string{"r"}}, + &console.StringFlag{Name: "service", Aliases: []string{"s"}}, + &console.StringFlag{Name: "to"}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:metrics", Name: "curl", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "metrics:curl", Hidden: true}, {Name: "upsun:metrics:curl", Hidden: true}, }, - Usage: "Run an authenticated cURL request on an environment's metrics API", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "data", Aliases: []string{"d"},}, - &console.BoolFlag{Name: "disable-compression",}, - &console.BoolFlag{Name: "enable-glob",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "fail", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "head", Aliases: []string{"I"},}, - &console.StringFlag{Name: "header", Aliases: []string{"H"},}, - &console.BoolFlag{Name: "include", Aliases: []string{"i"},}, - &console.StringFlag{Name: "json",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "request", Aliases: []string{"X"},}, + Usage: "Run an authenticated cURL request on an environment's metrics API", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "data", Aliases: []string{"d"}}, + &console.BoolFlag{Name: "disable-compression"}, + &console.BoolFlag{Name: "enable-glob"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "fail", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "head", Aliases: []string{"I"}}, + &console.StringFlag{Name: "header", Aliases: []string{"H"}}, + &console.BoolFlag{Name: "include", Aliases: []string{"i"}}, + &console.StringFlag{Name: "json"}, + &console.BoolFlag{Name: "no-retry-401"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "request", Aliases: []string{"X"}}, }, }, { Category: "cloud:metrics", Name: "disk-usage", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "metrics:disk-usage", Hidden: true}, {Name: "upsun:metrics:disk-usage", Hidden: true}, {Name: "cloud:disk"}, {Name: "upsun:disk", Hidden: true}, {Name: "disk", Hidden: true}, }, - Usage: "Show disk usage of an environment", - Flags: []console.Flag{ - &console.BoolFlag{Name: "bytes", Aliases: []string{"B"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "interval", Aliases: []string{"i"},}, - &console.BoolFlag{Name: "latest", Aliases: []string{"1"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "range", Aliases: []string{"r"},}, - &console.StringFlag{Name: "service", Aliases: []string{"s"},}, - &console.BoolFlag{Name: "tmp",}, - &console.StringFlag{Name: "to",}, - &console.StringFlag{Name: "type",}, + Usage: "Show disk usage of an environment", + Flags: []console.Flag{ + &console.BoolFlag{Name: "bytes", Aliases: []string{"B"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "interval", Aliases: []string{"i"}}, + &console.BoolFlag{Name: "latest", Aliases: []string{"1"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "range", Aliases: []string{"r"}}, + &console.StringFlag{Name: "service", Aliases: []string{"s"}}, + &console.BoolFlag{Name: "tmp"}, + &console.StringFlag{Name: "to"}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:metrics", Name: "memory", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "metrics:memory", Hidden: true}, {Name: "upsun:metrics:memory", Hidden: true}, {Name: "cloud:mem"}, @@ -1540,237 +1552,239 @@ var Commands = []*console.Command{ {Name: "upsun:memory", Hidden: true}, {Name: "memory", Hidden: true}, }, - Usage: "Show memory usage of an environment", - Flags: []console.Flag{ - &console.BoolFlag{Name: "bytes", Aliases: []string{"B"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "interval", Aliases: []string{"i"},}, - &console.BoolFlag{Name: "latest", Aliases: []string{"1"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "range", Aliases: []string{"r"},}, - &console.StringFlag{Name: "service", Aliases: []string{"s"},}, - &console.StringFlag{Name: "to",}, - &console.StringFlag{Name: "type",}, + Usage: "Show memory usage of an environment", + Flags: []console.Flag{ + &console.BoolFlag{Name: "bytes", Aliases: []string{"B"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "interval", Aliases: []string{"i"}}, + &console.BoolFlag{Name: "latest", Aliases: []string{"1"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "range", Aliases: []string{"r"}}, + &console.StringFlag{Name: "service", Aliases: []string{"s"}}, + &console.StringFlag{Name: "to"}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:mount", Name: "download", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "mount:download", Hidden: true}, {Name: "upsun:mount:download", Hidden: true}, }, - Usage: "Download files from a mount, using rsync", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.BoolFlag{Name: "delete",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude",}, - &console.StringFlag{Name: "include",}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.StringFlag{Name: "mount", Aliases: []string{"m"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, - &console.BoolFlag{Name: "source-path",}, - &console.StringFlag{Name: "target",}, - &console.StringFlag{Name: "worker",}, + Usage: "Download files from a mount, using rsync", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.BoolFlag{Name: "delete"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude"}, + &console.StringFlag{Name: "include"}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.StringFlag{Name: "mount", Aliases: []string{"m"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, + &console.BoolFlag{Name: "source-path"}, + &console.StringFlag{Name: "target"}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:mount", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "mount:list", Hidden: true}, {Name: "upsun:mount:list", Hidden: true}, {Name: "cloud:mounts"}, {Name: "upsun:mounts", Hidden: true}, {Name: "mounts", Hidden: true}, }, - Usage: "Get a list of mounts", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "paths",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, - &console.StringFlag{Name: "worker",}, + Usage: "Get a list of mounts", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "paths"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:mount", Name: "upload", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "mount:upload", Hidden: true}, {Name: "upsun:mount:upload", Hidden: true}, }, - Usage: "Upload files to a mount, using rsync", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.BoolFlag{Name: "delete",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "exclude",}, - &console.StringFlag{Name: "include",}, - &console.StringFlag{Name: "instance", Aliases: []string{"I"},}, - &console.StringFlag{Name: "mount", Aliases: []string{"m"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, - &console.StringFlag{Name: "source",}, - &console.StringFlag{Name: "worker",}, + Usage: "Upload files to a mount, using rsync", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.BoolFlag{Name: "delete"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "exclude"}, + &console.StringFlag{Name: "include"}, + &console.StringFlag{Name: "instance", Aliases: []string{"I"}}, + &console.StringFlag{Name: "mount", Aliases: []string{"m"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, + &console.StringFlag{Name: "source"}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:operation", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "operation:list", Hidden: true}, {Name: "upsun:operation:list", Hidden: true}, {Name: "cloud:ops"}, {Name: "upsun:ops", Hidden: true}, {Name: "ops", Hidden: true}, }, - Usage: "List runtime operations on an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "full",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "worker",}, + Usage: "List runtime operations on an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "full"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:operation", Name: "run", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "operation:run", Hidden: true}, {Name: "upsun:operation:run", Hidden: true}, }, - Usage: "Run an operation on the environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, - &console.StringFlag{Name: "worker",}, + Usage: "Run an operation on the environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:organization", Name: "billing:address", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:billing:address", Hidden: true}, {Name: "upsun:organization:billing:address", Hidden: true}, }, - Usage: "View or change an organization's billing address", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "View or change an organization's billing address", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:organization", Name: "billing:profile", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:billing:profile", Hidden: true}, {Name: "upsun:organization:billing:profile", Hidden: true}, }, - Usage: "View or change an organization's billing profile", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "View or change an organization's billing profile", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:organization", Name: "create", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:create", Hidden: true}, {Name: "upsun:organization:create", Hidden: true}, }, - Usage: "Create a new organization", - Flags: []console.Flag{ - &console.StringFlag{Name: "country",}, - &console.StringFlag{Name: "label",}, - &console.StringFlag{Name: "name",}, + Usage: "Create a new organization", + Flags: []console.Flag{ + &console.StringFlag{Name: "country"}, + &console.StringFlag{Name: "label"}, + &console.StringFlag{Name: "name"}, }, }, { Category: "cloud:organization", Name: "curl", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:curl", Hidden: true}, {Name: "upsun:organization:curl", Hidden: true}, }, - Usage: "Run an authenticated cURL request on an organization's API", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "data", Aliases: []string{"d"},}, - &console.BoolFlag{Name: "disable-compression",}, - &console.BoolFlag{Name: "enable-glob",}, - &console.BoolFlag{Name: "fail", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "head", Aliases: []string{"I"},}, - &console.StringFlag{Name: "header", Aliases: []string{"H"},}, - &console.BoolFlag{Name: "include", Aliases: []string{"i"},}, - &console.StringFlag{Name: "json",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "request", Aliases: []string{"X"},}, + Usage: "Run an authenticated cURL request on an organization's API", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "data", Aliases: []string{"d"}}, + &console.BoolFlag{Name: "disable-compression"}, + &console.BoolFlag{Name: "enable-glob"}, + &console.BoolFlag{Name: "fail", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "head", Aliases: []string{"I"}}, + &console.StringFlag{Name: "header", Aliases: []string{"H"}}, + &console.BoolFlag{Name: "include", Aliases: []string{"i"}}, + &console.StringFlag{Name: "json"}, + &console.BoolFlag{Name: "no-retry-401"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "request", Aliases: []string{"X"}}, }, }, { Category: "cloud:organization", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:delete", Hidden: true}, {Name: "upsun:organization:delete", Hidden: true}, }, - Usage: "Delete an organization", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Delete an organization", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:organization", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:info", Hidden: true}, {Name: "upsun:organization:info", Hidden: true}, }, - Usage: "View or change organization details", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "View or change organization details", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:organization", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:list", Hidden: true}, {Name: "upsun:organization:list", Hidden: true}, {Name: "cloud:orgs"}, @@ -1780,244 +1794,246 @@ var Commands = []*console.Command{ {Name: "upsun:organizations", Hidden: true}, {Name: "organizations", Hidden: true}, }, - Usage: "List organizations", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "my",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "reverse",}, - &console.StringFlag{Name: "sort",}, + Usage: "List organizations", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "my"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "reverse"}, + &console.StringFlag{Name: "sort"}, }, }, { Category: "cloud:organization", Name: "subscription:list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:subscription:list", Hidden: true}, {Name: "upsun:organization:subscription:list", Hidden: true}, {Name: "cloud:org:subs"}, {Name: "upsun:org:subs", Hidden: true}, {Name: "org:subs", Hidden: true}, }, - Usage: "List subscriptions within an organization", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns",}, - &console.StringFlag{Name: "count", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "page",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List subscriptions within an organization", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns"}, + &console.StringFlag{Name: "count", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "page"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:organization", Name: "user:add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:user:add", Hidden: true}, {Name: "upsun:organization:user:add", Hidden: true}, }, - Usage: "Invite a user to an organization", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "permission",}, + Usage: "Invite a user to an organization", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "permission"}, }, }, { Category: "cloud:organization", Name: "user:delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:user:delete", Hidden: true}, {Name: "upsun:organization:user:delete", Hidden: true}, }, - Usage: "Remove a user from an organization", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, + Usage: "Remove a user from an organization", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, }, }, { Category: "cloud:organization", Name: "user:get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:user:get", Hidden: true}, {Name: "upsun:organization:user:get", Hidden: true}, }, - Usage: "View an organization user", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View an organization user", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:organization", Name: "user:list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:user:list", Hidden: true}, {Name: "upsun:organization:user:list", Hidden: true}, {Name: "cloud:org:users"}, {Name: "upsun:org:users", Hidden: true}, {Name: "org:users", Hidden: true}, }, - Usage: "List organization users", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns",}, - &console.StringFlag{Name: "count", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.BoolFlag{Name: "reverse",}, - &console.StringFlag{Name: "sort", DefaultValue: "created_at",}, + Usage: "List organization users", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns"}, + &console.StringFlag{Name: "count", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.BoolFlag{Name: "reverse"}, + &console.StringFlag{Name: "sort", DefaultValue: "created_at"}, }, }, { Category: "cloud:organization", Name: "user:projects", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:user:projects", Hidden: true}, {Name: "upsun:organization:user:projects", Hidden: true}, {Name: "cloud:oups"}, {Name: "upsun:oups", Hidden: true}, {Name: "oups", Hidden: true}, }, - Usage: "List the projects a user can access", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "list-all",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, + Usage: "List the projects a user can access", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "list-all"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, }, }, { Category: "cloud:organization", Name: "user:update", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "organization:user:update", Hidden: true}, {Name: "upsun:organization:user:update", Hidden: true}, }, - Usage: "Update an organization user", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "permission",}, + Usage: "Update an organization user", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "permission"}, }, }, { Category: "cloud:project", Name: "clear-build-cache", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:clear-build-cache", Hidden: true}, {Name: "upsun:project:clear-build-cache", Hidden: true}, }, - Usage: "Clear a project's build cache", - Flags: []console.Flag{ - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Clear a project's build cache", + Flags: []console.Flag{ + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:project", Name: "create", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:create", Hidden: true}, {Name: "upsun:project:create", Hidden: true}, {Name: "cloud:create"}, {Name: "upsun:create", Hidden: true}, {Name: "create", Hidden: true}, }, - Usage: "Create a new project", - Flags: []console.Flag{ - &console.StringFlag{Name: "default-branch", DefaultValue: "main",}, - &console.StringFlag{Name: "environments",}, - &console.BoolFlag{Name: "no-set-remote",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "plan",}, - &console.StringFlag{Name: "region",}, - &console.BoolFlag{Name: "set-remote",}, - &console.StringFlag{Name: "storage",}, - &console.StringFlag{Name: "title", DefaultValue: "Untitled Project",}, + Usage: "Create a new project", + Flags: []console.Flag{ + &console.StringFlag{Name: "default-branch", DefaultValue: "main"}, + &console.StringFlag{Name: "environments"}, + &console.StringFlag{Name: "init-repo"}, + &console.BoolFlag{Name: "no-set-remote"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "plan"}, + &console.StringFlag{Name: "region"}, + &console.BoolFlag{Name: "set-remote"}, + &console.StringFlag{Name: "storage"}, + &console.StringFlag{Name: "title", DefaultValue: "Untitled Project"}, }, }, { Category: "cloud:project", Name: "curl", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:curl", Hidden: true}, {Name: "upsun:project:curl", Hidden: true}, }, - Usage: "Run an authenticated cURL request on a project's API", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "data", Aliases: []string{"d"},}, - &console.BoolFlag{Name: "disable-compression",}, - &console.BoolFlag{Name: "enable-glob",}, - &console.BoolFlag{Name: "fail", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "head", Aliases: []string{"I"},}, - &console.StringFlag{Name: "header", Aliases: []string{"H"},}, - &console.BoolFlag{Name: "include", Aliases: []string{"i"},}, - &console.StringFlag{Name: "json",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "request", Aliases: []string{"X"},}, + Usage: "Run an authenticated cURL request on a project's API", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "data", Aliases: []string{"d"}}, + &console.BoolFlag{Name: "disable-compression"}, + &console.BoolFlag{Name: "enable-glob"}, + &console.BoolFlag{Name: "fail", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "head", Aliases: []string{"I"}}, + &console.StringFlag{Name: "header", Aliases: []string{"H"}}, + &console.BoolFlag{Name: "include", Aliases: []string{"i"}}, + &console.StringFlag{Name: "json"}, + &console.BoolFlag{Name: "no-retry-401"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "request", Aliases: []string{"X"}}, }, }, { Category: "cloud:project", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:delete", Hidden: true}, {Name: "upsun:project:delete", Hidden: true}, }, - Usage: "Delete a project", - Flags: []console.Flag{ - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Delete a project", + Flags: []console.Flag{ + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:project", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:get", Hidden: true}, {Name: "upsun:project:get", Hidden: true}, {Name: "cloud:get"}, {Name: "upsun:get", Hidden: true}, {Name: "get", Hidden: true}, }, - Usage: "Clone a project locally", - Flags: []console.Flag{ - &console.BoolFlag{Name: "build",}, - &console.StringFlag{Name: "depth",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Clone a project locally", + Flags: []console.Flag{ + &console.BoolFlag{Name: "build"}, + &console.StringFlag{Name: "depth"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:project", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:info", Hidden: true}, {Name: "upsun:project:info", Hidden: true}, }, - Usage: "Read or set properties for a project", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Read or set properties for a project", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:project", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:list", Hidden: true}, {Name: "upsun:project:list", Hidden: true}, {Name: "cloud:projects"}, @@ -2027,88 +2043,127 @@ var Commands = []*console.Command{ {Name: "upsun:pro", Hidden: true}, {Name: "pro", Hidden: true}, }, - Usage: "Get a list of all active projects", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns",}, - &console.StringFlag{Name: "count", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "my",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "page",}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "refresh",}, - &console.StringFlag{Name: "region",}, - &console.BoolFlag{Name: "reverse",}, - &console.StringFlag{Name: "sort", DefaultValue: "title",}, - &console.StringFlag{Name: "title",}, + Usage: "Get a list of all active projects", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns"}, + &console.StringFlag{Name: "count", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "my"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "page"}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "refresh"}, + &console.StringFlag{Name: "region"}, + &console.BoolFlag{Name: "reverse"}, + &console.StringFlag{Name: "sort", DefaultValue: "title"}, + &console.StringFlag{Name: "title"}, }, }, { Category: "cloud:project", Name: "set-remote", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "project:set-remote", Hidden: true}, {Name: "upsun:project:set-remote", Hidden: true}, {Name: "cloud:set-remote"}, {Name: "upsun:set-remote", Hidden: true}, {Name: "set-remote", Hidden: true}, }, - Usage: "Set the remote project for the current Git repository", + Usage: "Set the remote project for the current Git repository", }, { Category: "cloud:repo", Name: "cat", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "repo:cat", Hidden: true}, {Name: "upsun:repo:cat", Hidden: true}, }, - Usage: "Read a file in the project repository", - Flags: []console.Flag{ - &console.StringFlag{Name: "commit", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Read a file in the project repository", + Flags: []console.Flag{ + &console.StringFlag{Name: "commit", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:repo", Name: "ls", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "repo:ls", Hidden: true}, {Name: "upsun:repo:ls", Hidden: true}, }, - Usage: "List files in the project repository", - Flags: []console.Flag{ - &console.StringFlag{Name: "commit", Aliases: []string{"c"},}, - &console.BoolFlag{Name: "directories", Aliases: []string{"d"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "files", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "git-style",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List files in the project repository", + Flags: []console.Flag{ + &console.StringFlag{Name: "commit", Aliases: []string{"c"}}, + &console.BoolFlag{Name: "directories", Aliases: []string{"d"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "files", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "git-style"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:repo", Name: "read", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "repo:read", Hidden: true}, {Name: "upsun:repo:read", Hidden: true}, {Name: "cloud:read"}, {Name: "upsun:read", Hidden: true}, {Name: "read", Hidden: true}, }, - Usage: "Read a directory or file in the project repository", - Flags: []console.Flag{ - &console.StringFlag{Name: "commit", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Read a directory or file in the project repository", + Flags: []console.Flag{ + &console.StringFlag{Name: "commit", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + }, + }, + { + Category: "cloud:resources", + Name: "build:get", + Aliases: []*console.Alias{ + {Name: "resources:build:get", Hidden: true}, + {Name: "upsun:resources:build:get", Hidden: true}, + {Name: "cloud:build-resources:get"}, + {Name: "upsun:build-resources:get", Hidden: true}, + {Name: "build-resources:get", Hidden: true}, + {Name: "cloud:build-resources"}, + {Name: "upsun:build-resources", Hidden: true}, + {Name: "build-resources", Hidden: true}, + }, + Usage: "View the build resources of a project", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + }, + }, + { + Category: "cloud:resources", + Name: "build:set", + Aliases: []*console.Alias{ + {Name: "resources:build:set", Hidden: true}, + {Name: "upsun:resources:build:set", Hidden: true}, + {Name: "cloud:build-resources:set"}, + {Name: "upsun:build-resources:set", Hidden: true}, + {Name: "build-resources:set", Hidden: true}, + }, + Usage: "Set the build resources of a project", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "cpu"}, + &console.StringFlag{Name: "memory"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:resources", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "resources:get", Hidden: true}, {Name: "upsun:resources:get", Hidden: true}, {Name: "cloud:resources"}, @@ -2118,464 +2173,483 @@ var Commands = []*console.Command{ {Name: "upsun:res", Hidden: true}, {Name: "res", Hidden: true}, }, - Usage: "View the resources of apps and services on an environment", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "app",}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "service", Aliases: []string{"s"},}, - &console.StringFlag{Name: "type",}, - &console.StringFlag{Name: "worker",}, + Usage: "View the resources of apps and services on an environment", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "app"}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "service", Aliases: []string{"s"}}, + &console.StringFlag{Name: "type"}, + &console.StringFlag{Name: "worker"}, }, }, { Category: "cloud:resources", Name: "set", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "resources:set", Hidden: true}, {Name: "upsun:resources:set", Hidden: true}, }, - Usage: "Set the resources of apps and services on an environment", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "count", Aliases: []string{"C"},}, - &console.StringFlag{Name: "disk", Aliases: []string{"D"},}, - &console.BoolFlag{Name: "dry-run",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "force", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "size", Aliases: []string{"S"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Set the resources of apps and services on an environment", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "count", Aliases: []string{"C"}}, + &console.StringFlag{Name: "disk", Aliases: []string{"D"}}, + &console.BoolFlag{Name: "dry-run"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "force", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "size", Aliases: []string{"S"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:resources", Name: "size:list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "resources:size:list", Hidden: true}, {Name: "upsun:resources:size:list", Hidden: true}, {Name: "cloud:resources:sizes"}, {Name: "upsun:resources:sizes", Hidden: true}, {Name: "resources:sizes", Hidden: true}, }, - Usage: "List container profile sizes", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "profile",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "service", Aliases: []string{"s"},}, + Usage: "List container profile sizes", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "profile"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "service", Aliases: []string{"s"}}, }, }, { Category: "cloud:route", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "route:get", Hidden: true}, {Name: "upsun:route:get", Hidden: true}, }, - Usage: "View detailed information about a route", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "id",}, - &console.StringFlag{Name: "identity-file", Aliases: []string{"i"},}, - &console.BoolFlag{Name: "primary", Aliases: []string{"1"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "View detailed information about a route", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "id"}, + &console.StringFlag{Name: "identity-file", Aliases: []string{"i"}}, + &console.BoolFlag{Name: "primary", Aliases: []string{"1"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:route", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "route:list", Hidden: true}, {Name: "upsun:route:list", Hidden: true}, {Name: "cloud:routes"}, {Name: "upsun:routes", Hidden: true}, {Name: "routes", Hidden: true}, }, - Usage: "List all routes for an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "List all routes for an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:self", Name: "config", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "upsun:self:config", Hidden: true}, }, - Usage: "Read CLI config", - Hidden: console.Hide, + Usage: "Read CLI config", + Hidden: console.Hide, }, { Category: "cloud:service", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "service:list", Hidden: true}, {Name: "upsun:service:list", Hidden: true}, {Name: "cloud:services"}, {Name: "upsun:services", Hidden: true}, {Name: "services", Hidden: true}, }, - Usage: "List services in the project", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "List services in the project", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, }, }, { Category: "cloud:service", Name: "mongo:dump", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "service:mongo:dump", Hidden: true}, {Name: "upsun:service:mongo:dump", Hidden: true}, {Name: "cloud:mongodump"}, {Name: "upsun:mongodump", Hidden: true}, {Name: "mongodump", Hidden: true}, }, - Usage: "Create a binary archive dump of data from MongoDB", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "collection", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "gzip", Aliases: []string{"z"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, - &console.BoolFlag{Name: "stdout", Aliases: []string{"o"},}, + Usage: "Create a binary archive dump of data from MongoDB", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "collection", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "gzip", Aliases: []string{"z"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, + &console.BoolFlag{Name: "stdout", Aliases: []string{"o"}}, }, }, { Category: "cloud:service", Name: "mongo:export", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "service:mongo:export", Hidden: true}, {Name: "upsun:service:mongo:export", Hidden: true}, {Name: "cloud:mongoexport"}, {Name: "upsun:mongoexport", Hidden: true}, {Name: "mongoexport", Hidden: true}, }, - Usage: "Export data from MongoDB", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "collection", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "fields", Aliases: []string{"f"},}, - &console.BoolFlag{Name: "jsonArray",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, - &console.StringFlag{Name: "type",}, + Usage: "Export data from MongoDB", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "collection", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "fields", Aliases: []string{"f"}}, + &console.BoolFlag{Name: "jsonArray"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, + &console.StringFlag{Name: "type"}, }, }, { Category: "cloud:service", Name: "mongo:restore", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "service:mongo:restore", Hidden: true}, {Name: "upsun:service:mongo:restore", Hidden: true}, {Name: "cloud:mongorestore"}, {Name: "upsun:mongorestore", Hidden: true}, {Name: "mongorestore", Hidden: true}, }, - Usage: "Restore a binary archive dump of data into MongoDB", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "collection", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, + Usage: "Restore a binary archive dump of data into MongoDB", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "collection", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, }, }, { Category: "cloud:service", Name: "mongo:shell", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "service:mongo:shell", Hidden: true}, {Name: "upsun:service:mongo:shell", Hidden: true}, {Name: "cloud:mongo"}, {Name: "upsun:mongo", Hidden: true}, {Name: "mongo", Hidden: true}, }, - Usage: "Use the MongoDB shell", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "eval",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, + Usage: "Use the MongoDB shell", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "eval"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, }, }, { Category: "cloud:service", Name: "redis-cli", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "service:redis-cli", Hidden: true}, {Name: "upsun:service:redis-cli", Hidden: true}, {Name: "cloud:redis"}, {Name: "upsun:redis", Hidden: true}, {Name: "redis", Hidden: true}, }, - Usage: "Access the Redis CLI", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, + Usage: "Access the Redis CLI", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, + }, + }, + { + Category: "cloud:service", + Name: "valkey-cli", + Aliases: []*console.Alias{ + {Name: "service:valkey-cli", Hidden: true}, + {Name: "upsun:service:valkey-cli", Hidden: true}, + {Name: "cloud:valkey"}, + {Name: "upsun:valkey", Hidden: true}, + {Name: "valkey", Hidden: true}, + }, + Usage: "Access the Valkey CLI", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, }, }, { Category: "cloud:session", Name: "switch", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "session:switch", Hidden: true}, {Name: "upsun:session:switch", Hidden: true}, }, - Usage: "BETA Switch between sessions", - Hidden: console.Hide, + Usage: "BETA Switch between sessions", + Hidden: console.Hide, }, { Category: "cloud:source-operation", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "source-operation:list", Hidden: true}, {Name: "upsun:source-operation:list", Hidden: true}, {Name: "cloud:source-ops"}, {Name: "upsun:source-ops", Hidden: true}, {Name: "source-ops", Hidden: true}, }, - Usage: "List source operations on an environment", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "full",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List source operations on an environment", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "full"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:source-operation", Name: "run", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "source-operation:run", Hidden: true}, {Name: "upsun:source-operation:run", Hidden: true}, }, - Usage: "Run a source operation", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "variable",}, - &console.BoolFlag{Name: "wait",}, + Usage: "Run a source operation", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "variable"}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:ssh-cert", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "ssh-cert:info", Hidden: true}, {Name: "upsun:ssh-cert:info", Hidden: true}, }, - Usage: "Display information about the current SSH certificate", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.BoolFlag{Name: "no-refresh",}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "Display information about the current SSH certificate", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.BoolFlag{Name: "no-refresh"}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:ssh-cert", Name: "load", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "ssh-cert:load", Hidden: true}, {Name: "upsun:ssh-cert:load", Hidden: true}, }, - Usage: "Generate an SSH certificate", - Flags: []console.Flag{ - &console.BoolFlag{Name: "new",}, - &console.BoolFlag{Name: "new-key",}, - &console.BoolFlag{Name: "refresh-only",}, + Usage: "Generate an SSH certificate", + Flags: []console.Flag{ + &console.BoolFlag{Name: "new"}, + &console.BoolFlag{Name: "new-key"}, + &console.BoolFlag{Name: "refresh-only"}, }, }, { Category: "cloud:ssh-key", Name: "add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "ssh-key:add", Hidden: true}, {Name: "upsun:ssh-key:add", Hidden: true}, }, - Usage: "Add a new SSH key", - Flags: []console.Flag{ - &console.StringFlag{Name: "name",}, + Usage: "Add a new SSH key", + Flags: []console.Flag{ + &console.StringFlag{Name: "name"}, }, }, { Category: "cloud:ssh-key", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "ssh-key:delete", Hidden: true}, {Name: "upsun:ssh-key:delete", Hidden: true}, }, - Usage: "Delete an SSH key", + Usage: "Delete an SSH key", }, { Category: "cloud:ssh-key", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "ssh-key:list", Hidden: true}, {Name: "upsun:ssh-key:list", Hidden: true}, {Name: "cloud:ssh-keys"}, {Name: "upsun:ssh-keys", Hidden: true}, {Name: "ssh-keys", Hidden: true}, }, - Usage: "Get a list of SSH keys in your account", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, + Usage: "Get a list of SSH keys in your account", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, }, }, { Category: "cloud:subscription", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "subscription:info", Hidden: true}, {Name: "upsun:subscription:info", Hidden: true}, }, - Usage: "Read or modify subscription properties", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "id", Aliases: []string{"s"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Read or modify subscription properties", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "id", Aliases: []string{"s"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:team", Name: "create", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:create", Hidden: true}, {Name: "upsun:team:create", Hidden: true}, }, - Usage: "Create a new team", - Flags: []console.Flag{ - &console.StringFlag{Name: "label",}, - &console.BoolFlag{Name: "no-check-unique",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.BoolFlag{Name: "output-id",}, - &console.StringFlag{Name: "role", Aliases: []string{"r"},}, + Usage: "Create a new team", + Flags: []console.Flag{ + &console.StringFlag{Name: "label"}, + &console.BoolFlag{Name: "no-check-unique"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.BoolFlag{Name: "output-id"}, + &console.StringFlag{Name: "role", Aliases: []string{"r"}}, }, }, { Category: "cloud:team", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:delete", Hidden: true}, {Name: "upsun:team:delete", Hidden: true}, }, - Usage: "Delete a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "Delete a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:get", Hidden: true}, {Name: "upsun:team:get", Hidden: true}, }, - Usage: "View a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "View a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:list", Hidden: true}, {Name: "upsun:team:list", Hidden: true}, {Name: "cloud:teams"}, {Name: "upsun:teams", Hidden: true}, {Name: "teams", Hidden: true}, }, - Usage: "List teams", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns",}, - &console.StringFlag{Name: "count", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "reverse",}, - &console.StringFlag{Name: "sort", DefaultValue: "label",}, + Usage: "List teams", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"A"}}, + &console.StringFlag{Name: "columns"}, + &console.StringFlag{Name: "count", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "reverse"}, + &console.StringFlag{Name: "sort", DefaultValue: "label"}, }, }, { Category: "cloud:team", Name: "project:add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:project:add", Hidden: true}, {Name: "upsun:team:project:add", Hidden: true}, }, - Usage: "Add project(s) to a team", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "Add project(s) to a team", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "project:delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:project:delete", Hidden: true}, {Name: "upsun:team:project:delete", Hidden: true}, }, - Usage: "Remove a project from a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "Remove a project from a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "project:list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:project:list", Hidden: true}, {Name: "upsun:team:project:list", Hidden: true}, {Name: "cloud:team:projects"}, @@ -2585,315 +2659,315 @@ var Commands = []*console.Command{ {Name: "upsun:team:pro", Hidden: true}, {Name: "team:pro", Hidden: true}, }, - Usage: "List projects in a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns",}, - &console.StringFlag{Name: "count", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "List projects in a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns"}, + &console.StringFlag{Name: "count", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "update", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:update", Hidden: true}, {Name: "upsun:team:update", Hidden: true}, }, - Usage: "Update a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "label",}, - &console.BoolFlag{Name: "no-check-unique",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "role", Aliases: []string{"r"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Update a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "label"}, + &console.BoolFlag{Name: "no-check-unique"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "role", Aliases: []string{"r"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:team", Name: "user:add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:user:add", Hidden: true}, {Name: "upsun:team:user:add", Hidden: true}, }, - Usage: "Add a user to a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "Add a user to a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "user:delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:user:delete", Hidden: true}, {Name: "upsun:team:user:delete", Hidden: true}, }, - Usage: "Remove a user from a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "Remove a user from a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:team", Name: "user:list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "team:user:list", Hidden: true}, {Name: "upsun:team:user:list", Hidden: true}, {Name: "cloud:team:users"}, {Name: "upsun:team:users", Hidden: true}, {Name: "team:users", Hidden: true}, }, - Usage: "List users in a team", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns",}, - &console.StringFlag{Name: "count", Aliases: []string{"c"},}, - &console.StringFlag{Name: "date-fmt", DefaultValue: "c",}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "org", Aliases: []string{"o"},}, - &console.StringFlag{Name: "team", Aliases: []string{"t"},}, + Usage: "List users in a team", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns"}, + &console.StringFlag{Name: "count", Aliases: []string{"c"}}, + &console.StringFlag{Name: "date-fmt", DefaultValue: "c"}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "org", Aliases: []string{"o"}}, + &console.StringFlag{Name: "team", Aliases: []string{"t"}}, }, }, { Category: "cloud:tunnel", Name: "close", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "tunnel:close", Hidden: true}, {Name: "upsun:tunnel:close", Hidden: true}, }, - Usage: "Close SSH tunnels", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Close SSH tunnels", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:tunnel", Name: "info", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "tunnel:info", Hidden: true}, {Name: "upsun:tunnel:info", Hidden: true}, }, - Usage: "View relationship info for SSH tunnels", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.BoolFlag{Name: "encode", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View relationship info for SSH tunnels", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.BoolFlag{Name: "encode", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:tunnel", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "tunnel:list", Hidden: true}, {Name: "upsun:tunnel:list", Hidden: true}, {Name: "cloud:tunnels"}, {Name: "upsun:tunnels", Hidden: true}, {Name: "tunnels", Hidden: true}, }, - Usage: "List SSH tunnels", - Flags: []console.Flag{ - &console.BoolFlag{Name: "all", Aliases: []string{"a"},}, - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List SSH tunnels", + Flags: []console.Flag{ + &console.BoolFlag{Name: "all", Aliases: []string{"a"}}, + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:tunnel", Name: "open", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "tunnel:open", Hidden: true}, {Name: "upsun:tunnel:open", Hidden: true}, }, - Usage: "Open SSH tunnels to an app's relationships", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "gateway-ports", Aliases: []string{"g"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "Open SSH tunnels to an app's relationships", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "gateway-ports", Aliases: []string{"g"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:tunnel", Name: "single", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "tunnel:single", Hidden: true}, {Name: "upsun:tunnel:single", Hidden: true}, }, - Usage: "Open a single SSH tunnel to an app relationship", - Flags: []console.Flag{ - &console.StringFlag{Name: "app", Aliases: []string{"A"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "gateway-ports", Aliases: []string{"g"},}, - &console.StringFlag{Name: "port",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "relationship", Aliases: []string{"r"},}, + Usage: "Open a single SSH tunnel to an app relationship", + Flags: []console.Flag{ + &console.StringFlag{Name: "app", Aliases: []string{"A"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "gateway-ports", Aliases: []string{"g"}}, + &console.StringFlag{Name: "port"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "relationship", Aliases: []string{"r"}}, }, }, { Category: "cloud:user", Name: "add", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "user:add", Hidden: true}, {Name: "upsun:user:add", Hidden: true}, }, - Usage: "Add a user to the project", - Flags: []console.Flag{ - &console.BoolFlag{Name: "force-invite",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "role", Aliases: []string{"r"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Add a user to the project", + Flags: []console.Flag{ + &console.BoolFlag{Name: "force-invite"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "role", Aliases: []string{"r"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:user", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "user:delete", Hidden: true}, {Name: "upsun:user:delete", Hidden: true}, }, - Usage: "Delete a user from the project", - Flags: []console.Flag{ - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete a user from the project", + Flags: []console.Flag{ + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:user", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "user:get", Hidden: true}, {Name: "upsun:user:get", Hidden: true}, }, - Usage: "View a user's role(s)", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "level", Aliases: []string{"l"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "role", Aliases: []string{"r"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "View a user's role(s)", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "level", Aliases: []string{"l"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "role", Aliases: []string{"r"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:user", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "user:list", Hidden: true}, {Name: "upsun:user:list", Hidden: true}, {Name: "cloud:users"}, {Name: "upsun:users", Hidden: true}, {Name: "users", Hidden: true}, }, - Usage: "List project users", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List project users", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:user", Name: "update", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "user:update", Hidden: true}, {Name: "upsun:user:update", Hidden: true}, }, - Usage: "Update user role(s) on a project", - Flags: []console.Flag{ - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "role", Aliases: []string{"r"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Update user role(s) on a project", + Flags: []console.Flag{ + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "role", Aliases: []string{"r"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:variable", Name: "create", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "variable:create", Hidden: true}, {Name: "upsun:variable:create", Hidden: true}, }, - Usage: "Create a variable", - Flags: []console.Flag{ - &console.BoolFlag{Name: "enabled", DefaultValue: true,}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "inheritable", DefaultValue: true,}, - &console.BoolFlag{Name: "json",}, - &console.StringFlag{Name: "level", Aliases: []string{"l"},}, - &console.StringFlag{Name: "name",}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "prefix", DefaultValue: "none",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "sensitive",}, - &console.BoolFlag{Name: "update", Aliases: []string{"u"},}, - &console.StringFlag{Name: "value",}, - &console.StringFlag{Name: "visible-build",}, - &console.BoolFlag{Name: "visible-runtime", DefaultValue: true,}, - &console.BoolFlag{Name: "wait",}, + Usage: "Create a variable", + Flags: []console.Flag{ + &console.BoolFlag{Name: "enabled", DefaultValue: true}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "inheritable", DefaultValue: true}, + &console.BoolFlag{Name: "json"}, + &console.StringFlag{Name: "level", Aliases: []string{"l"}}, + &console.StringFlag{Name: "name"}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "prefix", DefaultValue: "none"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "sensitive"}, + &console.BoolFlag{Name: "update", Aliases: []string{"u"}}, + &console.StringFlag{Name: "value"}, + &console.StringFlag{Name: "visible-build"}, + &console.BoolFlag{Name: "visible-runtime", DefaultValue: true}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:variable", Name: "delete", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "variable:delete", Hidden: true}, {Name: "upsun:variable:delete", Hidden: true}, }, - Usage: "Delete a variable", - Flags: []console.Flag{ - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "level", Aliases: []string{"l"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "wait",}, + Usage: "Delete a variable", + Flags: []console.Flag{ + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "level", Aliases: []string{"l"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:variable", Name: "get", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "variable:get", Hidden: true}, {Name: "upsun:variable:get", Hidden: true}, {Name: "cloud:vget"}, {Name: "upsun:vget", Hidden: true}, {Name: "vget", Hidden: true}, }, - Usage: "View a variable", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "level", Aliases: []string{"l"},}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.StringFlag{Name: "property", Aliases: []string{"P"},}, + Usage: "View a variable", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "level", Aliases: []string{"l"}}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.StringFlag{Name: "property", Aliases: []string{"P"}}, }, }, { Category: "cloud:variable", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "variable:list", Hidden: true}, {Name: "upsun:variable:list", Hidden: true}, {Name: "cloud:variables"}, @@ -2903,79 +2977,79 @@ var Commands = []*console.Command{ {Name: "upsun:var", Hidden: true}, {Name: "var", Hidden: true}, }, - Usage: "List variables", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.StringFlag{Name: "level", Aliases: []string{"l"},}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "List variables", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.StringFlag{Name: "level", Aliases: []string{"l"}}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:variable", Name: "update", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "variable:update", Hidden: true}, {Name: "upsun:variable:update", Hidden: true}, }, - Usage: "Update a variable", - Flags: []console.Flag{ - &console.BoolFlag{Name: "allow-no-change",}, - &console.BoolFlag{Name: "enabled", DefaultValue: true,}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.BoolFlag{Name: "inheritable", DefaultValue: true,}, - &console.BoolFlag{Name: "json",}, - &console.StringFlag{Name: "level", Aliases: []string{"l"},}, - &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"},}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "sensitive",}, - &console.StringFlag{Name: "value",}, - &console.StringFlag{Name: "visible-build",}, - &console.BoolFlag{Name: "visible-runtime", DefaultValue: true,}, - &console.BoolFlag{Name: "wait",}, + Usage: "Update a variable", + Flags: []console.Flag{ + &console.BoolFlag{Name: "allow-no-change"}, + &console.BoolFlag{Name: "enabled", DefaultValue: true}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.BoolFlag{Name: "inheritable", DefaultValue: true}, + &console.BoolFlag{Name: "json"}, + &console.StringFlag{Name: "level", Aliases: []string{"l"}}, + &console.BoolFlag{Name: "no-wait", Aliases: []string{"W"}}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "sensitive"}, + &console.StringFlag{Name: "value"}, + &console.StringFlag{Name: "visible-build"}, + &console.BoolFlag{Name: "visible-runtime", DefaultValue: true}, + &console.BoolFlag{Name: "wait"}, }, }, { Category: "cloud:version", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "version:list", Hidden: true}, {Name: "upsun:version:list", Hidden: true}, {Name: "cloud:versions"}, {Name: "upsun:versions", Hidden: true}, {Name: "versions", Hidden: true}, }, - Usage: "ALPHA List environment versions", - Hidden: console.Hide, - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, + Usage: "ALPHA List environment versions", + Hidden: console.Hide, + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, }, }, { Category: "cloud:worker", Name: "list", - Aliases: []*console.Alias{ + Aliases: []*console.Alias{ {Name: "worker:list", Hidden: true}, {Name: "upsun:worker:list", Hidden: true}, {Name: "cloud:workers"}, {Name: "upsun:workers", Hidden: true}, {Name: "workers", Hidden: true}, }, - Usage: "Get a list of all deployed workers", - Flags: []console.Flag{ - &console.StringFlag{Name: "columns", Aliases: []string{"c"},}, - &console.StringFlag{Name: "environment", Aliases: []string{"e"},}, - &console.StringFlag{Name: "format", DefaultValue: "table",}, - &console.BoolFlag{Name: "no-header",}, - &console.BoolFlag{Name: "pipe",}, - &console.StringFlag{Name: "project", Aliases: []string{"p"},}, - &console.BoolFlag{Name: "refresh",}, + Usage: "Get a list of all deployed workers", + Flags: []console.Flag{ + &console.StringFlag{Name: "columns", Aliases: []string{"c"}}, + &console.StringFlag{Name: "environment", Aliases: []string{"e"}}, + &console.StringFlag{Name: "format", DefaultValue: "table"}, + &console.BoolFlag{Name: "no-header"}, + &console.BoolFlag{Name: "pipe"}, + &console.StringFlag{Name: "project", Aliases: []string{"p"}}, + &console.BoolFlag{Name: "refresh"}, }, }, } diff --git a/local/platformsh/config.go b/local/platformsh/config.go index 667fa0e2..40e42bb0 100644 --- a/local/platformsh/config.go +++ b/local/platformsh/config.go @@ -23,74 +23,74 @@ package platformsh var availablePHPExts = map[string][]string{ - "amqp": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "amqp": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "apc": {"5.4"}, - "apcu": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "apcu": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "apcu_bc": {"7.0", "7.1", "7.2", "7.3", "7.4"}, "applepay": {"7.0", "7.1", "7.3", "7.4"}, - "bcmath": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "bcmath": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "blackfire": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "bz2": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "calendar": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "ctype": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "curl": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "bz2": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "calendar": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "ctype": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "curl": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "datadog": {"8.2", "8.3"}, - "dba": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "dom": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "dba": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "dom": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "enchant": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "event": {"7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"}, - "exif": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "event": {"7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "exif": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "ffi": {"7.4", "8.0", "8.1", "8.2", "8.3"}, - "fileinfo": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "ftp": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "gd": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "fileinfo": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "ftp": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "gd": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "gearman": {"5.4", "5.5", "5.6"}, "geoip": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "gettext": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "gettext": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "gmp": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "gnupg": {"8.2", "8.3"}, "http": {"5.4", "5.5", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "iconv": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "igbinary": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "iconv": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "igbinary": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "imagick": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0"}, - "imap": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "imap": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "interbase": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"}, - "intl": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "intl": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "ioncube": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"}, "json": {"5.6", "7.0", "7.1", "7.2", "7.3", "7.4"}, "ldap": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "mailparse": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "mbstring": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "mbstring": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "mcrypt": {"5.4", "5.5", "5.6", "7.0", "7.1"}, "memcache": {"5.4", "5.5", "5.6"}, "memcached": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "mongo": {"5.4", "5.5", "5.6"}, - "mongodb": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "mongodb": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "msgpack": {"5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "mssql": {"5.4", "5.5", "5.6"}, "mysql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "mysqli": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "mysqlnd": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "mysqli": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "mysqlnd": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "newrelic": {"5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "oauth": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "odbc": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "opcache": {"5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "openswoole": {"8.2", "8.3"}, "opentelemetry": {"8.2", "8.3"}, - "pdo": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "pdo_dblib": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "pdo_firebird": {"5.4", "5.5", "5.6", "7.0", "7.1"}, - "pdo_mysql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "pdo_odbc": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "pdo_pgsql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "pdo_sqlite": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "pdo": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "pdo_dblib": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "pdo_firebird": {"5.4", "5.5", "5.6", "7.0", "7.1", "8.2", "8.3", "8.4"}, + "pdo_mysql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "pdo_odbc": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "pdo_pgsql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "pdo_sqlite": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "pdo_sqlsrv": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "pecl-http": {"5.6"}, - "pgsql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "phar": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "pgsql": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "phar": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "phpdbg": {"5.6"}, "pinba": {"5.4", "5.5", "5.6"}, - "posix": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "posix": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "propro": {"5.6"}, "protobuf": {"8.1"}, "pspell": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, @@ -99,41 +99,42 @@ var availablePHPExts = map[string][]string{ "rdkafka": {"8.1", "8.2", "8.3"}, "readline": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "recode": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3"}, - "redis": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "shmop": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "simplexml": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "redis": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "shmop": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "simplexml": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "snmp": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "soap": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "sockets": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "sodium": {"7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "sourceguardian": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"}, + "soap": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "sockets": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "sodium": {"7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "sourceguardian": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "spplus": {"5.4", "5.5"}, - "sqlite3": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "sqlite3": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "sqlsrv": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "ssh2": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "swoole": {"8.2", "8.3"}, "sybase": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "sysvmsg": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "sysvsem": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "sysvshm": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "tideways": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "sysvmsg": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "sysvsem": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "sysvshm": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "tideways": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"}, "tideways_xhprof": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1"}, "tidy": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "tokenizer": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "tokenizer": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "uuid": {"7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "uv": {"8.3"}, "wddx": {"7.0", "7.1", "7.2", "7.3", "7.4"}, "xcache": {"5.4", "5.5"}, "xdebug": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "xhprof": {"5.4", "5.5", "5.6"}, - "xml": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "xmlreader": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "xmlrpc": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "xmlwriter": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, - "xsl": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "xml": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "xmlreader": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "xmlrpc": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "xmlwriter": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, + "xsl": {"5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, "yaml": {"7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, "zbarcode": {"7.0", "7.1", "7.2", "7.3"}, "zendopcache": {"5.4"}, - "zip": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"}, + "zip": {"7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"}, } var availableServices = []*service{ @@ -169,7 +170,7 @@ var availableServices = []*service{ Type: "mariadb", Versions: serviceVersions{ Deprecated: []string{"5.5", "10.0", "10.1", "10.2", "10.3"}, - Supported: []string{"10.4", "10.5", "10.6", "10.11", "11.0", "11.2"}, + Supported: []string{"10.4", "10.5", "10.6", "10.11", "11.0", "11.2", "11.4"}, }, }, { @@ -183,14 +184,14 @@ var availableServices = []*service{ Type: "mongodb", Versions: serviceVersions{ Deprecated: []string{"3.0", "3.2", "3.4", "3.6", "4.0.3"}, - Supported: []string{}, + Supported: []string{}, }, }, { Type: "mongodb-enterprise", Versions: serviceVersions{ - Deprecated: []string{"4.0"}, - Supported: []string{"4.2", "4.4", "5.0", "6.0", "7.0"}, + Deprecated: []string{"4.0", "4.2"}, + Supported: []string{"4.4", "5.0", "6.0", "7.0"}, }, }, { @@ -225,14 +226,14 @@ var availableServices = []*service{ Type: "postgresql", Versions: serviceVersions{ Deprecated: []string{"9.3", "9.4", "9.5", "9.6", "10", "11"}, - Supported: []string{"12", "13", "14", "15", "16"}, + Supported: []string{"12", "13", "14", "15", "16", "17"}, }, }, { Type: "rabbitmq", Versions: serviceVersions{ Deprecated: []string{"3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"}, - Supported: []string{"3.12", "3.13"}, + Supported: []string{"3.12", "3.13", "4.0", "4.1"}, }, }, { @@ -246,14 +247,14 @@ var availableServices = []*service{ Type: "solr", Versions: serviceVersions{ Deprecated: []string{"3.6", "4.10", "6.3", "6.6", "7.6", "7.7", "8.0", "8.4", "8.6"}, - Supported: []string{"8.11", "9.1", "9.2", "9.4"}, + Supported: []string{"8.11", "9.1", "9.2", "9.4", "9.6"}, }, }, { Type: "varnish", Versions: serviceVersions{ Deprecated: []string{"5.1", "5.2", "6.3", "6.4", "7.1"}, - Supported: []string{"6.0", "7.2", "7.3"}, + Supported: []string{"6.0", "7.2", "7.3", "7.6"}, }, }, { diff --git a/local/platformsh/db_versions.go b/local/platformsh/db_versions.go index 36d7a038..6086d072 100644 --- a/local/platformsh/db_versions.go +++ b/local/platformsh/db_versions.go @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package platformsh import ( @@ -8,23 +27,68 @@ import ( "strings" "github.com/joho/godotenv" + "github.com/rs/zerolog" "gopkg.in/yaml.v2" ) -func ReadDBVersionFromPlatformServiceYAML(projectDir string) (string, string, error) { - servicesYAML, err := os.ReadFile(filepath.Join(projectDir, ".platform", "services.yaml")) - if err != nil { - // no services.yaml or unreadable - return "", "", err - } - var services map[string]struct { - Type string `yaml:"type"` - } - if err := yaml.Unmarshal(servicesYAML, &services); err != nil { - // services.yaml format is wrong - return "", "", err +type serviceConfigs map[string]struct { + Type string `yaml:"type"` +} + +func ReadDBVersionFromPlatformServiceYAML(projectDir string, logger zerolog.Logger) (string, string, string) { + // Platform.sh + configFile := filepath.Join(".platform", "services.yaml") + if servicesYAML, err := os.ReadFile(filepath.Join(projectDir, configFile)); err == nil { + var services serviceConfigs + if err := yaml.Unmarshal(servicesYAML, &services); err == nil { + if dbName, dbVersion, err := extractCloudDatabaseType(services); err == nil { + logger.Debug().Msg("DB configured in .platform/services.yaml") + return configFile, dbName, dbVersion + } else { + logger.Debug().Msg("No DB configured in .platform/services.yaml") + } + } else { + logger.Debug().Msg("Unable to parse .platform/services.yaml file") + } + } else { + logger.Debug().Msg("No .platform/services.yaml file found or not readable") + } + + // Upsun + upsunDir := filepath.Join(projectDir, ".upsun") + if _, err := os.Stat(upsunDir); err == nil { + if files, err := os.ReadDir(upsunDir); err == nil { + for _, file := range files { + configFile := filepath.Join(".upsun", file.Name()) + if servicesYAML, err := os.ReadFile(filepath.Join(projectDir, configFile)); err == nil { + var config struct { + Services serviceConfigs `yaml:"services"` + } + if err := yaml.Unmarshal(servicesYAML, &config); err == nil { + if dbName, dbVersion, err := extractCloudDatabaseType(config.Services); err == nil { + logger.Debug().Msgf("DB configured in %s", configFile) + return configFile, dbName, dbVersion + } else { + logger.Debug().Msgf("No DB configured in %s", configFile) + } + } else { + logger.Debug().Msgf("Unable to parse the %s file", configFile) + } + } else { + logger.Debug().Msgf("Unable to read the %s file", configFile) + } + } + } else { + logger.Debug().Msg("Unable to list files under the .upsun directory") + } + } else { + logger.Debug().Msg("No .upsun directory found") } + logger.Debug().Msg("No DB configured") + return "", "", "" +} +func extractCloudDatabaseType(services serviceConfigs) (string, string, error) { dbName := "" dbVersion := "" for _, service := range services { diff --git a/local/platformsh/generator/commands.go b/local/platformsh/generator/commands.go index 21af685f..b99a16a0 100644 --- a/local/platformsh/generator/commands.go +++ b/local/platformsh/generator/commands.go @@ -1,9 +1,29 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package main import ( "bytes" "encoding/json" "fmt" + "go/format" "os" "os/exec" "sort" @@ -11,44 +31,11 @@ import ( "text/template" "github.com/mitchellh/go-homedir" - "github.com/pkg/errors" "github.com/symfony-cli/console" "github.com/symfony-cli/symfony-cli/local/platformsh" + "github.com/symfony-cli/symfony-cli/symfony" ) -type application struct { - Namespaces []namespace - Commands []command -} - -type namespace struct { - ID string - Commands []string -} - -type command struct { - Name string - Usage []string - Description string - Help string - Definition definition - Hidden bool - Aliases []string -} - -type definition struct { - Arguments map[string]argument - Options map[string]option -} - -type argument struct { -} - -type option struct { - Shortcut string - Default interface{} -} - var commandsTemplate = template.Must(template.New("output").Parse(`// Code generated by platformsh/generator/main.go // DO NOT EDIT @@ -107,25 +94,21 @@ func generateCommands() { if err != nil { panic(err) } - f.Write(buf.Bytes()) + source, err := format.Source(buf.Bytes()) + if err != nil { + panic(err) + } + f.Write(source) } func parseCommands(cloudPath string) (string, error) { - var buf bytes.Buffer - var bufErr bytes.Buffer - cmd := exec.Command(cloudPath, "list", "--format=json", "--all") - cmd.Stdout = &buf - cmd.Stderr = &bufErr - if err := cmd.Run(); err != nil { - return "", errors.Errorf("unable to list commands: %s\n%s\n%s", err, bufErr.String(), buf.String()) + wd, err := os.Getwd() + if err != nil { + return "", err } - - // Fix PHP types - cleanOutput := bytes.ReplaceAll(buf.Bytes(), []byte(`"arguments":[]`), []byte(`"arguments":{}`)) - - var definition application - if err := json.Unmarshal(cleanOutput, &definition); err != nil { + cliApp, err := symfony.NewGoCliApp(wd, cloudPath, []string{"--all"}) + if err != nil { return "", err } @@ -147,7 +130,7 @@ func parseCommands(cloudPath string) (string, error) { excludedOptions = append(excludedOptions, console.VersionFlag.Names()...) definitionAsString := "" - for _, command := range definition.Commands { + for _, command := range cliApp.Commands { if strings.Contains(command.Description, "deprecated") || strings.Contains(command.Description, "DEPRECATED") { continue } @@ -162,7 +145,7 @@ func parseCommands(cloudPath string) (string, error) { } namespace := "cloud" loop: - for _, n := range definition.Namespaces { + for _, n := range cliApp.Namespaces { for _, name := range n.Commands { if name == command.Name { if n.ID != "_global" { @@ -197,7 +180,7 @@ func parseCommands(cloudPath string) (string, error) { } aliasesAsString := "" if len(aliases) > 0 { - aliasesAsString += "\n\t\tAliases: []*console.Alias{\n" + aliasesAsString += "\n\t\tAliases: []*console.Alias{\n" for _, alias := range aliases { aliasesAsString += "\t\t\t" + alias + ",\n" } @@ -205,7 +188,7 @@ func parseCommands(cloudPath string) (string, error) { } hide := "" if command.Hidden { - hide = "\n\t\tHidden: console.Hide," + hide = "\n\t\tHidden: console.Hide," } optionNames := make([]string, 0, len(command.Definition.Options)) @@ -251,7 +234,7 @@ func parseCommands(cloudPath string) (string, error) { } flagsAsString := "" if len(flags) > 0 { - flagsAsString += "\n\t\tFlags: []console.Flag{\n" + flagsAsString += "\n\t\tFlags: []console.Flag{\n" for _, flag := range flags { flagsAsString += "\t\t\t" + flag + ",\n" } @@ -261,8 +244,8 @@ func parseCommands(cloudPath string) (string, error) { command.Description = strings.ReplaceAll(command.Description, "Platform.sh", "Platform.sh/Upsun") definitionAsString += fmt.Sprintf(` { Category: "%s", - Name: "%s",%s - Usage: %#v,%s%s + Name: "%s",%s + Usage: %#v,%s%s }, `, namespace, name, aliasesAsString, command.Description, hide, flagsAsString) } @@ -282,7 +265,7 @@ func getCommandAliases(name, cloudPath string) ([]string, error) { return []string{}, nil //return nil, errors.Errorf("unable to get definition for command %s: %s\n%s\n%s", name, err, bufErr.String(), buf.String()) } - var cmd command + var cmd symfony.CliCommand if err := json.Unmarshal(buf.Bytes(), &cmd); err != nil { return nil, err } diff --git a/local/platformsh/generator/config.go b/local/platformsh/generator/config.go index eaa770be..851eb8da 100644 --- a/local/platformsh/generator/config.go +++ b/local/platformsh/generator/config.go @@ -1,9 +1,29 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package main import ( "bytes" "encoding/json" "fmt" + "go/format" "io" "net/http" "os" @@ -82,7 +102,11 @@ func generateConfig() { if err != nil { panic(err) } - f.Write(buf.Bytes()) + source, err := format.Source(buf.Bytes()) + if err != nil { + panic(err) + } + f.Write(source) } func parseServices() (string, error) { @@ -126,7 +150,7 @@ func parseServices() (string, error) { servicesAsString += "\t\t\tDeprecated: []string{},\n" } if len(supportedVersions) > 0 { - servicesAsString += fmt.Sprintf("\t\t\tSupported: []string{\"%s\"},\n", strings.Join(supportedVersions, "\", \"")) + servicesAsString += fmt.Sprintf("\t\t\tSupported: []string{\"%s\"},\n", strings.Join(supportedVersions, "\", \"")) } else { servicesAsString += "\t\t\tSupported: []string{},\n" } @@ -195,25 +219,6 @@ func parsePHPExtensions() (string, error) { return extsAsString, nil } -func parseLine(line string) (string, []string) { - next := strings.Index(line[1:], "|") + 1 - name := strings.TrimSpace(line[1:next]) - var versions []string - for { - current := next + 1 - nextIndex := strings.Index(line[current:], "|") - if nextIndex == -1 { - break - } - next = nextIndex + current - versions = append(versions, strings.TrimSpace(line[current:next])) - if next >= len(line) { - break - } - } - return name, versions -} - func sortVersions(versions []string) ([]string, error) { parsedVersions := make([]*version.Version, len(versions)) for i, raw := range versions { diff --git a/local/platformsh/project.go b/local/platformsh/project.go index b9ff4c98..cffd7464 100644 --- a/local/platformsh/project.go +++ b/local/platformsh/project.go @@ -136,7 +136,6 @@ func getProjectIDFromGitConfig(brand CloudBrand, projectRoot string, debug bool) if len(matches) > 1 { return string(matches[1]) } - return "" } if debug { fmt.Fprintf(os.Stderr, "ERROR: unable to read the git config file\n") diff --git a/local/process/listener.go b/local/process/listener.go index 531b2856..a5b21368 100644 --- a/local/process/listener.go +++ b/local/process/listener.go @@ -20,8 +20,8 @@ package process import ( + "fmt" "net" - "strconv" "github.com/pkg/errors" ) @@ -29,7 +29,7 @@ import ( // CreateListener creates a listener on a port // Pass a preferred port (will increment by 1 if port is not available) // or pass 0 to auto-find any available port -func CreateListener(port, preferredPort int) (net.Listener, int, error) { +func CreateListener(listenIp string, port, preferredPort int) (net.Listener, int, error) { var ln net.Listener var err error tryPort := preferredPort @@ -40,11 +40,11 @@ func CreateListener(port, preferredPort int) (net.Listener, int, error) { } for { // we really want to test availability on 127.0.0.1 - ln, err = net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(tryPort)) + ln, err = net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", tryPort)) if err == nil { ln.Close() // but then, we want to listen to as many local IP's as possible - ln, err = net.Listen("tcp", ":"+strconv.Itoa(tryPort)) + ln, err = net.Listen("tcp", fmt.Sprintf("%s:%d", listenIp, tryPort)) if err == nil { break } diff --git a/local/project/config.go b/local/project/config.go index 0ea217bf..82049342 100644 --- a/local/project/config.go +++ b/local/project/config.go @@ -35,6 +35,7 @@ const DockerComposeWorkerKey = "docker_compose" type Config struct { HomeDir string ProjectDir string + ListenIp string DocumentRoot string `yaml:"document_root"` Passthru string `yaml:"passthru"` Port int `yaml:"port"` @@ -48,6 +49,7 @@ type Config struct { UseGzip bool `yaml:"use_gzip"` TlsKeyLogFile string `yaml:"tls_key_log_file"` NoWorkers bool `yaml:"no_workers"` + AllowCORS bool `yaml:"allow_cors"` } type FileConfig struct { @@ -83,6 +85,11 @@ func NewConfigFromContext(c *console.Context, projectDir string) (*Config, *File } config.AppVersion = c.App.Version config.ProjectDir = projectDir + if c.IsSet("allow-all-ip") { + config.ListenIp = "" + } else { + config.ListenIp = c.String("listen-ip") + } if c.IsSet("document-root") { config.DocumentRoot = c.String("document-root") } @@ -116,6 +123,9 @@ func NewConfigFromContext(c *console.Context, projectDir string) (*Config, *File if c.IsSet("no-workers") { config.NoWorkers = c.Bool("no-workers") } + if c.IsSet("allow-cors") { + config.AllowCORS = c.Bool("allow-cors") + } return config, fileConfig, nil } diff --git a/local/project/project.go b/local/project/project.go index a9605c65..ac179b12 100644 --- a/local/project/project.go +++ b/local/project/project.go @@ -34,11 +34,9 @@ import ( // Project represents a PHP project type Project struct { - HTTP *lhttp.Server - PHPServer *php.Server - Logger zerolog.Logger - homeDir string - projectDir string + HTTP *lhttp.Server + PHPServer *php.Server + Logger zerolog.Logger } // New creates a new PHP project @@ -49,19 +47,19 @@ func New(c *Config) (*Project, error) { } passthru, err := realPassthru(documentRoot, c.Passthru) p := &Project{ - Logger: c.Logger.With().Str("source", "HTTP").Logger(), - homeDir: c.HomeDir, - projectDir: c.ProjectDir, + Logger: c.Logger.With().Str("source", "HTTP").Logger(), HTTP: &lhttp.Server{ DocumentRoot: documentRoot, Port: c.Port, PreferredPort: c.PreferredPort, + ListenIp: c.ListenIp, Logger: c.Logger, PKCS12: c.PKCS12, AllowHTTP: c.AllowHTTP, UseGzip: c.UseGzip, Appversion: c.AppVersion, TlsKeyLogFile: c.TlsKeyLogFile, + AllowCORS: c.AllowCORS, }, } if err != nil { diff --git a/local/proxy/config.go b/local/proxy/config.go index 60b53179..d5db1627 100644 --- a/local/proxy/config.go +++ b/local/proxy/config.go @@ -158,6 +158,23 @@ func (c *Config) GetDomains(dir string) []string { return domains } +func (c *Config) GetReachableDomains(dir string) []string { + c.mu.Lock() + defer c.mu.Unlock() + domains := []string{} + for domain, d := range c.domains { + // domain is defined using a wildcard: we don't know the exact domain, + // so we can't use it directly as-is to reach the project + if strings.Contains(domain, "*") { + continue + } + if d == dir { + domains = append(domains, domain+"."+c.TLD) + } + } + return domains +} + func (c *Config) SetDomains(domains map[string]string) { c.mu.Lock() c.domains = domains diff --git a/local/proxy/config_test.go b/local/proxy/config_test.go index 73df9628..ebad7bf3 100644 --- a/local/proxy/config_test.go +++ b/local/proxy/config_test.go @@ -43,3 +43,16 @@ func (s *ProxySuite) TestGetDir(c *C) { c.Assert(p.GetDir("foo.symfony.com"), Equals, "any_symfony_com") c.Assert(p.GetDir("foo.live.symfony.com"), Equals, "any_live_symfony_com") } + +func (s *ProxySuite) TestGetReachableDomains(c *C) { + p := &Config{ + TLD: "wip", + domains: map[string]string{ + "*.symfony": "symfony_com", + "symfony": "symfony_com", + "custom.*.symfony": "symfony_com", + "*.live.symfony": "symfony_com", + }, + } + c.Assert(p.GetReachableDomains("symfony_com"), DeepEquals, []string{"symfony.wip"}) +} diff --git a/local/proxy/proxy.go b/local/proxy/proxy.go index c66b9e22..50bfc571 100644 --- a/local/proxy/proxy.go +++ b/local/proxy/proxy.go @@ -54,12 +54,12 @@ func tlsToLocalWebServer(proxy *goproxy.ProxyHttpServer, tlsConfig *tls.Config, ctx.Warnf("Error closing client connection: %s", err) } } - connectDial := func(proxy *goproxy.ProxyHttpServer, network, addr string) (c net.Conn, err error) { - if proxy.ConnectDial != nil { + connectDial := func(ctx *goproxy.ProxyCtx, network, addr string) (c net.Conn, err error) { + if ctx.Proxy.ConnectDial != nil { return proxy.ConnectDial(network, addr) } - if proxy.Tr.Dial != nil { - return proxy.Tr.Dial(network, addr) + if ctx.Proxy.Tr.DialContext != nil { + return proxy.Tr.DialContext(ctx.Req.Context(), network, addr) } return net.Dial(network, addr) } @@ -91,7 +91,7 @@ func tlsToLocalWebServer(proxy *goproxy.ProxyHttpServer, tlsConfig *tls.Config, } ctx.Logf("Assuming CONNECT is TLS, TLS proxying it") - targetSiteCon, err := connectDial(proxy, "tcp", fmt.Sprintf("127.0.0.1:%d", localPort)) + targetSiteCon, err := connectDial(ctx, "tcp", fmt.Sprintf("127.0.0.1:%d", localPort)) if err != nil { httpError(proxyClientTls, ctx, err) if targetSiteCon != nil { diff --git a/local/runner.go b/local/runner.go index b67ee30c..aa24bdc2 100644 --- a/local/runner.go +++ b/local/runner.go @@ -32,6 +32,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/rs/zerolog" "github.com/symfony-cli/console" "github.com/symfony-cli/symfony-cli/inotify" "github.com/symfony-cli/symfony-cli/local/pid" @@ -80,6 +81,12 @@ func NewRunner(pidFile *pid.PidFile, mode runnerMode) (*Runner, error) { } func (r *Runner) Run() error { + lw, err := r.pidFile.LogWriter() + if err != nil { + return err + } + logger := zerolog.New(lw).With().Str("source", "runner").Str("cmd", r.pidFile.String()).Timestamp().Logger() + if r.mode == RunnerModeLoopDetached { if !reexec.IsChild() { varDir := filepath.Join(util.GetHomeDir(), "var") @@ -108,7 +115,7 @@ func (r *Runner) Run() error { cmdExitChan := make(chan error) // receives command exit status, allow to cmd.Wait() in non-blocking way restartChan := make(chan bool) // receives requests to restart the command sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Kill, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM) + signal.Notify(sigChan, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM) defer signal.Stop(sigChan) if len(r.pidFile.Watched) > 0 { @@ -126,7 +133,7 @@ func (r *Runner) Run() error { continue } - terminal.Logger.Debug().Msg("Got event: " + event.Event().String()) + logger.Debug().Msg("Got event: " + event.Event().String()) select { case restartChan <- true: @@ -139,10 +146,10 @@ func (r *Runner) Run() error { if fi, err := os.Stat(watched); err != nil { continue } else if fi.IsDir() { - terminal.Logger.Info().Msg("Watching directory " + watched) + logger.Info().Msg("Watching directory " + watched) watched = filepath.Join(watched, "...") } else { - terminal.Logger.Info().Msg("Watching file " + watched) + logger.Info().Msg("Watching file " + watched) } if err := inotify.Watch(watched, c, inotify.All); err != nil { return errors.Wrapf(err, `could not watch "%s"`, watched) @@ -178,9 +185,10 @@ func (r *Runner) Run() error { if r.mode == RunnerModeLoopDetached { reexec.NotifyForeground("started") } - + logger.Debug().Msg("Waiting for channels (first boot)") select { case err := <-cmdExitChan: + logger.Debug().Msg("Received exit (first boot)") if err != nil { return errors.Wrapf(err, `command "%s" failed early`, r.pidFile) } @@ -191,6 +199,7 @@ func (r *Runner) Run() error { // finished later one go func() { cmdExitChan <- err }() case <-timer.C: + logger.Debug().Msg("Received timer message (first boot)") } } @@ -211,13 +220,14 @@ func (r *Runner) Run() error { select { case sig := <-sigChan: - terminal.Logger.Info().Msgf("Signal \"%s\" received, forwarding to command and exiting\n", sig) + logger.Info().Msgf("Signal \"%s\" received, forwarding and exiting\n", sig) err := cmd.Process.Signal(sig) if err != nil && runtime.GOOS == "windows" && strings.Contains(err.Error(), "not supported by windows") { return exec.Command("CMD", "/C", "TASKKILL", "/F", "/PID", strconv.Itoa(cmd.Process.Pid)).Run() } return err case <-restartChan: + logger.Debug().Msg("Received restart") // We use SIGTERM here because it's nicer and thus when we use our // wrappers, signal will be nicely forwarded cmd.Process.Signal(syscall.SIGTERM) @@ -225,9 +235,9 @@ func (r *Runner) Run() error { <-cmdExitChan // Command exited case err := <-cmdExitChan: - err = errors.Wrapf(err, `command "%s" failed`, r.pidFile) - + logger.Debug().Msg("Received exit") if err == nil && r.SuccessHook != nil { + logger.Debug().Msg("Running success hook") r.SuccessHook(r, cmd) } @@ -235,40 +245,33 @@ func (r *Runner) Run() error { // if the command is successful if !looping { if err != nil { + logger.Debug().Msg("Not looping, exiting with error") return err } + logger.Debug().Msg("Removing pid file") return r.pidFile.Remove() } - // Command is set up to restart on exit (usually PHP builtin - // server), so we restart immediately without waiting + // Command is set up to restart on exit (usually PHP builtin server) if r.AlwaysRestartOnExit { - terminal.Logger.Error().Msgf(`command "%s" exited, restarting it immediately`, r.pidFile) + logger.Debug().Msg("Looping") + // In case of error we want to wait up-to 5 seconds before + // restarting the command, this avoids overloading the system with a + // failing command + if err != nil { + logger.Error().Msgf(`command exited: %s, waiting 5 seconds before restarting it`, err) + timer.Reset(5 * time.Second) + } else { + logger.Error().Msg("command exited, restarting it immediately") + } continue } - // In case of error we want to wait up-to 5 seconds before - // restarting the command, this avoids overloading the system with a - // failing command - if err != nil { - terminal.Logger.Error().Msgf("%s, waiting 5 seconds before restarting it", err) - timer.Reset(5 * time.Second) - } - - // Wait for a timer to expire or a file to be changed to restart - // or a signal to be received to exit - select { - case sig := <-sigChan: - terminal.Logger.Info().Msgf(`Signal "%s" received, exiting`, sig) - return nil - case <-restartChan: - timer.Stop() - case <-timer.C: - } + return nil } - terminal.Logger.Info().Msgf(`Restarting command "%s"`, r.pidFile) + logger.Info().Msg("Restarting command") } } @@ -277,7 +280,7 @@ func (r *Runner) buildCmd() (*exec.Cmd, error) { cmd.Env = os.Environ() cmd.Dir = r.pidFile.Dir - if err := buildCmd(cmd); err != nil { + if err := buildCmd(cmd, r.mode == RunnerModeOnce && terminal.Stdin.IsInteractive()); err != nil { return nil, err } diff --git a/local/runner_posix.go b/local/runner_posix.go index a19321c2..80af5da5 100644 --- a/local/runner_posix.go +++ b/local/runner_posix.go @@ -1,6 +1,25 @@ //go:build !windows // +build !windows +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package local import ( @@ -8,11 +27,12 @@ import ( "syscall" ) -func buildCmd(cmd *exec.Cmd) error { +func buildCmd(cmd *exec.Cmd, foreground bool) error { cmd.SysProcAttr = &syscall.SysProcAttr{ // isolate each command in a new process group that we can cleanly send // signal to when we want to stop it - Setpgid: true, + Setpgid: true, + Foreground: foreground, } return nil diff --git a/local/runner_windows.go b/local/runner_windows.go index 46fe4438..868cae6c 100644 --- a/local/runner_windows.go +++ b/local/runner_windows.go @@ -1,7 +1,26 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package local import "os/exec" -func buildCmd(*exec.Cmd) error { +func buildCmd(*exec.Cmd, bool) error { return nil } diff --git a/main.go b/main.go index 9f6ba7f3..6497ce2b 100644 --- a/main.go +++ b/main.go @@ -23,11 +23,9 @@ package main import ( "fmt" - "io" "os" "time" - "github.com/rs/zerolog" "github.com/symfony-cli/console" "github.com/symfony-cli/symfony-cli/commands" "github.com/symfony-cli/symfony-cli/local/php" @@ -52,6 +50,10 @@ func getCliExtraEnv() []string { } func main() { + if os.Getenv("SC_DEBUG") == "1" { + terminal.SetLogLevel(5) + } + args := os.Args name := console.CurrentBinaryName() // called via "php"? @@ -66,27 +68,30 @@ func main() { BinName: args[1], Args: args[1:], ExtraEnv: getCliExtraEnv(), + Logger: terminal.Logger, } os.Exit(e.Execute(true)) } // called via "symfony console"? if len(args) >= 2 && args[1] == "console" { - args[1] = "bin/console" - if _, err := os.Stat("app/console"); err == nil { - args[1] = "app/console" - } - e := &php.Executor{ - BinName: "php", - Args: args, - ExtraEnv: getCliExtraEnv(), + if executor, err := php.SymfonyConsoleExecutor(terminal.Logger, args[2:]); err == nil { + executor.ExtraEnv = getCliExtraEnv() + os.Exit(executor.Execute(false)) } - os.Exit(e.Execute(false)) } - // called via "symfony composer"? - if len(args) >= 2 && args[1] == "composer" { - res := php.Composer("", args[2:], getCliExtraEnv(), os.Stdout, os.Stderr, io.Discard, zerolog.Nop()) - terminal.Eprintln(res.Error()) - os.Exit(res.ExitCode()) + // called via "symfony composer" or "symfony pie"? + if len(args) >= 2 { + if args[1] == "composer" { + res := php.Composer("", args[2:], getCliExtraEnv(), os.Stdout, os.Stderr, os.Stderr, terminal.Logger) + terminal.Eprintln(res.Error()) + os.Exit(res.ExitCode()) + } + + if args[1] == "pie" { + res := php.Pie("", args[2:], getCliExtraEnv(), os.Stdout, os.Stderr, os.Stderr, terminal.Logger) + terminal.Eprintln(res.Error()) + os.Exit(res.ExitCode()) + } } for _, env := range []string{"BRANCH", "ENV", "APPLICATION_NAME"} { diff --git a/reexec/reexec.go b/reexec/reexec.go index cabcdfa6..b1649672 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -85,6 +85,7 @@ func ExecBinaryWithEnv(binary string, envs []string) bool { } func Background(homeDir string) error { + terminal.Logger.Debug().Str("source", "reexec").Msg("let's go to the background!") if util.IsGoRun() { return errors.New("Not applicable in a Go run context") } @@ -116,7 +117,6 @@ func Background(homeDir string) error { os.Setenv("REEXEC_WATCH_PID", shellPID) } - terminal.Logger.Debug().Msg("Let's go to the background!") p, err := Respawn() if err != nil { return errors.Wrap(err, "Could not respawn") @@ -157,14 +157,13 @@ func Background(homeDir string) error { // end-up receiving a status in statusCh so no particular // processing to do here. case event := <-watcherChan: - terminal.Logger.Info().Msg("FS event received: " + event.Event().String()) + terminal.Logger.Debug().Str("source", "reexec").Msg("FS event received: " + event.Event().String()) if event.Event() == notify.Remove { return nil } if event.Event() == notify.Write { ticker.Stop() - break } case status := <-statusCh: return console.Exit("", status) @@ -176,6 +175,7 @@ func Background(homeDir string) error { } func NotifyForeground(status string) error { + terminal.Logger.Debug().Str("source", "reexec").Msg("notify foreground") if !IsChild() { return nil } @@ -195,6 +195,7 @@ func NotifyForeground(status string) error { } func WatchParent(stopCh chan bool) error { + terminal.Logger.Debug().Str("source", "reexec").Msg("watch parent") spid := os.Getenv("REEXEC_WATCH_PID") if spid == "" { return nil @@ -223,6 +224,7 @@ func WatchParent(stopCh chan bool) error { } func Restart(postRespawn func()) error { + terminal.Logger.Debug().Str("source", "reexec").Msg("restart") if err := os.Setenv("REEXEC_PPID", fmt.Sprint(os.Getpid())); nil != err { return errors.WithStack(err) } @@ -280,6 +282,7 @@ func Restart(postRespawn func()) error { } func Respawn() (*os.Process, error) { + terminal.Logger.Debug().Str("source", "reexec").Msg("respawn") argv0, err := console.CurrentBinaryPath() if err != nil { return nil, err diff --git a/symfony/cli.go b/symfony/cli.go new file mode 100644 index 00000000..b7130a25 --- /dev/null +++ b/symfony/cli.go @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package symfony + +import ( + "bytes" + "encoding/json" + "fmt" + "os/exec" + "strings" + + "github.com/pkg/errors" + "github.com/symfony-cli/symfony-cli/local/php" +) + +type CliApp struct { + Commands []CliCommand + Namespaces []CliNamespace +} + +type CliNamespace struct { + ID string + Commands []string +} + +type CliCommand struct { + Name string + Usage []string + Description string + Help string + Definition CliDefinition + Hidden bool + Aliases []string +} + +type CliDefinition struct { + Arguments map[string]CliArgument + Options map[string]CliOption +} + +type CliArgument struct { + Required bool `json:"is_required"` + IsArray bool `json:"is_array"` + Description string `json:"description"` + Default interface{} `json:"default"` +} + +type CliOption struct { + Shortcut string `json:"shortcut"` + Description string `json:"description"` + AcceptValue bool `json:"accept_value"` + IsValueRequired bool `json:"is_value_required"` + IsMultiple bool `json:"is_multiple"` + Default interface{} `json:"default"` +} + +func NewCliApp(projectDir string, args []string) (*CliApp, error) { + args = append(args, "list", "--format=json") + var buf bytes.Buffer + e := &php.Executor{ + BinName: "php", + Dir: projectDir, + Args: args, + Stdout: &buf, + Stderr: &buf, + } + if ret := e.Execute(false); ret != 0 { + return nil, errors.Errorf("unable to list commands (%s):\n%s", strings.Join(args, " "), buf.String()) + } + return parseCommands(buf.Bytes()) +} + +func NewGoCliApp(projectDir string, binPath string, args []string) (*CliApp, error) { + var buf bytes.Buffer + cmd := exec.Command(binPath, "list", "--format=json") + cmd.Args = append(cmd.Args, args...) + fmt.Println(cmd.Args) + cmd.Dir = projectDir + cmd.Stdout = &buf + cmd.Stderr = &buf + if err := cmd.Run(); err != nil { + return nil, errors.Errorf("unable to list commands (%s):\n%s\n%s", strings.Join(args, " "), err, buf.String()) + } + return parseCommands(buf.Bytes()) +} + +func parseCommands(output []byte) (*CliApp, error) { + // Fix PHP types + cleanOutput := bytes.ReplaceAll(output, []byte(`"arguments":[]`), []byte(`"arguments":{}`)) + var app *CliApp + if err := json.Unmarshal(cleanOutput, &app); err != nil { + return nil, err + } + return app, nil +}